Merge pull request #1884 from sdboyer/discard-version-unifier

gps: Remove versionTypeUnion
This commit is contained in:
sam boyer 2018-07-01 23:37:24 -04:00 коммит произвёл GitHub
Родитель 684854dd20 c9551eaba2
Коммит 6211c75ddb
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
15 изменённых файлов: 21 добавлений и 721 удалений

4
cmd/dep/testdata/harness_tests/ensure/add/desync/final/Gopkg.lock сгенерированный поставляемый
Просмотреть файл

@ -4,8 +4,8 @@
[[projects]]
name = "github.com/sdboyer/deptest"
packages = ["."]
revision = "ff2948a2ac8f538c4ecd55962e919d1e13e74baf"
version = "v1.0.0"
revision = "3f4c3bea144e112a69bbe5d8d01c1b09a544253f"
version = "v0.8.1"
[[projects]]
name = "github.com/sdboyer/deptestdos"

4
cmd/dep/testdata/harness_tests/ensure/empty/case2/final/Gopkg.lock сгенерированный поставляемый
Просмотреть файл

@ -4,8 +4,8 @@
[[projects]]
name = "github.com/sdboyer/deptest"
packages = ["."]
revision = "ff2948a2ac8f538c4ecd55962e919d1e13e74baf"
version = "v1.0.0"
revision = "3f4c3bea144e112a69bbe5d8d01c1b09a544253f"
version = "v0.8.1"
[solve-meta]
analyzer-name = "dep"

2
cmd/dep/testdata/harness_tests/ensure/pkg-ignored/wildcard-ignore/final/Gopkg.lock сгенерированный поставляемый
Просмотреть файл

@ -2,10 +2,10 @@
[[projects]]
branch = "master"
name = "github.com/sdboyer/deptest"
packages = ["."]
revision = "3f4c3bea144e112a69bbe5d8d01c1b09a544253f"
version = "v0.8.1"
[solve-meta]
analyzer-name = "dep"

4
cmd/dep/testdata/harness_tests/ensure/update/case1/final/Gopkg.lock сгенерированный поставляемый
Просмотреть файл

@ -4,8 +4,8 @@
[[projects]]
name = "github.com/sdboyer/deptest"
packages = ["."]
revision = "ff2948a2ac8f538c4ecd55962e919d1e13e74baf"
version = "v1.0.0"
revision = "3f4c3bea144e112a69bbe5d8d01c1b09a544253f"
version = "v0.8.1"
[[projects]]
name = "github.com/sdboyer/deptestdos"

4
cmd/dep/testdata/harness_tests/ensure/update/desync/final/Gopkg.lock сгенерированный поставляемый
Просмотреть файл

@ -4,8 +4,8 @@
[[projects]]
name = "github.com/sdboyer/deptest"
packages = ["."]
revision = "ff2948a2ac8f538c4ecd55962e919d1e13e74baf"
version = "v1.0.0"
revision = "3f4c3bea144e112a69bbe5d8d01c1b09a544253f"
version = "v0.8.1"
[[projects]]
name = "github.com/sdboyer/deptestdos"

Просмотреть файл

