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.
This commit is contained in:
Carolyn Van Slyck 2017-10-06 16:59:58 -05:00
Родитель d77cf70f5b
Коммит 56cefc4d23
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: AEF5F64E6B9D8197
16 изменённых файлов: 349 добавлений и 537 удалений

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

@ -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).

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

@ -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
}

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

@ -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")
}
}

25
cmd/dep/testdata/govendor/vendor-sub-pkg.json поставляемый
Просмотреть файл

@ -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"
}

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

@ -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"
}

8
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

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

@ -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"

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

@ -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"
]

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

@ -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
}

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

@ -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 {

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

@ -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
}

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

@ -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)
}
})
}
}

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

@ -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.

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

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

@ -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),
}
}

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

@ -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)
}