Skip to content

Commit

Permalink
Improve the implementation of force_latest_compatible_version
Browse files Browse the repository at this point in the history
  • Loading branch information
DilumAluthge committed Apr 30, 2021
1 parent 06adf29 commit 00bfbb2
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 103 deletions.
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=DEFAULT_IO[], 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
107 changes: 58 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,32 @@ 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

if force_latest_compatible_version
reset_all_compat!(temp_ctx.env.project)
end

# Absolutify stdlibs paths
for (uuid, entry) in temp_ctx.env.manifest
if is_stdlib(uuid)
Expand All @@ -1456,17 +1480,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 @@ -1813,64 +1826,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

0 comments on commit 00bfbb2

Please sign in to comment.