@ -10,7 +10,7 @@
{
"importpath": "github.com/sdboyer/deptestdos",
"repository": "https://github.com/sdboyer/deptestdos",
"revision": "5c607206be5decd28e6263ffffdcee067266015eXXX",
"revision": "5c607206be5decd28e6263ffffdcee067266015e",
"branch": "master"
},
{

Просмотреть файл

@ -169,12 +169,6 @@ func (c semverConstraint) typedString() string {
func (c semverConstraint) Matches(v Version) bool {
switch tv := v.(type) {
case versionTypeUnion:
for _, elem := range tv {
if c.Matches(elem) {
return true
}
}
case semVersion:
return c.c.Matches(tv.sv) == nil
case versionPair:
@ -194,12 +188,6 @@ func (c semverConstraint) Intersect(c2 Constraint) Constraint {
switch tc := c2.(type) {
case anyConstraint:
return c
case versionTypeUnion:
for _, elem := range tc {
if rc := c.Intersect(elem); rc != none {
return rc
}
}
case semverConstraint:
rc := c.c.Intersect(tc.c)
if !semver.IsNone(rc) {

Просмотреть файл

@ -697,183 +697,6 @@ func TestSemverConstraint_ImpliedCaret(t *testing.T) {
}
}
// Test that certain types of cross-version comparisons work when they are
// expressed as a version union (but that others don't).
func TestVersionUnion(t *testing.T) {
rev := Revision("flooboofoobooo")
v1 := NewBranch("master")
v2 := NewBranch("test")
v3 := NewVersion("1.0.0").Pair(rev)
v4 := NewVersion("1.0.1")
v5 := NewVersion("v2.0.5").Pair(Revision("notamatch"))
uv1 := versionTypeUnion{v1, v4, rev}
uv2 := versionTypeUnion{v2, v3}
if uv1.MatchesAny(none) {
t.Errorf("Union can't match none")
}
if none.MatchesAny(uv1) {
t.Errorf("Union can't match none")
}
if !uv1.MatchesAny(any) {
t.Errorf("Union must match any")
}
if !any.MatchesAny(uv1) {
t.Errorf("Union must match any")
}
// Basic matching
if !uv1.Matches(v4) {
t.Errorf("Union should match on branch to branch")
}
if !v4.Matches(uv1) {
t.Errorf("Union should reverse-match on branch to branch")
}
if !uv1.Matches(v3) {
t.Errorf("Union should match on rev to paired rev")
}
if !v3.Matches(uv1) {
t.Errorf("Union should reverse-match on rev to paired rev")
}
if uv1.Matches(v2) {
t.Errorf("Union should not match on anything in disjoint unpaired")
}
if v2.Matches(uv1) {
t.Errorf("Union should not reverse-match on anything in disjoint unpaired")
}
if uv1.Matches(v5) {
t.Errorf("Union should not match on anything in disjoint pair")
}
if v5.Matches(uv1) {
t.Errorf("Union should not reverse-match on anything in disjoint pair")
}
if !uv1.Matches(uv2) {
t.Errorf("Union should succeed on matching comparison to other union with some overlap")
}
// MatchesAny - repeat Matches for safety, but add more, too
if !uv1.MatchesAny(v4) {
t.Errorf("Union should match on branch to branch")
}
if !v4.MatchesAny(uv1) {
t.Errorf("Union should reverse-match on branch to branch")
}
if !uv1.MatchesAny(v3) {
t.Errorf("Union should match on rev to paired rev")
}
if !v3.MatchesAny(uv1) {
t.Errorf("Union should reverse-match on rev to paired rev")
}
if uv1.MatchesAny(v2) {
t.Errorf("Union should not match on anything in disjoint unpaired")
}
if v2.MatchesAny(uv1) {
t.Errorf("Union should not reverse-match on anything in disjoint unpaired")
}
if uv1.MatchesAny(v5) {
t.Errorf("Union should not match on anything in disjoint pair")
}
if v5.MatchesAny(uv1) {
t.Errorf("Union should not reverse-match on anything in disjoint pair")
}
c1, _ := NewSemverConstraint("~1.0.0")
c2, _ := NewSemverConstraint("~2.0.0")
if !uv1.MatchesAny(c1) {
t.Errorf("Union should have some overlap due to containing 1.0.1 version")
}
if !c1.MatchesAny(uv1) {
t.Errorf("Union should have some overlap due to containing 1.0.1 version")
}
if uv1.MatchesAny(c2) {
t.Errorf("Union should have no overlap with ~2.0.0 semver range")
}
if c2.MatchesAny(uv1) {
t.Errorf("Union should have no overlap with ~2.0.0 semver range")
}
if !uv1.MatchesAny(uv2) {
t.Errorf("Union should succeed on MatchAny against other union with some overlap")
}
// Intersect - repeat all previous
if uv1.Intersect(v4) != v4 {
t.Errorf("Union intersection on contained version should return that version")
}
if v4.Intersect(uv1) != v4 {
t.Errorf("Union reverse-intersection on contained version should return that version")
}
if uv1.Intersect(v3) != rev {
t.Errorf("Union intersection on paired version w/matching rev should return rev, got %s", uv1.Intersect(v3))
}
if v3.Intersect(uv1) != rev {
t.Errorf("Union reverse-intersection on paired version w/matching rev should return rev, got %s", v3.Intersect(uv1))
}
if uv1.Intersect(v2) != none {
t.Errorf("Union should not intersect with anything in disjoint unpaired")
}
if v2.Intersect(uv1) != none {
t.Errorf("Union should not reverse-intersect with anything in disjoint unpaired")
}
if uv1.Intersect(v5) != none {
t.Errorf("Union should not intersect with anything in disjoint pair")
}
if v5.Intersect(uv1) != none {
t.Errorf("Union should not reverse-intersect with anything in disjoint pair")
}
if uv1.Intersect(c1) != v4 {
t.Errorf("Union intersecting with semver range should return 1.0.1 version, got %s", uv1.Intersect(c1))
}
if c1.Intersect(uv1) != v4 {
t.Errorf("Union reverse-intersecting with semver range should return 1.0.1 version, got %s", c1.Intersect(uv1))
}
if uv1.Intersect(c2) != none {
t.Errorf("Union intersecting with non-overlapping semver range should return none, got %s", uv1.Intersect(c2))
}
if c2.Intersect(uv1) != none {
t.Errorf("Union reverse-intersecting with non-overlapping semver range should return none, got %s", uv1.Intersect(c2))
}
if uv1.Intersect(uv2) != rev {
t.Errorf("Unions should intersect down to rev, but got %s", uv1.Intersect(uv2))
}
}
func TestVersionUnionPanicOnType(t *testing.T) {
// versionTypeUnions need to panic if Type() gets called
defer func() {
if err := recover(); err == nil {
t.Error("versionTypeUnion did not panic on Type() call")
}
}()
_ = versionTypeUnion{}.Type()
}
func TestVersionUnionPanicOnString(t *testing.T) {
// versionStringUnions need to panic if String() gets called
defer func() {
if err := recover(); err == nil {
t.Error("versionStringUnion did not panic on String() call")
}
}()
_ = versionTypeUnion{}.String()
}
func TestTypedConstraintString(t *testing.T) {
// Also tests typedVersionString(), as this nests down into that
rev := Revision("flooboofoobooo")
@ -944,8 +767,6 @@ func TestConstraintsIdentical(t *testing.T) {
{Revision("test"), Revision("test"), true},
{Revision("test"), Revision("test2"), false},
{testSemverConstraint(t, "v2.10.7"), testSemverConstraint(t, "v2.10.7"), true},
{versionTypeUnion{NewVersion("test"), NewBranch("branch")},
versionTypeUnion{NewBranch("branch"), NewVersion("test")}, true},
} {
if test.eq != test.a.identical(test.b) {
want := "identical"

Просмотреть файл

@ -80,7 +80,7 @@ func (s *solver) check(a atomWithPackages, pkgonly bool) error {
// the constraints established by the current solution.
func (s *solver) checkAtomAllowable(pa atom) error {
constraint := s.sel.getConstraint(pa.id)
if s.vUnify.matches(pa.id, constraint, pa.v) {
if constraint.Matches(pa.v) {
return nil
}
// TODO(sdboyer) collect constraint failure reason (wait...aren't we, below?)
@ -88,7 +88,7 @@ func (s *solver) checkAtomAllowable(pa atom) error {
deps := s.sel.getDependenciesOn(pa.id)
var failparent []dependency
for _, dep := range deps {
if !s.vUnify.matches(pa.id, dep.dep.Constraint, pa.v) {
if !dep.dep.Constraint.Matches(pa.v) {
s.fail(dep.depender.id)
failparent = append(failparent, dep)
}
@ -150,7 +150,7 @@ func (s *solver) checkDepsConstraintsAllowable(a atomWithPackages, cdep complete
constraint := s.sel.getConstraint(dep.Ident)
// Ensure the constraint expressed by the dep has at least some possible
// intersection with the intersection of existing constraints.
if s.vUnify.matchesAny(dep.Ident, constraint, dep.Constraint) {
if constraint.MatchesAny(dep.Constraint) {
return nil
}
@ -159,7 +159,7 @@ func (s *solver) checkDepsConstraintsAllowable(a atomWithPackages, cdep complete
var failsib []dependency
var nofailsib []dependency
for _, sibling := range siblings {
if !s.vUnify.matchesAny(dep.Ident, sibling.dep.Constraint, dep.Constraint) {
if !sibling.dep.Constraint.MatchesAny(dep.Constraint) {
s.fail(sibling.depender.id)
failsib = append(failsib, sibling)
} else {
@ -181,7 +181,7 @@ func (s *solver) checkDepsConstraintsAllowable(a atomWithPackages, cdep complete
func (s *solver) checkDepsDisallowsSelected(a atomWithPackages, cdep completeDep) error {
dep := cdep.workingConstraint
selected, exists := s.sel.selected(dep.Ident)
if exists && !s.vUnify.matches(dep.Ident, dep.Constraint, selected.a.v) {
if exists && !dep.Constraint.Matches(selected.a.v) {
s.fail(dep.Ident)
return &constraintNotAllowedFailure{

Просмотреть файл

@ -16,8 +16,6 @@ type selection struct {
// ProjectRoots to the particular case variant that has currently been
// selected.
foldRoots map[string]ProjectRoot
// The versoinUnifier in use for this solve run.
vu *versionUnifier
}
type selected struct {
@ -159,7 +157,7 @@ func (s *selection) getConstraint(id ProjectIdentifier) Constraint {
// Start with the open set
var ret Constraint = any
for _, dep := range deps {
ret = s.vu.intersect(id, ret, dep.dep.Constraint)
ret = ret.Intersect(dep.dep.Constraint)
}
return ret

Просмотреть файл

@ -847,8 +847,8 @@ var basicFixtures = map[string]basicFixture{
"foo 1.0.1 foorev", // mkrevlock drops the 1.0.1
),
r: mksolution(
"foo 1.0.1 foorev",
"bar 1.0.1",
"foo 1.0.2",
"bar 1.0.2",
),
},
"lock to branch on old rev keeps old rev": {

Просмотреть файл

@ -127,10 +127,6 @@ type solver struct {
// names a SourceManager operates on.
b sourceBridge
// A versionUnifier, to facilitate cross-type version comparison and set
// operations.
vUnify *versionUnifier
// A stack containing projects and packages that are currently "selected" -
// that is, they have passed all satisfiability checks, and are part of the
// current solution.
@ -305,15 +301,11 @@ func Prepare(params SolveParameters, sm SourceManager) (Solver, error) {
if err != nil {
return nil, err
}
s.vUnify = &versionUnifier{
b: s.b,
}
// Initialize stacks and queues
s.sel = &selection{
deps: make(map[ProjectRoot][]dependency),
foldRoots: make(map[string]ProjectRoot),
vu: s.vUnify,
}
s.unsel = &unselected{
sl: make([]bimodalIdentifier, 0),
@ -447,7 +439,6 @@ func (s *solver) Solve(ctx context.Context) (Solution, error) {
// Set up a metrics object
s.mtr = newMetrics()
s.vUnify.mtr = s.mtr
// Prime the queues with the root project
if err := s.selectRoot(); err != nil {
@ -1007,35 +998,9 @@ func (s *solver) getLockVersionIfValid(id ProjectIdentifier) (Version, error) {
constraint := s.sel.getConstraint(id)
v := lp.Version()
if !constraint.Matches(v) {
var found bool
if tv, ok := v.(Revision); ok {
// If we only have a revision from the root's lock, allow matching
// against other versions that have that revision
for _, pv := range s.vUnify.pairRevision(id, tv) {
if constraint.Matches(pv) {
v = pv
found = true
break
}
}
//} else if _, ok := constraint.(Revision); ok {
//// If the current constraint is itself a revision, and the lock gave
//// an unpaired version, see if they match up
////
//if u, ok := v.(UnpairedVersion); ok {
//pv := s.sm.pairVersion(id, u)
//if constraint.Matches(pv) {
//v = pv
//found = true
//}
//}
}
if !found {
// No match found, which means we're going to be breaking the lock
// Still return the invalid version so that is included in the trace
s.b.breakLock()
}
// No match found, which means we're going to be breaking the lock
// Still return the invalid version so that is included in the trace
s.b.breakLock()
}
return v, nil

Просмотреть файл

@ -140,8 +140,6 @@ func (r Revision) Type() VersionType {
// version is the same Revision as itself.
func (r Revision) Matches(v Version) bool {
switch tv := v.(type) {
case versionTypeUnion:
return tv.Matches(r)
case Revision:
return r == tv
case versionPair:
@ -159,8 +157,6 @@ func (r Revision) MatchesAny(c Constraint) bool {
return true
case noneConstraint:
return false
case versionTypeUnion:
return tc.MatchesAny(r)
case Revision:
return r == tc
case versionPair:
@ -179,8 +175,6 @@ func (r Revision) Intersect(c Constraint) Constraint {
return r
case noneConstraint:
return none
case versionTypeUnion:
return tc.Intersect(r)
case Revision:
if r == tc {
return r
@ -230,8 +224,6 @@ func (v branchVersion) Type() VersionType {
func (v branchVersion) Matches(v2 Version) bool {
switch tv := v2.(type) {
case versionTypeUnion:
return tv.Matches(v)
case branchVersion:
return v.name == tv.name
case versionPair:
@ -248,8 +240,6 @@ func (v branchVersion) MatchesAny(c Constraint) bool {
return true
case noneConstraint:
return false
case versionTypeUnion:
return tc.MatchesAny(v)
case branchVersion:
return v.name == tc.name
case versionPair:
@ -267,8 +257,6 @@ func (v branchVersion) Intersect(c Constraint) Constraint {
return v
case noneConstraint:
return none
case versionTypeUnion:
return tc.Intersect(v)
case branchVersion:
if v.name == tc.name {
return v
@ -328,8 +316,6 @@ func (v plainVersion) Type() VersionType {
func (v plainVersion) Matches(v2 Version) bool {
switch tv := v2.(type) {
case versionTypeUnion:
return tv.Matches(v)
case plainVersion:
return v == tv
case versionPair:
@ -346,8 +332,6 @@ func (v plainVersion) MatchesAny(c Constraint) bool {
return true
case noneConstraint:
return false
case versionTypeUnion:
return tc.MatchesAny(v)
case plainVersion:
return v == tc
case versionPair:
@ -365,8 +349,6 @@ func (v plainVersion) Intersect(c Constraint) Constraint {
return v
case noneConstraint:
return none
case versionTypeUnion:
return tc.Intersect(v)
case plainVersion:
if v == tc {
return v
@ -428,8 +410,6 @@ func (v semVersion) Type() VersionType {
func (v semVersion) Matches(v2 Version) bool {
switch tv := v2.(type) {
case versionTypeUnion:
return tv.Matches(v)
case semVersion:
return v.sv.Equal(tv.sv)
case versionPair:
@ -446,8 +426,6 @@ func (v semVersion) MatchesAny(c Constraint) bool {
return true
case noneConstraint:
return false
case versionTypeUnion:
return tc.MatchesAny(v)
case semVersion:
return v.sv.Equal(tc.sv)
case semverConstraint:
@ -467,8 +445,6 @@ func (v semVersion) Intersect(c Constraint) Constraint {
return v
case noneConstraint:
return none
case versionTypeUnion:
return tc.Intersect(v)
case semVersion:
if v.sv.Equal(tc.sv) {
return v
@ -537,8 +513,6 @@ func (v versionPair) Unpair() UnpairedVersion {
func (v versionPair) Matches(v2 Version) bool {
switch tv2 := v2.(type) {
case versionTypeUnion:
return tv2.Matches(v)
case versionPair:
return v.r == tv2.r
case Revision:
@ -571,8 +545,6 @@ func (v versionPair) Intersect(c2 Constraint) Constraint {
return v
case noneConstraint:
return none
case versionTypeUnion:
return tc.Intersect(v)
case versionPair:
if v.r == tc.r {
return v.r

Просмотреть файл

@ -1,302 +0,0 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gps
import "github.com/golang/dep/gps/internal/pb"
// versionUnifier facilitates cross-type version comparison and set operations.
type versionUnifier struct {
b sourceBridge
mtr *metrics
}
// pairVersion takes an UnpairedVersion and attempts to pair it with an
// underlying Revision in the context of the provided ProjectIdentifier by
// consulting the canonical version list.
func (vu versionUnifier) pairVersion(id ProjectIdentifier, v UnpairedVersion) PairedVersion {
vl, err := vu.b.listVersions(id)
if err != nil {
return nil
}
vu.mtr.push("b-pair-version")
// doing it like this is a bit sloppy
for _, v2 := range vl {
if p, ok := v2.(PairedVersion); ok {
if p.Matches(v) {
vu.mtr.pop()
return p
}
}
}
vu.mtr.pop()
return nil
}
// pairRevision takes a Revision and attempts to pair it with all possible
// versionsby consulting the canonical version list of the provided
// ProjectIdentifier.
func (vu versionUnifier) pairRevision(id ProjectIdentifier, r Revision) []Version {
vl, err := vu.b.listVersions(id)
if err != nil {
return nil
}
vu.mtr.push("b-pair-rev")
p := []Version{r}
// doing it like this is a bit sloppy
for _, v2 := range vl {
if pv, ok := v2.(PairedVersion); ok {
if pv.Matches(r) {
p = append(p, pv)
}
}
}
vu.mtr.pop()
return p
}
// matches performs a typical match check between the provided version and
// constraint. If that basic check fails and the provided version is incomplete
// (e.g. an unpaired version or bare revision), it will attempt to gather more
// information on one or the other and re-perform the comparison.
func (vu versionUnifier) matches(id ProjectIdentifier, c Constraint, v Version) bool {
if c.Matches(v) {
return true
}
vu.mtr.push("b-matches")
// This approach is slightly wasteful, but just SO much less verbose, and
// more easily understood.
vtu := vu.createTypeUnion(id, v)
var uc Constraint
if cv, ok := c.(Version); ok {
uc = vu.createTypeUnion(id, cv)
} else {
uc = c
}
vu.mtr.pop()
return uc.Matches(vtu)
}
// matchesAny is the authoritative version of Constraint.MatchesAny.
func (vu versionUnifier) matchesAny(id ProjectIdentifier, c1, c2 Constraint) bool {
if c1.MatchesAny(c2) {
return true
}
vu.mtr.push("b-matches-any")
// This approach is slightly wasteful, but just SO much less verbose, and
// more easily understood.
var uc1, uc2 Constraint
if v1, ok := c1.(Version); ok {
uc1 = vu.createTypeUnion(id, v1)
} else {
uc1 = c1
}
if v2, ok := c2.(Version); ok {
uc2 = vu.createTypeUnion(id, v2)
} else {
uc2 = c2
}
vu.mtr.pop()
return uc1.MatchesAny(uc2)
}
// intersect is the authoritative version of Constraint.Intersect.
func (vu versionUnifier) intersect(id ProjectIdentifier, c1, c2 Constraint) Constraint {
rc := c1.Intersect(c2)
if rc != none {
return rc
}
vu.mtr.push("b-intersect")
// This approach is slightly wasteful, but just SO much less verbose, and
// more easily understood.
var uc1, uc2 Constraint
if v1, ok := c1.(Version); ok {
uc1 = vu.createTypeUnion(id, v1)
} else {
uc1 = c1
}
if v2, ok := c2.(Version); ok {
uc2 = vu.createTypeUnion(id, v2)
} else {
uc2 = c2
}
vu.mtr.pop()
return uc1.Intersect(uc2)
}
// createTypeUnion creates a versionTypeUnion for the provided version.
//
// This union may (and typically will) end up being nothing more than the single
// input version, but creating a versionTypeUnion guarantees that 'local'
// constraint checks (direct method calls) are authoritative.
func (vu versionUnifier) createTypeUnion(id ProjectIdentifier, v Version) versionTypeUnion {
switch tv := v.(type) {
case Revision:
return versionTypeUnion(vu.pairRevision(id, tv))
case PairedVersion:
return versionTypeUnion(vu.pairRevision(id, tv.Revision()))
case UnpairedVersion:
pv := vu.pairVersion(id, tv)
if pv == nil {
return versionTypeUnion{tv}
}
return versionTypeUnion(vu.pairRevision(id, pv.Revision()))
}
return nil
}
// versionTypeUnion represents a set of versions that are, within the scope of
// this solver run, equivalent.
//
// The simple case here is just a pair - a normal version plus its underlying
// revision - but if a tag or branch point at the same rev, then we consider
// them equivalent. Again, however, this equivalency is short-lived; it must be
// re-assessed during every solver run.
//
// The union members are treated as being OR'd together: all constraint
// operations attempt each member, and will take the most open/optimistic
// answer.
//
// This technically does allow tags to match branches - something we otherwise
// try hard to avoid - but because the original input constraint never actually
// changes (and is never written out in the Solution), there's no harmful case
// of a user suddenly riding a branch when they expected a fixed tag.
type versionTypeUnion []Version
// This should generally not be called, but is required for the interface. If it
// is called, we have a bigger problem (the type has escaped the solver); thus,
// panic.
func (vtu versionTypeUnion) String() string {
panic("versionTypeUnion should never be turned into a string; it is solver internal-only")
}
// This should generally not be called, but is required for the interface. If it
// is called, we have a bigger problem (the type has escaped the solver); thus,
// panic.
func (vtu versionTypeUnion) ImpliedCaretString() string {
panic("versionTypeUnion should never be turned into a string; it is solver internal-only")
}
func (vtu versionTypeUnion) typedString() string {
panic("versionTypeUnion should never be turned into a string; it is solver internal-only")
}
// This should generally not be called, but is required for the interface. If it
// is called, we have a bigger problem (the type has escaped the solver); thus,
// panic.
func (vtu versionTypeUnion) Type() VersionType {
panic("versionTypeUnion should never need to answer a Type() call; it is solver internal-only")
}
// Matches takes a version, and returns true if that version matches any version
// contained in the union.
//
// This DOES allow tags to match branches, albeit indirectly through a revision.
func (vtu versionTypeUnion) Matches(v Version) bool {
vtu2, otherIs := v.(versionTypeUnion)
for _, v1 := range vtu {
if otherIs {
for _, v2 := range vtu2 {
if v1.Matches(v2) {
return true
}
}
} else if v1.Matches(v) {
return true
}
}
return false
}
// MatchesAny returns true if any of the contained versions (which are also
// constraints) in the union successfully MatchAny with the provided
// constraint.
func (vtu versionTypeUnion) MatchesAny(c Constraint) bool {
vtu2, otherIs := c.(versionTypeUnion)
for _, v1 := range vtu {
if otherIs {
for _, v2 := range vtu2 {
if v1.MatchesAny(v2) {
return true
}
}
} else if v1.MatchesAny(c) {
return true
}
}
return false
}
// Intersect takes a constraint, and attempts to intersect it with all the
// versions contained in the union until one returns non-none. If that never
// happens, then none is returned.
//
// In order to avoid weird version floating elsewhere in the solver, the union
// always returns the input constraint. (This is probably obviously correct, but
// is still worth noting.)
func (vtu versionTypeUnion) Intersect(c Constraint) Constraint {
vtu2, otherIs := c.(versionTypeUnion)
for _, v1 := range vtu {
if otherIs {
for _, v2 := range vtu2 {
if rc := v1.Intersect(v2); rc != none {
return rc
}
}
} else if rc := v1.Intersect(c); rc != none {
return rc
}
}
return none
}
func (vtu versionTypeUnion) identical(c Constraint) bool {
vtu2, ok := c.(versionTypeUnion)
if !ok {
return false
}
if len(vtu) != len(vtu2) {
return false
}
used := make([]bool, len(vtu))
outter:
for _, v := range vtu {
for i, v2 := range vtu2 {
if used[i] {
continue
}
if v.identical(v2) {
used[i] = true
continue outter
}
}
return false
}
return true
}
func (vtu versionTypeUnion) copyTo(*pb.Constraint) {
panic("versionTypeUnion should never be serialized; it is solver internal-only")
}

Просмотреть файл

@ -1,142 +0,0 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gps
import (
"testing"
"github.com/golang/dep/gps/pkgtree"
)
type lvFixBridge []Version
var lvfb1 lvFixBridge
func init() {
rev1 := Revision("revision-one")
rev2 := Revision("revision-two")
rev3 := Revision("revision-three")
lvfb1 = lvFixBridge{
NewBranch("master").Pair(rev1),
NewBranch("test").Pair(rev2),
NewVersion("1.0.0").Pair(rev1),
NewVersion("1.0.1").Pair("other1"),
NewVersion("v2.0.5").Pair(rev3),
NewVersion("2.0.5.2").Pair(rev3),
newDefaultBranch("unwrapped").Pair(rev3),
NewVersion("20.0.5.2").Pair(rev1),
NewVersion("v1.5.5-beta.4").Pair("other2"),
NewVersion("v3.0.1-alpha.1").Pair(rev2),
}
}
func (lb lvFixBridge) listVersions(ProjectIdentifier) ([]Version, error) {
return lb, nil
}
func TestCreateTyepUnion(t *testing.T) {
vu := versionUnifier{
b: lvfb1,
mtr: newMetrics(),
}
rev1 := Revision("revision-one")
rev2 := Revision("revision-two")
id := mkPI("irrelevant")
vtu := vu.createTypeUnion(id, rev1)
if len(vtu) != 4 {
t.Fatalf("wanted a type union with four elements, got %v: \n%#v", len(vtu), vtu)
}
vtu = vu.createTypeUnion(id, NewBranch("master"))
if len(vtu) != 4 {
t.Fatalf("wanted a type union with four elements, got %v: \n%#v", len(vtu), vtu)
}
vtu = vu.createTypeUnion(id, Revision("notexist"))
if len(vtu) != 1 {
t.Fatalf("wanted a type union with one elements, got %v: \n%#v", len(vtu), vtu)
}
vtu = vu.createTypeUnion(id, rev2)
if len(vtu) != 3 {
t.Fatalf("wanted a type union with three elements, got %v: \n%#v", len(vtu), vtu)
}
vtu = vu.createTypeUnion(id, nil)
if vtu != nil {
t.Fatalf("wanted a nil return on nil input, got %#v", vtu)
}
}
func TestTypeUnionIntersect(t *testing.T) {
vu := versionUnifier{
b: lvfb1,
mtr: newMetrics(),
}
rev1 := Revision("revision-one")
rev2 := Revision("revision-two")
rev3 := Revision("revision-three")
id := mkPI("irrelevant")
c, _ := NewSemverConstraint("^2.0.0")
gotc := vu.intersect(id, rev2, c)
if gotc != none {
t.Fatalf("wanted empty set from intersect, got %#v", gotc)
}
gotc = vu.intersect(id, c, rev1)
if gotc != none {
t.Fatalf("wanted empty set from intersect, got %#v", gotc)
}
gotc = vu.intersect(id, c, rev3)
if gotc != NewVersion("v2.0.5").Pair(rev3) {
t.Fatalf("wanted v2.0.5, got %s from intersect", gotc.typedString())
}
}
func (lb lvFixBridge) SourceExists(ProjectIdentifier) (bool, error) {
panic("not implemented")
}
func (lb lvFixBridge) SyncSourceFor(ProjectIdentifier) error {
panic("not implemented")
}
func (lb lvFixBridge) RevisionPresentIn(ProjectIdentifier, Revision) (bool, error) {
panic("not implemented")
}
func (lb lvFixBridge) ListPackages(ProjectIdentifier, Version) (pkgtree.PackageTree, error) {
panic("not implemented")
}
func (lb lvFixBridge) GetManifestAndLock(ProjectIdentifier, Version, ProjectAnalyzer) (Manifest, Lock, error) {
panic("not implemented")
}
func (lb lvFixBridge) ExportProject(ProjectIdentifier, Version, string) error {
panic("not implemented")
}
func (lb lvFixBridge) DeduceProjectRoot(ip string) (ProjectRoot, error) {
panic("not implemented")
}
func (lb lvFixBridge) verifyRootDir(path string) error {
panic("not implemented")
}
func (lb lvFixBridge) vendorCodeExists(ProjectIdentifier) (bool, error) {
panic("not implemented")
}
func (lb lvFixBridge) breakLock() {
panic("not implemented")
}