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

Refactor: use VersionSpec as the canonical compat representation #2480

Merged
merged 1 commit into from
Apr 2, 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
34 changes: 17 additions & 17 deletions src/Operations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,12 @@ end
#######################################
# Dependency gathering and resolution #
#######################################
get_compat(proj::Project, name::String) = haskey(proj.compat, name) ? proj.compat[name].val : Types.VersionSpec()
get_compat_str(proj::Project, name::String) = haskey(proj.compat, name) ? proj.compat[name].str : nothing
function set_compat(proj::Project, name::String, compat::String)
proj.compat[name] = Types.Compat(Types.semver_spec(compat), compat)
end

function collect_project!(pkg::PackageSpec, path::String,
deps_map::Dict{UUID,Vector{PackageSpec}})
deps_map[pkg.uuid] = PackageSpec[]
Expand All @@ -179,15 +185,15 @@ function collect_project!(pkg::PackageSpec, path::String,
pkgerror("could not find project file for package $(err_rep(pkg)) at `$path`")
end
project = read_package(project_file)
julia_compat = get(project.compat, "julia", nothing)
julia_compat = get_compat(project, "julia")
#=
# TODO, this should either error or be quiet
if julia_compat !== nothing && !(VERSION in Types.semver_spec(julia_compat))
if julia_compat !== nothing && !(VERSION in julia_compat)
println(io, "julia version requirement for package $(err_rep(pkg)) not satisfied")
end
=#
for (name, uuid) in project.deps
vspec = Types.semver_spec(get(project.compat, name, ">= 0"))
vspec = get_compat(project, name)
push!(deps_map[pkg.uuid], PackageSpec(name, uuid, vspec))
end
if project.version !== nothing
Expand Down Expand Up @@ -264,10 +270,6 @@ function collect_fixed!(env::EnvCache, pkgs::Vector{PackageSpec}, names::Dict{UU
end


function project_compatibility(env::EnvCache, name::String)
return VersionSpec(Types.semver_spec(get(env.project.compat, name, ">= 0")))
end

# Resolve a set of versions given package version specs
# looks at uuid, version, repo/path,
# sets version to a VersionNumber
Expand All @@ -276,7 +278,7 @@ end
function resolve_versions!(env::EnvCache, registries::Vector{Registry.RegistryInstance}, pkgs::Vector{PackageSpec}, julia_version)
# compatibility
if julia_version !== nothing
v = intersect(julia_version, project_compatibility(env, "julia"))
v = intersect(julia_version, get_compat(env.project, "julia"))
if isempty(v)
@warn "julia version requirement for project not satisfied" _module=nothing _file=nothing
end
Expand All @@ -300,7 +302,7 @@ function resolve_versions!(env::EnvCache, registries::Vector{Registry.RegistryIn

# check compat
for pkg in pkgs
compat = project_compatibility(env, pkg.name)
compat = get_compat(env.project, pkg.name)
v = intersect(pkg.version, compat)
if isempty(v)
throw(Resolve.ResolverError(
Expand Down Expand Up @@ -1432,7 +1434,6 @@ 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

try
Pkg.resolve(temp_ctx; io=devnull)
@debug "Using _parent_ dep graph"
Expand Down Expand Up @@ -1526,9 +1527,9 @@ function gen_target_project(env::EnvCache, registries::Vector{Registry.RegistryI
end
# collect compat entries
for (name, uuid) in test_project.deps
compat = get(source_env.project.compat, name, nothing)
compat = get_compat_str(source_env.project, name)
compat === nothing && continue
test_project.compat[name] = compat
set_compat(test_project, name, compat)
end
return test_project
end
Expand Down Expand Up @@ -1842,11 +1843,11 @@ function check_force_latest_compatible_version(ctx::Types.Context,
end
return true
end
compat_entry_string = ctx.env.project.compat[name]
compat_entry = ctx.env.project.compat[name].val
latest_compatible_version = get_latest_compatible_version(
ctx,
uuid,
compat_entry_string,
compat_entry,
)
earliest_backwards_compatible_version = get_earliest_backwards_compatible_version(latest_compatible_version)
if allow_earlier_backwards_compatible_versions
Expand All @@ -1859,7 +1860,7 @@ function check_force_latest_compatible_version(ctx::Types.Context,
"Package is not at the latest compatible version",
name,
uuid,
compat_entry_string,
compat_entry,
active_version,
latest_compatible_version,
earliest_backwards_compatible_version,
Expand All @@ -1877,9 +1878,8 @@ end

function get_latest_compatible_version(ctx::Types.Context,
uuid::Base.UUID,
compat_entry_string::AbstractString)
compat_spec::VersionSpec)
all_registered_versions = get_all_registered_versions(ctx, uuid)
compat_spec = Pkg.Types.semver_spec(compat_entry_string)
compatible_versions = filter(in(compat_spec), all_registered_versions)
latest_compatible_version = maximum(compatible_versions)
return latest_compatible_version
Expand Down
7 changes: 6 additions & 1 deletion src/Types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,11 @@ function find_project_file(env::Union{Nothing,String}=nothing)
return Pkg.safe_realpath(project_file)
end

Base.@kwdef mutable struct Compat
val::VersionSpec
str::String
end

Base.@kwdef mutable struct Project
other::Dict{String,Any} = Dict{String,Any}()
# Fields
Expand All @@ -206,7 +211,7 @@ Base.@kwdef mutable struct Project
deps::Dict{String,UUID} = Dict{String,UUID}()
extras::Dict{String,UUID} = Dict{String,UUID}()
targets::Dict{String,Vector{String}} = Dict{String,Vector{String}}()
compat::Dict{String,String} = Dict{String,String}()# TODO Dict{String, VersionSpec}
compat::Dict{String,Compat} = Dict{String,Compat}()
end
Base.:(==)(t1::Project, t2::Project) = all(x -> (getfield(t1, x) == getfield(t2, x))::Bool, fieldnames(Project))
Base.hash(x::Project, h::UInt) = foldr(hash, [getfield(t, x) for x in fieldnames(Project)], init=h)
Expand Down
16 changes: 12 additions & 4 deletions src/project.jl
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,17 @@ end
read_project_targets(raw, project::Project) =
pkgerror("Expected `targets` section to be a key-value list")

read_project_compat(::Nothing, project::Project) = Dict{String,Any}()
read_project_compat(::Nothing, project::Project) = Dict{String,Compat}()
function read_project_compat(raw::Dict{String,Any}, project::Project)
compat = Dict{String,Compat}()
for (name, version) in raw
try VersionSpec(semver_spec(version))
try
compat[name] = Compat(semver_spec(version), version)
catch err
pkgerror("Could not parse compatibility version for dependency `$name`")
end
end
return raw
return compat
end
read_project_compat(raw, project::Project) =
pkgerror("Expected `compat` section to be a key-value list")
Expand Down Expand Up @@ -147,6 +149,12 @@ end
function destructure(project::Project)::Dict
raw = deepcopy(project.other)

# sanity check for consistency between compat value and string representation
for (name, compat) in project.compat
@assert compat.val == semver_spec(compat.str) "inconsistency between compat values and string representation"
end

# if a field is set to its default value, don't include it in the write
should_delete(x::Dict) = isempty(x)
should_delete(x) = x === nothing
entry!(key::String, src) = should_delete(src) ? delete!(raw, key) : (raw[key] = src)
Expand All @@ -157,7 +165,7 @@ function destructure(project::Project)::Dict
entry!("manifest", project.manifest)
entry!("deps", project.deps)
entry!("extras", project.extras)
entry!("compat", project.compat)
entry!("compat", Dict(name => x.str for (name, x) in project.compat))
entry!("targets", project.targets)
return raw
end
Expand Down