Update to latest gps
This update is to catch the changes to NewLockedProject's signature, but
is mostly about getting us the fixes to ProjectIdentifier.NetworkName.
diff --git a/cfg/lock.go b/cfg/lock.go
index fa5b018..0d91363 100644
--- a/cfg/lock.go
+++ b/cfg/lock.go
@@ -156,7 +156,11 @@
v = r
}
- lp[k] = gps.NewLockedProject(gps.ProjectRoot(l.Name), v, l.Repository, nil)
+ id := gps.ProjectIdentifier{
+ ProjectRoot: gps.ProjectRoot(l.Name),
+ NetworkName: l.Repository,
+ }
+ lp[k] = gps.NewLockedProject(id, v, nil)
}
return lp
diff --git a/glide.lock b/glide.lock
index a5d5c91..0482f9d 100644
--- a/glide.lock
+++ b/glide.lock
@@ -10,7 +10,7 @@
- name: github.com/Masterminds/vcs
version: fbe9fb6ad5b5f35b3e82a7c21123cfc526cbf895
- name: github.com/sdboyer/gps
- version: f6e74e8d79b34ee6954d0cc8b770758ec99870ad
+ version: 6e8a101af5e735feedcdae1f716bebc338b74525
- name: github.com/termie/go-shutil
version: bcacb06fecaeec8dc42af03c87c6949f4a05c74c
- name: gopkg.in/yaml.v2
diff --git a/gom/gom.go b/gom/gom.go
index 08f0c2c..a33601d 100644
--- a/gom/gom.go
+++ b/gom/gom.go
@@ -143,23 +143,27 @@
dep.Constraint = gps.NewBranch(body)
}
+ id := gps.ProjectIdentifier{
+ ProjectRoot: gps.ProjectRoot(dir),
+ }
+ var version gps.Version
if val, ok := gom.options["commit"]; ok {
body := val.(string)
if v != nil {
- v.Is(gps.Revision(body))
- l = append(l, gps.NewLockedProject(gps.ProjectRoot(dir), v, dir, nil))
+ version = v.Is(gps.Revision(body))
} else {
// As with the other third-party system integrations, we're
// going to choose not to put revisions into a manifest, even
// though gom has a lot more information than most and the
// argument could be made for it.
dep.Constraint = gps.Any()
- l = append(l, gps.NewLockedProject(gps.ProjectRoot(dir), gps.Revision(body), dir, nil))
+ version = gps.Revision(body)
}
} else if v != nil {
// This is kinda uncomfortable - lock w/no immut - but OK
- l = append(l, gps.NewLockedProject(gps.ProjectRoot(dir), v, dir, nil))
+ version = v
}
+ l = append(l, gps.NewLockedProject(id, version, nil))
// TODO We ignore GOOS, GOARCH for now
}
diff --git a/vendor/github.com/sdboyer/gps/bridge.go b/vendor/github.com/sdboyer/gps/bridge.go
index 298b023..a7368e3 100644
--- a/vendor/github.com/sdboyer/gps/bridge.go
+++ b/vendor/github.com/sdboyer/gps/bridge.go
@@ -4,7 +4,6 @@
"fmt"
"os"
"path/filepath"
- "sort"
"sync/atomic"
"github.com/Masterminds/semver"
@@ -91,9 +90,9 @@
}
if b.s.params.Downgrade {
- sort.Sort(downgradeVersionSorter(vl))
+ SortForDowngrade(vl)
} else {
- sort.Sort(upgradeVersionSorter(vl))
+ SortForUpgrade(vl)
}
b.vlists[id] = vl
@@ -556,96 +555,3 @@
}
func (av versionTypeUnion) _private() {}
-
-type upgradeVersionSorter []Version
-type downgradeVersionSorter []Version
-
-func (vs upgradeVersionSorter) Len() int {
- return len(vs)
-}
-
-func (vs upgradeVersionSorter) Swap(i, j int) {
- vs[i], vs[j] = vs[j], vs[i]
-}
-
-func (vs downgradeVersionSorter) Len() int {
- return len(vs)
-}
-
-func (vs downgradeVersionSorter) Swap(i, j int) {
- vs[i], vs[j] = vs[j], vs[i]
-}
-
-func (vs upgradeVersionSorter) Less(i, j int) bool {
- l, r := vs[i], vs[j]
-
- if tl, ispair := l.(versionPair); ispair {
- l = tl.v
- }
- if tr, ispair := r.(versionPair); ispair {
- r = tr.v
- }
-
- switch compareVersionType(l, r) {
- case -1:
- return true
- case 1:
- return false
- case 0:
- break
- default:
- panic("unreachable")
- }
-
- switch l.(type) {
- // For these, now nothing to do but alpha sort
- case Revision, branchVersion, plainVersion:
- return l.String() < r.String()
- }
-
- // This ensures that pre-release versions are always sorted after ALL
- // full-release versions
- lsv, rsv := l.(semVersion).sv, r.(semVersion).sv
- lpre, rpre := lsv.Prerelease() == "", rsv.Prerelease() == ""
- if (lpre && !rpre) || (!lpre && rpre) {
- return lpre
- }
- return lsv.GreaterThan(rsv)
-}
-
-func (vs downgradeVersionSorter) Less(i, j int) bool {
- l, r := vs[i], vs[j]
-
- if tl, ispair := l.(versionPair); ispair {
- l = tl.v
- }
- if tr, ispair := r.(versionPair); ispair {
- r = tr.v
- }
-
- switch compareVersionType(l, r) {
- case -1:
- return true
- case 1:
- return false
- case 0:
- break
- default:
- panic("unreachable")
- }
-
- switch l.(type) {
- // For these, now nothing to do but alpha
- case Revision, branchVersion, plainVersion:
- return l.String() < r.String()
- }
-
- // This ensures that pre-release versions are always sorted after ALL
- // full-release versions
- lsv, rsv := l.(semVersion).sv, r.(semVersion).sv
- lpre, rpre := lsv.Prerelease() == "", rsv.Prerelease() == ""
- if (lpre && !rpre) || (!lpre && rpre) {
- return lpre
- }
- return lsv.LessThan(rsv)
-}
diff --git a/vendor/github.com/sdboyer/gps/constraints.go b/vendor/github.com/sdboyer/gps/constraints.go
index 794100e..cf1b484 100644
--- a/vendor/github.com/sdboyer/gps/constraints.go
+++ b/vendor/github.com/sdboyer/gps/constraints.go
@@ -192,7 +192,7 @@
for _, pc := range l {
final[pc.Ident.ProjectRoot] = ProjectProperties{
- NetworkName: pc.Ident.netName(),
+ NetworkName: pc.Ident.NetworkName,
Constraint: pc.Constraint,
}
}
@@ -207,7 +207,7 @@
final[pc.Ident.ProjectRoot] = pp
} else {
final[pc.Ident.ProjectRoot] = ProjectProperties{
- NetworkName: pc.Ident.netName(),
+ NetworkName: pc.Ident.NetworkName,
Constraint: pc.Constraint,
}
}
@@ -257,7 +257,7 @@
// ProjectConstraints map.
func (m ProjectConstraints) override(pc ProjectConstraint) workingConstraint {
wc := workingConstraint{
- Ident: pc.Ident.normalize(), // necessary to normalize?
+ Ident: pc.Ident,
Constraint: pc.Constraint,
}
diff --git a/vendor/github.com/sdboyer/gps/glide.yaml b/vendor/github.com/sdboyer/gps/glide.yaml
index 690f9e1..5e379fa 100644
--- a/vendor/github.com/sdboyer/gps/glide.yaml
+++ b/vendor/github.com/sdboyer/gps/glide.yaml
@@ -2,13 +2,8 @@
owners:
- name: Sam Boyer
email: tech@samboyer.org
-import:
+dependencies:
- package: github.com/Masterminds/semver
branch: 2.x
- vcs: git
-- package: github.com/Masterminds/vcs
- vcs: git
- package: github.com/termie/go-shutil
version: bcacb06fecaeec8dc42af03c87c6949f4a05c74c
- vcs: git
-- package: github.com/armon/go-radix
diff --git a/vendor/github.com/sdboyer/gps/hash_test.go b/vendor/github.com/sdboyer/gps/hash_test.go
index 171f377..f356ced 100644
--- a/vendor/github.com/sdboyer/gps/hash_test.go
+++ b/vendor/github.com/sdboyer/gps/hash_test.go
@@ -26,10 +26,8 @@
elems := []string{
"a",
- "a",
"1.0.0",
"b",
- "b",
"1.0.0",
stdlibPkgs,
appenginePkgs,
@@ -75,10 +73,8 @@
elems := []string{
"a",
- "a",
"1.0.0",
"b",
- "b",
"1.0.0",
stdlibPkgs,
appenginePkgs,
@@ -129,10 +125,8 @@
elems := []string{
"a",
- "a",
"1.0.0",
"b",
- "b",
"1.0.0",
stdlibPkgs,
appenginePkgs,
@@ -168,10 +162,8 @@
elems = []string{
"a",
- "a",
"1.0.0",
"b",
- "b",
"1.0.0",
stdlibPkgs,
appenginePkgs,
@@ -210,10 +202,8 @@
elems = []string{
"a",
- "a",
"1.0.0",
"b",
- "b",
"1.0.0",
stdlibPkgs,
appenginePkgs,
@@ -254,10 +244,8 @@
elems = []string{
"a",
- "a",
"fluglehorn",
"b",
- "b",
"1.0.0",
stdlibPkgs,
appenginePkgs,
@@ -303,7 +291,6 @@
"nota",
"1.0.0",
"b",
- "b",
"1.0.0",
stdlibPkgs,
appenginePkgs,
@@ -350,7 +337,6 @@
"nota",
"fluglehorn",
"b",
- "b",
"1.0.0",
stdlibPkgs,
appenginePkgs,
diff --git a/vendor/github.com/sdboyer/gps/lock.go b/vendor/github.com/sdboyer/gps/lock.go
index 1d4db56..729d501 100644
--- a/vendor/github.com/sdboyer/gps/lock.go
+++ b/vendor/github.com/sdboyer/gps/lock.go
@@ -1,5 +1,7 @@
package gps
+import "sort"
+
// Lock represents data from a lock file (or however the implementing tool
// chooses to store it) at a particular version that is relevant to the
// satisfiability solving process.
@@ -56,16 +58,13 @@
// to simply dismiss that project. By creating a hard failure case via panic
// instead, we are trying to avoid inflicting the resulting pain on the user by
// instead forcing a decision on the Analyzer implementation.
-func NewLockedProject(n ProjectRoot, v Version, url string, pkgs []string) LockedProject {
+func NewLockedProject(id ProjectIdentifier, v Version, pkgs []string) LockedProject {
if v == nil {
panic("must provide a non-nil version to create a LockedProject")
}
lp := LockedProject{
- pi: ProjectIdentifier{
- ProjectRoot: n,
- NetworkName: url,
- },
+ pi: id,
pkgs: pkgs,
}
@@ -136,26 +135,36 @@
return sl.p
}
-// prepLock ensures a lock is prepared and safe for use by the solver.
-// This entails two things:
-//
-// * Ensuring that all LockedProject's identifiers are normalized.
-// * Defensively ensuring that no outside routine can modify the lock while the
-// solver is in-flight.
+// prepLock ensures a lock is prepared and safe for use by the solver. This is
+// mostly about defensively ensuring that no outside routine can modify the lock
+// while the solver is in-flight.
//
// This is achieved by copying the lock's data into a new safeLock.
func prepLock(l Lock) Lock {
pl := l.Projects()
- rl := safeLock{
- h: l.InputHash(),
- p: make([]LockedProject, len(pl)),
- }
-
- for k, lp := range pl {
- lp.pi = lp.pi.normalize()
- rl.p[k] = lp
- }
+ rl := safeLock{h: l.InputHash()}
+ copy(rl.p, pl)
return rl
}
+
+// SortLockedProjects sorts a slice of LockedProject in alphabetical order by
+// ProjectRoot.
+func SortLockedProjects(lps []LockedProject) {
+ sort.Stable(lpsorter(lps))
+}
+
+type lpsorter []LockedProject
+
+func (lps lpsorter) Swap(i, j int) {
+ lps[i], lps[j] = lps[j], lps[i]
+}
+
+func (lps lpsorter) Len() int {
+ return len(lps)
+}
+
+func (lps lpsorter) Less(i, j int) bool {
+ return lps[i].pi.ProjectRoot < lps[j].pi.ProjectRoot
+}
diff --git a/vendor/github.com/sdboyer/gps/lock_test.go b/vendor/github.com/sdboyer/gps/lock_test.go
new file mode 100644
index 0000000..b580502
--- /dev/null
+++ b/vendor/github.com/sdboyer/gps/lock_test.go
@@ -0,0 +1,26 @@
+package gps
+
+import (
+ "reflect"
+ "testing"
+)
+
+func TestLockedProjectSorting(t *testing.T) {
+ // version doesn't matter here
+ lps := []LockedProject{
+ NewLockedProject(mkPI("github.com/sdboyer/gps"), NewVersion("v0.10.0"), nil),
+ NewLockedProject(mkPI("foo"), NewVersion("nada"), nil),
+ NewLockedProject(mkPI("bar"), NewVersion("zip"), nil),
+ NewLockedProject(mkPI("qux"), NewVersion("zilch"), nil),
+ }
+ lps2 := make([]LockedProject, len(lps))
+ copy(lps2, lps)
+
+ SortLockedProjects(lps2)
+
+ // only the two should have switched positions
+ lps[0], lps[2] = lps[2], lps[0]
+ if !reflect.DeepEqual(lps, lps2) {
+ t.Errorf("SortLockedProject did not sort as expected:\n\t(GOT) %s\n\t(WNT) %s", lps2, lps)
+ }
+}
diff --git a/vendor/github.com/sdboyer/gps/manager_test.go b/vendor/github.com/sdboyer/gps/manager_test.go
index df85293..f3892d6 100644
--- a/vendor/github.com/sdboyer/gps/manager_test.go
+++ b/vendor/github.com/sdboyer/gps/manager_test.go
@@ -7,7 +7,6 @@
"path"
"path/filepath"
"runtime"
- "sort"
"sync"
"testing"
@@ -124,7 +123,7 @@
}
}()
- id := mkPI("github.com/Masterminds/VCSTestRepo")
+ id := mkPI("github.com/Masterminds/VCSTestRepo").normalize()
v, err := sm.ListVersions(id)
if err != nil {
t.Errorf("Unexpected error during initial project setup/fetching %s", err)
@@ -142,7 +141,7 @@
// SourceManager itself doesn't guarantee ordering; sort them here so we
// can dependably check output
- sort.Sort(upgradeVersionSorter(v))
+ SortForUpgrade(v)
for k, e := range expected {
if v[k] != e {
@@ -220,7 +219,7 @@
func TestMgrMethodsFailWithBadPath(t *testing.T) {
// a symbol will always bork it up
- bad := mkPI("foo/##&^")
+ bad := mkPI("foo/##&^").normalize()
sm, clean := mkNaiveSM(t)
defer clean()
@@ -257,9 +256,9 @@
sm, clean := mkNaiveSM(t)
pil := []ProjectIdentifier{
- mkPI("github.com/Masterminds/VCSTestRepo"),
- mkPI("bitbucket.org/mattfarina/testhgrepo"),
- mkPI("launchpad.net/govcstestbzrrepo"),
+ mkPI("github.com/Masterminds/VCSTestRepo").normalize(),
+ mkPI("bitbucket.org/mattfarina/testhgrepo").normalize(),
+ mkPI("launchpad.net/govcstestbzrrepo").normalize(),
}
wg := &sync.WaitGroup{}
@@ -325,7 +324,7 @@
// setup done, now do the test
- id := mkPI("github.com/Masterminds/VCSTestRepo")
+ id := mkPI("github.com/Masterminds/VCSTestRepo").normalize()
_, _, err := sm.GetManifestAndLock(id, NewVersion("1.0.0"))
if err != nil {
diff --git a/vendor/github.com/sdboyer/gps/manifest.go b/vendor/github.com/sdboyer/gps/manifest.go
index 86d06cc..94513d0 100644
--- a/vendor/github.com/sdboyer/gps/manifest.go
+++ b/vendor/github.com/sdboyer/gps/manifest.go
@@ -92,12 +92,8 @@
}
// prepManifest ensures a manifest is prepared and safe for use by the solver.
-// This entails two things:
-//
-// * Ensuring that all ProjectIdentifiers are normalized (otherwise matching
-// can get screwy and the queues go out of alignment)
-// * Defensively ensuring that no outside routine can modify the manifest while
-// the solver is in-flight.
+// This is mostly about ensuring that no outside routine can modify the manifest
+// while the solver is in-flight.
//
// This is achieved by copying the manifest's data into a new SimpleManifest.
func prepManifest(m Manifest) Manifest {
@@ -114,11 +110,9 @@
}
for k, d := range deps {
- d.Ident = d.Ident.normalize()
rm.Deps[k] = d
}
for k, d := range ddeps {
- d.Ident = d.Ident.normalize()
rm.TestDeps[k] = d
}
diff --git a/vendor/github.com/sdboyer/gps/result.go b/vendor/github.com/sdboyer/gps/result.go
index 00dac45..d62d06b 100644
--- a/vendor/github.com/sdboyer/gps/result.go
+++ b/vendor/github.com/sdboyer/gps/result.go
@@ -32,6 +32,10 @@
// whether or not to strip vendor directories contained in the exported
// dependencies.
func WriteDepTree(basedir string, l Lock, sm SourceManager, sv bool) error {
+ if l == nil {
+ return fmt.Errorf("must provide non-nil Lock to WriteDepTree")
+ }
+
err := os.MkdirAll(basedir, 0777)
if err != nil {
return err
@@ -49,7 +53,7 @@
err = sm.ExportProject(p.Ident(), p.Version(), to)
if err != nil {
removeAll(basedir)
- return fmt.Errorf("Error while exporting %s: %s", p.Ident().ProjectRoot, err)
+ return fmt.Errorf("error while exporting %s: %s", p.Ident().ProjectRoot, err)
}
if sv {
filepath.Walk(to, stripVendor)
diff --git a/vendor/github.com/sdboyer/gps/result_test.go b/vendor/github.com/sdboyer/gps/result_test.go
index 2ae07ec..ac98678 100644
--- a/vendor/github.com/sdboyer/gps/result_test.go
+++ b/vendor/github.com/sdboyer/gps/result_test.go
@@ -37,10 +37,10 @@
}
}
-func TestResultCreateVendorTree(t *testing.T) {
+func TestWriteDepTree(t *testing.T) {
// This test is a bit slow, skip it on -short
if testing.Short() {
- t.Skip("Skipping vendor tree creation test in short mode")
+ t.Skip("Skipping dep tree writing test in short mode")
}
r := basicResult
@@ -51,7 +51,13 @@
sm, clean := mkNaiveSM(t)
defer clean()
- err := WriteDepTree(path.Join(tmp, "export"), r, sm, true)
+ // nil lock/result should err immediately
+ err := WriteDepTree(path.Join(tmp, "export"), nil, sm, true)
+ if err == nil {
+ t.Errorf("Should error if nil lock is passed to WriteDepTree")
+ }
+
+ err = WriteDepTree(path.Join(tmp, "export"), r, sm, true)
if err != nil {
t.Errorf("Unexpected error while creating vendor tree: %s", err)
}
diff --git a/vendor/github.com/sdboyer/gps/satisfy.go b/vendor/github.com/sdboyer/gps/satisfy.go
index ef9e688..78cffa0 100644
--- a/vendor/github.com/sdboyer/gps/satisfy.go
+++ b/vendor/github.com/sdboyer/gps/satisfy.go
@@ -194,22 +194,20 @@
// network source is.
func (s *solver) checkIdentMatches(a atomWithPackages, cdep completeDep) error {
dep := cdep.workingConstraint
- if cur, exists := s.names[dep.Ident.ProjectRoot]; exists {
- if cur != dep.Ident.netName() {
- deps := s.sel.getDependenciesOn(a.a.id)
- // Fail all the other deps, as there's no way atom can ever be
- // compatible with them
- for _, d := range deps {
- s.fail(d.depender.id)
- }
+ if curid, has := s.sel.getIdentFor(dep.Ident.ProjectRoot); has && !curid.equiv(dep.Ident) {
+ deps := s.sel.getDependenciesOn(a.a.id)
+ // Fail all the other deps, as there's no way atom can ever be
+ // compatible with them
+ for _, d := range deps {
+ s.fail(d.depender.id)
+ }
- return &sourceMismatchFailure{
- shared: dep.Ident.ProjectRoot,
- sel: deps,
- current: cur,
- mismatch: dep.Ident.netName(),
- prob: a.a,
- }
+ return &sourceMismatchFailure{
+ shared: dep.Ident.ProjectRoot,
+ sel: deps,
+ current: curid.netName(),
+ mismatch: dep.Ident.netName(),
+ prob: a.a,
}
}
diff --git a/vendor/github.com/sdboyer/gps/selection.go b/vendor/github.com/sdboyer/gps/selection.go
index 9362fb0..7f03c51 100644
--- a/vendor/github.com/sdboyer/gps/selection.go
+++ b/vendor/github.com/sdboyer/gps/selection.go
@@ -2,7 +2,7 @@
type selection struct {
projects []selected
- deps map[ProjectIdentifier][]dependency
+ deps map[ProjectRoot][]dependency
sm sourceBridge
}
@@ -12,13 +12,29 @@
}
func (s *selection) getDependenciesOn(id ProjectIdentifier) []dependency {
- if deps, exists := s.deps[id]; exists {
+ if deps, exists := s.deps[id.ProjectRoot]; exists {
return deps
}
return nil
}
+// getIdentFor returns the ProjectIdentifier (so, the network name) currently in
+// use for the provided ProjectRoot.
+//
+// If no dependencies are present yet that designate a network name for
+// the provided root, this will return an empty ProjectIdentifier and false.
+func (s *selection) getIdentFor(pr ProjectRoot) (ProjectIdentifier, bool) {
+ deps := s.getDependenciesOn(ProjectIdentifier{ProjectRoot: pr})
+ if len(deps) == 0 {
+ return ProjectIdentifier{}, false
+ }
+
+ // For now, at least, the solver maintains (assumes?) the invariant that
+ // whatever is first in the deps list decides the net name to be used.
+ return deps[0].dep.Ident, true
+}
+
// pushSelection pushes a new atomWithPackages onto the selection stack, along
// with an indicator as to whether this selection indicates a new project *and*
// packages, or merely some new packages on a project that was already selected.
@@ -40,21 +56,21 @@
}
func (s *selection) pushDep(dep dependency) {
- s.deps[dep.dep.Ident] = append(s.deps[dep.dep.Ident], dep)
+ s.deps[dep.dep.Ident.ProjectRoot] = append(s.deps[dep.dep.Ident.ProjectRoot], dep)
}
func (s *selection) popDep(id ProjectIdentifier) (dep dependency) {
- deps := s.deps[id]
- dep, s.deps[id] = deps[len(deps)-1], deps[:len(deps)-1]
+ deps := s.deps[id.ProjectRoot]
+ dep, s.deps[id.ProjectRoot] = deps[len(deps)-1], deps[:len(deps)-1]
return dep
}
func (s *selection) depperCount(id ProjectIdentifier) int {
- return len(s.deps[id])
+ return len(s.deps[id.ProjectRoot])
}
func (s *selection) setDependenciesOn(id ProjectIdentifier, deps []dependency) {
- s.deps[id] = deps
+ s.deps[id.ProjectRoot] = deps
}
// Compute a list of the unique packages within the given ProjectIdentifier that
@@ -64,7 +80,7 @@
// precompute it on pushing a new dep, and preferably with an immut
// structure so that we can pop with zero cost.
uniq := make(map[string]int)
- for _, dep := range s.deps[id] {
+ for _, dep := range s.deps[id.ProjectRoot] {
for _, pkg := range dep.dep.pl {
if count, has := uniq[pkg]; has {
count++
@@ -103,7 +119,7 @@
}
func (s *selection) getConstraint(id ProjectIdentifier) Constraint {
- deps, exists := s.deps[id]
+ deps, exists := s.deps[id.ProjectRoot]
if !exists || len(deps) == 0 {
return any
}
@@ -133,7 +149,7 @@
// have happened later.
func (s *selection) selected(id ProjectIdentifier) (atomWithPackages, bool) {
for _, p := range s.projects {
- if p.a.a.id.eq(id) {
+ if p.a.a.id.ProjectRoot == id.ProjectRoot {
return p.a, true
}
}
diff --git a/vendor/github.com/sdboyer/gps/solve_basic_test.go b/vendor/github.com/sdboyer/gps/solve_basic_test.go
index e4c1352..c0ca587 100644
--- a/vendor/github.com/sdboyer/gps/solve_basic_test.go
+++ b/vendor/github.com/sdboyer/gps/solve_basic_test.go
@@ -8,7 +8,7 @@
"github.com/Masterminds/semver"
)
-var regfrom = regexp.MustCompile(`^(\w*) from (\w*) ([0-9\.]*)`)
+var regfrom = regexp.MustCompile(`^(\w*) from (\w*) ([0-9\.\*]*)`)
// nvSplit splits an "info" string on " " into the pair of name and
// version/constraint, and returns each individually.
@@ -28,9 +28,6 @@
}
id.ProjectRoot, version = ProjectRoot(s[0]), s[1]
- if id.NetworkName == "" {
- id.NetworkName = string(id.ProjectRoot)
- }
return
}
@@ -44,7 +41,7 @@
func nvrSplit(info string) (id ProjectIdentifier, version string, revision Revision) {
if strings.Contains(info, " from ") {
parts := regfrom.FindStringSubmatch(info)
- info = parts[1] + " " + parts[3]
+ info = fmt.Sprintf("%s %s", parts[1], parts[3])
id.NetworkName = parts[2]
}
@@ -54,9 +51,6 @@
}
id.ProjectRoot, version = ProjectRoot(s[0]), s[1]
- if id.NetworkName == "" {
- id.NetworkName = string(id.ProjectRoot)
- }
if len(s) == 3 {
revision = Revision(s[2])
@@ -211,7 +205,7 @@
// treated as a test-only dependency.
func mkDepspec(pi string, deps ...string) depspec {
pa := mkAtom(pi)
- if string(pa.id.ProjectRoot) != pa.id.NetworkName {
+ if string(pa.id.ProjectRoot) != pa.id.NetworkName && pa.id.NetworkName != "" {
panic("alternate source on self makes no sense")
}
@@ -249,7 +243,6 @@
workingConstraint: workingConstraint{
Ident: ProjectIdentifier{
ProjectRoot: ProjectRoot(pdep),
- NetworkName: pdep,
},
Constraint: c,
},
@@ -259,11 +252,13 @@
}
// mkPI creates a ProjectIdentifier with the ProjectRoot as the provided
-// string, and with the NetworkName normalized to be the same.
+// string, and the NetworkName unset.
+//
+// Call normalize() on the returned value if you need the NetworkName to be be
+// equal to the ProjectRoot.
func mkPI(root string) ProjectIdentifier {
return ProjectIdentifier{
ProjectRoot: ProjectRoot(root),
- NetworkName: root,
}
}
@@ -281,7 +276,7 @@
l := make(fixLock, 0)
for _, s := range pairs {
pa := mkAtom(s)
- l = append(l, NewLockedProject(pa.id.ProjectRoot, pa.v, pa.id.netName(), nil))
+ l = append(l, NewLockedProject(pa.id, pa.v, nil))
}
return l
@@ -293,19 +288,18 @@
l := make(fixLock, 0)
for _, s := range pairs {
pa := mkAtom(s)
- l = append(l, NewLockedProject(pa.id.ProjectRoot, pa.v.(PairedVersion).Underlying(), pa.id.netName(), nil))
+ l = append(l, NewLockedProject(pa.id, pa.v.(PairedVersion).Underlying(), nil))
}
return l
}
// mksolution makes a result set
-func mksolution(pairs ...string) map[string]Version {
- m := make(map[string]Version)
+func mksolution(pairs ...string) map[ProjectIdentifier]Version {
+ m := make(map[ProjectIdentifier]Version)
for _, pair := range pairs {
a := mkAtom(pair)
- // TODO(sdboyer) identifierify
- m[string(a.id.ProjectRoot)] = a.v
+ m[a.id] = a.v
}
return m
@@ -356,7 +350,7 @@
rootmanifest() RootManifest
specs() []depspec
maxTries() int
- solution() map[string]Version
+ solution() map[ProjectIdentifier]Version
failure() error
}
@@ -380,7 +374,7 @@
// depspecs. always treat first as root
ds []depspec
// results; map of name/version pairs
- r map[string]Version
+ r map[ProjectIdentifier]Version
// max attempts the solver should need to find solution. 0 means no limit
maxAttempts int
// Use downgrade instead of default upgrade sorter
@@ -407,7 +401,7 @@
return f.maxAttempts
}
-func (f basicFixture) solution() map[string]Version {
+func (f basicFixture) solution() map[ProjectIdentifier]Version {
return f.r
}
@@ -519,28 +513,6 @@
),
maxAttempts: 2,
},
- "with mismatched net addrs": {
- ds: []depspec{
- mkDepspec("root 1.0.0", "foo 1.0.0", "bar 1.0.0"),
- mkDepspec("foo 1.0.0", "bar from baz 1.0.0"),
- mkDepspec("bar 1.0.0"),
- },
- fail: &noVersionError{
- pn: mkPI("foo"),
- fails: []failedVersion{
- {
- v: NewVersion("1.0.0"),
- f: &sourceMismatchFailure{
- shared: ProjectRoot("bar"),
- current: "bar",
- mismatch: "baz",
- prob: mkAtom("foo 1.0.0"),
- sel: []dependency{mkDep("root", "foo 1.0.0", "foo")},
- },
- },
- },
- },
- },
// fixtures with locks
"with compatible locked dependency": {
ds: []depspec{
@@ -1098,7 +1070,7 @@
},
r: mksolution(
"foo 1.0.0",
- "bar 1.0.0",
+ "bar from bar 1.0.0",
),
},
@@ -1204,7 +1176,7 @@
func (sm *depspecSourceManager) GetManifestAndLock(id ProjectIdentifier, v Version) (Manifest, Lock, error) {
for _, ds := range sm.specs {
- if id.ProjectRoot == ds.n && v.Matches(ds.v) {
+ if id.netName() == string(ds.n) && v.Matches(ds.v) {
return ds, dummyLock{}, nil
}
}
@@ -1218,7 +1190,7 @@
}
func (sm *depspecSourceManager) ExternalReach(id ProjectIdentifier, v Version) (map[string][]string, error) {
- pid := pident{n: id.ProjectRoot, v: v}
+ pid := pident{n: ProjectRoot(id.netName()), v: v}
if m, exists := sm.rm[pid]; exists {
return m, nil
}
@@ -1227,7 +1199,7 @@
func (sm *depspecSourceManager) ListExternal(id ProjectIdentifier, v Version) ([]string, error) {
// This should only be called for the root
- pid := pident{n: id.ProjectRoot, v: v}
+ pid := pident{n: ProjectRoot(id.netName()), v: v}
if r, exists := sm.rm[pid]; exists {
return r[string(id.ProjectRoot)], nil
}
@@ -1235,18 +1207,17 @@
}
func (sm *depspecSourceManager) ListPackages(id ProjectIdentifier, v Version) (PackageTree, error) {
- pid := pident{n: id.ProjectRoot, v: v}
- n := id.ProjectRoot
+ pid := pident{n: ProjectRoot(id.netName()), v: v}
if r, exists := sm.rm[pid]; exists {
ptree := PackageTree{
- ImportRoot: string(n),
+ ImportRoot: string(pid.n),
Packages: map[string]PackageOrErr{
- string(n): {
+ string(pid.n): {
P: Package{
- ImportPath: string(n),
- Name: string(n),
- Imports: r[string(n)],
+ ImportPath: string(pid.n),
+ Name: string(pid.n),
+ Imports: r[string(pid.n)],
},
},
},
@@ -1254,14 +1225,14 @@
return ptree, nil
}
- return PackageTree{}, fmt.Errorf("Project %s at version %s could not be found", n, v)
+ return PackageTree{}, fmt.Errorf("Project %s at version %s could not be found", pid.n, v)
}
func (sm *depspecSourceManager) ListVersions(id ProjectIdentifier) (pi []Version, err error) {
for _, ds := range sm.specs {
// To simulate the behavior of the real SourceManager, we do not return
// revisions from ListVersions().
- if _, isrev := ds.v.(Revision); !isrev && id.ProjectRoot == ds.n {
+ if _, isrev := ds.v.(Revision); !isrev && id.netName() == string(ds.n) {
pi = append(pi, ds.v)
}
}
@@ -1275,7 +1246,7 @@
func (sm *depspecSourceManager) RevisionPresentIn(id ProjectIdentifier, r Revision) (bool, error) {
for _, ds := range sm.specs {
- if id.ProjectRoot == ds.n && r == ds.v {
+ if id.netName() == string(ds.n) && r == ds.v {
return true, nil
}
}
@@ -1285,7 +1256,7 @@
func (sm *depspecSourceManager) SourceExists(id ProjectIdentifier) (bool, error) {
for _, ds := range sm.specs {
- if id.ProjectRoot == ds.n {
+ if id.netName() == string(ds.n) {
return true, nil
}
}
diff --git a/vendor/github.com/sdboyer/gps/solve_bimodal_test.go b/vendor/github.com/sdboyer/gps/solve_bimodal_test.go
index f62619d..9ebe483 100644
--- a/vendor/github.com/sdboyer/gps/solve_bimodal_test.go
+++ b/vendor/github.com/sdboyer/gps/solve_bimodal_test.go
@@ -516,6 +516,172 @@
"a 1.0.0",
),
},
+ "alternate net address": {
+ ds: []depspec{
+ dsp(mkDepspec("root 1.0.0", "foo from bar 2.0.0"),
+ pkg("root", "foo")),
+ dsp(mkDepspec("foo 1.0.0"),
+ pkg("foo")),
+ dsp(mkDepspec("foo 2.0.0"),
+ pkg("foo")),
+ dsp(mkDepspec("bar 1.0.0"),
+ pkg("foo")),
+ dsp(mkDepspec("bar 2.0.0"),
+ pkg("foo")),
+ },
+ r: mksolution(
+ "foo from bar 2.0.0",
+ ),
+ },
+ "alternate net address, version only in alt": {
+ ds: []depspec{
+ dsp(mkDepspec("root 1.0.0", "foo from bar 2.0.0"),
+ pkg("root", "foo")),
+ dsp(mkDepspec("foo 1.0.0"),
+ pkg("foo")),
+ dsp(mkDepspec("bar 1.0.0"),
+ pkg("foo")),
+ dsp(mkDepspec("bar 2.0.0"),
+ pkg("foo")),
+ },
+ r: mksolution(
+ "foo from bar 2.0.0",
+ ),
+ },
+ "alternate net address in dep": {
+ ds: []depspec{
+ dsp(mkDepspec("root 1.0.0", "foo 1.0.0"),
+ pkg("root", "foo")),
+ dsp(mkDepspec("foo 1.0.0", "bar from baz 2.0.0"),
+ pkg("foo", "bar")),
+ dsp(mkDepspec("bar 1.0.0"),
+ pkg("bar")),
+ dsp(mkDepspec("baz 1.0.0"),
+ pkg("bar")),
+ dsp(mkDepspec("baz 2.0.0"),
+ pkg("bar")),
+ },
+ r: mksolution(
+ "foo 1.0.0",
+ "bar from baz 2.0.0",
+ ),
+ },
+ // Because NOT specifying an alternate net address for a given import path
+ // is taken as an "eh, whatever", if we see an empty net addr after
+ // something else has already set an alternate one, then the second should
+ // just "go along" with whatever's already been specified.
+ "alternate net address with second depper": {
+ ds: []depspec{
+ dsp(mkDepspec("root 1.0.0", "foo from bar 2.0.0"),
+ pkg("root", "foo", "baz")),
+ dsp(mkDepspec("foo 1.0.0"),
+ pkg("foo")),
+ dsp(mkDepspec("foo 2.0.0"),
+ pkg("foo")),
+ dsp(mkDepspec("bar 1.0.0"),
+ pkg("foo")),
+ dsp(mkDepspec("bar 2.0.0"),
+ pkg("foo")),
+ dsp(mkDepspec("baz 1.0.0"),
+ pkg("baz", "foo")),
+ },
+ r: mksolution(
+ "foo from bar 2.0.0",
+ "baz 1.0.0",
+ ),
+ },
+ // Same as the previous, except the alternate declaration originates in a
+ // dep, not the root.
+ "alternate net addr from dep, with second default depper": {
+ ds: []depspec{
+ dsp(mkDepspec("root 1.0.0", "foo 1.0.0"),
+ pkg("root", "foo", "bar")),
+ dsp(mkDepspec("foo 1.0.0", "bar 2.0.0"),
+ pkg("foo", "baz")),
+ dsp(mkDepspec("foo 2.0.0", "bar 2.0.0"),
+ pkg("foo", "baz")),
+ dsp(mkDepspec("bar 2.0.0", "baz from quux 1.0.0"),
+ pkg("bar", "baz")),
+ dsp(mkDepspec("baz 1.0.0"),
+ pkg("baz")),
+ dsp(mkDepspec("baz 2.0.0"),
+ pkg("baz")),
+ dsp(mkDepspec("quux 1.0.0"),
+ pkg("baz")),
+ },
+ r: mksolution(
+ "foo 1.0.0",
+ "bar 2.0.0",
+ "baz from quux 1.0.0",
+ ),
+ },
+ // When a given project is initially brought in using the default (i.e.,
+ // empty) ProjectIdentifier.NetworkName, and a later, presumably
+ // as-yet-undiscovered dependency specifies an alternate net addr for it, we
+ // have to fail - even though, if the deps were visited in the opposite
+ // order (deeper dep w/the alternate location first, default location
+ // second), it would be fine.
+ //
+ // TODO A better solution here would involve restarting the solver w/a
+ // marker to use that alternate, or (ugh) introducing a new failure
+ // path/marker type that changes how backtracking works. (In fact, these
+ // approaches are probably demonstrably equivalent.)
+ "fails with net mismatch when deeper dep specs it": {
+ ds: []depspec{
+ dsp(mkDepspec("root 1.0.0", "foo 1.0.0"),
+ pkg("root", "foo", "baz")),
+ dsp(mkDepspec("foo 1.0.0", "bar 2.0.0"),
+ pkg("foo", "bar")),
+ dsp(mkDepspec("bar 2.0.0", "baz from quux 1.0.0"),
+ pkg("bar", "baz")),
+ dsp(mkDepspec("baz 1.0.0"),
+ pkg("baz")),
+ dsp(mkDepspec("quux 1.0.0"),
+ pkg("baz")),
+ },
+ fail: &noVersionError{
+ pn: mkPI("bar"),
+ fails: []failedVersion{
+ {
+ v: NewVersion("2.0.0"),
+ f: &sourceMismatchFailure{
+ shared: ProjectRoot("baz"),
+ current: "baz",
+ mismatch: "quux",
+ prob: mkAtom("bar 2.0.0"),
+ sel: []dependency{mkDep("foo 1.0.0", "bar 2.0.0", "bar")},
+ },
+ },
+ },
+ },
+ },
+ "with mismatched net addrs": {
+ ds: []depspec{
+ dsp(mkDepspec("root 1.0.0", "foo 1.0.0", "bar 1.0.0"),
+ pkg("root", "foo", "bar")),
+ dsp(mkDepspec("foo 1.0.0", "bar from baz 1.0.0"),
+ pkg("foo", "bar")),
+ dsp(mkDepspec("bar 1.0.0"),
+ pkg("bar")),
+ dsp(mkDepspec("baz 1.0.0"),
+ pkg("bar")),
+ },
+ fail: &noVersionError{
+ pn: mkPI("foo"),
+ fails: []failedVersion{
+ {
+ v: NewVersion("1.0.0"),
+ f: &sourceMismatchFailure{
+ shared: ProjectRoot("bar"),
+ current: "bar",
+ mismatch: "baz",
+ prob: mkAtom("foo 1.0.0"),
+ sel: []dependency{mkDep("root", "foo 1.0.0", "foo")},
+ },
+ },
+ },
+ },
+ },
"overridden mismatched net addrs, alt in dep": {
ds: []depspec{
dsp(mkDepspec("root 0.0.0"),
@@ -575,7 +741,7 @@
// bimodal project. first is always treated as root project
ds []depspec
// results; map of name/version pairs
- r map[string]Version
+ r map[ProjectIdentifier]Version
// max attempts the solver should need to find solution. 0 means no limit
maxAttempts int
// Use downgrade instead of default upgrade sorter
@@ -607,7 +773,7 @@
return f.maxAttempts
}
-func (f bimodalFixture) solution() map[string]Version {
+func (f bimodalFixture) solution() map[ProjectIdentifier]Version {
return f.r
}
@@ -652,9 +818,9 @@
func (sm *bmSourceManager) ListPackages(id ProjectIdentifier, v Version) (PackageTree, error) {
for k, ds := range sm.specs {
// Cheat for root, otherwise we blow up b/c version is empty
- if id.ProjectRoot == ds.n && (k == 0 || ds.v.Matches(v)) {
+ if id.netName() == string(ds.n) && (k == 0 || ds.v.Matches(v)) {
ptree := PackageTree{
- ImportRoot: string(id.ProjectRoot),
+ ImportRoot: id.netName(),
Packages: make(map[string]PackageOrErr),
}
for _, pkg := range ds.pkgs {
@@ -676,8 +842,8 @@
func (sm *bmSourceManager) GetManifestAndLock(id ProjectIdentifier, v Version) (Manifest, Lock, error) {
for _, ds := range sm.specs {
- if id.ProjectRoot == ds.n && v.Matches(ds.v) {
- if l, exists := sm.lm[string(id.ProjectRoot)+" "+v.String()]; exists {
+ if id.netName() == string(ds.n) && v.Matches(ds.v) {
+ if l, exists := sm.lm[id.netName()+" "+v.String()]; exists {
return ds, l, nil
}
return ds, dummyLock{}, nil
diff --git a/vendor/github.com/sdboyer/gps/solve_test.go b/vendor/github.com/sdboyer/gps/solve_test.go
index 94ed8ba..53bcdcd 100644
--- a/vendor/github.com/sdboyer/gps/solve_test.go
+++ b/vendor/github.com/sdboyer/gps/solve_test.go
@@ -1,7 +1,9 @@
package gps
import (
+ "bytes"
"flag"
+ "fmt"
"io/ioutil"
"log"
"math/rand"
@@ -153,6 +155,14 @@
}
func fixtureSolveSimpleChecks(fix specfix, soln Solution, err error, t *testing.T) (Solution, error) {
+ ppi := func(id ProjectIdentifier) string {
+ // need this so we can clearly tell if there's a NetworkName or not
+ if id.NetworkName == "" {
+ return string(id.ProjectRoot)
+ }
+ return fmt.Sprintf("%s (from %s)", id.ProjectRoot, id.NetworkName)
+ }
+
fixfail := fix.failure()
if err != nil {
if fixfail == nil {
@@ -163,7 +173,12 @@
t.Errorf("(fixture: %q) Failure mismatch:\n\t(GOT): %s\n\t(WNT): %s", fix.name(), err, fixfail)
}
} else if fixfail != nil {
- t.Errorf("(fixture: %q) Solver succeeded, but expecting failure:\n%s", fix.name(), fixfail)
+ var buf bytes.Buffer
+ fmt.Fprintf(&buf, "(fixture: %q) Solver succeeded, but expecting failure:\n%s\nProjects in solution:", fix.name(), fixfail)
+ for _, p := range soln.Projects() {
+ fmt.Fprintf(&buf, "\n\t- %s at %s", ppi(p.Ident()), p.Version())
+ }
+ t.Error(buf.String())
} else {
r := soln.(solution)
if fix.maxTries() > 0 && r.Attempts() > fix.maxTries() {
@@ -171,10 +186,10 @@
}
// Dump result projects into a map for easier interrogation
- rp := make(map[string]Version)
+ rp := make(map[ProjectIdentifier]Version)
for _, p := range r.p {
pa := p.toAtom()
- rp[string(pa.id.ProjectRoot)] = pa.v
+ rp[pa.id] = pa.v
}
fixlen, rlen := len(fix.solution()), len(rp)
@@ -187,12 +202,12 @@
// Walk through fixture/expected results first
for p, v := range fix.solution() {
if av, exists := rp[p]; !exists {
- t.Errorf("(fixture: %q) Project %q expected but missing from results", fix.name(), p)
+ t.Errorf("(fixture: %q) Project %q expected but missing from results", fix.name(), ppi(p))
} else {
// delete result from map so we skip it on the reverse pass
delete(rp, p)
if v != av {
- t.Errorf("(fixture: %q) Expected version %q of project %q, but actual version was %q", fix.name(), v, p, av)
+ t.Errorf("(fixture: %q) Expected version %q of project %q, but actual version was %q", fix.name(), v, ppi(p), av)
}
}
}
@@ -200,9 +215,9 @@
// Now walk through remaining actual results
for p, v := range rp {
if fv, exists := fix.solution()[p]; !exists {
- t.Errorf("(fixture: %q) Unexpected project %q present in results", fix.name(), p)
+ t.Errorf("(fixture: %q) Unexpected project %q present in results", fix.name(), ppi(p))
} else if v != fv {
- t.Errorf("(fixture: %q) Got version %q of project %q, but expected version was %q", fix.name(), v, p, fv)
+ t.Errorf("(fixture: %q) Got version %q of project %q, but expected version was %q", fix.name(), v, ppi(p), fv)
}
}
}
diff --git a/vendor/github.com/sdboyer/gps/solver.go b/vendor/github.com/sdboyer/gps/solver.go
index 507133b..f7d9a24 100644
--- a/vendor/github.com/sdboyer/gps/solver.go
+++ b/vendor/github.com/sdboyer/gps/solver.go
@@ -145,22 +145,17 @@
// A map of the ProjectRoot (local names) that should be allowed to change
chng map[ProjectRoot]struct{}
- // A map of the ProjectRoot (local names) that are currently selected, and
- // the network name to which they currently correspond.
- // TODO(sdboyer) i think this is cruft and can be removed
- names map[ProjectRoot]string
-
// A ProjectConstraints map containing the validated (guaranteed non-empty)
// overrides declared by the root manifest.
ovr ProjectConstraints
- // A map of the names listed in the root's lock.
- rlm map[ProjectIdentifier]LockedProject
+ // A map of the project names listed in the root's lock.
+ rlm map[ProjectRoot]LockedProject
- // A normalized, copied version of the root manifest.
+ // A defensively-copied instance of the root manifest.
rm Manifest
- // A normalized, copied version of the root lock.
+ // A defensively-copied instance of the root lock.
rl Lock
}
@@ -253,8 +248,7 @@
// Initialize maps
s.chng = make(map[ProjectRoot]struct{})
- s.rlm = make(map[ProjectIdentifier]LockedProject)
- s.names = make(map[ProjectRoot]string)
+ s.rlm = make(map[ProjectRoot]LockedProject)
for _, v := range s.params.ToChange {
s.chng[v] = struct{}{}
@@ -262,7 +256,7 @@
// Initialize stacks and queues
s.sel = &selection{
- deps: make(map[ProjectIdentifier][]dependency),
+ deps: make(map[ProjectRoot][]dependency),
sm: s.b,
}
s.unsel = &unselected{
@@ -274,7 +268,7 @@
s.rm = prepManifest(s.params.Manifest)
if s.params.Lock != nil {
for _, lp := range s.params.Lock.Projects() {
- s.rlm[lp.Ident().normalize()] = lp
+ s.rlm[lp.Ident().ProjectRoot] = lp
}
// Also keep a prepped one, mostly for the bridge. This is probably
@@ -305,8 +299,8 @@
}
// An err here is impossible; it could only be caused by a parsing error
- // of the root tree, but that necessarily succeeded back up
- // selectRoot(), so we can ignore this err
+ // of the root tree, but that necessarily already succeeded back up in
+ // selectRoot(), so we can ignore the err return here
soln.hd, _ = s.HashInputs()
// Convert ProjectAtoms into LockedProjects
@@ -426,7 +420,7 @@
return projs, nil
}
-// selectRoot is a specialized selectAtomWithPackages, used solely to initially
+// selectRoot is a specialized selectAtom, used solely to initially
// populate the queues at the beginning of a solve run.
func (s *solver) selectRoot() error {
pa := atom{
@@ -480,13 +474,12 @@
// If we have no lock, or if this dep isn't in the lock, then prefetch
// it. See explanation longer comment in selectRoot() for how we benefit
// from parallelism here.
- if _, has := s.rlm[dep.Ident]; !has {
+ if _, has := s.rlm[dep.Ident.ProjectRoot]; !has {
go s.b.SyncSourceFor(dep.Ident)
}
s.sel.pushDep(dependency{depender: pa, dep: dep})
// Add all to unselected queue
- s.names[dep.Ident.ProjectRoot] = dep.Ident.netName()
heap.Push(s.unsel, bimodalIdentifier{id: dep.Ident, pl: dep.pl, fromRoot: true})
}
@@ -546,7 +539,6 @@
}
deps := s.ovr.overrideAll(m.DependencyConstraints())
-
return s.intersectConstraintsWithImports(deps, reach)
}
@@ -575,19 +567,8 @@
// Look for a prefix match; it'll be the root project/repo containing
// the reached package
- if k, idep, match := xt.LongestPrefix(rp); match {
- // The radix tree gets it mostly right, but we have to guard against
- // possibilities like this:
- //
- // github.com/sdboyer/foo
- // github.com/sdboyer/foobar/baz
- //
- // The latter would incorrectly be conflated with the former. So, as
- // we know we're operating on strings that describe paths, guard
- // against this case by verifying that either the input is the same
- // length as the match (in which case we know they're equal), or
- // that the next character is the is the PathSeparator.
- if len(k) == len(rp) || strings.IndexRune(rp[:len(k)], os.PathSeparator) == 0 {
+ if pre, idep, match := xt.LongestPrefix(rp); match {
+ if isPathPrefixOrEqual(pre, rp) {
// Match is valid; put it in the dmap, either creating a new
// completeDep or appending it to the existing one for this base
// project/prefix.
@@ -616,7 +597,6 @@
pd := s.ovr.override(ProjectConstraint{
Ident: ProjectIdentifier{
ProjectRoot: root,
- NetworkName: string(root),
},
Constraint: Any(),
})
@@ -843,7 +823,7 @@
}
}
- lp, exists := s.rlm[id]
+ lp, exists := s.rlm[id.ProjectRoot]
if !exists {
return nil, nil
}
@@ -980,6 +960,9 @@
// FIXME the impl here is currently O(n) in the number of selections; it
// absolutely cannot stay in a hot sorting path like this
+ // FIXME while other solver invariants probably protect us from it, this
+ // call-out means that it's possible for external state change to invalidate
+ // heap invariants.
_, isel := s.sel.selected(iname)
_, jsel := s.sel.selected(jname)
@@ -994,8 +977,8 @@
return false
}
- _, ilock := s.rlm[iname]
- _, jlock := s.rlm[jname]
+ _, ilock := s.rlm[iname.ProjectRoot]
+ _, jlock := s.rlm[jname.ProjectRoot]
switch {
case ilock && !jlock:
@@ -1101,7 +1084,7 @@
// few microseconds before blocking later. Best case, the dep doesn't
// come up next, but some other dep comes up that wasn't prefetched, and
// both fetches proceed in parallel.
- if _, has := s.rlm[dep.Ident]; !has {
+ if _, has := s.rlm[dep.Ident.ProjectRoot]; !has {
go s.b.SyncSourceFor(dep.Ident)
}
@@ -1128,10 +1111,6 @@
}
heap.Push(s.unsel, bmi)
}
-
- if s.sel.depperCount(dep.Ident) == 1 {
- s.names[dep.Ident.ProjectRoot] = dep.Ident.netName()
- }
}
s.traceSelect(a, pkgonly)
@@ -1153,7 +1132,6 @@
// if no parents/importers, remove from unselected queue
if s.sel.depperCount(dep.Ident) == 0 {
- delete(s.names, dep.Ident.ProjectRoot)
s.unsel.remove(bimodalIdentifier{id: dep.Ident, pl: dep.pl})
}
}
@@ -1164,7 +1142,7 @@
// simple (temporary?) helper just to convert atoms into locked projects
func pa2lp(pa atom, pkgs map[string]struct{}) LockedProject {
lp := LockedProject{
- pi: pa.id.normalize(), // shouldn't be necessary, but normalize just in case
+ pi: pa.id,
}
switch v := pa.v.(type) {
diff --git a/vendor/github.com/sdboyer/gps/source_manager.go b/vendor/github.com/sdboyer/gps/source_manager.go
index dc5a7ef..82064e4 100644
--- a/vendor/github.com/sdboyer/gps/source_manager.go
+++ b/vendor/github.com/sdboyer/gps/source_manager.go
@@ -257,9 +257,11 @@
// The non-matching tail of the import path could still be malformed.
// Validate just that part, if it exists
if prefix != ip {
- if !pathvld.MatchString(strings.TrimPrefix(ip, prefix)) {
- return "", fmt.Errorf("%q is not a valid import path", ip)
- }
+ // TODO(sdboyer) commented until i find a proper description of how
+ // to validate an import path
+ //if !pathvld.MatchString(strings.TrimPrefix(ip, prefix+"/")) {
+ //return "", fmt.Errorf("%q is not a valid import path", ip)
+ //}
// There was one, and it validated fine - add it so we don't have to
// revalidate it later
sm.rootxt.Insert(ip, root)
diff --git a/vendor/github.com/sdboyer/gps/source_test.go b/vendor/github.com/sdboyer/gps/source_test.go
index 907d9c3..ffee963 100644
--- a/vendor/github.com/sdboyer/gps/source_test.go
+++ b/vendor/github.com/sdboyer/gps/source_test.go
@@ -4,7 +4,6 @@
"io/ioutil"
"net/url"
"reflect"
- "sort"
"testing"
)
@@ -84,7 +83,7 @@
if len(vlist) != 3 {
t.Errorf("git test repo should've produced three versions, got %v: vlist was %s", len(vlist), vlist)
} else {
- sort.Sort(upgradeVersionSorter(vlist))
+ SortForUpgrade(vlist)
evl := []Version{
NewVersion("1.0.0").Is(Revision("30605f6ac35fcb075ad0bfa9296f90a7d891523e")),
NewBranch("master").Is(Revision("30605f6ac35fcb075ad0bfa9296f90a7d891523e")),
@@ -281,7 +280,7 @@
if len(vlist) != 2 {
t.Errorf("hg test repo should've produced one version, got %v", len(vlist))
} else {
- sort.Sort(upgradeVersionSorter(vlist))
+ SortForUpgrade(vlist)
if !reflect.DeepEqual(vlist, evl) {
t.Errorf("Version list was not what we expected:\n\t(GOT): %s\n\t(WNT): %s", vlist, evl)
}
@@ -303,7 +302,7 @@
if len(vlist) != 2 {
t.Errorf("hg test repo should've produced one version, got %v", len(vlist))
} else {
- sort.Sort(upgradeVersionSorter(vlist))
+ SortForUpgrade(vlist)
if !reflect.DeepEqual(vlist, evl) {
t.Errorf("Version list was not what we expected:\n\t(GOT): %s\n\t(WNT): %s", vlist, evl)
}
diff --git a/vendor/github.com/sdboyer/gps/typed_radix.go b/vendor/github.com/sdboyer/gps/typed_radix.go
index 9f56a9b..76b2f68 100644
--- a/vendor/github.com/sdboyer/gps/typed_radix.go
+++ b/vendor/github.com/sdboyer/gps/typed_radix.go
@@ -26,24 +26,24 @@
// Delete is used to delete a key, returning the previous value and if it was deleted
func (t deducerTrie) Delete(s string) (pathDeducer, bool) {
- if v, had := t.t.Delete(s); had {
- return v.(pathDeducer), had
+ if d, had := t.t.Delete(s); had {
+ return d.(pathDeducer), had
}
return nil, false
}
// Get is used to lookup a specific key, returning the value and if it was found
func (t deducerTrie) Get(s string) (pathDeducer, bool) {
- if v, has := t.t.Get(s); has {
- return v.(pathDeducer), has
+ if d, has := t.t.Get(s); has {
+ return d.(pathDeducer), has
}
return nil, false
}
// Insert is used to add a newentry or update an existing entry. Returns if updated.
-func (t deducerTrie) Insert(s string, v pathDeducer) (pathDeducer, bool) {
- if v2, had := t.t.Insert(s, v); had {
- return v2.(pathDeducer), had
+func (t deducerTrie) Insert(s string, d pathDeducer) (pathDeducer, bool) {
+ if d2, had := t.t.Insert(s, d); had {
+ return d2.(pathDeducer), had
}
return nil, false
}
@@ -56,8 +56,8 @@
// LongestPrefix is like Get, but instead of an exact match, it will return the
// longest prefix match.
func (t deducerTrie) LongestPrefix(s string) (string, pathDeducer, bool) {
- if p, v, has := t.t.LongestPrefix(s); has {
- return p, v.(pathDeducer), has
+ if p, d, has := t.t.LongestPrefix(s); has {
+ return p, d.(pathDeducer), has
}
return "", nil, false
}
@@ -65,8 +65,8 @@
// ToMap is used to walk the tree and convert it to a map.
func (t deducerTrie) ToMap() map[string]pathDeducer {
m := make(map[string]pathDeducer)
- t.t.Walk(func(s string, v interface{}) bool {
- m[s] = v.(pathDeducer)
+ t.t.Walk(func(s string, d interface{}) bool {
+ m[s] = d.(pathDeducer)
return false
})
@@ -85,24 +85,24 @@
// Delete is used to delete a key, returning the previous value and if it was deleted
func (t prTrie) Delete(s string) (ProjectRoot, bool) {
- if v, had := t.t.Delete(s); had {
- return v.(ProjectRoot), had
+ if pr, had := t.t.Delete(s); had {
+ return pr.(ProjectRoot), had
}
return "", false
}
// Get is used to lookup a specific key, returning the value and if it was found
func (t prTrie) Get(s string) (ProjectRoot, bool) {
- if v, has := t.t.Get(s); has {
- return v.(ProjectRoot), has
+ if pr, has := t.t.Get(s); has {
+ return pr.(ProjectRoot), has
}
return "", false
}
// Insert is used to add a newentry or update an existing entry. Returns if updated.
-func (t prTrie) Insert(s string, v ProjectRoot) (ProjectRoot, bool) {
- if v2, had := t.t.Insert(s, v); had {
- return v2.(ProjectRoot), had
+func (t prTrie) Insert(s string, pr ProjectRoot) (ProjectRoot, bool) {
+ if pr2, had := t.t.Insert(s, pr); had {
+ return pr2.(ProjectRoot), had
}
return "", false
}
@@ -115,8 +115,8 @@
// LongestPrefix is like Get, but instead of an exact match, it will return the
// longest prefix match.
func (t prTrie) LongestPrefix(s string) (string, ProjectRoot, bool) {
- if p, v, has := t.t.LongestPrefix(s); has && isPathPrefixOrEqual(p, s) {
- return p, v.(ProjectRoot), has
+ if p, pr, has := t.t.LongestPrefix(s); has && isPathPrefixOrEqual(p, s) {
+ return p, pr.(ProjectRoot), has
}
return "", "", false
}
@@ -124,8 +124,8 @@
// ToMap is used to walk the tree and convert it to a map.
func (t prTrie) ToMap() map[string]ProjectRoot {
m := make(map[string]ProjectRoot)
- t.t.Walk(func(s string, v interface{}) bool {
- m[s] = v.(ProjectRoot)
+ t.t.Walk(func(s string, pr interface{}) bool {
+ m[s] = pr.(ProjectRoot)
return false
})
@@ -133,7 +133,8 @@
}
// isPathPrefixOrEqual is an additional helper check to ensure that the literal
-// string prefix returned from a radix tree prefix match is also a tree match.
+// string prefix returned from a radix tree prefix match is also a path tree
+// match.
//
// The radix tree gets it mostly right, but we have to guard against
// possibilities like this:
@@ -142,10 +143,18 @@
// github.com/sdboyer/foobar/baz
//
// The latter would incorrectly be conflated with the former. As we know we're
-// operating on strings that describe paths, guard against this case by
+// operating on strings that describe import paths, guard against this case by
// verifying that either the input is the same length as the match (in which
-// case we know they're equal), or that the next character is a "/".
+// case we know they're equal), or that the next character is a "/". (Import
+// paths are defined to always use "/", not the OS-specific path separator.)
func isPathPrefixOrEqual(pre, path string) bool {
- prflen := len(pre)
- return prflen == len(path) || strings.Index(path[:prflen], "/") == 0
+ prflen, pathlen := len(pre), len(path)
+ if pathlen == prflen+1 {
+ // this can never be the case
+ return false
+ }
+
+ // we assume something else (a trie) has done equality check up to the point
+ // of the prefix, so we just check len
+ return prflen == pathlen || strings.Index(path[prflen:], "/") == 0
}
diff --git a/vendor/github.com/sdboyer/gps/typed_radix_test.go b/vendor/github.com/sdboyer/gps/typed_radix_test.go
new file mode 100644
index 0000000..8edf39b
--- /dev/null
+++ b/vendor/github.com/sdboyer/gps/typed_radix_test.go
@@ -0,0 +1,22 @@
+package gps
+
+import "testing"
+
+// basically a regression test
+func TestPathPrefixOrEqual(t *testing.T) {
+ if !isPathPrefixOrEqual("foo", "foo") {
+ t.Error("Same path should return true")
+ }
+
+ if isPathPrefixOrEqual("foo", "fooer") {
+ t.Error("foo is not a path-type prefix of fooer")
+ }
+
+ if !isPathPrefixOrEqual("foo", "foo/bar") {
+ t.Error("foo is a path prefix of foo/bar")
+ }
+
+ if isPathPrefixOrEqual("foo", "foo/") {
+ t.Error("special case - foo is not a path prefix of foo/")
+ }
+}
diff --git a/vendor/github.com/sdboyer/gps/types.go b/vendor/github.com/sdboyer/gps/types.go
index 657d786..11221e3 100644
--- a/vendor/github.com/sdboyer/gps/types.go
+++ b/vendor/github.com/sdboyer/gps/types.go
@@ -84,7 +84,7 @@
return false
}
- return i.NetworkName < j.NetworkName
+ return i.netName() < j.netName()
}
func (i ProjectIdentifier) eq(j ProjectIdentifier) bool {
@@ -100,7 +100,32 @@
return true
}
- // TODO(sdboyer) attempt conversion to URL and compare base + path
+ return false
+}
+
+// equiv will check if the two identifiers are "equivalent," under special
+// rules.
+//
+// Given that the ProjectRoots are equal (==), equivalency occurs if:
+//
+// 1. The NetworkNames are equal (==), OR
+// 2. The LEFT (the receiver) NetworkName is non-empty, and the right
+// NetworkName is empty.
+//
+// *This is, very much intentionally, an asymmetric binary relation.* It's
+// specifically intended to facilitate the case where we allow for a
+// ProjectIdentifier with an explicit NetworkName to match one without.
+func (i ProjectIdentifier) equiv(j ProjectIdentifier) bool {
+ if i.ProjectRoot != j.ProjectRoot {
+ return false
+ }
+ if i.NetworkName == j.NetworkName {
+ return true
+ }
+
+ if i.NetworkName != "" && j.NetworkName == "" {
+ return true
+ }
return false
}
diff --git a/vendor/github.com/sdboyer/gps/version.go b/vendor/github.com/sdboyer/gps/version.go
index ad79bff..1e15029 100644
--- a/vendor/github.com/sdboyer/gps/version.go
+++ b/vendor/github.com/sdboyer/gps/version.go
@@ -1,6 +1,10 @@
package gps
-import "github.com/Masterminds/semver"
+import (
+ "sort"
+
+ "github.com/Masterminds/semver"
+)
// Version represents one of the different types of versions used by gps.
//
@@ -297,7 +301,11 @@
}
func (v semVersion) String() string {
- return v.sv.Original()
+ str := v.sv.Original()
+ if str == "" {
+ str = v.sv.String()
+ }
+ return str
}
func (r semVersion) Type() string {
@@ -513,3 +521,151 @@
}
panic("unknown version type")
}
+
+// SortForUpgrade sorts a slice of []Version in roughly descending order, so
+// that presumably newer versions are visited first. The rules are:
+//
+// - All semver versions come first, and sort mostly according to the semver
+// 2.0 spec (as implemented by github.com/Masterminds/semver lib), with one
+// exception:
+// - Semver versions with a prerelease are after *all* non-prerelease semver.
+// Against each other, they are sorted first by their numerical component, then
+// lexicographically by their prerelease version.
+// - All non-semver versions (tags) are next, and sort lexicographically
+// against each other.
+// - All branches are next, and sort lexicographically against each other.
+// - Revisions are last, and sort lexicographically against each other.
+//
+// So, given a slice of the following versions:
+//
+// - Branch: master devel
+// - Semver tags: v1.0.0, v1.1.0, v1.1.0-alpha1
+// - Non-semver tags: footag
+// - Revision: f6e74e8d
+//
+// Sorting for upgrade will result in the following slice.
+//
+// [v1.1.0 v1.0.0 v1.1.0-alpha1 footag devel master f6e74e8d]
+func SortForUpgrade(vl []Version) {
+ sort.Sort(upgradeVersionSorter(vl))
+}
+
+// SortForDowngrade sorts a slice of []Version in roughly ascending order, so
+// that presumably older versions are visited first.
+//
+// This is *not* the reverse of the same as SortForUpgrade (or you could simply
+// sort.Reverse(). The type precedence is the same, including the
+// semver vs. semver-with-prerelease relation. Lexicographic comparisons within
+// non-semver tags, branches, and revisions remains the same as well; because
+// these domains have no implicit chronology, there is no reason to reverse
+// them.
+//
+// The only binary relation that is reversed for downgrade is within-type
+// comparisons for semver (with and without prerelease).
+//
+// So, given a slice of the following versions:
+//
+// - Branch: master devel
+// - Semver tags: v1.0.0, v1.1.0, v1.1.0-alpha1
+// - Non-semver tags: footag
+// - Revision: f6e74e8d
+//
+// Sorting for downgrade will result in the following slice.
+//
+// [v1.0.0 v1.1.0 v1.1.0-alpha1 footag devel master f6e74e8d]
+func SortForDowngrade(vl []Version) {
+ sort.Sort(downgradeVersionSorter(vl))
+}
+
+type upgradeVersionSorter []Version
+type downgradeVersionSorter []Version
+
+func (vs upgradeVersionSorter) Len() int {
+ return len(vs)
+}
+
+func (vs upgradeVersionSorter) Swap(i, j int) {
+ vs[i], vs[j] = vs[j], vs[i]
+}
+
+func (vs downgradeVersionSorter) Len() int {
+ return len(vs)
+}
+
+func (vs downgradeVersionSorter) Swap(i, j int) {
+ vs[i], vs[j] = vs[j], vs[i]
+}
+
+func (vs upgradeVersionSorter) Less(i, j int) bool {
+ l, r := vs[i], vs[j]
+
+ if tl, ispair := l.(versionPair); ispair {
+ l = tl.v
+ }
+ if tr, ispair := r.(versionPair); ispair {
+ r = tr.v
+ }
+
+ switch compareVersionType(l, r) {
+ case -1:
+ return true
+ case 1:
+ return false
+ case 0:
+ break
+ default:
+ panic("unreachable")
+ }
+
+ switch l.(type) {
+ // For these, now nothing to do but alpha sort
+ case Revision, branchVersion, plainVersion:
+ return l.String() < r.String()
+ }
+
+ // This ensures that pre-release versions are always sorted after ALL
+ // full-release versions
+ lsv, rsv := l.(semVersion).sv, r.(semVersion).sv
+ lpre, rpre := lsv.Prerelease() == "", rsv.Prerelease() == ""
+ if (lpre && !rpre) || (!lpre && rpre) {
+ return lpre
+ }
+ return lsv.GreaterThan(rsv)
+}
+
+func (vs downgradeVersionSorter) Less(i, j int) bool {
+ l, r := vs[i], vs[j]
+
+ if tl, ispair := l.(versionPair); ispair {
+ l = tl.v
+ }
+ if tr, ispair := r.(versionPair); ispair {
+ r = tr.v
+ }
+
+ switch compareVersionType(l, r) {
+ case -1:
+ return true
+ case 1:
+ return false
+ case 0:
+ break
+ default:
+ panic("unreachable")
+ }
+
+ switch l.(type) {
+ // For these, now nothing to do but alpha
+ case Revision, branchVersion, plainVersion:
+ return l.String() < r.String()
+ }
+
+ // This ensures that pre-release versions are always sorted after ALL
+ // full-release versions
+ lsv, rsv := l.(semVersion).sv, r.(semVersion).sv
+ lpre, rpre := lsv.Prerelease() == "", rsv.Prerelease() == ""
+ if (lpre && !rpre) || (!lpre && rpre) {
+ return lpre
+ }
+ return lsv.LessThan(rsv)
+}
diff --git a/vendor/github.com/sdboyer/gps/version_queue.go b/vendor/github.com/sdboyer/gps/version_queue.go
index 7c92253..dc5da98 100644
--- a/vendor/github.com/sdboyer/gps/version_queue.go
+++ b/vendor/github.com/sdboyer/gps/version_queue.go
@@ -18,6 +18,7 @@
b sourceBridge
failed bool
allLoaded bool
+ adverr error
}
func newVersionQueue(id ProjectIdentifier, lockv, prefv Version, b sourceBridge) (*versionQueue, error) {
@@ -63,10 +64,10 @@
// advance moves the versionQueue forward to the next available version,
// recording the failure that eliminated the current version.
-func (vq *versionQueue) advance(fail error) (err error) {
+func (vq *versionQueue) advance(fail error) error {
// Nothing in the queue means...nothing in the queue, nicely enough
- if len(vq.pi) == 0 {
- return
+ if vq.adverr != nil || len(vq.pi) == 0 { // should be a redundant check, but just in case
+ return vq.adverr
}
// Record the fail reason and pop the queue
@@ -80,32 +81,43 @@
if len(vq.pi) == 0 {
if vq.allLoaded {
// This branch gets hit when the queue is first fully exhausted,
- // after having been populated by ListVersions() on a previous
- // advance()
- return
+ // after a previous advance() already called ListVersions().
+ return nil
}
-
vq.allLoaded = true
- vq.pi, err = vq.b.ListVersions(vq.id)
- if err != nil {
- return err
- }
- // search for and remove locked and pref versions
+ var vltmp []Version
+ vltmp, vq.adverr = vq.b.ListVersions(vq.id)
+ if vq.adverr != nil {
+ return vq.adverr
+ }
+ // defensive copy - calling ListVersions here means slice contents may
+ // be modified when removing prefv/lockv.
+ vq.pi = make([]Version, len(vltmp))
+ copy(vq.pi, vltmp)
+
+ // search for and remove lockv and prefv, in a pointer GC-safe manner
//
// could use the version comparator for binary search here to avoid
// O(n) each time...if it matters
+ var delkeys []int
for k, pi := range vq.pi {
if pi == vq.lockv || pi == vq.prefv {
- // GC-safe deletion for slice w/pointer elements
- vq.pi, vq.pi[len(vq.pi)-1] = append(vq.pi[:k], vq.pi[k+1:]...), nil
- //vq.pi = append(vq.pi[:k], vq.pi[k+1:]...)
+ delkeys = append(delkeys, k)
}
}
+ for k, dk := range delkeys {
+ dk -= k
+ copy(vq.pi[dk:], vq.pi[dk+1:])
+ // write nil to final position for GC safety
+ vq.pi[len(vq.pi)-1] = nil
+ vq.pi = vq.pi[:len(vq.pi)-1]
+ }
+
if len(vq.pi) == 0 {
// If listing versions added nothing (new), then return now
- return
+ return nil
}
}
@@ -117,7 +129,7 @@
// If all have been loaded and the queue is empty, we're definitely out
// of things to try. Return empty, though, because vq semantics dictate
// that we don't explicitly indicate the end of the queue here.
- return
+ return nil
}
// isExhausted indicates whether or not the queue has definitely been exhausted,
diff --git a/vendor/github.com/sdboyer/gps/version_queue_test.go b/vendor/github.com/sdboyer/gps/version_queue_test.go
new file mode 100644
index 0000000..2e6174d
--- /dev/null
+++ b/vendor/github.com/sdboyer/gps/version_queue_test.go
@@ -0,0 +1,249 @@
+package gps
+
+import (
+ "fmt"
+ "testing"
+)
+
+// just need a ListVersions method
+type fakeBridge struct {
+ *bridge
+ vl []Version
+}
+
+var fakevl = []Version{
+ NewVersion("v2.0.0").Is("200rev"),
+ NewVersion("v1.1.1").Is("111rev"),
+ NewVersion("v1.1.0").Is("110rev"),
+ NewVersion("v1.0.0").Is("100rev"),
+ NewBranch("master").Is("masterrev"),
+}
+
+func init() {
+ SortForUpgrade(fakevl)
+}
+
+func (fb *fakeBridge) ListVersions(id ProjectIdentifier) ([]Version, error) {
+ // it's a fixture, we only ever do the one, regardless of id
+ return fb.vl, nil
+}
+
+type fakeFailBridge struct {
+ *bridge
+}
+
+var vqerr = fmt.Errorf("vqerr")
+
+func (fb *fakeFailBridge) ListVersions(id ProjectIdentifier) ([]Version, error) {
+ return nil, vqerr
+}
+
+func TestVersionQueueSetup(t *testing.T) {
+ id := ProjectIdentifier{ProjectRoot: ProjectRoot("foo")}.normalize()
+
+ // shouldn't even need to embed a real bridge
+ fb := &fakeBridge{vl: fakevl}
+ ffb := &fakeFailBridge{}
+
+ _, err := newVersionQueue(id, nil, nil, ffb)
+ if err == nil {
+ t.Error("Expected err when providing no prefv or lockv, and injected bridge returns err from ListVersions()")
+ }
+
+ vq, err := newVersionQueue(id, nil, nil, fb)
+ if err != nil {
+ t.Errorf("Unexpected err on vq create: %s", err)
+ } else {
+ if len(vq.pi) != 5 {
+ t.Errorf("Should have five versions from ListVersions() when providing no prefv or lockv; got %v:\n\t%s", len(vq.pi), vq.String())
+ }
+ if !vq.allLoaded {
+ t.Errorf("allLoaded flag should be set, but wasn't")
+ }
+
+ if vq.prefv != nil || vq.lockv != nil {
+ t.Error("lockv and prefv should be nil")
+ }
+ if vq.current() != fakevl[0] {
+ t.Errorf("current should be head of fakevl (%s), got %s", fakevl[0], vq.current())
+ }
+ }
+
+ lockv := fakevl[0]
+ prefv := fakevl[1]
+ vq, err = newVersionQueue(id, lockv, nil, fb)
+ if err != nil {
+ t.Errorf("Unexpected err on vq create: %s", err)
+ } else {
+ if len(vq.pi) != 1 {
+ t.Errorf("Should have one version when providing only a lockv; got %v:\n\t%s", len(vq.pi), vq.String())
+ }
+ if vq.allLoaded {
+ t.Errorf("allLoaded flag should not be set")
+ }
+ if vq.lockv != lockv {
+ t.Errorf("lockv should be %s, was %s", lockv, vq.lockv)
+ }
+ if vq.current() != lockv {
+ t.Errorf("current should be lockv (%s), got %s", lockv, vq.current())
+ }
+ }
+
+ vq, err = newVersionQueue(id, nil, prefv, fb)
+ if err != nil {
+ t.Errorf("Unexpected err on vq create: %s", err)
+ } else {
+ if len(vq.pi) != 1 {
+ t.Errorf("Should have one version when providing only a prefv; got %v:\n\t%s", len(vq.pi), vq.String())
+ }
+ if vq.allLoaded {
+ t.Errorf("allLoaded flag should not be set")
+ }
+ if vq.prefv != prefv {
+ t.Errorf("prefv should be %s, was %s", prefv, vq.prefv)
+ }
+ if vq.current() != prefv {
+ t.Errorf("current should be prefv (%s), got %s", prefv, vq.current())
+ }
+ }
+
+ vq, err = newVersionQueue(id, lockv, prefv, fb)
+ if err != nil {
+ t.Errorf("Unexpected err on vq create: %s", err)
+ } else {
+ if len(vq.pi) != 2 {
+ t.Errorf("Should have two versions when providing both a prefv and lockv; got %v:\n\t%s", len(vq.pi), vq.String())
+ }
+ if vq.allLoaded {
+ t.Errorf("allLoaded flag should not be set")
+ }
+ if vq.prefv != prefv {
+ t.Errorf("prefv should be %s, was %s", prefv, vq.prefv)
+ }
+ if vq.lockv != lockv {
+ t.Errorf("lockv should be %s, was %s", lockv, vq.lockv)
+ }
+ if vq.current() != lockv {
+ t.Errorf("current should be lockv (%s), got %s", lockv, vq.current())
+ }
+ }
+}
+
+func TestVersionQueueAdvance(t *testing.T) {
+ fb := &fakeBridge{vl: fakevl}
+ id := ProjectIdentifier{ProjectRoot: ProjectRoot("foo")}.normalize()
+
+ // First with no prefv or lockv
+ vq, err := newVersionQueue(id, nil, nil, fb)
+ if err != nil {
+ t.Errorf("Unexpected err on vq create: %s", err)
+ t.FailNow()
+ }
+
+ for k, v := range fakevl[1:] {
+ err = vq.advance(fmt.Errorf("advancment fail for %s", fakevl[k]))
+ if err != nil {
+ t.Errorf("error on advancing vq from %s to %s", fakevl[k], v)
+ break
+ }
+
+ if vq.current() != v {
+ t.Errorf("on advance() %v, current should be %s, got %s", k, v, vq.current())
+ }
+ }
+
+ if vq.isExhausted() {
+ t.Error("should not be exhausted until advancing 'past' the end")
+ }
+ if err = vq.advance(fmt.Errorf("final advance failure")); err != nil {
+ t.Errorf("should not error on advance, even past end, but got %s", err)
+ }
+
+ if !vq.isExhausted() {
+ t.Error("advanced past end, should now report exhaustion")
+ }
+ if vq.current() != nil {
+ t.Error("advanced past end, current should return nil")
+ }
+
+ // now, do one with both a prefv and lockv
+ lockv := fakevl[2]
+ prefv := fakevl[0]
+ vq, err = newVersionQueue(id, lockv, prefv, fb)
+ if vq.String() != "[v1.1.0, v2.0.0]" {
+ t.Error("stringifying vq did not have expected outcome, got", vq.String())
+ }
+ if vq.isExhausted() {
+ t.Error("can't be exhausted, we aren't even 'allLoaded' yet")
+ }
+
+ err = vq.advance(fmt.Errorf("dequeue lockv"))
+ if err != nil {
+ t.Error("unexpected error when advancing past lockv", err)
+ } else {
+ if vq.current() != prefv {
+ t.Errorf("current should be prefv (%s) after first advance, got %s", prefv, vq.current())
+ }
+ if len(vq.pi) != 1 {
+ t.Errorf("should have just prefv elem left in vq, but there are %v:\n\t%s", len(vq.pi), vq.String())
+ }
+ }
+
+ err = vq.advance(fmt.Errorf("dequeue prefv"))
+ if err != nil {
+ t.Error("unexpected error when advancing past prefv", err)
+ } else {
+ if !vq.allLoaded {
+ t.Error("allLoaded should now be true")
+ }
+ if len(vq.pi) != 3 {
+ t.Errorf("should have three remaining versions after removing prefv and lockv, but there are %v:\n\t%s", len(vq.pi), vq.String())
+ }
+ if vq.current() != fakevl[1] {
+ t.Errorf("current should be first elem of fakevl (%s) after advancing into all, got %s", fakevl[1], vq.current())
+ }
+ }
+
+ // make sure the queue ordering is still right even with a double-delete
+ vq.advance(nil)
+ if vq.current() != fakevl[3] {
+ t.Errorf("second elem after ListVersions() should be idx 3 of fakevl (%s), got %s", fakevl[3], vq.current())
+ }
+ vq.advance(nil)
+ if vq.current() != fakevl[4] {
+ t.Errorf("third elem after ListVersions() should be idx 4 of fakevl (%s), got %s", fakevl[4], vq.current())
+ }
+ vq.advance(nil)
+ if vq.current() != nil || !vq.isExhausted() {
+ t.Error("should be out of versions in the queue")
+ }
+
+ // Make sure we handle things correctly when listVersions adds nothing new
+ fb = &fakeBridge{vl: []Version{lockv, prefv}}
+ vq, err = newVersionQueue(id, lockv, prefv, fb)
+ vq.advance(nil)
+ vq.advance(nil)
+ if vq.current() != nil || !vq.isExhausted() {
+ t.Errorf("should have no versions left, as ListVersions() added nothing new, but still have %s", vq.String())
+ }
+ err = vq.advance(nil)
+ if err != nil {
+ t.Errorf("should be fine to advance on empty queue, per docs, but got err %s", err)
+ }
+
+ // Also handle it well when advancing calls ListVersions() and it gets an
+ // error
+ vq, err = newVersionQueue(id, lockv, nil, &fakeFailBridge{})
+ if err != nil {
+ t.Errorf("should not err on creation when preseeded with lockv, but got err %s", err)
+ }
+ err = vq.advance(nil)
+ if err == nil {
+ t.Error("advancing should trigger call to erroring bridge, but no err")
+ }
+ err = vq.advance(nil)
+ if err == nil {
+ t.Error("err should be stored for reuse on any subsequent calls")
+ }
+
+}
diff --git a/vendor/github.com/sdboyer/gps/version_test.go b/vendor/github.com/sdboyer/gps/version_test.go
index f8b9b89..436dbe4 100644
--- a/vendor/github.com/sdboyer/gps/version_test.go
+++ b/vendor/github.com/sdboyer/gps/version_test.go
@@ -1,9 +1,6 @@
package gps
-import (
- "sort"
- "testing"
-)
+import "testing"
func TestVersionSorts(t *testing.T) {
rev := Revision("flooboofoobooo")
@@ -47,7 +44,7 @@
rev, // revs
}
- sort.Sort(upgradeVersionSorter(up))
+ SortForUpgrade(up)
var wrong []int
for k, v := range up {
if eup[k] != v {
@@ -60,7 +57,7 @@
t.Errorf("Upgrade sort positions with wrong versions: %v", wrong)
}
- sort.Sort(downgradeVersionSorter(down))
+ SortForDowngrade(down)
wrong = wrong[:0]
for k, v := range down {
if edown[k] != v {
@@ -74,7 +71,7 @@
}
// Now make sure we sort back the other way correctly...just because
- sort.Sort(upgradeVersionSorter(down))
+ SortForUpgrade(down)
wrong = wrong[:0]
for k, v := range down {
if eup[k] != v {
@@ -88,7 +85,7 @@
}
// Now make sure we sort back the other way correctly...just because
- sort.Sort(downgradeVersionSorter(up))
+ SortForDowngrade(up)
wrong = wrong[:0]
for k, v := range up {
if edown[k] != v {