From 8da26b1f9bdaaf8f13aee9f87ca34f1b83954065 Mon Sep 17 00:00:00 2001 From: Spencer Nelson Date: Tue, 8 Aug 2017 15:07:58 -0400 Subject: [PATCH 1/6] Add vndr importer --- cmd/dep/root_analyzer.go | 1 + cmd/dep/testdata/vndr/vendor.conf | 4 + cmd/dep/vndr_importer.go | 150 ++++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+) create mode 100644 cmd/dep/testdata/vndr/vendor.conf create mode 100644 cmd/dep/vndr_importer.go diff --git a/cmd/dep/root_analyzer.go b/cmd/dep/root_analyzer.go index 9f93b7eb22..5c5f3c3fc6 100644 --- a/cmd/dep/root_analyzer.go +++ b/cmd/dep/root_analyzer.go @@ -73,6 +73,7 @@ func (a *rootAnalyzer) importManifestAndLock(dir string, pr gps.ProjectRoot, sup importers := []importer{ newGlideImporter(logger, a.ctx.Verbose, a.sm), newGodepImporter(logger, a.ctx.Verbose, a.sm), + newVndrImporter(logger, a.ctx.Verbose, a.sm), } for _, i := range importers { diff --git a/cmd/dep/testdata/vndr/vendor.conf b/cmd/dep/testdata/vndr/vendor.conf new file mode 100644 index 0000000000..072166aa57 --- /dev/null +++ b/cmd/dep/testdata/vndr/vendor.conf @@ -0,0 +1,4 @@ +github.com/sdboyer/deptest 3f4c3bea144e112a69bbe5d8d01c1b09a544253f https://github.com/sdboyer/deptest.git # trailing comment +# line comment + +github.com/sdboyer/deptestdos v2.0.0 # trailing comment diff --git a/cmd/dep/vndr_importer.go b/cmd/dep/vndr_importer.go new file mode 100644 index 0000000000..ec14b18068 --- /dev/null +++ b/cmd/dep/vndr_importer.go @@ -0,0 +1,150 @@ +// 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 ( + "bufio" + "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" +) + +func vndrFile(dir string) string { + return filepath.Join(dir, "vendor.conf") +} + +type vndrImporter struct { + logger *log.Logger + sm gps.SourceManager +} + +func newVndrImporter(log *log.Logger, verbose bool, sm gps.SourceManager) *vndrImporter { + return &vndrImporter{ + logger: log, + sm: sm, + } +} + +func (v *vndrImporter) Name() string { return "vndr" } + +func (v *vndrImporter) HasDepMetadata(dir string) bool { + _, err := os.Stat(vndrFile(dir)) + return err == nil +} + +func (v *vndrImporter) Import(dir string, pr gps.ProjectRoot) (*dep.Manifest, *dep.Lock, error) { + v.logger.Println("Converting from vendor.conf") + + packages, err := parseVndrFile(dir) + if err != nil { + return nil, nil, errors.Wrapf(err, "unable to parse vndr file") + } + + manifest := &dep.Manifest{ + Constraints: make(gps.ProjectConstraints), + } + lock := &dep.Lock{} + + for _, pkg := range packages { + pc := gps.ProjectConstraint{ + Ident: gps.ProjectIdentifier{ + ProjectRoot: gps.ProjectRoot(pkg.importPath), + Source: pkg.repository, + }, + } + pc.Constraint, err = v.sm.InferConstraint(pkg.revision, pc.Ident) + if err != nil { + pc.Constraint = gps.Revision(pkg.revision) + } + + fb.NewConstraintFeedback(pc, fb.DepTypeImported).LogFeedback(v.logger) + + manifest.Constraints[pc.Ident.ProjectRoot] = gps.ProjectProperties{ + Source: pc.Ident.Source, + Constraint: pc.Constraint, + } + + revision := gps.Revision(pkg.revision) + version, err := lookupVersionForLockedProject(pc.Ident, pc.Constraint, revision, v.sm) + if err != nil { + v.logger.Println(err.Error()) + } + + lp := gps.NewLockedProject(pc.Ident, version, nil) + + fb.NewLockedProjectFeedback(lp, fb.DepTypeImported).LogFeedback(v.logger) + lock.P = append(lock.P) + } + + return manifest, lock, nil +} + +func parseVndrFile(dir string) ([]vndrPackage, error) { + f, err := os.Open(vndrFile(dir)) + if err != nil { + return nil, errors.Wrapf(err, "Unable to open %s", vndrFile(dir)) + } + defer f.Close() + + var packages []vndrPackage + scanner := bufio.NewScanner(f) + for scanner.Scan() { + pkg, err := parseVndrLine(scanner.Text()) + if err != nil { + return nil, errors.Wrapf(err, "unable to parse line") + } + if pkg == nil { + // Could be an empty line or one which is just a comment + continue + } + packages = append(packages, *pkg) + } + + if scanner.Err() != nil { + return nil, errors.Wrapf(err, "unable to read %s", vndrFile(dir)) + } + + return packages, nil +} + +func parseVndrLine(line string) (*vndrPackage, error) { + commentIdx := strings.Index(line, "#") + if commentIdx >= 0 { + line = line[:commentIdx] + } + line = strings.TrimSpace(line) + + if line == "" { + return nil, nil + } + + parts := strings.Fields(line) + + if !(len(parts) == 2 || len(parts) == 3) { + return nil, errors.Errorf("invalid config format: %q", line) + } + + pkg := &vndrPackage{ + importPath: parts[0], + revision: parts[1], + } + if len(parts) == 3 { + pkg.repository = parts[2] + } + + return pkg, nil +} + +type vndrPackage struct { + importPath string + revision string + repository string +} From 29b8f33b0fac345a89512f70d17645cf76a22230 Mon Sep 17 00:00:00 2001 From: Spencer Nelson Date: Tue, 8 Aug 2017 17:28:24 -0400 Subject: [PATCH 2/6] Add vndr importer integration test --- cmd/dep/glide_importer_test.go | 34 +++++++-------- cmd/dep/godep_importer_test.go | 14 +++--- cmd/dep/testdata/vndr/golden.txt | 6 +++ cmd/dep/vndr_importer.go | 27 ++++++------ cmd/dep/vndr_importer_test.go | 74 ++++++++++++++++++++++++++++++++ 5 files changed, 118 insertions(+), 37 deletions(-) create mode 100644 cmd/dep/testdata/vndr/golden.txt create mode 100644 cmd/dep/vndr_importer_test.go diff --git a/cmd/dep/glide_importer_test.go b/cmd/dep/glide_importer_test.go index bb138ce308..ee2240e345 100644 --- a/cmd/dep/glide_importer_test.go +++ b/cmd/dep/glide_importer_test.go @@ -18,8 +18,6 @@ import ( "github.com/pkg/errors" ) -const testGlideProjectRoot = "github.com/golang/notexist" - var ( discardLogger = log.New(ioutil.Discard, "", 0) ) @@ -43,10 +41,10 @@ func TestGlideConfig_Import(t *testing.T) { h.Must(err) defer sm.Release() - h.TempDir(filepath.Join("src", testGlideProjectRoot)) - h.TempCopy(filepath.Join(testGlideProjectRoot, glideYamlName), "glide/glide.yaml") - h.TempCopy(filepath.Join(testGlideProjectRoot, glideLockName), "glide/glide.lock") - projectRoot := h.Path(testGlideProjectRoot) + h.TempDir(filepath.Join("src", testProjectRoot)) + h.TempCopy(filepath.Join(testProjectRoot, glideYamlName), "glide/glide.yaml") + h.TempCopy(filepath.Join(testProjectRoot, glideLockName), "glide/glide.lock") + projectRoot := h.Path(testProjectRoot) // Capture stderr so we can verify output verboseOutput := &bytes.Buffer{} @@ -57,7 +55,7 @@ func TestGlideConfig_Import(t *testing.T) { t.Fatal("Expected the importer to detect the glide configuration files") } - m, l, err := g.Import(projectRoot, testGlideProjectRoot) + m, l, err := g.Import(projectRoot, testProjectRoot) h.Must(err) if m == nil { @@ -91,16 +89,16 @@ func TestGlideConfig_Import_MissingLockFile(t *testing.T) { h.Must(err) defer sm.Release() - h.TempDir(filepath.Join("src", testGlideProjectRoot)) - h.TempCopy(filepath.Join(testGlideProjectRoot, glideYamlName), "glide/glide.yaml") - projectRoot := h.Path(testGlideProjectRoot) + h.TempDir(filepath.Join("src", testProjectRoot)) + h.TempCopy(filepath.Join(testProjectRoot, glideYamlName), "glide/glide.yaml") + projectRoot := h.Path(testProjectRoot) g := newGlideImporter(ctx.Err, true, sm) if !g.HasDepMetadata(projectRoot) { t.Fatal("The glide importer should gracefully handle when only glide.yaml is present") } - m, l, err := g.Import(projectRoot, testGlideProjectRoot) + m, l, err := g.Import(projectRoot, testProjectRoot) h.Must(err) if m == nil { @@ -144,7 +142,7 @@ func TestGlideConfig_Convert_Project(t *testing.T) { }, } - manifest, lock, err := g.convert(testGlideProjectRoot) + manifest, lock, err := g.convert(testProjectRoot) if err != nil { t.Fatal(err) } @@ -230,7 +228,7 @@ func TestGlideConfig_Convert_TestProject(t *testing.T) { }, } - manifest, lock, err := g.convert(testGlideProjectRoot) + manifest, lock, err := g.convert(testProjectRoot) if err != nil { t.Fatal(err) } @@ -265,7 +263,7 @@ func TestGlideConfig_Convert_Ignore(t *testing.T) { Ignores: []string{pkg}, } - manifest, _, err := g.convert(testGlideProjectRoot) + manifest, _, err := g.convert(testProjectRoot) if err != nil { t.Fatal(err) } @@ -293,7 +291,7 @@ func TestGlideConfig_Convert_ExcludeDir(t *testing.T) { ExcludeDirs: []string{"samples"}, } - manifest, _, err := g.convert(testGlideProjectRoot) + manifest, _, err := g.convert(testProjectRoot) if err != nil { t.Fatal(err) } @@ -322,7 +320,7 @@ func TestGlideConfig_Convert_ExcludeDir_IgnoresMismatchedPackageName(t *testing. ExcludeDirs: []string{"samples"}, } - manifest, _, err := g.convert(testGlideProjectRoot) + manifest, _, err := g.convert(testProjectRoot) if err != nil { t.Fatal(err) } @@ -364,7 +362,7 @@ func TestGlideConfig_Convert_WarnsForUnusedFields(t *testing.T) { Imports: []glidePackage{pkg}, } - _, _, err = g.convert(testGlideProjectRoot) + _, _, err = g.convert(testProjectRoot) if err != nil { t.Fatal(err) } @@ -391,7 +389,7 @@ func TestGlideConfig_Convert_BadInput_EmptyPackageName(t *testing.T) { Imports: []glidePackage{{Name: ""}}, } - _, _, err = g.convert(testGlideProjectRoot) + _, _, err = g.convert(testProjectRoot) if err == nil { t.Fatal("Expected conversion to fail because the package name is empty") } diff --git a/cmd/dep/godep_importer_test.go b/cmd/dep/godep_importer_test.go index d471886d3d..4daeb1259c 100644 --- a/cmd/dep/godep_importer_test.go +++ b/cmd/dep/godep_importer_test.go @@ -16,7 +16,7 @@ import ( "github.com/pkg/errors" ) -const testGodepProjectRoot = "github.com/golang/notexist" +const testProjectRoot = "github.com/golang/notexist" func TestGodepConfig_Import(t *testing.T) { h := test.NewHelper(t) @@ -25,10 +25,10 @@ func TestGodepConfig_Import(t *testing.T) { cacheDir := "gps-repocache" h.TempDir(cacheDir) h.TempDir("src") - h.TempDir(filepath.Join("src", testGodepProjectRoot)) - h.TempCopy(filepath.Join(testGodepProjectRoot, godepPath), "godep/Godeps.json") + h.TempDir(filepath.Join("src", testProjectRoot)) + h.TempCopy(filepath.Join(testProjectRoot, godepPath), "godep/Godeps.json") - projectRoot := h.Path(testGodepProjectRoot) + projectRoot := h.Path(testProjectRoot) sm, err := gps.NewSourceManager(h.Path(cacheDir)) h.Must(err) defer sm.Release() @@ -42,7 +42,7 @@ func TestGodepConfig_Import(t *testing.T) { t.Fatal("Expected the importer to detect godep configuration file") } - m, l, err := g.Import(projectRoot, testGodepProjectRoot) + m, l, err := g.Import(projectRoot, testProjectRoot) h.Must(err) if m == nil { @@ -88,9 +88,9 @@ func TestGodepConfig_JsonLoad(t *testing.T) { ctx := newTestContext(h) - h.TempCopy(filepath.Join(testGodepProjectRoot, godepPath), "godep/Godeps.json") + h.TempCopy(filepath.Join(testProjectRoot, godepPath), "godep/Godeps.json") - projectRoot := h.Path(testGodepProjectRoot) + projectRoot := h.Path(testProjectRoot) g := newGodepImporter(ctx.Err, true, nil) err := g.load(projectRoot) diff --git a/cmd/dep/testdata/vndr/golden.txt b/cmd/dep/testdata/vndr/golden.txt new file mode 100644 index 0000000000..a35fdc8669 --- /dev/null +++ b/cmd/dep/testdata/vndr/golden.txt @@ -0,0 +1,6 @@ +Detected vndr configuration file... +Converting from vendor.conf... + Using 3f4c3bea144e112a69bbe5d8d01c1b09a544253f as initial hint 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) as initial lock for imported dep github.com/sdboyer/deptestdos diff --git a/cmd/dep/vndr_importer.go b/cmd/dep/vndr_importer.go index ec14b18068..76603fc920 100644 --- a/cmd/dep/vndr_importer.go +++ b/cmd/dep/vndr_importer.go @@ -22,14 +22,16 @@ func vndrFile(dir string) string { } type vndrImporter struct { - logger *log.Logger - sm gps.SourceManager + logger *log.Logger + verbose bool + sm gps.SourceManager } func newVndrImporter(log *log.Logger, verbose bool, sm gps.SourceManager) *vndrImporter { return &vndrImporter{ - logger: log, - sm: sm, + logger: log, + verbose: verbose, + sm: sm, } } @@ -41,11 +43,11 @@ func (v *vndrImporter) HasDepMetadata(dir string) bool { } func (v *vndrImporter) Import(dir string, pr gps.ProjectRoot) (*dep.Manifest, *dep.Lock, error) { - v.logger.Println("Converting from vendor.conf") + v.logger.Println("Detected vndr configuration file...") - packages, err := parseVndrFile(dir) + packages, err := v.loadVndrFile(dir) if err != nil { - return nil, nil, errors.Wrapf(err, "unable to parse vndr file") + return nil, nil, errors.Wrapf(err, "unable to load vndr file") } manifest := &dep.Manifest{ @@ -62,15 +64,14 @@ func (v *vndrImporter) Import(dir string, pr gps.ProjectRoot) (*dep.Manifest, *d } pc.Constraint, err = v.sm.InferConstraint(pkg.revision, pc.Ident) if err != nil { - pc.Constraint = gps.Revision(pkg.revision) + return nil, nil, errors.Wrapf(err, "Unable to interpret revision specifier '%s' for package %s", pkg.importPath, pkg.revision) } - fb.NewConstraintFeedback(pc, fb.DepTypeImported).LogFeedback(v.logger) - manifest.Constraints[pc.Ident.ProjectRoot] = gps.ProjectProperties{ Source: pc.Ident.Source, Constraint: pc.Constraint, } + fb.NewConstraintFeedback(pc, fb.DepTypeImported).LogFeedback(v.logger) revision := gps.Revision(pkg.revision) version, err := lookupVersionForLockedProject(pc.Ident, pc.Constraint, revision, v.sm) @@ -80,14 +81,16 @@ func (v *vndrImporter) Import(dir string, pr gps.ProjectRoot) (*dep.Manifest, *d lp := gps.NewLockedProject(pc.Ident, version, nil) - fb.NewLockedProjectFeedback(lp, fb.DepTypeImported).LogFeedback(v.logger) lock.P = append(lock.P) + fb.NewLockedProjectFeedback(lp, fb.DepTypeImported).LogFeedback(v.logger) } return manifest, lock, nil } -func parseVndrFile(dir string) ([]vndrPackage, error) { +func (v *vndrImporter) loadVndrFile(dir string) ([]vndrPackage, error) { + v.logger.Printf("Converting from vendor.conf...") + f, err := os.Open(vndrFile(dir)) if err != nil { return nil, errors.Wrapf(err, "Unable to open %s", vndrFile(dir)) diff --git a/cmd/dep/vndr_importer_test.go b/cmd/dep/vndr_importer_test.go new file mode 100644 index 0000000000..d9caa95b86 --- /dev/null +++ b/cmd/dep/vndr_importer_test.go @@ -0,0 +1,74 @@ +// 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 ( + "bytes" + "log" + "path/filepath" + "testing" + + "github.com/golang/dep/internal/test" + "github.com/pkg/errors" +) + +func TestVndrConfig_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", testProjectRoot)) + h.TempCopy(vndrFile(testProjectRoot), "vndr/vendor.conf") + projectRoot := h.Path(testProjectRoot) + + logOutput := bytes.NewBuffer(nil) + ctx.Err = log.New(logOutput, "", 0) + + v := newVndrImporter(ctx.Err, false, sm) + if !v.HasDepMetadata(projectRoot) { + t.Fatal("Expected the importer to detect vndr configuration file") + } + + // m, l, err := v.Import(projectRoot, testProjectRoot) + _, _, err = v.Import(projectRoot, testProjectRoot) + h.Must(err) + + // if m == nil { + // t.Error("expected manifest to be generated") + // } else { + // if len(m.Constraints) != 2 { + // t.Errorf("expected 2 constraints in manifest, have %+v", m.Constraints) + // } else { + // p1, ok := m.Constraints[gps.ProjectRoot("github.com/sdboyer/deptest")] + // if !ok { + // t.Errorf("expected constraint to for github.com/sdboyer/deptest, have %+v", m.Constraints) + // } else { + // if want := "https://github.com/sdboyer/deptest"; p1.Source != want { + // t.Errorf("unexpected source, have=%v, want=%v", p1.Source, want) + // } + // if want := "3f4c3bea144e112a69bbe5d8d01c1b09a544253f", p1.Constraint.String() != want { + // t.Errorf("unexpected constraint, have=%v, want=%v", p1.Constraint.String(), want) + // } + // } + // } + // } + + goldenFile := "vndr/golden.txt" + got := logOutput.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) + } + } +} From cbb749f2a3e309706b74593252059a5fc0e8f44a Mon Sep 17 00:00:00 2001 From: Spencer Nelson Date: Tue, 8 Aug 2017 17:54:04 -0400 Subject: [PATCH 3/6] Add check of manifest and lock contents --- cmd/dep/vndr_importer.go | 2 +- cmd/dep/vndr_importer_test.go | 64 +++++++++++++++++++++++------------ 2 files changed, 44 insertions(+), 22 deletions(-) diff --git a/cmd/dep/vndr_importer.go b/cmd/dep/vndr_importer.go index 76603fc920..4e91b575ad 100644 --- a/cmd/dep/vndr_importer.go +++ b/cmd/dep/vndr_importer.go @@ -81,7 +81,7 @@ func (v *vndrImporter) Import(dir string, pr gps.ProjectRoot) (*dep.Manifest, *d lp := gps.NewLockedProject(pc.Ident, version, nil) - lock.P = append(lock.P) + lock.P = append(lock.P, lp) fb.NewLockedProjectFeedback(lp, fb.DepTypeImported).LogFeedback(v.logger) } diff --git a/cmd/dep/vndr_importer_test.go b/cmd/dep/vndr_importer_test.go index d9caa95b86..13c65a25d2 100644 --- a/cmd/dep/vndr_importer_test.go +++ b/cmd/dep/vndr_importer_test.go @@ -8,8 +8,11 @@ import ( "bytes" "log" "path/filepath" + "reflect" "testing" + "github.com/golang/dep" + "github.com/golang/dep/internal/gps" "github.com/golang/dep/internal/test" "github.com/pkg/errors" ) @@ -35,29 +38,48 @@ func TestVndrConfig_Import(t *testing.T) { t.Fatal("Expected the importer to detect vndr configuration file") } - // m, l, err := v.Import(projectRoot, testProjectRoot) - _, _, err = v.Import(projectRoot, testProjectRoot) + m, l, err := v.Import(projectRoot, testProjectRoot) h.Must(err) - // if m == nil { - // t.Error("expected manifest to be generated") - // } else { - // if len(m.Constraints) != 2 { - // t.Errorf("expected 2 constraints in manifest, have %+v", m.Constraints) - // } else { - // p1, ok := m.Constraints[gps.ProjectRoot("github.com/sdboyer/deptest")] - // if !ok { - // t.Errorf("expected constraint to for github.com/sdboyer/deptest, have %+v", m.Constraints) - // } else { - // if want := "https://github.com/sdboyer/deptest"; p1.Source != want { - // t.Errorf("unexpected source, have=%v, want=%v", p1.Source, want) - // } - // if want := "3f4c3bea144e112a69bbe5d8d01c1b09a544253f", p1.Constraint.String() != want { - // t.Errorf("unexpected constraint, have=%v, want=%v", p1.Constraint.String(), want) - // } - // } - // } - // } + constraint, err := gps.NewSemverConstraint("^2.0.0") + h.Must(err) + wantM := &dep.Manifest{ + Constraints: gps.ProjectConstraints{ + "github.com/sdboyer/deptest": gps.ProjectProperties{ + Source: "https://github.com/sdboyer/deptest.git", + Constraint: gps.Revision("3f4c3bea144e112a69bbe5d8d01c1b09a544253f"), + }, + "github.com/sdboyer/deptestdos": gps.ProjectProperties{ + Constraint: constraint, + }, + }, + } + if !reflect.DeepEqual(wantM, m) { + t.Errorf("unexpected manifest\nhave=%+v\nwant=%+v", m, wantM) + } + + wantL := &dep.Lock{ + P: []gps.LockedProject{ + gps.NewLockedProject( + gps.ProjectIdentifier{ + ProjectRoot: "github.com/sdboyer/deptest", + Source: "https://github.com/sdboyer/deptest.git", + }, + gps.NewVersion("v0.8.1").Pair(gps.Revision("3f4c3bea144e112a69bbe5d8d01c1b09a544253f")), + nil, + ), + gps.NewLockedProject( + gps.ProjectIdentifier{ + ProjectRoot: "github.com/sdboyer/deptestdos", + }, + gps.Revision("v2.0.0"), + nil, + ), + }, + } + if !reflect.DeepEqual(wantL, l) { + t.Errorf("unexpected lock\nhave=%+v\nwant=%+v", l, wantL) + } goldenFile := "vndr/golden.txt" got := logOutput.String() From d9b5e54578603bc10c702c23081fe67a97d549b3 Mon Sep 17 00:00:00 2001 From: Spencer Nelson Date: Tue, 8 Aug 2017 18:16:48 -0400 Subject: [PATCH 4/6] Add tests of parsing vndr lines --- cmd/dep/vndr_importer_test.go | 68 +++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/cmd/dep/vndr_importer_test.go b/cmd/dep/vndr_importer_test.go index 13c65a25d2..39e9c4a040 100644 --- a/cmd/dep/vndr_importer_test.go +++ b/cmd/dep/vndr_importer_test.go @@ -94,3 +94,71 @@ func TestVndrConfig_Import(t *testing.T) { } } } + +func TestParseVndrLine(t *testing.T) { + testcase := func(in string, wantPkg *vndrPackage, wantErr error) func(*testing.T) { + return func(t *testing.T) { + havePkg, haveErr := parseVndrLine(in) + switch { + case wantPkg == nil: + if havePkg != nil { + t.Errorf("expected nil package, have %v", havePkg) + } + case havePkg == nil: + if wantPkg != nil { + t.Errorf("expected non-nil package %v, have nil", wantPkg) + } + default: + if !reflect.DeepEqual(havePkg, wantPkg) { + t.Errorf("unexpected package, have=%v, want=%v", *havePkg, *wantPkg) + } + } + + switch { + case wantErr == nil: + if haveErr != nil { + t.Errorf("expected nil err, have %v", haveErr) + } + case haveErr == nil: + if wantErr != nil { + t.Errorf("expected non-nil err %v, have nil", wantErr) + } + default: + if haveErr.Error() != wantErr.Error() { + t.Errorf("expected err=%q, have err=%q", wantErr.Error(), haveErr.Error()) + } + } + } + } + t.Run("normal line", + testcase("github.com/golang/notreal v1.0.0", + &vndrPackage{ + importPath: "github.com/golang/notreal", + revision: "v1.0.0", + }, nil)) + + t.Run("with repo", + testcase("github.com/golang/notreal v1.0.0 https://github.com/golang/notreal", + &vndrPackage{ + importPath: "github.com/golang/notreal", + revision: "v1.0.0", + repository: "https://github.com/golang/notreal", + }, nil)) + + t.Run("trailing comment", + testcase("github.com/golang/notreal v1.0.0 https://github.com/golang/notreal # cool comment", + &vndrPackage{ + importPath: "github.com/golang/notreal", + revision: "v1.0.0", + repository: "https://github.com/golang/notreal", + }, nil)) + + t.Run("empty line", testcase("", nil, nil)) + t.Run("comment line", testcase("# comment", nil, nil)) + t.Run("comment line with leading whitespace", testcase(" # comment", nil, nil)) + + t.Run("missing revision", + testcase("github.com/golang/notreal", nil, + errors.New("invalid config format: \"github.com/golang/notreal\""), + )) +} From f5bf00640cdf9267b5cfe3ce4a3113f0fd5e6f14 Mon Sep 17 00:00:00 2001 From: Spencer Nelson Date: Thu, 10 Aug 2017 08:46:02 -0400 Subject: [PATCH 5/6] Add integration test case for vndr --- .../init/vndr/case1/final/Gopkg.lock | 21 +++++++++++++++++++ .../init/vndr/case1/final/Gopkg.toml | 4 ++++ .../init/vndr/case1/initial/main.go | 16 ++++++++++++++ .../init/vndr/case1/initial/vendor.conf | 3 +++ .../init/vndr/case1/testcase.json | 13 ++++++++++++ 5 files changed, 57 insertions(+) create mode 100644 cmd/dep/testdata/harness_tests/init/vndr/case1/final/Gopkg.lock create mode 100644 cmd/dep/testdata/harness_tests/init/vndr/case1/final/Gopkg.toml create mode 100644 cmd/dep/testdata/harness_tests/init/vndr/case1/initial/main.go create mode 100644 cmd/dep/testdata/harness_tests/init/vndr/case1/initial/vendor.conf create mode 100644 cmd/dep/testdata/harness_tests/init/vndr/case1/testcase.json diff --git a/cmd/dep/testdata/harness_tests/init/vndr/case1/final/Gopkg.lock b/cmd/dep/testdata/harness_tests/init/vndr/case1/final/Gopkg.lock new file mode 100644 index 0000000000..ac445c05d2 --- /dev/null +++ b/cmd/dep/testdata/harness_tests/init/vndr/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 = "3f4c3bea144e112a69bbe5d8d01c1b09a544253f" + version = "v0.8.1" + +[[projects]] + name = "github.com/sdboyer/deptestdos" + packages = ["."] + revision = "5c607206be5decd28e6263ffffdcee067266015e" + version = "v2.0.0" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + inputs-digest = "1ed417a0bec57ffe988fae1cba8f3d49994fb893394d61844e0b3c96d69573fe" + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/cmd/dep/testdata/harness_tests/init/vndr/case1/final/Gopkg.toml b/cmd/dep/testdata/harness_tests/init/vndr/case1/final/Gopkg.toml new file mode 100644 index 0000000000..aaf78303fa --- /dev/null +++ b/cmd/dep/testdata/harness_tests/init/vndr/case1/final/Gopkg.toml @@ -0,0 +1,4 @@ + +[[constraint]] + name = "github.com/sdboyer/deptestdos" + version = "2.0.0" diff --git a/cmd/dep/testdata/harness_tests/init/vndr/case1/initial/main.go b/cmd/dep/testdata/harness_tests/init/vndr/case1/initial/main.go new file mode 100644 index 0000000000..2b2c7c396e --- /dev/null +++ b/cmd/dep/testdata/harness_tests/init/vndr/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/vndr/case1/initial/vendor.conf b/cmd/dep/testdata/harness_tests/init/vndr/case1/initial/vendor.conf new file mode 100644 index 0000000000..d91f18b3e2 --- /dev/null +++ b/cmd/dep/testdata/harness_tests/init/vndr/case1/initial/vendor.conf @@ -0,0 +1,3 @@ +# Comment on its own line +github.com/sdboyer/deptest 3f4c3bea144e112a69bbe5d8d01c1b09a544253f https://github.com/sdboyer/deptest.git +github.com/sdboyer/deptestdos v2.0.0 diff --git a/cmd/dep/testdata/harness_tests/init/vndr/case1/testcase.json b/cmd/dep/testdata/harness_tests/init/vndr/case1/testcase.json new file mode 100644 index 0000000000..017dc4cd55 --- /dev/null +++ b/cmd/dep/testdata/harness_tests/init/vndr/case1/testcase.json @@ -0,0 +1,13 @@ +{ + "commands": [ + ["init", "-no-examples"] + ], + "error-expected": "", + "gopath-initial": { + "github.com/sdboyer/deptest": "3f4c3bea144e112a69bbe5d8d01c1b09a544253f" + }, + "vendor-final": [ + "github.com/sdboyer/deptest", + "github.com/sdboyer/deptestdos" + ] +} From 65c6d9802d87fef33a3877cb0e76de2fd830d6b3 Mon Sep 17 00:00:00 2001 From: Spencer Nelson Date: Thu, 10 Aug 2017 10:05:54 -0400 Subject: [PATCH 6/6] Use table of tests for vndr importer --- cmd/dep/vndr_importer.go | 86 ++++++++++++---------- cmd/dep/vndr_importer_test.go | 132 ++++++++++++++++++++++++++++++++++ 2 files changed, 179 insertions(+), 39 deletions(-) diff --git a/cmd/dep/vndr_importer.go b/cmd/dep/vndr_importer.go index 4e91b575ad..db936401c1 100644 --- a/cmd/dep/vndr_importer.go +++ b/cmd/dep/vndr_importer.go @@ -22,6 +22,8 @@ func vndrFile(dir string) string { } type vndrImporter struct { + packages []vndrPackage + logger *log.Logger verbose bool sm gps.SourceManager @@ -45,17 +47,53 @@ func (v *vndrImporter) HasDepMetadata(dir string) bool { func (v *vndrImporter) Import(dir string, pr gps.ProjectRoot) (*dep.Manifest, *dep.Lock, error) { v.logger.Println("Detected vndr configuration file...") - packages, err := v.loadVndrFile(dir) + err := v.loadVndrFile(dir) if err != nil { return nil, nil, errors.Wrapf(err, "unable to load vndr file") } - manifest := &dep.Manifest{ - Constraints: make(gps.ProjectConstraints), + return v.convert(pr) +} + +func (v *vndrImporter) loadVndrFile(dir string) error { + v.logger.Printf("Converting from vendor.conf...") + + f, err := os.Open(vndrFile(dir)) + if err != nil { + return errors.Wrapf(err, "Unable to open %s", vndrFile(dir)) } - lock := &dep.Lock{} + defer f.Close() - for _, pkg := range packages { + scanner := bufio.NewScanner(f) + for scanner.Scan() { + pkg, err := parseVndrLine(scanner.Text()) + if err != nil { + return errors.Wrapf(err, "unable to parse line") + } + if pkg == nil { + // Could be an empty line or one which is just a comment + continue + } + v.packages = append(v.packages, *pkg) + } + + if scanner.Err() != nil { + return errors.Wrapf(err, "unable to read %s", vndrFile(dir)) + } + + return nil +} + +func (v *vndrImporter) convert(pr gps.ProjectRoot) (*dep.Manifest, *dep.Lock, error) { + var ( + manifest = &dep.Manifest{ + Constraints: make(gps.ProjectConstraints), + } + lock = &dep.Lock{} + err error + ) + + for _, pkg := range v.packages { pc := gps.ProjectConstraint{ Ident: gps.ProjectIdentifier{ ProjectRoot: gps.ProjectRoot(pkg.importPath), @@ -88,34 +126,10 @@ func (v *vndrImporter) Import(dir string, pr gps.ProjectRoot) (*dep.Manifest, *d return manifest, lock, nil } -func (v *vndrImporter) loadVndrFile(dir string) ([]vndrPackage, error) { - v.logger.Printf("Converting from vendor.conf...") - - f, err := os.Open(vndrFile(dir)) - if err != nil { - return nil, errors.Wrapf(err, "Unable to open %s", vndrFile(dir)) - } - defer f.Close() - - var packages []vndrPackage - scanner := bufio.NewScanner(f) - for scanner.Scan() { - pkg, err := parseVndrLine(scanner.Text()) - if err != nil { - return nil, errors.Wrapf(err, "unable to parse line") - } - if pkg == nil { - // Could be an empty line or one which is just a comment - continue - } - packages = append(packages, *pkg) - } - - if scanner.Err() != nil { - return nil, errors.Wrapf(err, "unable to read %s", vndrFile(dir)) - } - - return packages, nil +type vndrPackage struct { + importPath string + revision string + repository string } func parseVndrLine(line string) (*vndrPackage, error) { @@ -145,9 +159,3 @@ func parseVndrLine(line string) (*vndrPackage, error) { return pkg, nil } - -type vndrPackage struct { - importPath string - revision string - repository string -} diff --git a/cmd/dep/vndr_importer_test.go b/cmd/dep/vndr_importer_test.go index 39e9c4a040..2d7fb1a045 100644 --- a/cmd/dep/vndr_importer_test.go +++ b/cmd/dep/vndr_importer_test.go @@ -17,6 +17,138 @@ import ( "github.com/pkg/errors" ) +func TestVndrConfig_Convert(t *testing.T) { + testCases := map[string]struct { + vndr []vndrPackage + wantConvertErr bool + matchPairedVersion bool + projectRoot gps.ProjectRoot + wantConstraint string + wantRevision gps.Revision + wantVersion string + wantLockCount int + }{ + "project": { + vndr: []vndrPackage{{ + importPath: "github.com/sdboyer/deptest", + revision: "v0.8.0", + repository: "https://github.com/sdboyer/deptest.git", + }}, + matchPairedVersion: false, + projectRoot: gps.ProjectRoot("github.com/sdboyer/deptest"), + wantConstraint: "^0.8.0", + wantRevision: gps.Revision("ff2948a2ac8f538c4ecd55962e919d1e13e74baf"), + wantVersion: "v0.8.0", + wantLockCount: 1, + }, + "with semver suffix": { + vndr: []vndrPackage{{ + importPath: "github.com/sdboyer/deptest", + revision: "v1.12.0-12-g2fd980e", + }}, + matchPairedVersion: false, + projectRoot: gps.ProjectRoot("github.com/sdboyer/deptest"), + wantConstraint: "^1.12.0-12-g2fd980e", + wantVersion: "v1.0.0", + wantLockCount: 1, + }, + "hash revision": { + vndr: []vndrPackage{{ + importPath: "github.com/sdboyer/deptest", + revision: "ff2948a2ac8f538c4ecd55962e919d1e13e74baf", + }}, + matchPairedVersion: false, + projectRoot: gps.ProjectRoot("github.com/sdboyer/deptest"), + wantConstraint: "ff2948a2ac8f538c4ecd55962e919d1e13e74baf", + wantVersion: "v1.0.0", + wantLockCount: 1, + }, + "missing importPath": { + vndr: []vndrPackage{{ + revision: "v1.0.0", + }}, + wantConvertErr: true, + }, + } + + h := test.NewHelper(t) + defer h.Cleanup() + + ctx := newTestContext(h) + sm, err := ctx.SourceManager() + h.Must(err) + defer sm.Release() + + for name, testCase := range testCases { + t.Run(name, func(t *testing.T) { + v := newVndrImporter(discardLogger, true, sm) + v.packages = testCase.vndr + + manifest, lock, err := v.convert(testCase.projectRoot) + if err != nil { + if testCase.wantConvertErr { + return + } + t.Fatal(err) + } else { + if testCase.wantConvertErr { + t.Fatal("expected err, have nil") + } + } + + if len(lock.P) != testCase.wantLockCount { + t.Fatalf("Expected lock to have %d project(s), got %d", + testCase.wantLockCount, + len(lock.P)) + } + + d, ok := manifest.Constraints[testCase.projectRoot] + if !ok { + t.Fatalf("Expected the manifest to have a dependency for '%s' but got none", + testCase.projectRoot) + } + + c := d.Constraint.String() + if c != testCase.wantConstraint { + t.Fatalf("Expected manifest constraint to be %s, got %s", testCase.wantConstraint, c) + } + + p := lock.P[0] + if p.Ident().ProjectRoot != testCase.projectRoot { + t.Fatalf("Expected the lock to have a project for '%s' but got '%s'", + testCase.projectRoot, + p.Ident().ProjectRoot) + } + + lv := p.Version() + lpv, ok := lv.(gps.PairedVersion) + + if !ok { + if testCase.matchPairedVersion { + t.Fatalf("Expected locked version to be PairedVersion but got %T", lv) + } + + return + } + + ver := lpv.String() + if ver != testCase.wantVersion { + t.Fatalf("Expected locked version to be '%s', got %s", testCase.wantVersion, ver) + } + + if testCase.wantRevision != "" { + rev := lpv.Revision() + if rev != testCase.wantRevision { + t.Fatalf("Expected locked revision to be '%s', got %s", + testCase.wantRevision, + rev) + } + } + }) + } + +} + func TestVndrConfig_Import(t *testing.T) { h := test.NewHelper(t) defer h.Cleanup()