543 lines
13 KiB
Julia
543 lines
13 KiB
Julia
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
|
|
|
using Base.Pkg.Types
|
|
using Base.Pkg.Query
|
|
using Base.Pkg.Resolve
|
|
using Base.Pkg.Resolve.VersionWeights
|
|
import Base.Pkg.PkgError
|
|
|
|
# Check that VersionWeight keeps the same ordering as VersionNumber
|
|
|
|
vlst = [
|
|
v"0.0.0",
|
|
v"0.0.1",
|
|
v"0.1.0",
|
|
v"0.1.1",
|
|
v"1.0.0",
|
|
v"1.0.1",
|
|
v"1.1.0",
|
|
v"1.1.1",
|
|
v"1.0.0-pre",
|
|
v"1.0.0-pre1",
|
|
v"1.0.1-pre",
|
|
v"1.0.0-0.pre.2",
|
|
v"1.0.0-0.pre.3",
|
|
v"1.0.0-0.pre1.tst",
|
|
v"1.0.0-pre.1+0.1",
|
|
v"1.0.0-pre.1+0.1plus",
|
|
v"1.0.0-pre.1-+0.1plus",
|
|
v"1.0.0-pre.1-+0.1Plus",
|
|
v"1.0.0-pre.1-+0.1pLUs",
|
|
v"1.0.0-pre.1-+0.1pluS",
|
|
v"1.0.0+0.1plus",
|
|
v"1.0.0+0.1plus-",
|
|
v"1.0.0+-",
|
|
v"1.0.0-",
|
|
v"1.0.0+",
|
|
v"1.0.0--",
|
|
v"1.0.0---",
|
|
v"1.0.0--+-",
|
|
v"1.0.0+--",
|
|
v"1.0.0+-.-",
|
|
v"1.0.0+0.-",
|
|
v"1.0.0+-.0",
|
|
v"1.0.0-a+--",
|
|
v"1.0.0-a+-.-",
|
|
v"1.0.0-a+0.-",
|
|
v"1.0.0-a+-.0"
|
|
]
|
|
|
|
for v1 in vlst, v2 in vlst
|
|
vw1 = VersionWeight(v1)
|
|
vw2 = VersionWeight(v2)
|
|
clt = v1 < v2
|
|
@test clt == (vw1 < vw2)
|
|
ceq = v1 == v2
|
|
@test ceq == (vw1 == vw2)
|
|
end
|
|
|
|
# auxiliary functions
|
|
|
|
function deps_from_data(deps_data)
|
|
deps = Dict{String,Dict{VersionNumber,Available}}()
|
|
for d in deps_data
|
|
p = d[1]; vn = d[2]; r = d[3:end]
|
|
if !haskey(deps, p)
|
|
deps[p] = Dict{VersionNumber,Available}()
|
|
end
|
|
if !haskey(deps[p], vn)
|
|
deps[p][vn] = Available("$(p)_$(vn)_sha1", Dict{String,VersionSet}())
|
|
end
|
|
isempty(r) && continue
|
|
rp = r[1]
|
|
if length(r) > 1
|
|
rvs = VersionSet(VersionNumber[r[2:end]...])
|
|
else
|
|
rvs = VersionSet()
|
|
end
|
|
deps[p][vn].requires[rp] = rvs
|
|
end
|
|
deps
|
|
end
|
|
function reqs_from_data(reqs_data)
|
|
reqs = Dict{String,VersionSet}()
|
|
for r in reqs_data
|
|
p = r[1]
|
|
reqs[p] = VersionSet(VersionNumber[r[2:end]...])
|
|
end
|
|
reqs
|
|
end
|
|
function sanity_tst(deps_data, expected_result; pkgs=[])
|
|
deps = deps_from_data(deps_data)
|
|
#println("deps=$deps")
|
|
#println()
|
|
result = sanity_check(deps, Set(String[pkgs...]))
|
|
length(result) == length(expected_result) || return false
|
|
for (p, vn, pp) in result
|
|
(p, vn) ∈ expected_result || return false
|
|
end
|
|
return true
|
|
end
|
|
sanity_tst(deps_data; kw...) = sanity_tst(deps_data, []; kw...)
|
|
|
|
function resolve_tst(deps_data, reqs_data, want_data = nothing)
|
|
deps = deps_from_data(deps_data)
|
|
reqs = reqs_from_data(reqs_data)
|
|
|
|
#println()
|
|
#println("deps=$deps")
|
|
#println("reqs=$reqs")
|
|
deps = Query.prune_dependencies(reqs, deps)
|
|
want = resolve(reqs, deps)
|
|
return want == want_data
|
|
end
|
|
|
|
## DEPENDENCY SCHEME 1: TWO PACKAGES, DAG
|
|
deps_data = Any[
|
|
["A", v"1", "B", v"1"],
|
|
["A", v"2", "B", v"2"],
|
|
["B", v"1"],
|
|
["B", v"2"]
|
|
]
|
|
|
|
@test sanity_tst(deps_data)
|
|
@test sanity_tst(deps_data, pkgs=["A", "B"])
|
|
@test sanity_tst(deps_data, pkgs=["B"])
|
|
@test sanity_tst(deps_data, pkgs=["A"])
|
|
|
|
# require just B
|
|
reqs_data = Any[
|
|
["B"]
|
|
]
|
|
|
|
want_data = Dict("B"=>v"2")
|
|
@test resolve_tst(deps_data, reqs_data, want_data)
|
|
|
|
# require just A: must bring in B
|
|
reqs_data = Any[
|
|
["A"]
|
|
]
|
|
want_data = Dict("A"=>v"2", "B"=>v"2")
|
|
@test resolve_tst(deps_data, reqs_data, want_data)
|
|
|
|
|
|
## DEPENDENCY SCHEME 2: TWO PACKAGES, CYCLIC
|
|
deps_data = Any[
|
|
["A", v"1", "B", v"2"],
|
|
["A", v"2", "B", v"1"],
|
|
["B", v"1", "A", v"2"],
|
|
["B", v"2", "A", v"1"]
|
|
]
|
|
|
|
@test sanity_tst(deps_data)
|
|
|
|
# require just A
|
|
reqs_data = Any[
|
|
["A"]
|
|
]
|
|
want_data = Dict("A"=>v"2", "B"=>v"2")
|
|
@test resolve_tst(deps_data, reqs_data, want_data)
|
|
|
|
# require just B, force lower version
|
|
reqs_data = Any[
|
|
["B", v"1", v"2"]
|
|
]
|
|
want_data = Dict("A"=>v"2", "B"=>v"1")
|
|
@test resolve_tst(deps_data, reqs_data, want_data)
|
|
|
|
# require just A, force lower version
|
|
reqs_data = Any[
|
|
["A", v"1", v"2"]
|
|
]
|
|
want_data = Dict("A"=>v"1", "B"=>v"2")
|
|
@test resolve_tst(deps_data, reqs_data, want_data)
|
|
|
|
|
|
## DEPENDENCY SCHEME 3: THREE PACKAGES, CYCLIC, TWO MUTUALLY EXCLUSIVE SOLUTIONS
|
|
deps_data = Any[
|
|
["A", v"1", "B", v"2"],
|
|
["A", v"2", "B", v"1", v"2"],
|
|
["B", v"1", "C", v"2"],
|
|
["B", v"2", "C", v"1", v"2"],
|
|
["C", v"1", "A", v"1", v"2"],
|
|
["C", v"2", "A", v"2"]
|
|
]
|
|
|
|
@test sanity_tst(deps_data)
|
|
|
|
# require just A (must choose solution which has the highest version for A)
|
|
reqs_data = Any[
|
|
["A"]
|
|
]
|
|
want_data = Dict("A"=>v"2", "B"=>v"1", "C"=>v"2")
|
|
@test resolve_tst(deps_data, reqs_data, want_data)
|
|
|
|
# require just B (must choose solution which has the highest version for B)
|
|
reqs_data = Any[
|
|
["B"]
|
|
]
|
|
want_data = Dict("A"=>v"1", "B"=>v"2", "C"=>v"1")
|
|
@test resolve_tst(deps_data, reqs_data, want_data)
|
|
|
|
# require just A, force lower version
|
|
reqs_data = Any[
|
|
["A", v"1", v"2"]
|
|
]
|
|
want_data = Dict("A"=>v"1", "B"=>v"2", "C"=>v"1")
|
|
@test resolve_tst(deps_data, reqs_data, want_data)
|
|
|
|
# require A and C, incompatible versions
|
|
reqs_data = Any[
|
|
["A", v"1", v"2"],
|
|
["C", v"2"]
|
|
]
|
|
@test_throws PkgError resolve_tst(deps_data, reqs_data)
|
|
|
|
|
|
## DEPENDENCY SCHEME 4: TWO PACKAGES, DAG, WITH TRIVIAL INCONSISTENCY
|
|
deps_data = Any[
|
|
["A", v"1", "B", v"2"],
|
|
["B", v"1"]
|
|
]
|
|
|
|
@test sanity_tst(deps_data, [("A", v"1")])
|
|
@test sanity_tst(deps_data, [("A", v"1")], pkgs=["B"])
|
|
|
|
# require B (must not give errors)
|
|
reqs_data = Any[
|
|
["B"]
|
|
]
|
|
want_data = Dict("B"=>v"1")
|
|
@test resolve_tst(deps_data, reqs_data, want_data)
|
|
|
|
|
|
## DEPENDENCY SCHEME 5: THREE PACKAGES, DAG, WITH IMPLICIT INCONSISTENCY
|
|
deps_data = Any[
|
|
["A", v"1", "B", v"2"],
|
|
["A", v"1", "C", v"2"],
|
|
["A", v"2", "B", v"1", v"2"],
|
|
["A", v"2", "C", v"1", v"2"],
|
|
["B", v"1", "C", v"2"],
|
|
["B", v"2", "C", v"2"],
|
|
["C", v"1"],
|
|
["C", v"2"]
|
|
]
|
|
|
|
@test sanity_tst(deps_data, [("A", v"2")])
|
|
@test sanity_tst(deps_data, [("A", v"2")], pkgs=["B"])
|
|
@test sanity_tst(deps_data, [("A", v"2")], pkgs=["C"])
|
|
|
|
# require A, any version (must use the highest non-inconsistent)
|
|
reqs_data = Any[
|
|
["A"]
|
|
]
|
|
want_data = Dict("A"=>v"1", "B"=>v"2", "C"=>v"2")
|
|
@test resolve_tst(deps_data, reqs_data, want_data)
|
|
|
|
# require A, force highest version (impossible)
|
|
reqs_data = Any[
|
|
["A", v"2"]
|
|
]
|
|
@test_throws PkgError resolve_tst(deps_data, reqs_data)
|
|
|
|
|
|
## DEPENDENCY SCHEME 6: TWO PACKAGES, CYCLIC, TOTALLY INCONSISTENT
|
|
deps_data = Any[
|
|
["A", v"1", "B", v"2"],
|
|
["A", v"2", "B", v"1", v"2"],
|
|
["B", v"1", "A", v"1", v"2"],
|
|
["B", v"2", "A", v"2"]
|
|
]
|
|
|
|
@test sanity_tst(deps_data, [("A", v"1"), ("A", v"2"),
|
|
("B", v"1"), ("B", v"2")])
|
|
|
|
# require A (impossible)
|
|
reqs_data = Any[
|
|
["A"]
|
|
]
|
|
@test_throws PkgError resolve_tst(deps_data, reqs_data)
|
|
|
|
# require B (impossible)
|
|
reqs_data = Any[
|
|
["B"]
|
|
]
|
|
@test_throws PkgError resolve_tst(deps_data, reqs_data)
|
|
|
|
|
|
## DEPENDENCY SCHEME 7: THREE PACKAGES, CYCLIC, WITH INCONSISTENCY
|
|
deps_data = Any[
|
|
["A", v"1", "B", v"1", v"2"],
|
|
["A", v"2", "B", v"2"],
|
|
["B", v"1", "C", v"1", v"2"],
|
|
["B", v"2", "C", v"2"],
|
|
["C", v"1", "A", v"2"],
|
|
["C", v"2", "A", v"2"],
|
|
]
|
|
|
|
@test sanity_tst(deps_data, [("A", v"1"), ("B", v"1"),
|
|
("C", v"1")])
|
|
|
|
# require A
|
|
reqs_data = Any[
|
|
["A"]
|
|
]
|
|
want_data = Dict("A"=>v"2", "B"=>v"2", "C"=>v"2")
|
|
@test resolve_tst(deps_data, reqs_data, want_data)
|
|
|
|
# require C
|
|
reqs_data = Any[
|
|
["C"]
|
|
]
|
|
want_data = Dict("A"=>v"2", "B"=>v"2", "C"=>v"2")
|
|
@test resolve_tst(deps_data, reqs_data, want_data)
|
|
|
|
# require C, lowest version (impossible)
|
|
reqs_data = Any[
|
|
["C", v"1", v"2"]
|
|
]
|
|
@test_throws PkgError resolve_tst(deps_data, reqs_data)
|
|
|
|
|
|
## DEPENDENCY SCHEME 8: THREE PACKAGES, CYCLIC, TOTALLY INCONSISTENT
|
|
deps_data = Any[
|
|
["A", v"1", "B", v"1", v"2"],
|
|
["A", v"2", "B", v"2"],
|
|
["B", v"1", "C", v"1", v"2"],
|
|
["B", v"2", "C", v"2"],
|
|
["C", v"1", "A", v"2"],
|
|
["C", v"2", "A", v"1", v"2"],
|
|
]
|
|
|
|
@test sanity_tst(deps_data, [("A", v"1"), ("A", v"2"),
|
|
("B", v"1"), ("B", v"2"),
|
|
("C", v"1"), ("C", v"2")])
|
|
|
|
# require A (impossible)
|
|
reqs_data = Any[
|
|
["A"]
|
|
]
|
|
@test_throws PkgError resolve_tst(deps_data, reqs_data)
|
|
|
|
# require B (impossible)
|
|
reqs_data = Any[
|
|
["B"]
|
|
]
|
|
@test_throws PkgError resolve_tst(deps_data, reqs_data)
|
|
|
|
# require C (impossible)
|
|
reqs_data = Any[
|
|
["C"]
|
|
]
|
|
@test_throws PkgError resolve_tst(deps_data, reqs_data)
|
|
|
|
## DEPENDENCY SCHEME 9: SIX PACKAGES, DAG
|
|
deps_data = Any[
|
|
["A", v"1"],
|
|
["A", v"2"],
|
|
["A", v"3"],
|
|
["B", v"1", "A", v"1", v"2"],
|
|
["B", v"2", "A"],
|
|
["C", v"1", "A", v"2", v"3"],
|
|
["C", v"2", "A", v"2"],
|
|
["D", v"1", "B", v"1"],
|
|
["D", v"2", "B", v"2"],
|
|
["E", v"1", "D"],
|
|
["F", v"1", "A", v"1", v"3"],
|
|
["F", v"1", "E"],
|
|
["F", v"2", "C", v"2"],
|
|
["F", v"2", "E"],
|
|
]
|
|
|
|
@test sanity_tst(deps_data)
|
|
|
|
# require just F
|
|
reqs_data = Any[
|
|
["F"]
|
|
]
|
|
want_data = Dict("A"=>v"3", "B"=>v"2", "C"=>v"2",
|
|
"D"=>v"2", "E"=>v"1", "F"=>v"2")
|
|
@test resolve_tst(deps_data, reqs_data, want_data)
|
|
|
|
# require just F, lower version
|
|
reqs_data = Any[
|
|
["F", v"1", v"2"]
|
|
]
|
|
want_data = Dict("A"=>v"2", "B"=>v"2", "D"=>v"2",
|
|
"E"=>v"1", "F"=>v"1")
|
|
@test resolve_tst(deps_data, reqs_data, want_data)
|
|
|
|
# require F and B; force lower B version -> must bring down F, A, and D versions too
|
|
reqs_data = Any[
|
|
["F"],
|
|
["B", v"1", v"2"]
|
|
]
|
|
want_data = Dict("A"=>v"1", "B"=>v"1", "D"=>v"1",
|
|
"E"=>v"1", "F"=>v"1")
|
|
@test resolve_tst(deps_data, reqs_data, want_data)
|
|
|
|
# require F and D; force lower D version -> must not bring down F version
|
|
reqs_data = Any[
|
|
["F"],
|
|
["D", v"1", v"2"]
|
|
]
|
|
want_data = Dict("A"=>v"3", "B"=>v"2", "C"=>v"2",
|
|
"D"=>v"1", "E"=>v"1", "F"=>v"2")
|
|
@test resolve_tst(deps_data, reqs_data, want_data)
|
|
|
|
# require F and C; force lower C version -> must bring down F and A versions
|
|
reqs_data = Any[
|
|
["F"],
|
|
["C", v"1", v"2"]
|
|
]
|
|
want_data = Dict("A"=>v"2", "B"=>v"2", "C"=>v"1",
|
|
"D"=>v"2", "E"=>v"1", "F"=>v"1")
|
|
@test resolve_tst(deps_data, reqs_data, want_data)
|
|
|
|
## DEPENDENCY SCHEME 10: SIX PACKAGES, DAG, WITH PRERELEASE/BUILD VERSIONS
|
|
deps_data = Any[
|
|
["A", v"1"],
|
|
["A", v"2-rc.1"],
|
|
["A", v"2-rc.1+bld"],
|
|
["A", v"2"],
|
|
["A", v"2.1.0"],
|
|
["B", v"1", "A", v"1", v"2-"],
|
|
["B", v"1.0.1-beta", "A", v"2-rc"],
|
|
["B", v"1.0.1", "A"],
|
|
["C", v"1", "A", v"2-", v"2.1"],
|
|
["C", v"1+BLD", "A", v"2-rc.1", v"2.1"],
|
|
["C", v"2", "A", v"2-rc.1"],
|
|
["D", v"1", "B", v"1"],
|
|
["D", v"2", "B", v"1.0.1-"],
|
|
["E", v"1-plztst", "D"],
|
|
["E", v"1", "D"],
|
|
["F", v"1.1", "A", v"1", v"2.1"],
|
|
["F", v"1.1", "E", v"1"],
|
|
["F", v"2-rc.1", "A", v"2-", v"2.1"],
|
|
["F", v"2-rc.1", "C", v"1"],
|
|
["F", v"2-rc.1", "E"],
|
|
["F", v"2-rc.2", "A", v"2-", v"2.1"],
|
|
["F", v"2-rc.2", "C", v"2"],
|
|
["F", v"2-rc.2", "E"],
|
|
["F", v"2", "C", v"2"],
|
|
["F", v"2", "E"],
|
|
]
|
|
|
|
@test sanity_tst(deps_data)
|
|
|
|
# require just F
|
|
reqs_data = Any[
|
|
["F"]
|
|
]
|
|
want_data = Dict("A"=>v"2.1", "B"=>v"1.0.1", "C"=>v"2",
|
|
"D"=>v"2", "E"=>v"1", "F"=>v"2")
|
|
@test resolve_tst(deps_data, reqs_data, want_data)
|
|
|
|
# require just F, lower version
|
|
reqs_data = Any[
|
|
["F", v"1", v"2-"]
|
|
]
|
|
want_data = Dict("A"=>v"2", "B"=>v"1.0.1", "D"=>v"2",
|
|
"E"=>v"1", "F"=>v"1.1")
|
|
@test resolve_tst(deps_data, reqs_data, want_data)
|
|
|
|
# require F and B; force lower B version -> must bring down F, A, and D versions too
|
|
reqs_data = Any[
|
|
["F"],
|
|
["B", v"1", v"1.0.1-"]
|
|
]
|
|
want_data = Dict("A"=>v"1", "B"=>v"1", "D"=>v"1",
|
|
"E"=>v"1", "F"=>v"1.1")
|
|
@test resolve_tst(deps_data, reqs_data, want_data)
|
|
|
|
# require F and D; force lower D version -> must not bring down F version
|
|
reqs_data = Any[
|
|
["F"],
|
|
["D", v"1", v"2"]
|
|
]
|
|
want_data = Dict("A"=>v"2.1", "B"=>v"1.0.1", "C"=>v"2",
|
|
"D"=>v"1", "E"=>v"1", "F"=>v"2")
|
|
@test resolve_tst(deps_data, reqs_data, want_data)
|
|
|
|
# require F and C; force lower C version -> must bring down F and A versions
|
|
reqs_data = Any[
|
|
["F"],
|
|
["C", v"1", v"2"]
|
|
]
|
|
want_data = Dict("A"=>v"2", "B"=>v"1.0.1", "C"=>v"1+BLD",
|
|
"D"=>v"2", "E"=>v"1", "F"=>v"2-rc.1")
|
|
@test resolve_tst(deps_data, reqs_data, want_data)
|
|
|
|
## DEPENDENCY SCHEME 11: FIVE PACKAGES, SAME AS SCHEMES 5 + 1, UNCONNECTED
|
|
deps_data = Any[
|
|
["A", v"1", "B", v"2"],
|
|
["A", v"1", "C", v"2"],
|
|
["A", v"2", "B", v"1", v"2"],
|
|
["A", v"2", "C", v"1", v"2"],
|
|
["B", v"1", "C", v"2"],
|
|
["B", v"2", "C", v"2"],
|
|
["C", v"1"],
|
|
["C", v"2"],
|
|
["D", v"1", "E", v"1"],
|
|
["D", v"2", "E", v"2"],
|
|
["E", v"1"],
|
|
["E", v"2"]
|
|
]
|
|
|
|
@test sanity_tst(deps_data, [("A", v"2")])
|
|
@test sanity_tst(deps_data, [("A", v"2")], pkgs=["B"])
|
|
@test sanity_tst(deps_data, pkgs=["D"])
|
|
@test sanity_tst(deps_data, pkgs=["E"])
|
|
@test sanity_tst(deps_data, [("A", v"2")], pkgs=["B", "D"])
|
|
|
|
# require A, any version (must use the highest non-inconsistent)
|
|
reqs_data = Any[
|
|
["A"]
|
|
]
|
|
want_data = Dict("A"=>v"1", "B"=>v"2", "C"=>v"2")
|
|
@test resolve_tst(deps_data, reqs_data, want_data)
|
|
|
|
# require just D: must bring in E
|
|
reqs_data = Any[
|
|
["D"]
|
|
]
|
|
want_data = Dict("D"=>v"2", "E"=>v"2")
|
|
@test resolve_tst(deps_data, reqs_data, want_data)
|
|
|
|
|
|
# require A and D, must be the merge of the previous two cases
|
|
reqs_data = Any[
|
|
["A"],
|
|
["D"]
|
|
]
|
|
want_data = Dict("A"=>v"1", "B"=>v"2", "C"=>v"2", "D"=>v"2", "E"=>v"2")
|
|
@test resolve_tst(deps_data, reqs_data, want_data)
|
|
|
|
## DEPENDENCY SCHEME 12: A REALISTIC EXAMPLE
|
|
## ref issue #21485
|
|
|
|
include("resolvedata1.jl")
|
|
|
|
@test sanity_tst(deps_data, problematic_data)
|
|
@test resolve_tst(deps_data, reqs_data, want_data)
|