https://github.com/JuliaLang/julia
Raw File
Tip revision: d33fc677595f6a1d83006e120e4e8fa21c195edc authored by Andy Ferris on 30 October 2017, 11:48:52 UTC
WIP: Associative iterates values
Tip revision: d33fc67
resolve.jl
# 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)
back to top