diff --git a/cmd/dep/status.go b/cmd/dep/status.go index a1f9a0a8c1..a43c38f8c3 100644 --- a/cmd/dep/status.go +++ b/cmd/dep/status.go @@ -19,7 +19,6 @@ import ( "github.com/golang/dep" "github.com/golang/dep/gps" "github.com/golang/dep/gps/paths" - "github.com/golang/dep/gps/pkgtree" "github.com/pkg/errors" ) @@ -389,7 +388,7 @@ func runStatusAll(ctx *dep.Ctx, out outputter, p *dep.Project, sm gps.SourceMana return false, 0, errors.Wrapf(err, "could not set up solver for input hashing") } - cm := collectConstraints(ptree, p, sm) + cm := collectConstraints(ctx, p, sm) // Get the project list and sort it so that the printed output users see is // deterministically ordered. (This may be superfluous if the lock is always @@ -461,7 +460,7 @@ func runStatusAll(ctx *dep.Ctx, out outputter, p *dep.Project, sm gps.SourceMana } else { bs.Constraint = gps.Any() for _, c := range cm[bs.ProjectRoot] { - bs.Constraint = c.Intersect(bs.Constraint) + bs.Constraint = c.Constraint.Intersect(bs.Constraint) } } @@ -470,7 +469,12 @@ func runStatusAll(ctx *dep.Ctx, out outputter, p *dep.Project, sm gps.SourceMana if bs.Version != nil && bs.Version.Type() != gps.IsVersion { c, has := p.Manifest.Constraints[proj.Ident().ProjectRoot] if !has { - c.Constraint = gps.Any() + // Get constraint for locked project + for _, lockedP := range p.Lock.P { + if lockedP.Ident().ProjectRoot == proj.Ident().ProjectRoot { + c.Constraint = lockedP.Version() + } + } } // TODO: This constraint is only the constraint imposed by the // current project, not by any transitive deps. As a result, @@ -639,7 +643,49 @@ func formatVersion(v gps.Version) string { return v.String() } -func collectConstraints(ptree pkgtree.PackageTree, p *dep.Project, sm gps.SourceManager) map[string][]gps.Constraint { - // TODO - return map[string][]gps.Constraint{} +// projectConstraint stores ProjectRoot and Constraint for that project. +type projectConstraint struct { + Project gps.ProjectRoot + Constraint gps.Constraint +} + +// constraintsCollection is a map of ProjectRoot(dependency) and a collection of +// projectConstraint for the dependencies. This can be used to find constraints +// on a dependency and the projects that apply those constraints. +type constraintsCollection map[string][]projectConstraint + +// collectConstraints collects constraints declared by all the dependencies. +func collectConstraints(ctx *dep.Ctx, p *dep.Project, sm gps.SourceManager) constraintsCollection { + constraintCollection := make(constraintsCollection) + + // Get direct deps of the root project. + _, directDeps, err := getDirectDependencies(sm, p) + if err != nil { + ctx.Err.Println("Error getting direct deps:", err) + } + // Create a root analyzer. + rootAnalyzer := newRootAnalyzer(false, ctx, directDeps, sm) + + // Iterate through the locked projects and collect constraints of all the projects. + for _, proj := range p.Lock.Projects() { + manifest, _, err := sm.GetManifestAndLock(proj.Ident(), proj.Version(), rootAnalyzer) + if err != nil { + ctx.Err.Println("Error getting manifest and lock:", err) + continue + } + + // Get project constraints. + pc := manifest.DependencyConstraints() + + // Iterate through the project constraints to get individual dependency + // project and constraint values. + for pr, pp := range pc { + constraintCollection[string(pr)] = append( + constraintCollection[string(pr)], + projectConstraint{proj.Ident().ProjectRoot, pp.Constraint}, + ) + } + } + + return constraintCollection } diff --git a/cmd/dep/status_test.go b/cmd/dep/status_test.go index 1558343a6e..6f0eb3f4d0 100644 --- a/cmd/dep/status_test.go +++ b/cmd/dep/status_test.go @@ -6,6 +6,9 @@ package main import ( "bytes" + "io/ioutil" + "log" + "reflect" "testing" "text/tabwriter" @@ -13,6 +16,7 @@ import ( "github.com/golang/dep" "github.com/golang/dep/gps" + "github.com/golang/dep/internal/test" ) func TestStatusFormatVersion(t *testing.T) { @@ -287,3 +291,118 @@ func TestBasicStatusGetConsolidatedLatest(t *testing.T) { }) } } + +func TestCollectConstraints(t *testing.T) { + ver1, _ := gps.NewSemverConstraintIC("v1.0.0") + ver08, _ := gps.NewSemverConstraintIC("v0.8.0") + ver2, _ := gps.NewSemverConstraintIC("v2.0.0") + + cases := []struct { + name string + project dep.Project + wantConstraints constraintsCollection + }{ + { + name: "without any constraints", + project: dep.Project{ + Lock: &dep.Lock{ + P: []gps.LockedProject{ + gps.NewLockedProject( + gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot("github.com/sdboyer/deptest")}, + gps.NewVersion("v1.0.0"), + []string{"."}, + ), + }, + }, + }, + wantConstraints: constraintsCollection{}, + }, + { + name: "with multiple constraints", + project: dep.Project{ + Lock: &dep.Lock{ + P: []gps.LockedProject{ + gps.NewLockedProject( + gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot("github.com/sdboyer/deptest")}, + gps.NewVersion("v1.0.0"), + []string{"."}, + ), + gps.NewLockedProject( + gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot("github.com/darkowlzz/deptest-project-1")}, + gps.NewVersion("v0.1.0"), + []string{"."}, + ), + gps.NewLockedProject( + gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot("github.com/darkowlzz/deptest-project-2")}, + gps.NewBranch("master").Pair(gps.Revision("824a8d56a4c6b2f4718824a98cd6d70d3dbd4c3e")), + []string{"."}, + ), + }, + }, + }, + wantConstraints: constraintsCollection{ + "github.com/sdboyer/deptest": []projectConstraint{ + {"github.com/darkowlzz/deptest-project-1", ver1}, + {"github.com/darkowlzz/deptest-project-2", ver08}, + }, + "github.com/sdboyer/deptestdos": []projectConstraint{ + {"github.com/darkowlzz/deptest-project-2", ver2}, + }, + "github.com/sdboyer/dep-test": []projectConstraint{ + {"github.com/darkowlzz/deptest-project-2", ver1}, + }, + }, + }, + { + name: "skip projects with invalid versions", + project: dep.Project{ + Lock: &dep.Lock{ + P: []gps.LockedProject{ + gps.NewLockedProject( + gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot("github.com/darkowlzz/deptest-project-1")}, + gps.NewVersion("v0.1.0"), + []string{"."}, + ), + gps.NewLockedProject( + gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot("github.com/darkowlzz/deptest-project-2")}, + gps.NewVersion("v1.0.0"), + []string{"."}, + ), + }, + }, + }, + wantConstraints: constraintsCollection{ + "github.com/sdboyer/deptest": []projectConstraint{ + {"github.com/darkowlzz/deptest-project-1", ver1}, + }, + }, + }, + } + + h := test.NewHelper(t) + defer h.Cleanup() + + h.TempDir("src") + pwd := h.Path(".") + discardLogger := log.New(ioutil.Discard, "", 0) + + ctx := &dep.Ctx{ + GOPATH: pwd, + Out: discardLogger, + Err: discardLogger, + } + + sm, err := ctx.SourceManager() + h.Must(err) + defer sm.Release() + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + gotConstraints := collectConstraints(ctx, &c.project, sm) + + if !reflect.DeepEqual(gotConstraints, c.wantConstraints) { + t.Fatalf("Unexpected collected constraints: \n\t(GOT): %v\n\t(WNT): %v", gotConstraints, c.wantConstraints) + } + }) + } +} diff --git a/cmd/dep/testdata/harness_tests/status/case1/json/stdout.txt b/cmd/dep/testdata/harness_tests/status/case1/json/stdout.txt index e995757921..381f3246d5 100644 --- a/cmd/dep/testdata/harness_tests/status/case1/json/stdout.txt +++ b/cmd/dep/testdata/harness_tests/status/case1/json/stdout.txt @@ -1 +1 @@ -[{"ProjectRoot":"github.com/sdboyer/deptest","Constraint":"^0.8.0","Version":"v0.8.0","Revision":"ff2948a2ac8f538c4ecd55962e919d1e13e74baf","Latest":"3f4c3bea144e112a69bbe5d8d01c1b09a544253f","PackageCount":1},{"ProjectRoot":"github.com/sdboyer/deptestdos","Constraint":"*","Version":"v2.0.0","Revision":"5c607206be5decd28e6263ffffdcee067266015e","Latest":"5c607206be5decd28e6263ffffdcee067266015e","PackageCount":1}] +[{"ProjectRoot":"github.com/sdboyer/deptest","Constraint":"^0.8.0","Version":"v0.8.0","Revision":"ff2948a2ac8f538c4ecd55962e919d1e13e74baf","Latest":"3f4c3bea144e112a69bbe5d8d01c1b09a544253f","PackageCount":1},{"ProjectRoot":"github.com/sdboyer/deptestdos","Constraint":"v2.0.0","Version":"v2.0.0","Revision":"5c607206be5decd28e6263ffffdcee067266015e","Latest":"5c607206be5decd28e6263ffffdcee067266015e","PackageCount":1}] diff --git a/cmd/dep/testdata/harness_tests/status/case1/table/stdout.txt b/cmd/dep/testdata/harness_tests/status/case1/table/stdout.txt index f77f65a927..dbe1b29360 100644 --- a/cmd/dep/testdata/harness_tests/status/case1/table/stdout.txt +++ b/cmd/dep/testdata/harness_tests/status/case1/table/stdout.txt @@ -1,3 +1,3 @@ PROJECT CONSTRAINT VERSION REVISION LATEST PKGS USED github.com/sdboyer/deptest ^0.8.0 v0.8.0 ff2948a 3f4c3be 1 -github.com/sdboyer/deptestdos * v2.0.0 5c60720 5c60720 1 +github.com/sdboyer/deptestdos v2.0.0 v2.0.0 5c60720 5c60720 1 diff --git a/cmd/dep/testdata/harness_tests/status/override_constraint/stdout.txt b/cmd/dep/testdata/harness_tests/status/override_constraint/stdout.txt index e3df72b63d..202f122e20 100644 --- a/cmd/dep/testdata/harness_tests/status/override_constraint/stdout.txt +++ b/cmd/dep/testdata/harness_tests/status/override_constraint/stdout.txt @@ -1,3 +1,3 @@ -PROJECT CONSTRAINT VERSION REVISION LATEST PKGS USED -github.com/sdboyer/deptest * (override) v0.8.1 3f4c3be ff2948a 1 -github.com/sdboyer/deptestdos * v2.0.0 5c60720 5c60720 1 +PROJECT CONSTRAINT VERSION REVISION LATEST PKGS USED +github.com/sdboyer/deptest v0.8.1 (override) v0.8.1 3f4c3be 3f4c3be 1 +github.com/sdboyer/deptestdos v2.0.0 v2.0.0 5c60720 5c60720 1