Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve the implementation of force_latest_compatible_version #2541

Merged
merged 1 commit into from
May 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions src/API.jl
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,9 @@ end

function up(ctx::Context, pkgs::Vector{PackageSpec};
level::UpgradeLevel=UPLEVEL_MAJOR, mode::PackageMode=PKGMODE_PROJECT,
update_registry::Bool=true, kwargs...)
update_registry::Bool=true,
skip_writing_project::Bool=false,
kwargs...)
Context!(ctx; kwargs...)
if update_registry
Registry.download_default_registries(ctx.io)
Expand All @@ -328,13 +330,13 @@ function up(ctx::Context, pkgs::Vector{PackageSpec};
manifest_resolve!(ctx.env.manifest, pkgs)
ensure_resolved(ctx.env.manifest, pkgs)
end
Operations.up(ctx, pkgs, level)
Operations.up(ctx, pkgs, level; skip_writing_project)
return
end

resolve(; io::IO=stderr_f(), kwargs...) = resolve(Context(;io); kwargs...)
function resolve(ctx::Context; kwargs...)
up(ctx; level=UPLEVEL_FIXED, mode=PKGMODE_MANIFEST, update_registry=false, kwargs...)
function resolve(ctx::Context; skip_writing_project::Bool=false, kwargs...)
up(ctx; level=UPLEVEL_FIXED, mode=PKGMODE_MANIFEST, update_registry=false, skip_writing_project, kwargs...)
return nothing
end

Expand Down
105 changes: 56 additions & 49 deletions src/Operations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,16 @@ function set_compat(proj::Project, name::String, compat::String)
proj.compat[name] = Types.Compat(Types.semver_spec(compat), compat)
end

function reset_all_compat!(proj::Project)
for name in keys(proj.compat)
compat = proj.compat[name]
if compat.val != Types.semver_spec(compat.str)
proj.compat[name] = Types.Compat(Types.semver_spec(compat.str), compat.str)
end
end
return nothing
end

function collect_project!(pkg::PackageSpec, path::String,
deps_map::Dict{UUID,Vector{PackageSpec}})
deps_map[pkg.uuid] = PackageSpec[]
Expand Down Expand Up @@ -1218,7 +1228,8 @@ function up_load_manifest_info!(pkg::PackageSpec, entry::PackageEntry)
# `pkg.version` and `pkg.tree_hash` is set by `up_load_versions!`
end

function up(ctx::Context, pkgs::Vector{PackageSpec}, level::UpgradeLevel)
function up(ctx::Context, pkgs::Vector{PackageSpec}, level::UpgradeLevel;
skip_writing_project::Bool=false)
new_git = Set{UUID}()
# TODO check all pkg.version == VersionSpec()
# set version constraints according to `level`
Expand All @@ -1236,7 +1247,7 @@ function up(ctx::Context, pkgs::Vector{PackageSpec}, level::UpgradeLevel)
update_manifest!(ctx.env, pkgs, deps_map, ctx.julia_version)
new_apply = download_source(ctx)
download_artifacts(ctx.env, julia_version=ctx.julia_version, io=ctx.io)
write_env(ctx.env) # write env before building
write_env(ctx.env; skip_writing_project) # write env before building
show_update(ctx.env; io=ctx.io)
build_versions(ctx, union(new_apply, new_git))
end
Expand Down Expand Up @@ -1435,19 +1446,30 @@ function sandbox(fn::Function, ctx::Context, target::PackageSpec, target_path::S
with_temp_env(tmp) do
temp_ctx = Context()
temp_ctx.env.project.deps[target.name] = target.uuid

if force_latest_compatible_version
apply_force_latest_compatible_version!(
temp_ctx;
target_name = target.name,
allow_earlier_backwards_compatible_versions,
)
end

try
Pkg.resolve(temp_ctx; io=devnull)
Pkg.resolve(temp_ctx; io=devnull, skip_writing_project=true)
@debug "Using _parent_ dep graph"
catch err# TODO
err isa Resolve.ResolverError || rethrow()
allow_reresolve || rethrow()
@debug err
@warn "Could not use exact versions of packages in manifest, re-resolving"
temp_ctx.env.manifest = Dict(uuid => entry for (uuid, entry) in temp_ctx.env.manifest if isfixed(entry))
Pkg.resolve(temp_ctx; io=devnull)
Pkg.resolve(temp_ctx; io=devnull, skip_writing_project=true)
@debug "Using _clean_ dep graph"
end

reset_all_compat!(temp_ctx.env.project)

# Absolutify stdlibs paths
for (uuid, entry) in temp_ctx.env.manifest
if is_stdlib(uuid)
Expand All @@ -1456,17 +1478,6 @@ function sandbox(fn::Function, ctx::Context, target::PackageSpec, target_path::S
end
write_env(temp_ctx.env, update_undo = false)

if force_latest_compatible_version
result = check_force_latest_compatible_version(
temp_ctx;
target_name = target.name,
allow_earlier_backwards_compatible_versions,
)
if !result
pkgerror("One or more direct dependencies is not at the latest compatible version")
end
end

# Run sandboxed code
path_sep = Sys.iswindows() ? ';' : ':'
withenv(fn, "JULIA_LOAD_PATH" => "@$(path_sep)$(tmp)", "JULIA_PROJECT" => nothing)
Expand Down Expand Up @@ -1814,64 +1825,60 @@ function status(env::EnvCache, pkgs::Vector{PackageSpec}=PackageSpec[];
end
end

function check_force_latest_compatible_version(ctx::Types.Context;
target_name = nothing,
allow_earlier_backwards_compatible_versions::Bool = true)
function apply_force_latest_compatible_version!(ctx::Types.Context;
target_name = nothing,
allow_earlier_backwards_compatible_versions::Bool = true)
direct_deps = load_direct_deps(ctx.env)
direct_deps_uuids = [dep.uuid for dep in direct_deps]
uuid_list = filter(!is_stdlib, direct_deps_uuids)
isempty(uuid_list) && return true
results = check_force_latest_compatible_version.(
Ref(ctx),
uuid_list;
target_name,
allow_earlier_backwards_compatible_versions,
)
return all(results)
for uuid in uuid_list
apply_force_latest_compatible_version!(
ctx,
uuid;
target_name,
allow_earlier_backwards_compatible_versions,
)
end
return nothing
end

function check_force_latest_compatible_version(ctx::Types.Context,
uuid::Base.UUID;
target_name= nothing,
allow_earlier_backwards_compatible_versions::Bool = true)
function apply_force_latest_compatible_version!(ctx::Types.Context,
uuid::Base.UUID;
target_name= nothing,
allow_earlier_backwards_compatible_versions::Bool = true)
dep = ctx.env.manifest[uuid]
name = dep.name
active_version = dep.version
has_compat = haskey(ctx.env.project.compat, name)
if !has_compat
if name != target_name
@warn(
"Package does not have a [compat] entry",
"Dependency does not have a [compat] entry",
name, uuid, active_version, target_name,
)
end
return true
return nothing
end
compat_entry = ctx.env.project.compat[name].val
old_compat_spec = ctx.env.project.compat[name].val
latest_compatible_version = get_latest_compatible_version(
ctx,
uuid,
compat_entry,
old_compat_spec,
)
earliest_backwards_compatible_version = get_earliest_backwards_compatible_version(latest_compatible_version)
if allow_earlier_backwards_compatible_versions
result = active_version >= earliest_backwards_compatible_version
version_for_intersect = only_major_minor_patch(earliest_backwards_compatible_version)
else
result = active_version >= latest_compatible_version
end
if !result
@error(
"Package is not at the latest compatible version",
name,
uuid,
compat_entry,
active_version,
latest_compatible_version,
earliest_backwards_compatible_version,
allow_earlier_backwards_compatible_versions,
)
version_for_intersect = only_major_minor_patch(latest_compatible_version)
end
return result
compat_for_intersect = Pkg.Types.semver_spec("≥ $(version_for_intersect)")
new_compat_spec = Base.intersect(old_compat_spec, compat_for_intersect)
ctx.env.project.compat[name].val = new_compat_spec
return nothing
end

function only_major_minor_patch(ver::Base.VersionNumber)
return Base.VersionNumber(ver.major, ver.minor, ver.patch)
end

function get_earliest_backwards_compatible_version(ver::Base.VersionNumber)
Expand Down
5 changes: 3 additions & 2 deletions src/Types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -932,8 +932,9 @@ manifest_info(::Manifest, uuid::Nothing) = nothing
function manifest_info(manifest::Manifest, uuid::UUID)::Union{PackageEntry,Nothing}
return get(manifest, uuid, nothing)
end
function write_env(env::EnvCache; update_undo=true)
if env.project != env.original_project
function write_env(env::EnvCache; update_undo=true,
skip_writing_project::Bool=false)
if (env.project != env.original_project) && (!skip_writing_project)
write_project(env)
end
if env.manifest != env.original_manifest
Expand Down
Loading