From 52b7df138b19eb9ae47300e9125ab71e12dcb6b3 Mon Sep 17 00:00:00 2001 From: Kyle Conroy Date: Sat, 15 Jul 2017 10:52:40 -0600 Subject: [PATCH 1/6] internal/importers: add govendor importer Add skeleton for govendor importer Parse the vendor.json file Contemplate version when generating Gopkg.toml Add ignored packages from vendor file Remove unnecessary vendor file fields --- cmd/dep/govendor_importer.go | 139 +++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 cmd/dep/govendor_importer.go diff --git a/cmd/dep/govendor_importer.go b/cmd/dep/govendor_importer.go new file mode 100644 index 00000000..5d508427 --- /dev/null +++ b/cmd/dep/govendor_importer.go @@ -0,0 +1,139 @@ +// Copyright 2016 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 main + +import ( + "encoding/json" + "io/ioutil" + "log" + "os" + "path/filepath" + "strings" + + "github.com/golang/dep" + fb "github.com/golang/dep/internal/feedback" + "github.com/golang/dep/internal/gps" + "github.com/pkg/errors" +) + +const govendorDir = "vendor" +const govendorName = "vendor.json" + +type govendorImporter struct { + file govendorFile + + logger *log.Logger + verbose bool + sm gps.SourceManager +} + +func newGovendorImporter(logger *log.Logger, verbose bool, sm gps.SourceManager) *govendorImporter { + return &govendorImporter{ + logger: logger, + verbose: verbose, + sm: sm, + } +} + +// File is the structure of the vendor file. +type govendorFile struct { + RootPath string // Import path of vendor folder + Ignore string + Package []*govendorPackage +} + +// Package represents each package. +type govendorPackage struct { + // See the vendor spec for definitions. + Origin string + Path string + Tree bool + Revision string + Version string +} + +func (g *govendorImporter) Name() string { + return "govendor" +} + +func (g *govendorImporter) HasDepMetadata(dir string) bool { + y := filepath.Join(dir, govendorDir, govendorName) + if _, err := os.Stat(y); err != nil { + return false + } + return true +} + +func (g *govendorImporter) Import(dir string, pr gps.ProjectRoot) (*dep.Manifest, *dep.Lock, error) { + err := g.load(dir) + if err != nil { + return nil, nil, err + } + return g.convert(pr) +} + +func (g *govendorImporter) load(projectDir string) error { + g.logger.Println("Detected govendor configuration file...") + v := filepath.Join(projectDir, govendorDir, govendorName) + if g.verbose { + g.logger.Printf(" Loading %s", v) + } + vb, err := ioutil.ReadFile(v) + if err != nil { + return errors.Wrapf(err, "Unable to read %s", v) + } + err = json.Unmarshal(vb, &g.file) + if err != nil { + return errors.Wrapf(err, "Unable to parse %s", v) + } + return nil +} + +func (g *govendorImporter) convert(pr gps.ProjectRoot) (*dep.Manifest, *dep.Lock, error) { + g.logger.Println("Converting from vendor.json...") + + manifest := &dep.Manifest{ + Constraints: make(gps.ProjectConstraints), + } + + if len(g.file.Ignore) > 0 { + manifest.Ignored = strings.Split(g.file.Ignore, " ") + } + + for _, pkg := range g.file.Package { + pc, err := g.buildProjectConstraint(pkg) + if err != nil { + return nil, nil, err + } + manifest.Constraints[pc.Ident.ProjectRoot] = gps.ProjectProperties{ + Source: pc.Ident.Source, + Constraint: pc.Constraint, + } + } + return manifest, nil, nil +} + +func (g *govendorImporter) buildProjectConstraint(pkg *govendorPackage) (pc gps.ProjectConstraint, err error) { + if pkg.Path == "" { + err = errors.New("Invalid vendor configuration, package path is required") + return + } + + ref := pkg.Version + if ref == "" { + ref = pkg.Revision + } + + pc.Ident = gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot(pkg.Path), Source: pkg.Path} + pc.Constraint, err = g.sm.InferConstraint(ref, pc.Ident) + if err != nil { + return + } + + f := fb.NewConstraintFeedback(pc, fb.DepTypeImported) + f.LogFeedback(g.logger) + + return +} From 6c922d62c1ff67a949c3831cf1d53b006c7eb42f Mon Sep 17 00:00:00 2001 From: Christopher O'Toole Date: Sat, 15 Jul 2017 12:49:46 -0500 Subject: [PATCH 2/6] internal/importers: add govendor importer Add sample vendor.json for writing tests Add skeleton test file for Govendor Initial stab at generating lock from govendor Get our first test passing Fixes some bad porting of code from godeps implementation. Removes some ported code from glide implementation. Update govendor ignore logic for full package names Add warnings for unhandled ignore Update feedback to support revision without version Doing this so we can get feedback for the detached head use case that govendor frequently has. --- cmd/dep/govendor_importer.go | 101 ++++++++++++++++++++++++-- cmd/dep/govendor_importer_test.go | 64 ++++++++++++++++ cmd/dep/testdata/govendor/golden.txt | 7 ++ cmd/dep/testdata/govendor/vendor.json | 22 ++++++ 4 files changed, 187 insertions(+), 7 deletions(-) create mode 100644 cmd/dep/govendor_importer_test.go create mode 100644 cmd/dep/testdata/govendor/golden.txt create mode 100644 cmd/dep/testdata/govendor/vendor.json diff --git a/cmd/dep/govendor_importer.go b/cmd/dep/govendor_importer.go index 5d508427..9d005f26 100644 --- a/cmd/dep/govendor_importer.go +++ b/cmd/dep/govendor_importer.go @@ -75,7 +75,7 @@ func (g *govendorImporter) Import(dir string, pr gps.ProjectRoot) (*dep.Manifest } func (g *govendorImporter) load(projectDir string) error { - g.logger.Println("Detected govendor configuration file...") + g.logger.Println("Detected govendor configuration files...") v := filepath.Join(projectDir, govendorDir, govendorName) if g.verbose { g.logger.Printf(" Loading %s", v) @@ -99,20 +99,88 @@ func (g *govendorImporter) convert(pr gps.ProjectRoot) (*dep.Manifest, *dep.Lock } if len(g.file.Ignore) > 0 { - manifest.Ignored = strings.Split(g.file.Ignore, " ") + // Govendor has three use cases here + // 1. 'test' - special case for ignoring test files + // 2. build tags - any string without a slash (/) in it + // 3. path and path prefix - any string with a slash (/) in it. + // The path case could be a full path or just a prefix. + // Dep doesn't support build tags right now: https://github.com/golang/dep/issues/120 + for _, i := range strings.Split(g.file.Ignore, " ") { + if !strings.Contains(i, "/") { + g.logger.Printf("Warning: Not able to convert ignoring of build tag '%v'", i) + continue + } + _, err := g.sm.DeduceProjectRoot(i) + if err == nil { + manifest.Ignored = append(manifest.Ignored, i) + } else { + g.logger.Println("Warning: Not able to convert ignoring of build tag '%v'", i) + } + } } + lock := &dep.Lock{} for _, pkg := range g.file.Package { - pc, err := g.buildProjectConstraint(pkg) + // Path must not be empty + if pkg.Path == "" { + err := errors.New("Invalid govendor configuration, Path is required") + return nil, nil, err + } + + // Obtain ProjectRoot. Required for avoiding sub-package imports. + // Use Path instead of Origin since we are trying to group by project here + pr, err := g.sm.DeduceProjectRoot(pkg.Path) if err != nil { return nil, nil, err } - manifest.Constraints[pc.Ident.ProjectRoot] = gps.ProjectProperties{ - Source: pc.Ident.Source, - Constraint: pc.Constraint, + pkg.Path = string(pr) + + // Check if it already existing in locked projects + if projectExistsInLock(lock, pkg.Path) { + continue } + + // Revision must not be empty + if pkg.Revision == "" { + err := errors.New("Invalid govendor configuration, Revision is required") + return nil, nil, err + } + + if pkg.Version == "" { + // When no version is specified try to get the corresponding version + pi := gps.ProjectIdentifier{ + ProjectRoot: gps.ProjectRoot(pkg.Path), + } + if pkg.Origin != "" { + pi.Source = pkg.Origin + } + revision := gps.Revision(pkg.Revision) + version, err := lookupVersionForLockedProject(pi, nil, revision, g.sm) + if err != nil { + // Only warn about the problem, it is not enough to warrant failing + g.logger.Println(err.Error()) + } else { + pp := getProjectPropertiesFromVersion(version) + if pp.Constraint != nil { + pkg.Version = pp.Constraint.String() + } + } + } + + if pkg.Version != "" { + // If there's a version, use it to create project constraint + pc, err := g.buildProjectConstraint(pkg) + if err != nil { + return nil, nil, err + } + manifest.Constraints[pc.Ident.ProjectRoot] = gps.ProjectProperties{Constraint: pc.Constraint} + } + + lp := g.buildLockedProject(pkg, manifest) + lock.P = append(lock.P, lp) } - return manifest, nil, nil + + return manifest, lock, nil } func (g *govendorImporter) buildProjectConstraint(pkg *govendorPackage) (pc gps.ProjectConstraint, err error) { @@ -137,3 +205,22 @@ func (g *govendorImporter) buildProjectConstraint(pkg *govendorPackage) (pc gps. return } + +// buildLockedProject uses the package Rev and Comment to create lock project +func (g *govendorImporter) buildLockedProject(pkg *govendorPackage, manifest *dep.Manifest) gps.LockedProject { + pi := gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot(pkg.Path)} + revision := gps.Revision(pkg.Revision) + pp := manifest.Constraints[pi.ProjectRoot] + + version, err := lookupVersionForLockedProject(pi, pp.Constraint, revision, g.sm) + if err != nil { + // Only warn about the problem, it is not enough to warrant failing + g.logger.Println(err.Error()) + } + + lp := gps.NewLockedProject(pi, version, nil) + f := fb.NewLockedProjectFeedback(lp, fb.DepTypeImported) + f.LogFeedback(g.logger) + + return lp +} diff --git a/cmd/dep/govendor_importer_test.go b/cmd/dep/govendor_importer_test.go new file mode 100644 index 00000000..ad23a002 --- /dev/null +++ b/cmd/dep/govendor_importer_test.go @@ -0,0 +1,64 @@ +// Copyright 2016 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 main + +import ( + "bytes" + "log" + "path/filepath" + "testing" + + "github.com/golang/dep/internal/test" + "github.com/pkg/errors" +) + +const testGovendorProjectRoot = "github.com/golang/notexist" + +func TestGovendorConfig_Import(t *testing.T) { + h := test.NewHelper(t) + defer h.Cleanup() + + ctx := newTestContext(h) + sm, err := ctx.SourceManager() + h.Must(err) + defer sm.Release() + + h.TempDir(filepath.Join("src", testGovendorProjectRoot)) + h.TempCopy(filepath.Join(testGovendorProjectRoot, govendorDir, govendorName), "govendor/vendor.json") + projectRoot := h.Path(testGovendorProjectRoot) + + // Capture stderr so we can verify output + verboseOutput := &bytes.Buffer{} + ctx.Err = log.New(verboseOutput, "", 0) + + g := newGovendorImporter(ctx.Err, false, sm) // Disable verbose so that we don't print values that change each test run + if !g.HasDepMetadata(projectRoot) { + t.Fatal("Expected the importer to detect the govendor configuration files") + } + + m, l, err := g.Import(projectRoot, testGovendorProjectRoot) + h.Must(err) + + if m == nil { + t.Fatal("Expected the manifest to be generated") + } + + if l == nil { + t.Fatal("Expected the lock to be generated") + } + + goldenFile := "govendor/golden.txt" + got := verboseOutput.String() + want := h.GetTestFileString(goldenFile) + if want != got { + if *test.UpdateGolden { + if err := h.WriteTestFile(goldenFile, got); err != nil { + t.Fatalf("%+v", errors.Wrapf(err, "Unable to write updated golden file %s", goldenFile)) + } + } else { + t.Fatalf("expected %s, got %s", want, got) + } + } +} diff --git a/cmd/dep/testdata/govendor/golden.txt b/cmd/dep/testdata/govendor/golden.txt new file mode 100644 index 00000000..fde8e9fb --- /dev/null +++ b/cmd/dep/testdata/govendor/golden.txt @@ -0,0 +1,7 @@ +Detected govendor configuration files... +Converting from vendor.json... +Warning: Not able to convert ignoring of build tag 'test' + Using ^0.8.1 as initial constraint for imported dep github.com/sdboyer/deptest + Trying v0.8.1 (3f4c3be) as initial lock for imported dep github.com/sdboyer/deptest + Using ^2.0.0 as initial constraint for imported dep github.com/sdboyer/deptestdos + Trying v2.0.0 (5c60720) as initial lock for imported dep github.com/sdboyer/deptestdos diff --git a/cmd/dep/testdata/govendor/vendor.json b/cmd/dep/testdata/govendor/vendor.json new file mode 100644 index 00000000..983f15f6 --- /dev/null +++ b/cmd/dep/testdata/govendor/vendor.json @@ -0,0 +1,22 @@ +{ + "comment": "", + "ignore": "test github.com/sdboyer/dep-test", + "package": [ + { + "checksumSHA1": "4R6TQcq0/gI/I2kKeUunuO/pEec=", + "origin": "github.com/carolynvs/deptest", + "path": "github.com/sdboyer/deptest", + "revision": "3f4c3bea144e112a69bbe5d8d01c1b09a544253f", + "revisionTime": "2017-02-22T03:31:47Z" + }, + { + "checksumSHA1": "96YwrJjpE07ENey/eDWWnCWKQOw=", + "path": "github.com/sdboyer/deptestdos", + "revision": "5c607206be5decd28e6263ffffdcee067266015e", + "revisionTime": "2017-02-22T03:34:58Z", + "version": "v2", + "versionExact": "v2.0.0" + } + ], + "rootPath": "github.com/golang/notexist" +} From 90a984dd5fea2ea36d277fd525a2ac7bbdf70401 Mon Sep 17 00:00:00 2001 From: Brendan Munro Date: Sat, 15 Jul 2017 12:55:54 -0700 Subject: [PATCH 3/6] internal/importers: add govendor importer Add vendor.json examples for govendor corner cases. Add first integration test case --- cmd/dep/testdata/govendor/vendor-sub-pkg.json | 25 +++++++++++++++++++ .../govendor/vendor-vendored-dep.json | 21 ++++++++++++++++ .../init/govendor/case1/README.md | 1 + .../init/govendor/case1/final/Gopkg.lock | 21 ++++++++++++++++ .../init/govendor/case1/final/Gopkg.toml | 5 ++++ .../init/govendor/case1/initial/main.go | 16 ++++++++++++ .../govendor/case1/initial/samples/samples.go | 12 +++++++++ .../govendor/case1/initial/vendor/vendor.json | 22 ++++++++++++++++ .../init/govendor/case1/testcase.json | 14 +++++++++++ 9 files changed, 137 insertions(+) create mode 100644 cmd/dep/testdata/govendor/vendor-sub-pkg.json create mode 100644 cmd/dep/testdata/govendor/vendor-vendored-dep.json create mode 100644 cmd/dep/testdata/harness_tests/init/govendor/case1/README.md create mode 100644 cmd/dep/testdata/harness_tests/init/govendor/case1/final/Gopkg.lock create mode 100644 cmd/dep/testdata/harness_tests/init/govendor/case1/final/Gopkg.toml create mode 100644 cmd/dep/testdata/harness_tests/init/govendor/case1/initial/main.go create mode 100644 cmd/dep/testdata/harness_tests/init/govendor/case1/initial/samples/samples.go create mode 100644 cmd/dep/testdata/harness_tests/init/govendor/case1/initial/vendor/vendor.json create mode 100644 cmd/dep/testdata/harness_tests/init/govendor/case1/testcase.json diff --git a/cmd/dep/testdata/govendor/vendor-sub-pkg.json b/cmd/dep/testdata/govendor/vendor-sub-pkg.json new file mode 100644 index 00000000..4d47fc3d --- /dev/null +++ b/cmd/dep/testdata/govendor/vendor-sub-pkg.json @@ -0,0 +1,25 @@ +{ + "comment": "", + "ignore": "test", + "package": [ + { + "checksumSHA1": "c+MCTe4HOVzNBjFpjmPYWFSs06U=", + "path": "github.com/sdboyer/deptest", + "revision": "e1b5acf7f78e07bc0a8e51121ca0c7e174975d7e", + "revisionTime": "2017-07-15T19:32:19Z" + }, + { + "checksumSHA1": "cp+gzxyVhoM8sZWLPrsigvpdDuc=", + "path": "github.com/sdboyer/deptest/floats", + "revision": "e1b5acf7f78e07bc0a8e51121ca0c7e174975d7e", + "revisionTime": "2017-07-15T19:32:19Z" + }, + { + "checksumSHA1": "5yiF57bPBKmLr6AFDDxfTmWYZJ4=", + "path": "github.com/sdboyer/deptest/strings", + "revision": "e1b5acf7f78e07bc0a8e51121ca0c7e174975d7e", + "revisionTime": "2017-07-15T19:32:19Z" + } + ], + "rootPath": "github.com/golang/notexist" +} diff --git a/cmd/dep/testdata/govendor/vendor-vendored-dep.json b/cmd/dep/testdata/govendor/vendor-vendored-dep.json new file mode 100644 index 00000000..e8098657 --- /dev/null +++ b/cmd/dep/testdata/govendor/vendor-vendored-dep.json @@ -0,0 +1,21 @@ +{ + "comment": "", + "ignore": "test", + "package": [ + { + "checksumSHA1": "q6es/GCwizh2GbLTKWWj8bB6Lc8=", + "origin": "github.com/sdboyer/deptest/vendor/github.com/sdboyer/coolint", + "path": "github.com/sdboyer/coolint", + "revision": "a920fd05db2031ad1ba94f62035fab5def190141", + "revisionTime": "2017-07-15T19:22:11Z" + }, + { + "checksumSHA1": "c+MCTe4HOVzNBjFpjmPYWFSs06U=", + "path": "github.com/sdboyer/deptest", + "revision": "a920fd05db2031ad1ba94f62035fab5def190141", + "revisionTime": "2017-07-15T19:22:11Z" + } + ], + "rootPath": "github.com/golang/notexist" +} + diff --git a/cmd/dep/testdata/harness_tests/init/govendor/case1/README.md b/cmd/dep/testdata/harness_tests/init/govendor/case1/README.md new file mode 100644 index 00000000..640eb069 --- /dev/null +++ b/cmd/dep/testdata/harness_tests/init/govendor/case1/README.md @@ -0,0 +1 @@ +Import govendor config in vendor dir. diff --git a/cmd/dep/testdata/harness_tests/init/govendor/case1/final/Gopkg.lock b/cmd/dep/testdata/harness_tests/init/govendor/case1/final/Gopkg.lock new file mode 100644 index 00000000..56f9bb2b --- /dev/null +++ b/cmd/dep/testdata/harness_tests/init/govendor/case1/final/Gopkg.lock @@ -0,0 +1,21 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + name = "github.com/sdboyer/deptest" + packages = ["."] + revision = "ff2948a2ac8f538c4ecd55962e919d1e13e74baf" + version = "v1.0.0" + +[[projects]] + name = "github.com/sdboyer/deptestdos" + packages = ["."] + revision = "5c607206be5decd28e6263ffffdcee067266015e" + version = "v2.0.0" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + inputs-digest = "c53803413bd0160505cce903e1cba743e0b964088f8cc42a6123f6fe1a0ae9d3" + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/cmd/dep/testdata/harness_tests/init/govendor/case1/final/Gopkg.toml b/cmd/dep/testdata/harness_tests/init/govendor/case1/final/Gopkg.toml new file mode 100644 index 00000000..ab7893d7 --- /dev/null +++ b/cmd/dep/testdata/harness_tests/init/govendor/case1/final/Gopkg.toml @@ -0,0 +1,5 @@ +ignored = ["github.com/sdboyer/dep-test","github.com/golang/notexist/samples"] + +[[constraint]] + name = "github.com/sdboyer/deptestdos" + version = "2.0.0" diff --git a/cmd/dep/testdata/harness_tests/init/govendor/case1/initial/main.go b/cmd/dep/testdata/harness_tests/init/govendor/case1/initial/main.go new file mode 100644 index 00000000..2b2c7c39 --- /dev/null +++ b/cmd/dep/testdata/harness_tests/init/govendor/case1/initial/main.go @@ -0,0 +1,16 @@ +// 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 main + +import ( + "fmt" + + "github.com/sdboyer/deptestdos" +) + +func main() { + var x deptestdos.Bar + fmt.Println(x) +} diff --git a/cmd/dep/testdata/harness_tests/init/govendor/case1/initial/samples/samples.go b/cmd/dep/testdata/harness_tests/init/govendor/case1/initial/samples/samples.go new file mode 100644 index 00000000..3e160f22 --- /dev/null +++ b/cmd/dep/testdata/harness_tests/init/govendor/case1/initial/samples/samples.go @@ -0,0 +1,12 @@ +// Copyright 2016 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 samples + +import dt "github.com/carolynvs/go-dep-test" + +func Sample1() int { + var x = dt.Thing + return x +} diff --git a/cmd/dep/testdata/harness_tests/init/govendor/case1/initial/vendor/vendor.json b/cmd/dep/testdata/harness_tests/init/govendor/case1/initial/vendor/vendor.json new file mode 100644 index 00000000..983f15f6 --- /dev/null +++ b/cmd/dep/testdata/harness_tests/init/govendor/case1/initial/vendor/vendor.json @@ -0,0 +1,22 @@ +{ + "comment": "", + "ignore": "test github.com/sdboyer/dep-test", + "package": [ + { + "checksumSHA1": "4R6TQcq0/gI/I2kKeUunuO/pEec=", + "origin": "github.com/carolynvs/deptest", + "path": "github.com/sdboyer/deptest", + "revision": "3f4c3bea144e112a69bbe5d8d01c1b09a544253f", + "revisionTime": "2017-02-22T03:31:47Z" + }, + { + "checksumSHA1": "96YwrJjpE07ENey/eDWWnCWKQOw=", + "path": "github.com/sdboyer/deptestdos", + "revision": "5c607206be5decd28e6263ffffdcee067266015e", + "revisionTime": "2017-02-22T03:34:58Z", + "version": "v2", + "versionExact": "v2.0.0" + } + ], + "rootPath": "github.com/golang/notexist" +} diff --git a/cmd/dep/testdata/harness_tests/init/govendor/case1/testcase.json b/cmd/dep/testdata/harness_tests/init/govendor/case1/testcase.json new file mode 100644 index 00000000..e1197654 --- /dev/null +++ b/cmd/dep/testdata/harness_tests/init/govendor/case1/testcase.json @@ -0,0 +1,14 @@ +{ + "commands": [ + ["init", "-no-examples", "-gopath"] + ], + "error-expected": "", + "gopath-initial": { + "github.com/sdboyer/deptest": "3f4c3bea144e112a69bbe5d8d01c1b09a544253f", + "github.com/sdboyer/deptestdos": "5c607206be5decd28e6263ffffdcee067266015e" + }, + "vendor-final": [ + "github.com/sdboyer/deptest", + "github.com/sdboyer/deptestdos" + ] +} From 9033856a5baf296910b8ea34de60f088cee724bf Mon Sep 17 00:00:00 2001 From: Joey Goode Date: Sat, 15 Jul 2017 15:47:03 -0400 Subject: [PATCH 4/6] internal/importers: add govendor importer Translate glide unit tests to govendor Include revision in test govendorFiles Add a test for ignored packages Don't expect ignored directories to actually be ignored Use printf for formatting directives --- cmd/dep/govendor_importer.go | 2 +- cmd/dep/govendor_importer_test.go | 179 ++++++++++++++++++ .../init/govendor/case1/final/Gopkg.lock | 12 +- .../init/govendor/case1/final/Gopkg.toml | 6 +- .../govendor/case1/initial/vendor/vendor.json | 3 +- .../init/govendor/case1/testcase.json | 1 + 6 files changed, 196 insertions(+), 7 deletions(-) diff --git a/cmd/dep/govendor_importer.go b/cmd/dep/govendor_importer.go index 9d005f26..5df9dc5c 100644 --- a/cmd/dep/govendor_importer.go +++ b/cmd/dep/govendor_importer.go @@ -114,7 +114,7 @@ func (g *govendorImporter) convert(pr gps.ProjectRoot) (*dep.Manifest, *dep.Lock if err == nil { manifest.Ignored = append(manifest.Ignored, i) } else { - g.logger.Println("Warning: Not able to convert ignoring of build tag '%v'", i) + g.logger.Printf("Warning: Not able to convert ignoring of build tag '%v'\n", i) } } } diff --git a/cmd/dep/govendor_importer_test.go b/cmd/dep/govendor_importer_test.go index ad23a002..eb92711a 100644 --- a/cmd/dep/govendor_importer_test.go +++ b/cmd/dep/govendor_importer_test.go @@ -8,8 +8,10 @@ import ( "bytes" "log" "path/filepath" + "strings" "testing" + "github.com/golang/dep/internal/gps" "github.com/golang/dep/internal/test" "github.com/pkg/errors" ) @@ -62,3 +64,180 @@ func TestGovendorConfig_Import(t *testing.T) { } } } + +func TestGovendorConfig_Convert_Project(t *testing.T) { + h := test.NewHelper(t) + defer h.Cleanup() + + ctx := newTestContext(h) + sm, err := ctx.SourceManager() + h.Must(err) + defer sm.Release() + + pkg := "github.com/sdboyer/deptest" + + g := newGovendorImporter(ctx.Err, true, sm) + g.file = govendorFile{ + Package: []*govendorPackage{ + { + Path: pkg, + Revision: "ff2948a2ac8f538c4ecd55962e919d1e13e74baf", + Version: "v1.0.0", + }, + }, + } + + manifest, lock, err := g.convert(testGovendorProjectRoot) + if err != nil { + t.Fatal(err) + } + + if manifest == nil { + t.Fatal("Expected the manifest to be generated") + } + + if lock == nil { + t.Fatal("Expected the lock file to be generated") + } + + d, ok := manifest.Constraints[gps.ProjectRoot(pkg)] + if !ok { + t.Fatal("Expected the manifest to have a dependency for 'github.com/sdboyer/deptest' but got none") + } + + wantC := "^1.0.0" + gotC := d.Constraint.String() + if gotC != wantC { + t.Fatalf("Expected manifest constraint to be %s, got %s", wantC, gotC) + } + + wantP := 1 + gotP := len(lock.P) + if gotP != 1 { + t.Fatalf("Expected the lock to contain %d project but got %d", wantP, gotP) + } + + p := lock.P[0] + gotPr := string(p.Ident().ProjectRoot) + if gotPr != pkg { + t.Fatalf("Expected the lock to have a project for %s but got '%s'", pkg, gotPr) + } + + lv := p.Version() + lpv, ok := lv.(gps.PairedVersion) + if !ok { + t.Fatalf("Expected locked version to be a PairedVersion but got %T", lv) + } + + wantRev := "ff2948a2ac8f538c4ecd55962e919d1e13e74baf" + gotRev := lpv.Revision().String() + if gotRev != wantRev { + t.Fatalf("Expected locked revision to be %s, got %s", wantRev, gotRev) + } + + wantV := "v1.0.0" + gotV := lpv.String() + if gotV != wantV { + t.Fatalf("Expected locked version to be %s, got %s", wantV, gotV) + } +} + +func TestGovendorConfig_Convert_TestProject(t *testing.T) { + h := test.NewHelper(t) + defer h.Cleanup() + + ctx := newTestContext(h) + sm, err := ctx.SourceManager() + h.Must(err) + defer sm.Release() + + pkg := "github.com/sdboyer/deptest" + + g := newGovendorImporter(ctx.Err, true, sm) + g.file = govendorFile{ + Package: []*govendorPackage{ + { + Path: pkg, + Revision: "ff2948a2ac8f538c4ecd55962e919d1e13e74baf", + Version: "v1.0.0", + }, + }, + } + + manifest, lock, err := g.convert(testGovendorProjectRoot) + if err != nil { + t.Fatal(err) + } + + if manifest == nil { + t.Fatal("Expected the manifest to be generated") + } + + if lock == nil { + t.Fatal("Expected the lock file to be generated") + } + + _, ok := manifest.Constraints[gps.ProjectRoot(pkg)] + if !ok { + t.Fatalf("Expected the manifest to have a dependency for %s but got none", pkg) + } + + if len(lock.P) != 1 { + t.Fatalf("Expected the lock to contain 1 project but got %d", len(lock.P)) + } + p := lock.P[0] + if p.Ident().ProjectRoot != gps.ProjectRoot(pkg) { + t.Fatalf("Expected the lock to have a project for %s but got '%s'", pkg, p.Ident().ProjectRoot) + } +} + +func TestGovendorConfig_Convert_Ignore(t *testing.T) { + h := test.NewHelper(t) + defer h.Cleanup() + + ctx := newTestContext(h) + sm, err := ctx.SourceManager() + h.Must(err) + defer sm.Release() + + pkg := "github.com/sdboyer/deptest" + + g := newGovendorImporter(ctx.Err, true, sm) + g.file = govendorFile{ + Ignore: strings.Join([]string{"test", pkg, "linux_amd64", "github.com/sdboyer/"}, " "), + } + + m, _, err := g.convert(testGovendorProjectRoot) + if err != nil { + t.Fatal(err) + } + + if len(m.Ignored) != 1 { + t.Fatalf("Expected the ignored list to contain 1 project but got %d", len(m.Ignored)) + } + + p := m.Ignored[0] + if p != pkg { + t.Fatalf("Expected the ignored list to have an element for %s but got '%s'", pkg, p) + } +} + +func TestGovendorConfig_Convert_BadInput_EmptyPackagePath(t *testing.T) { + h := test.NewHelper(t) + defer h.Cleanup() + + ctx := newTestContext(h) + sm, err := ctx.SourceManager() + h.Must(err) + defer sm.Release() + + g := newGovendorImporter(ctx.Err, true, sm) + g.file = govendorFile{ + Package: []*govendorPackage{{Path: ""}}, + } + + _, _, err = g.convert(testGovendorProjectRoot) + if err == nil { + t.Fatal("Expected conversion to fail because the package name is empty") + } +} diff --git a/cmd/dep/testdata/harness_tests/init/govendor/case1/final/Gopkg.lock b/cmd/dep/testdata/harness_tests/init/govendor/case1/final/Gopkg.lock index 56f9bb2b..db52fe25 100644 --- a/cmd/dep/testdata/harness_tests/init/govendor/case1/final/Gopkg.lock +++ b/cmd/dep/testdata/harness_tests/init/govendor/case1/final/Gopkg.lock @@ -1,11 +1,17 @@ # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. +[[projects]] + name = "github.com/carolynvs/go-dep-test" + packages = ["."] + revision = "6b35265ebb3003525cd3ad6498d7e81a89be106b" + version = "0.2.0" + [[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" @@ -16,6 +22,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "c53803413bd0160505cce903e1cba743e0b964088f8cc42a6123f6fe1a0ae9d3" + inputs-digest = "f8e9ea65524b2cebafacf6c9b91441301c6b231bdaf408700a27ae7f9418a273" solver-name = "gps-cdcl" solver-version = 1 diff --git a/cmd/dep/testdata/harness_tests/init/govendor/case1/final/Gopkg.toml b/cmd/dep/testdata/harness_tests/init/govendor/case1/final/Gopkg.toml index ab7893d7..130ae179 100644 --- a/cmd/dep/testdata/harness_tests/init/govendor/case1/final/Gopkg.toml +++ b/cmd/dep/testdata/harness_tests/init/govendor/case1/final/Gopkg.toml @@ -1,4 +1,8 @@ -ignored = ["github.com/sdboyer/dep-test","github.com/golang/notexist/samples"] +ignored = ["github.com/sdboyer/dep-test"] + +[[constraint]] + name = "github.com/carolynvs/go-dep-test" + version = "0.2.0" [[constraint]] name = "github.com/sdboyer/deptestdos" diff --git a/cmd/dep/testdata/harness_tests/init/govendor/case1/initial/vendor/vendor.json b/cmd/dep/testdata/harness_tests/init/govendor/case1/initial/vendor/vendor.json index 983f15f6..b1b44ab9 100644 --- a/cmd/dep/testdata/harness_tests/init/govendor/case1/initial/vendor/vendor.json +++ b/cmd/dep/testdata/harness_tests/init/govendor/case1/initial/vendor/vendor.json @@ -1,10 +1,9 @@ { "comment": "", - "ignore": "test github.com/sdboyer/dep-test", + "ignore": "test github.com/sdboyer/dep-test samples/", "package": [ { "checksumSHA1": "4R6TQcq0/gI/I2kKeUunuO/pEec=", - "origin": "github.com/carolynvs/deptest", "path": "github.com/sdboyer/deptest", "revision": "3f4c3bea144e112a69bbe5d8d01c1b09a544253f", "revisionTime": "2017-02-22T03:31:47Z" diff --git a/cmd/dep/testdata/harness_tests/init/govendor/case1/testcase.json b/cmd/dep/testdata/harness_tests/init/govendor/case1/testcase.json index e1197654..7a1a04de 100644 --- a/cmd/dep/testdata/harness_tests/init/govendor/case1/testcase.json +++ b/cmd/dep/testdata/harness_tests/init/govendor/case1/testcase.json @@ -8,6 +8,7 @@ "github.com/sdboyer/deptestdos": "5c607206be5decd28e6263ffffdcee067266015e" }, "vendor-final": [ + "github.com/carolynvs/go-dep-test", "github.com/sdboyer/deptest", "github.com/sdboyer/deptestdos" ] From d77cf70f5ba1ede4a5da2601f367b0317c788916 Mon Sep 17 00:00:00 2001 From: Kyle Conroy Date: Sat, 15 Jul 2017 15:19:54 -0600 Subject: [PATCH 5/6] internal/importers: add govendor importer Add an `Any` constraint for projects Standardize warnings around ignored build tags Also make few minor changes to logging messages. Add govendor to the list of supported tools Sort the list of organized tools alphabetically as well. Use manifest constructor function --- cmd/dep/govendor_importer.go | 49 +++++++++++----------------- cmd/dep/init.go | 2 +- cmd/dep/testdata/govendor/golden.txt | 4 +-- docs/FAQ.md | 2 +- 4 files changed, 23 insertions(+), 34 deletions(-) diff --git a/cmd/dep/govendor_importer.go b/cmd/dep/govendor_importer.go index 5df9dc5c..69d37939 100644 --- a/cmd/dep/govendor_importer.go +++ b/cmd/dep/govendor_importer.go @@ -49,7 +49,6 @@ type govendorPackage struct { // See the vendor spec for definitions. Origin string Path string - Tree bool Revision string Version string } @@ -75,7 +74,7 @@ func (g *govendorImporter) Import(dir string, pr gps.ProjectRoot) (*dep.Manifest } func (g *govendorImporter) load(projectDir string) error { - g.logger.Println("Detected govendor configuration files...") + g.logger.Println("Detected govendor configuration file...") v := filepath.Join(projectDir, govendorDir, govendorName) if g.verbose { g.logger.Printf(" Loading %s", v) @@ -94,9 +93,7 @@ func (g *govendorImporter) load(projectDir string) error { func (g *govendorImporter) convert(pr gps.ProjectRoot) (*dep.Manifest, *dep.Lock, error) { g.logger.Println("Converting from vendor.json...") - manifest := &dep.Manifest{ - Constraints: make(gps.ProjectConstraints), - } + manifest := dep.NewManifest() if len(g.file.Ignore) > 0 { // Govendor has three use cases here @@ -107,14 +104,14 @@ func (g *govendorImporter) convert(pr gps.ProjectRoot) (*dep.Manifest, *dep.Lock // Dep doesn't support build tags right now: https://github.com/golang/dep/issues/120 for _, i := range strings.Split(g.file.Ignore, " ") { if !strings.Contains(i, "/") { - g.logger.Printf("Warning: Not able to convert ignoring of build tag '%v'", i) + g.logger.Printf(" Govendor was configured to ignore the %s build tag, but that isn't supported by dep yet, and will be ignored. See https://github.com/golang/dep/issues/291.", i) continue } _, err := g.sm.DeduceProjectRoot(i) if err == nil { manifest.Ignored = append(manifest.Ignored, i) } else { - g.logger.Printf("Warning: Not able to convert ignoring of build tag '%v'\n", i) + g.logger.Printf(" Govendor was configured to ignore the %s package prefix, but that isn't supported by dep yet, and will be ignored.", i) } } } @@ -136,7 +133,7 @@ func (g *govendorImporter) convert(pr gps.ProjectRoot) (*dep.Manifest, *dep.Lock pkg.Path = string(pr) // Check if it already existing in locked projects - if projectExistsInLock(lock, pkg.Path) { + if projectExistsInLock(lock, pr) { continue } @@ -149,7 +146,7 @@ func (g *govendorImporter) convert(pr gps.ProjectRoot) (*dep.Manifest, *dep.Lock if pkg.Version == "" { // When no version is specified try to get the corresponding version pi := gps.ProjectIdentifier{ - ProjectRoot: gps.ProjectRoot(pkg.Path), + ProjectRoot: pr, } if pkg.Origin != "" { pi.Source = pkg.Origin @@ -167,14 +164,12 @@ func (g *govendorImporter) convert(pr gps.ProjectRoot) (*dep.Manifest, *dep.Lock } } - if pkg.Version != "" { - // If there's a version, use it to create project constraint - pc, err := g.buildProjectConstraint(pkg) - if err != nil { - return nil, nil, err - } - manifest.Constraints[pc.Ident.ProjectRoot] = gps.ProjectProperties{Constraint: pc.Constraint} + // If there's a version, use it to create project constraint + pc, err := g.buildProjectConstraint(pkg) + if err != nil { + return nil, nil, err } + manifest.Constraints[pc.Ident.ProjectRoot] = gps.ProjectProperties{Constraint: pc.Constraint} lp := g.buildLockedProject(pkg, manifest) lock.P = append(lock.P, lp) @@ -184,20 +179,15 @@ func (g *govendorImporter) convert(pr gps.ProjectRoot) (*dep.Manifest, *dep.Lock } func (g *govendorImporter) buildProjectConstraint(pkg *govendorPackage) (pc gps.ProjectConstraint, err error) { - if pkg.Path == "" { - err = errors.New("Invalid vendor configuration, package path is required") - return - } - - ref := pkg.Version - if ref == "" { - ref = pkg.Revision - } - pc.Ident = gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot(pkg.Path), Source: pkg.Path} - pc.Constraint, err = g.sm.InferConstraint(ref, pc.Ident) - if err != nil { - return + + if pkg.Version != "" { + pc.Constraint, err = g.sm.InferConstraint(pkg.Version, pc.Ident) + if err != nil { + return + } + } else { + pc.Constraint = gps.Any() } f := fb.NewConstraintFeedback(pc, fb.DepTypeImported) @@ -206,7 +196,6 @@ func (g *govendorImporter) buildProjectConstraint(pkg *govendorPackage) (pc gps. return } -// buildLockedProject uses the package Rev and Comment to create lock project func (g *govendorImporter) buildLockedProject(pkg *govendorPackage, manifest *dep.Manifest) gps.LockedProject { pi := gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot(pkg.Path)} revision := gps.Revision(pkg.Revision) diff --git a/cmd/dep/init.go b/cmd/dep/init.go index 0c6a36a9..19e19fc0 100644 --- a/cmd/dep/init.go +++ b/cmd/dep/init.go @@ -30,7 +30,7 @@ specified, use the current directory. When configuration for another dependency management tool is detected, it is imported into the initial manifest and lock. Use the -skip-tools flag to disable this behavior. The following external tools are supported: -glide, godep, vndr, govend, gb, gvt. +glide, godep, vndr, govend, gb, gvt, govendor. Any dependencies that are not constrained by external configuration use the GOPATH analysis below. diff --git a/cmd/dep/testdata/govendor/golden.txt b/cmd/dep/testdata/govendor/golden.txt index fde8e9fb..4fa314d1 100644 --- a/cmd/dep/testdata/govendor/golden.txt +++ b/cmd/dep/testdata/govendor/golden.txt @@ -1,6 +1,6 @@ -Detected govendor configuration files... +Detected govendor configuration file... Converting from vendor.json... -Warning: Not able to convert ignoring of build tag 'test' + Govendor was configured to ignore the test build tag, but that isn't supported by dep yet, and will be ignored. See https://github.com/golang/dep/issues/291. Using ^0.8.1 as initial constraint for imported dep github.com/sdboyer/deptest Trying v0.8.1 (3f4c3be) as initial lock for imported dep github.com/sdboyer/deptest Using ^2.0.0 as initial constraint for imported dep github.com/sdboyer/deptestdos diff --git a/docs/FAQ.md b/docs/FAQ.md index 4a8a582b..69aa2115 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -217,7 +217,7 @@ about what's going on. During `dep init` configuration from other dependency managers is detected and imported, unless `-skip-tools` is specified. -The following tools are supported: `glide`, `godep`, `vndr`, `govend`, `gb` and `gvt`. +The following tools are supported: `glide`, `godep`, `vndr`, `govend`, `gb`, `gvt` and `govendor`. See [#186](https://github.com/golang/dep/issues/186#issuecomment-306363441) for how to add support for another tool. From 56cefc4d23f8aa5efc1193b372c723cd3388c0b7 Mon Sep 17 00:00:00 2001 From: Carolyn Van Slyck Date: Fri, 6 Oct 2017 16:59:58 -0500 Subject: [PATCH 6/6] internal/importers: add govendor importer Move govendor files into importers pkg Expose the base importer's source manager It is used by the govendor importer to detect ignored packaegs Update govendor importer to use base importer Document exported members Remove unused testdata Import ignores with wildcards Add govendor support to changelog Do not import vendored sources Don't require a revision to import govendor config There are valid govendor configs in the wild that do not have a revision set, essentially requiring the package but not locking to a revision. We should allow that and not stop the import. --- CHANGELOG.md | 4 + cmd/dep/govendor_importer.go | 215 ---------------- cmd/dep/govendor_importer_test.go | 243 ------------------ cmd/dep/testdata/govendor/vendor-sub-pkg.json | 25 -- .../govendor/vendor-vendored-dep.json | 21 -- .../init/govendor/case1/final/Gopkg.lock | 8 +- .../init/govendor/case1/final/Gopkg.toml | 6 +- .../init/govendor/case1/testcase.json | 1 - internal/importers/base/importer.go | 37 +-- internal/importers/base/importer_test.go | 15 +- internal/importers/govendor/importer.go | 150 +++++++++++ internal/importers/govendor/importer_test.go | 155 +++++++++++ .../importers/govendor/testdata}/golden.txt | 2 +- .../importers/govendor/testdata}/vendor.json | 0 internal/importers/importers.go | 2 + internal/importers/importertest/testcase.go | 2 +- 16 files changed, 349 insertions(+), 537 deletions(-) delete mode 100644 cmd/dep/govendor_importer.go delete mode 100644 cmd/dep/govendor_importer_test.go delete mode 100644 cmd/dep/testdata/govendor/vendor-sub-pkg.json delete mode 100644 cmd/dep/testdata/govendor/vendor-vendored-dep.json create mode 100644 internal/importers/govendor/importer.go create mode 100644 internal/importers/govendor/importer_test.go rename {cmd/dep/testdata/govendor => internal/importers/govendor/testdata}/golden.txt (100%) rename {cmd/dep/testdata/govendor => internal/importers/govendor/testdata}/vendor.json (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3cd6e2e..cc7697a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # v0.3.3 (Unreleased) +NEW FEATURES: +* Add support for importing from [govendor](https://github.com/kardianos/govendor) + based projects (#815). + BUG FIXES: * Releases targeting Windows now have a `.exe` suffix (#1291). diff --git a/cmd/dep/govendor_importer.go b/cmd/dep/govendor_importer.go deleted file mode 100644 index 69d37939..00000000 --- a/cmd/dep/govendor_importer.go +++ /dev/null @@ -1,215 +0,0 @@ -// Copyright 2016 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 main - -import ( - "encoding/json" - "io/ioutil" - "log" - "os" - "path/filepath" - "strings" - - "github.com/golang/dep" - fb "github.com/golang/dep/internal/feedback" - "github.com/golang/dep/internal/gps" - "github.com/pkg/errors" -) - -const govendorDir = "vendor" -const govendorName = "vendor.json" - -type govendorImporter struct { - file govendorFile - - logger *log.Logger - verbose bool - sm gps.SourceManager -} - -func newGovendorImporter(logger *log.Logger, verbose bool, sm gps.SourceManager) *govendorImporter { - return &govendorImporter{ - logger: logger, - verbose: verbose, - sm: sm, - } -} - -// File is the structure of the vendor file. -type govendorFile struct { - RootPath string // Import path of vendor folder - Ignore string - Package []*govendorPackage -} - -// Package represents each package. -type govendorPackage struct { - // See the vendor spec for definitions. - Origin string - Path string - Revision string - Version string -} - -func (g *govendorImporter) Name() string { - return "govendor" -} - -func (g *govendorImporter) HasDepMetadata(dir string) bool { - y := filepath.Join(dir, govendorDir, govendorName) - if _, err := os.Stat(y); err != nil { - return false - } - return true -} - -func (g *govendorImporter) Import(dir string, pr gps.ProjectRoot) (*dep.Manifest, *dep.Lock, error) { - err := g.load(dir) - if err != nil { - return nil, nil, err - } - return g.convert(pr) -} - -func (g *govendorImporter) load(projectDir string) error { - g.logger.Println("Detected govendor configuration file...") - v := filepath.Join(projectDir, govendorDir, govendorName) - if g.verbose { - g.logger.Printf(" Loading %s", v) - } - vb, err := ioutil.ReadFile(v) - if err != nil { - return errors.Wrapf(err, "Unable to read %s", v) - } - err = json.Unmarshal(vb, &g.file) - if err != nil { - return errors.Wrapf(err, "Unable to parse %s", v) - } - return nil -} - -func (g *govendorImporter) convert(pr gps.ProjectRoot) (*dep.Manifest, *dep.Lock, error) { - g.logger.Println("Converting from vendor.json...") - - manifest := dep.NewManifest() - - if len(g.file.Ignore) > 0 { - // Govendor has three use cases here - // 1. 'test' - special case for ignoring test files - // 2. build tags - any string without a slash (/) in it - // 3. path and path prefix - any string with a slash (/) in it. - // The path case could be a full path or just a prefix. - // Dep doesn't support build tags right now: https://github.com/golang/dep/issues/120 - for _, i := range strings.Split(g.file.Ignore, " ") { - if !strings.Contains(i, "/") { - g.logger.Printf(" Govendor was configured to ignore the %s build tag, but that isn't supported by dep yet, and will be ignored. See https://github.com/golang/dep/issues/291.", i) - continue - } - _, err := g.sm.DeduceProjectRoot(i) - if err == nil { - manifest.Ignored = append(manifest.Ignored, i) - } else { - g.logger.Printf(" Govendor was configured to ignore the %s package prefix, but that isn't supported by dep yet, and will be ignored.", i) - } - } - } - - lock := &dep.Lock{} - for _, pkg := range g.file.Package { - // Path must not be empty - if pkg.Path == "" { - err := errors.New("Invalid govendor configuration, Path is required") - return nil, nil, err - } - - // Obtain ProjectRoot. Required for avoiding sub-package imports. - // Use Path instead of Origin since we are trying to group by project here - pr, err := g.sm.DeduceProjectRoot(pkg.Path) - if err != nil { - return nil, nil, err - } - pkg.Path = string(pr) - - // Check if it already existing in locked projects - if projectExistsInLock(lock, pr) { - continue - } - - // Revision must not be empty - if pkg.Revision == "" { - err := errors.New("Invalid govendor configuration, Revision is required") - return nil, nil, err - } - - if pkg.Version == "" { - // When no version is specified try to get the corresponding version - pi := gps.ProjectIdentifier{ - ProjectRoot: pr, - } - if pkg.Origin != "" { - pi.Source = pkg.Origin - } - revision := gps.Revision(pkg.Revision) - version, err := lookupVersionForLockedProject(pi, nil, revision, g.sm) - if err != nil { - // Only warn about the problem, it is not enough to warrant failing - g.logger.Println(err.Error()) - } else { - pp := getProjectPropertiesFromVersion(version) - if pp.Constraint != nil { - pkg.Version = pp.Constraint.String() - } - } - } - - // If there's a version, use it to create project constraint - pc, err := g.buildProjectConstraint(pkg) - if err != nil { - return nil, nil, err - } - manifest.Constraints[pc.Ident.ProjectRoot] = gps.ProjectProperties{Constraint: pc.Constraint} - - lp := g.buildLockedProject(pkg, manifest) - lock.P = append(lock.P, lp) - } - - return manifest, lock, nil -} - -func (g *govendorImporter) buildProjectConstraint(pkg *govendorPackage) (pc gps.ProjectConstraint, err error) { - pc.Ident = gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot(pkg.Path), Source: pkg.Path} - - if pkg.Version != "" { - pc.Constraint, err = g.sm.InferConstraint(pkg.Version, pc.Ident) - if err != nil { - return - } - } else { - pc.Constraint = gps.Any() - } - - f := fb.NewConstraintFeedback(pc, fb.DepTypeImported) - f.LogFeedback(g.logger) - - return -} - -func (g *govendorImporter) buildLockedProject(pkg *govendorPackage, manifest *dep.Manifest) gps.LockedProject { - pi := gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot(pkg.Path)} - revision := gps.Revision(pkg.Revision) - pp := manifest.Constraints[pi.ProjectRoot] - - version, err := lookupVersionForLockedProject(pi, pp.Constraint, revision, g.sm) - if err != nil { - // Only warn about the problem, it is not enough to warrant failing - g.logger.Println(err.Error()) - } - - lp := gps.NewLockedProject(pi, version, nil) - f := fb.NewLockedProjectFeedback(lp, fb.DepTypeImported) - f.LogFeedback(g.logger) - - return lp -} diff --git a/cmd/dep/govendor_importer_test.go b/cmd/dep/govendor_importer_test.go deleted file mode 100644 index eb92711a..00000000 --- a/cmd/dep/govendor_importer_test.go +++ /dev/null @@ -1,243 +0,0 @@ -// Copyright 2016 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 main - -import ( - "bytes" - "log" - "path/filepath" - "strings" - "testing" - - "github.com/golang/dep/internal/gps" - "github.com/golang/dep/internal/test" - "github.com/pkg/errors" -) - -const testGovendorProjectRoot = "github.com/golang/notexist" - -func TestGovendorConfig_Import(t *testing.T) { - h := test.NewHelper(t) - defer h.Cleanup() - - ctx := newTestContext(h) - sm, err := ctx.SourceManager() - h.Must(err) - defer sm.Release() - - h.TempDir(filepath.Join("src", testGovendorProjectRoot)) - h.TempCopy(filepath.Join(testGovendorProjectRoot, govendorDir, govendorName), "govendor/vendor.json") - projectRoot := h.Path(testGovendorProjectRoot) - - // Capture stderr so we can verify output - verboseOutput := &bytes.Buffer{} - ctx.Err = log.New(verboseOutput, "", 0) - - g := newGovendorImporter(ctx.Err, false, sm) // Disable verbose so that we don't print values that change each test run - if !g.HasDepMetadata(projectRoot) { - t.Fatal("Expected the importer to detect the govendor configuration files") - } - - m, l, err := g.Import(projectRoot, testGovendorProjectRoot) - h.Must(err) - - if m == nil { - t.Fatal("Expected the manifest to be generated") - } - - if l == nil { - t.Fatal("Expected the lock to be generated") - } - - goldenFile := "govendor/golden.txt" - got := verboseOutput.String() - want := h.GetTestFileString(goldenFile) - if want != got { - if *test.UpdateGolden { - if err := h.WriteTestFile(goldenFile, got); err != nil { - t.Fatalf("%+v", errors.Wrapf(err, "Unable to write updated golden file %s", goldenFile)) - } - } else { - t.Fatalf("expected %s, got %s", want, got) - } - } -} - -func TestGovendorConfig_Convert_Project(t *testing.T) { - h := test.NewHelper(t) - defer h.Cleanup() - - ctx := newTestContext(h) - sm, err := ctx.SourceManager() - h.Must(err) - defer sm.Release() - - pkg := "github.com/sdboyer/deptest" - - g := newGovendorImporter(ctx.Err, true, sm) - g.file = govendorFile{ - Package: []*govendorPackage{ - { - Path: pkg, - Revision: "ff2948a2ac8f538c4ecd55962e919d1e13e74baf", - Version: "v1.0.0", - }, - }, - } - - manifest, lock, err := g.convert(testGovendorProjectRoot) - if err != nil { - t.Fatal(err) - } - - if manifest == nil { - t.Fatal("Expected the manifest to be generated") - } - - if lock == nil { - t.Fatal("Expected the lock file to be generated") - } - - d, ok := manifest.Constraints[gps.ProjectRoot(pkg)] - if !ok { - t.Fatal("Expected the manifest to have a dependency for 'github.com/sdboyer/deptest' but got none") - } - - wantC := "^1.0.0" - gotC := d.Constraint.String() - if gotC != wantC { - t.Fatalf("Expected manifest constraint to be %s, got %s", wantC, gotC) - } - - wantP := 1 - gotP := len(lock.P) - if gotP != 1 { - t.Fatalf("Expected the lock to contain %d project but got %d", wantP, gotP) - } - - p := lock.P[0] - gotPr := string(p.Ident().ProjectRoot) - if gotPr != pkg { - t.Fatalf("Expected the lock to have a project for %s but got '%s'", pkg, gotPr) - } - - lv := p.Version() - lpv, ok := lv.(gps.PairedVersion) - if !ok { - t.Fatalf("Expected locked version to be a PairedVersion but got %T", lv) - } - - wantRev := "ff2948a2ac8f538c4ecd55962e919d1e13e74baf" - gotRev := lpv.Revision().String() - if gotRev != wantRev { - t.Fatalf("Expected locked revision to be %s, got %s", wantRev, gotRev) - } - - wantV := "v1.0.0" - gotV := lpv.String() - if gotV != wantV { - t.Fatalf("Expected locked version to be %s, got %s", wantV, gotV) - } -} - -func TestGovendorConfig_Convert_TestProject(t *testing.T) { - h := test.NewHelper(t) - defer h.Cleanup() - - ctx := newTestContext(h) - sm, err := ctx.SourceManager() - h.Must(err) - defer sm.Release() - - pkg := "github.com/sdboyer/deptest" - - g := newGovendorImporter(ctx.Err, true, sm) - g.file = govendorFile{ - Package: []*govendorPackage{ - { - Path: pkg, - Revision: "ff2948a2ac8f538c4ecd55962e919d1e13e74baf", - Version: "v1.0.0", - }, - }, - } - - manifest, lock, err := g.convert(testGovendorProjectRoot) - if err != nil { - t.Fatal(err) - } - - if manifest == nil { - t.Fatal("Expected the manifest to be generated") - } - - if lock == nil { - t.Fatal("Expected the lock file to be generated") - } - - _, ok := manifest.Constraints[gps.ProjectRoot(pkg)] - if !ok { - t.Fatalf("Expected the manifest to have a dependency for %s but got none", pkg) - } - - if len(lock.P) != 1 { - t.Fatalf("Expected the lock to contain 1 project but got %d", len(lock.P)) - } - p := lock.P[0] - if p.Ident().ProjectRoot != gps.ProjectRoot(pkg) { - t.Fatalf("Expected the lock to have a project for %s but got '%s'", pkg, p.Ident().ProjectRoot) - } -} - -func TestGovendorConfig_Convert_Ignore(t *testing.T) { - h := test.NewHelper(t) - defer h.Cleanup() - - ctx := newTestContext(h) - sm, err := ctx.SourceManager() - h.Must(err) - defer sm.Release() - - pkg := "github.com/sdboyer/deptest" - - g := newGovendorImporter(ctx.Err, true, sm) - g.file = govendorFile{ - Ignore: strings.Join([]string{"test", pkg, "linux_amd64", "github.com/sdboyer/"}, " "), - } - - m, _, err := g.convert(testGovendorProjectRoot) - if err != nil { - t.Fatal(err) - } - - if len(m.Ignored) != 1 { - t.Fatalf("Expected the ignored list to contain 1 project but got %d", len(m.Ignored)) - } - - p := m.Ignored[0] - if p != pkg { - t.Fatalf("Expected the ignored list to have an element for %s but got '%s'", pkg, p) - } -} - -func TestGovendorConfig_Convert_BadInput_EmptyPackagePath(t *testing.T) { - h := test.NewHelper(t) - defer h.Cleanup() - - ctx := newTestContext(h) - sm, err := ctx.SourceManager() - h.Must(err) - defer sm.Release() - - g := newGovendorImporter(ctx.Err, true, sm) - g.file = govendorFile{ - Package: []*govendorPackage{{Path: ""}}, - } - - _, _, err = g.convert(testGovendorProjectRoot) - if err == nil { - t.Fatal("Expected conversion to fail because the package name is empty") - } -} diff --git a/cmd/dep/testdata/govendor/vendor-sub-pkg.json b/cmd/dep/testdata/govendor/vendor-sub-pkg.json deleted file mode 100644 index 4d47fc3d..00000000 --- a/cmd/dep/testdata/govendor/vendor-sub-pkg.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "comment": "", - "ignore": "test", - "package": [ - { - "checksumSHA1": "c+MCTe4HOVzNBjFpjmPYWFSs06U=", - "path": "github.com/sdboyer/deptest", - "revision": "e1b5acf7f78e07bc0a8e51121ca0c7e174975d7e", - "revisionTime": "2017-07-15T19:32:19Z" - }, - { - "checksumSHA1": "cp+gzxyVhoM8sZWLPrsigvpdDuc=", - "path": "github.com/sdboyer/deptest/floats", - "revision": "e1b5acf7f78e07bc0a8e51121ca0c7e174975d7e", - "revisionTime": "2017-07-15T19:32:19Z" - }, - { - "checksumSHA1": "5yiF57bPBKmLr6AFDDxfTmWYZJ4=", - "path": "github.com/sdboyer/deptest/strings", - "revision": "e1b5acf7f78e07bc0a8e51121ca0c7e174975d7e", - "revisionTime": "2017-07-15T19:32:19Z" - } - ], - "rootPath": "github.com/golang/notexist" -} diff --git a/cmd/dep/testdata/govendor/vendor-vendored-dep.json b/cmd/dep/testdata/govendor/vendor-vendored-dep.json deleted file mode 100644 index e8098657..00000000 --- a/cmd/dep/testdata/govendor/vendor-vendored-dep.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "comment": "", - "ignore": "test", - "package": [ - { - "checksumSHA1": "q6es/GCwizh2GbLTKWWj8bB6Lc8=", - "origin": "github.com/sdboyer/deptest/vendor/github.com/sdboyer/coolint", - "path": "github.com/sdboyer/coolint", - "revision": "a920fd05db2031ad1ba94f62035fab5def190141", - "revisionTime": "2017-07-15T19:22:11Z" - }, - { - "checksumSHA1": "c+MCTe4HOVzNBjFpjmPYWFSs06U=", - "path": "github.com/sdboyer/deptest", - "revision": "a920fd05db2031ad1ba94f62035fab5def190141", - "revisionTime": "2017-07-15T19:22:11Z" - } - ], - "rootPath": "github.com/golang/notexist" -} - diff --git a/cmd/dep/testdata/harness_tests/init/govendor/case1/final/Gopkg.lock b/cmd/dep/testdata/harness_tests/init/govendor/case1/final/Gopkg.lock index db52fe25..529e4889 100644 --- a/cmd/dep/testdata/harness_tests/init/govendor/case1/final/Gopkg.lock +++ b/cmd/dep/testdata/harness_tests/init/govendor/case1/final/Gopkg.lock @@ -1,12 +1,6 @@ # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. -[[projects]] - name = "github.com/carolynvs/go-dep-test" - packages = ["."] - revision = "6b35265ebb3003525cd3ad6498d7e81a89be106b" - version = "0.2.0" - [[projects]] name = "github.com/sdboyer/deptest" packages = ["."] @@ -22,6 +16,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "f8e9ea65524b2cebafacf6c9b91441301c6b231bdaf408700a27ae7f9418a273" + inputs-digest = "9cc662f2e1b80c8df205d9d667fe2c47825a06961ceae378f44a8290d01dd359" solver-name = "gps-cdcl" solver-version = 1 diff --git a/cmd/dep/testdata/harness_tests/init/govendor/case1/final/Gopkg.toml b/cmd/dep/testdata/harness_tests/init/govendor/case1/final/Gopkg.toml index 130ae179..adef29b9 100644 --- a/cmd/dep/testdata/harness_tests/init/govendor/case1/final/Gopkg.toml +++ b/cmd/dep/testdata/harness_tests/init/govendor/case1/final/Gopkg.toml @@ -1,8 +1,4 @@ -ignored = ["github.com/sdboyer/dep-test"] - -[[constraint]] - name = "github.com/carolynvs/go-dep-test" - version = "0.2.0" +ignored = ["github.com/golang/notexist/samples*","github.com/sdboyer/dep-test*"] [[constraint]] name = "github.com/sdboyer/deptestdos" diff --git a/cmd/dep/testdata/harness_tests/init/govendor/case1/testcase.json b/cmd/dep/testdata/harness_tests/init/govendor/case1/testcase.json index 7a1a04de..e1197654 100644 --- a/cmd/dep/testdata/harness_tests/init/govendor/case1/testcase.json +++ b/cmd/dep/testdata/harness_tests/init/govendor/case1/testcase.json @@ -8,7 +8,6 @@ "github.com/sdboyer/deptestdos": "5c607206be5decd28e6263ffffdcee067266015e" }, "vendor-final": [ - "github.com/carolynvs/go-dep-test", "github.com/sdboyer/deptest", "github.com/sdboyer/deptestdos" ] diff --git a/internal/importers/base/importer.go b/internal/importers/base/importer.go index 8b3be146..9d17b072 100644 --- a/internal/importers/base/importer.go +++ b/internal/importers/base/importer.go @@ -6,6 +6,7 @@ package base import ( "log" + "strings" "github.com/golang/dep" "github.com/golang/dep/gps" @@ -16,28 +17,27 @@ import ( // Importer provides a common implementation for importing from other // dependency managers. type Importer struct { - sm gps.SourceManager - - Logger *log.Logger - Verbose bool - Manifest *dep.Manifest - Lock *dep.Lock + SourceManager gps.SourceManager + Logger *log.Logger + Verbose bool + Manifest *dep.Manifest + Lock *dep.Lock } // NewImporter creates a new Importer for embedding in an importer. func NewImporter(logger *log.Logger, verbose bool, sm gps.SourceManager) *Importer { return &Importer{ - Logger: logger, - Verbose: verbose, - Manifest: dep.NewManifest(), - Lock: &dep.Lock{}, - sm: sm, + Logger: logger, + Verbose: verbose, + Manifest: dep.NewManifest(), + Lock: &dep.Lock{}, + SourceManager: sm, } } // isTag determines if the specified value is a tag (plain or semver). func (i *Importer) isTag(pi gps.ProjectIdentifier, value string) (bool, gps.Version, error) { - versions, err := i.sm.ListVersions(pi) + versions, err := i.SourceManager.ListVersions(pi) if err != nil { return false, nil, errors.Wrapf(err, "unable to list versions for %s(%s)", pi.ProjectRoot, pi.Source) } @@ -61,7 +61,7 @@ func (i *Importer) isTag(pi gps.ProjectIdentifier, value string) (bool, gps.Vers // manifest, then finally the revision. func (i *Importer) lookupVersionForLockedProject(pi gps.ProjectIdentifier, c gps.Constraint, rev gps.Revision) (gps.Version, error) { // Find the version that goes with this revision, if any - versions, err := i.sm.ListVersions(pi) + versions, err := i.SourceManager.ListVersions(pi) if err != nil { return rev, errors.Wrapf(err, "Unable to lookup the version represented by %s in %s(%s). Falling back to locking the revision only.", rev, pi.ProjectRoot, pi.Source) } @@ -130,7 +130,7 @@ func (i *Importer) loadPackages(packages []ImportedPackage) ([]importedProject, projects := make(map[gps.ProjectRoot]*importedProject, len(packages)) for _, pkg := range packages { - pr, err := i.sm.DeduceProjectRoot(pkg.Name) + pr, err := i.SourceManager.DeduceProjectRoot(pkg.Name) if err != nil { return nil, errors.Wrapf(err, "Cannot determine the project root for %s", pkg.Name) } @@ -188,6 +188,9 @@ func (i *Importer) ImportPackages(packages []ImportedPackage, defaultConstraintF source = "" } else if isDefault { source = "" + } else if strings.Contains(source, "/vendor/") { + i.Logger.Printf(" Ignoring imported source %s for %s because vendored sources aren't supported", source, prj.Root) + source = "" } } @@ -198,7 +201,7 @@ func (i *Importer) ImportPackages(packages []ImportedPackage, defaultConstraintF }, } - pc.Constraint, err = i.sm.InferConstraint(prj.ConstraintHint, pc.Ident) + pc.Constraint, err = i.SourceManager.InferConstraint(prj.ConstraintHint, pc.Ident) if err != nil { pc.Constraint = gps.Any() } @@ -306,12 +309,12 @@ func (i *Importer) convertToConstraint(v gps.Version) gps.Constraint { func (i *Importer) isDefaultSource(projectRoot gps.ProjectRoot, sourceURL string) (bool, error) { // this condition is mainly for gopkg.in imports, // as some importers specify the repository url as https://gopkg.in/..., - // but sm.SourceURLsForPath() returns https://github.com/... urls for gopkg.in + // but SourceManager.SourceURLsForPath() returns https://github.com/... urls for gopkg.in if sourceURL == "https://"+string(projectRoot) { return true, nil } - sourceURLs, err := i.sm.SourceURLsForPath(string(projectRoot)) + sourceURLs, err := i.SourceManager.SourceURLsForPath(string(projectRoot)) if err != nil { return false, err } diff --git a/internal/importers/base/importer_test.go b/internal/importers/base/importer_test.go index be76ecde..8d38b816 100644 --- a/internal/importers/base/importer_test.go +++ b/internal/importers/base/importer_test.go @@ -382,7 +382,7 @@ func TestBaseImporter_ImportProjects(t *testing.T) { }, }, }, - "ignoring default source": { + "ignore default source": { importertest.TestCase{ WantConstraint: "*", WantSourceRepo: "", @@ -394,6 +394,19 @@ func TestBaseImporter_ImportProjects(t *testing.T) { }, }, }, + "ignore vendored source": { + importertest.TestCase{ + WantConstraint: "*", + WantSourceRepo: "", + WantWarning: "vendored sources aren't supported", + }, + []ImportedPackage{ + { + Name: importertest.Project, + Source: "example.com/vendor/" + importertest.Project, + }, + }, + }, } for name, tc := range testcases { diff --git a/internal/importers/govendor/importer.go b/internal/importers/govendor/importer.go new file mode 100644 index 00000000..f7a5d44d --- /dev/null +++ b/internal/importers/govendor/importer.go @@ -0,0 +1,150 @@ +// Copyright 2016 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 govendor + +import ( + "encoding/json" + "io/ioutil" + "log" + "os" + "path" + "path/filepath" + "strings" + + "github.com/golang/dep" + "github.com/golang/dep/gps" + "github.com/golang/dep/internal/importers/base" + "github.com/pkg/errors" +) + +const govendorDir = "vendor" +const govendorName = "vendor.json" + +// Importer imports govendor configuration into the dep configuration format. +type Importer struct { + *base.Importer + + file govendorFile +} + +// NewImporter for govendor. +func NewImporter(logger *log.Logger, verbose bool, sm gps.SourceManager) *Importer { + return &Importer{Importer: base.NewImporter(logger, verbose, sm)} +} + +// File is the structure of the vendor file. +type govendorFile struct { + RootPath string // Import path of vendor folder + Ignore string + Package []*govendorPackage +} + +// Package represents each package. +type govendorPackage struct { + // See the vendor spec for definitions. + Origin string + Path string + Revision string + Version string +} + +// Name of the importer. +func (g *Importer) Name() string { + return "govendor" +} + +// HasDepMetadata checks if a directory contains config that the importer can handle. +func (g *Importer) HasDepMetadata(dir string) bool { + y := filepath.Join(dir, govendorDir, govendorName) + if _, err := os.Stat(y); err != nil { + return false + } + return true +} + +// Import the config found in the directory. +func (g *Importer) Import(dir string, pr gps.ProjectRoot) (*dep.Manifest, *dep.Lock, error) { + err := g.load(dir) + if err != nil { + return nil, nil, err + } + return g.convert(pr) +} + +func (g *Importer) load(projectDir string) error { + g.Logger.Println("Detected govendor configuration file...") + v := filepath.Join(projectDir, govendorDir, govendorName) + if g.Verbose { + g.Logger.Printf(" Loading %s", v) + } + vb, err := ioutil.ReadFile(v) + if err != nil { + return errors.Wrapf(err, "unable to read %s", v) + } + err = json.Unmarshal(vb, &g.file) + if err != nil { + return errors.Wrapf(err, "unable to parse %s", v) + } + return nil +} + +func (g *Importer) convert(pr gps.ProjectRoot) (*dep.Manifest, *dep.Lock, error) { + g.Logger.Println("Converting from vendor.json...") + + packages := make([]base.ImportedPackage, 0, len(g.file.Package)) + for _, pkg := range g.file.Package { + // Path must not be empty + if pkg.Path == "" { + err := errors.New("invalid govendor configuration, Path is required") + return nil, nil, err + } + + // There are valid govendor configs in the wild that don't have a revision set + // so we are not requiring it to be set during import + + ip := base.ImportedPackage{ + Name: pkg.Path, + Source: pkg.Origin, + LockHint: pkg.Revision, + } + packages = append(packages, ip) + } + + err := g.ImportPackages(packages, true) + if err != nil { + return nil, nil, err + } + + if len(g.file.Ignore) > 0 { + // Govendor has three use cases here + // 1. 'test' - special case for ignoring test files + // 2. build tags - any string without a slash (/) in it + // 3. path and path prefix - any string with a slash (/) in it. + // The path case could be a full path or just a prefix. + // Dep doesn't support build tags right now: https://github.com/golang/dep/issues/120 + for _, i := range strings.Split(g.file.Ignore, " ") { + if !strings.Contains(i, "/") { + g.Logger.Printf(" Govendor was configured to ignore the %s build tag, but that isn't supported by dep yet, and will be ignored. See https://github.com/golang/dep/issues/291.", i) + continue + } + + var ignorePattern string + _, err := g.SourceManager.DeduceProjectRoot(i) + if err == nil { // external package + ignorePattern = i + } else { // relative package path in the current project + ignorePattern = path.Join(string(pr), i) + } + + // Convert to a a wildcard ignore + ignorePattern = strings.TrimRight(ignorePattern, "/") + ignorePattern += "*" + + g.Manifest.Ignored = append(g.Manifest.Ignored, ignorePattern) + } + } + + return g.Manifest, g.Lock, nil +} diff --git a/internal/importers/govendor/importer_test.go b/internal/importers/govendor/importer_test.go new file mode 100644 index 00000000..f0e28f70 --- /dev/null +++ b/internal/importers/govendor/importer_test.go @@ -0,0 +1,155 @@ +// Copyright 2016 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 govendor + +import ( + "bytes" + "log" + "path/filepath" + "testing" + + "github.com/golang/dep" + "github.com/golang/dep/gps" + "github.com/golang/dep/internal/importers/importertest" + "github.com/golang/dep/internal/test" + "github.com/pkg/errors" +) + +const testGovendorProjectRoot = "github.com/golang/notexist" + +func TestGovendorConfig_Import(t *testing.T) { + h := test.NewHelper(t) + defer h.Cleanup() + + ctx := importertest.NewTestContext(h) + sm, err := ctx.SourceManager() + h.Must(err) + defer sm.Release() + + h.TempDir(filepath.Join("src", testGovendorProjectRoot)) + h.TempCopy(filepath.Join(testGovendorProjectRoot, govendorDir, govendorName), "vendor.json") + projectRoot := h.Path(testGovendorProjectRoot) + + // Capture stderr so we can verify output + verboseOutput := &bytes.Buffer{} + ctx.Err = log.New(verboseOutput, "", 0) + + g := NewImporter(ctx.Err, false, sm) // Disable verbose so that we don't print values that change each test run + if !g.HasDepMetadata(projectRoot) { + t.Fatal("Expected the importer to detect the govendor configuration files") + } + + m, l, err := g.Import(projectRoot, testGovendorProjectRoot) + h.Must(err) + + if m == nil { + t.Fatal("Expected the manifest to be generated") + } + + if l == nil { + t.Fatal("Expected the lock to be generated") + } + + goldenFile := "golden.txt" + got := verboseOutput.String() + want := h.GetTestFileString(goldenFile) + if want != got { + if *test.UpdateGolden { + if err := h.WriteTestFile(goldenFile, got); err != nil { + t.Fatalf("%+v", errors.Wrapf(err, "Unable to write updated golden file %s", goldenFile)) + } + } else { + t.Fatalf("expected %s, got %s", want, got) + } + } +} + +func TestGovendorConfig_Convert(t *testing.T) { + testCases := map[string]struct { + file govendorFile + importertest.TestCase + }{ + "project": { + govendorFile{ + Package: []*govendorPackage{ + { + Path: importertest.Project, + Origin: importertest.ProjectSrc, + Revision: importertest.V1Rev, + }, + }, + }, + importertest.TestCase{ + WantSourceRepo: importertest.ProjectSrc, + WantConstraint: importertest.V1Constraint, + WantRevision: importertest.V1Rev, + WantVersion: importertest.V1Tag, + }, + }, + "skipped build tags": { + govendorFile{ + Ignore: "test linux_amd64", + }, + importertest.TestCase{ + WantIgnored: nil, + }, + }, + "ignored external package": { + govendorFile{ + Ignore: "github.com/sdboyer/deptest k8s.io/apimachinery", + }, + importertest.TestCase{ + WantIgnored: []string{"github.com/sdboyer/deptest*", "k8s.io/apimachinery*"}, + }, + }, + "ignored internal package": { + govendorFile{ + Ignore: "samples/ foo/bar", + }, + importertest.TestCase{ + WantIgnored: []string{importertest.RootProject + "/samples*", importertest.RootProject + "/foo/bar*"}, + }, + }, + "missing package path": { + govendorFile{ + Package: []*govendorPackage{ + { + Revision: importertest.V2PatchRev, + }, + }, + }, + importertest.TestCase{ + WantConvertErr: true, + }, + }, + "missing package revision doesn't cause an error": { + govendorFile{ + Package: []*govendorPackage{ + { + Path: importertest.Project, + }, + }, + }, + importertest.TestCase{ + WantConstraint: "*", + }, + }, + } + + for name, testCase := range testCases { + name := name + testCase := testCase + t.Run(name, func(t *testing.T) { + err := testCase.Execute(t, func(logger *log.Logger, sm gps.SourceManager) (*dep.Manifest, *dep.Lock, error) { + g := NewImporter(logger, true, sm) + g.file = testCase.file + return g.convert(importertest.RootProject) + }) + if err != nil { + t.Fatalf("%#v", err) + } + }) + } +} diff --git a/cmd/dep/testdata/govendor/golden.txt b/internal/importers/govendor/testdata/golden.txt similarity index 100% rename from cmd/dep/testdata/govendor/golden.txt rename to internal/importers/govendor/testdata/golden.txt index 4fa314d1..51a348f7 100644 --- a/cmd/dep/testdata/govendor/golden.txt +++ b/internal/importers/govendor/testdata/golden.txt @@ -1,7 +1,7 @@ Detected govendor configuration file... Converting from vendor.json... - Govendor was configured to ignore the test build tag, but that isn't supported by dep yet, and will be ignored. See https://github.com/golang/dep/issues/291. Using ^0.8.1 as initial constraint for imported dep github.com/sdboyer/deptest Trying v0.8.1 (3f4c3be) as initial lock for imported dep github.com/sdboyer/deptest Using ^2.0.0 as initial constraint for imported dep github.com/sdboyer/deptestdos Trying v2.0.0 (5c60720) as initial lock for imported dep github.com/sdboyer/deptestdos + Govendor was configured to ignore the test build tag, but that isn't supported by dep yet, and will be ignored. See https://github.com/golang/dep/issues/291. diff --git a/cmd/dep/testdata/govendor/vendor.json b/internal/importers/govendor/testdata/vendor.json similarity index 100% rename from cmd/dep/testdata/govendor/vendor.json rename to internal/importers/govendor/testdata/vendor.json diff --git a/internal/importers/importers.go b/internal/importers/importers.go index 283effee..3f535e2c 100644 --- a/internal/importers/importers.go +++ b/internal/importers/importers.go @@ -12,6 +12,7 @@ import ( "github.com/golang/dep/internal/importers/glide" "github.com/golang/dep/internal/importers/godep" "github.com/golang/dep/internal/importers/govend" + "github.com/golang/dep/internal/importers/govendor" "github.com/golang/dep/internal/importers/gvt" "github.com/golang/dep/internal/importers/vndr" ) @@ -37,5 +38,6 @@ func BuildAll(logger *log.Logger, verbose bool, sm gps.SourceManager) []Importer vndr.NewImporter(logger, verbose, sm), govend.NewImporter(logger, verbose, sm), gvt.NewImporter(logger, verbose, sm), + govendor.NewImporter(logger, verbose, sm), } } diff --git a/internal/importers/importertest/testcase.go b/internal/importers/importertest/testcase.go index c3fa62ff..0d629531 100644 --- a/internal/importers/importertest/testcase.go +++ b/internal/importers/importertest/testcase.go @@ -79,7 +79,7 @@ func (tc TestCase) validate(manifest *dep.Manifest, lock *dep.Lock, convertErr e } if !equalSlice(manifest.Ignored, tc.WantIgnored) { - return errors.Errorf("unexpected set of ignored projects: \n\t(GOT) %v \n\t(WNT) %v", + return errors.Errorf("unexpected set of ignored projects: \n\t(GOT) %#v \n\t(WNT) %#v", manifest.Ignored, tc.WantIgnored) }