This repository has been archived by the owner on Sep 9, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
441 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
// 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 ( | ||
"encoding/json" | ||
"io/ioutil" | ||
"log" | ||
"os" | ||
"path/filepath" | ||
|
||
"github.com/golang/dep" | ||
fb "github.com/golang/dep/internal/feedback" | ||
"github.com/golang/dep/internal/gps" | ||
"github.com/pkg/errors" | ||
) | ||
|
||
// gbImporter imports gb configuration into the dep configuration format. | ||
type gbImporter struct { | ||
manifest gbManifest | ||
logger *log.Logger | ||
verbose bool | ||
sm gps.SourceManager | ||
} | ||
|
||
func newGbImporter(logger *log.Logger, verbose bool, sm gps.SourceManager) *gbImporter { | ||
return &gbImporter{ | ||
logger: logger, | ||
verbose: verbose, | ||
sm: sm, | ||
} | ||
} | ||
|
||
// gbManifest represents the manifest file for GB projects | ||
type gbManifest struct { | ||
Dependencies []gbDependency `json:"dependencies"` | ||
} | ||
|
||
type gbDependency struct { | ||
Importpath string `json:"importpath"` | ||
Repository string `json:"repository"` | ||
|
||
// All gb vendored dependencies have a specific revision | ||
Revision string `json:"revision"` | ||
|
||
// Branch may be HEAD or an actual branch. In the case of HEAD, that means | ||
// the user vendored a dependency by specifying a tag or a specific revision | ||
// which results in a detached HEAD | ||
Branch string `json:"branch"` | ||
} | ||
|
||
func (i *gbImporter) Name() string { | ||
return "gb" | ||
} | ||
|
||
func (i *gbImporter) HasDepMetadata(dir string) bool { | ||
// gb stores the manifest in the vendor tree | ||
var m = filepath.Join(dir, "vendor", "manifest") | ||
if _, err := os.Stat(m); err != nil { | ||
return false | ||
} | ||
|
||
return true | ||
} | ||
|
||
func (i *gbImporter) Import(dir string, pr gps.ProjectRoot) (*dep.Manifest, *dep.Lock, error) { | ||
err := i.load(dir) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
return i.convert(pr) | ||
} | ||
|
||
// load the gb manifest | ||
func (i *gbImporter) load(projectDir string) error { | ||
i.logger.Println("Detected gb manifest file...") | ||
var mf = filepath.Join(projectDir, "vendor", "manifest") | ||
if i.verbose { | ||
i.logger.Printf(" Loading %s", mf) | ||
} | ||
|
||
var buf []byte | ||
var err error | ||
if buf, err = ioutil.ReadFile(mf); err != nil { | ||
return errors.Wrapf(err, "Unable to read %s", mf) | ||
} | ||
if err := json.Unmarshal(buf, &i.manifest); err != nil { | ||
return errors.Wrapf(err, "Unable to parse %s", mf) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// convert the gb manifest into dep configuration files. | ||
func (i *gbImporter) convert(pr gps.ProjectRoot) (*dep.Manifest, *dep.Lock, error) { | ||
i.logger.Println("Converting from gb manifest...") | ||
|
||
manifest := &dep.Manifest{ | ||
Constraints: make(gps.ProjectConstraints), | ||
} | ||
|
||
lock := &dep.Lock{} | ||
|
||
for _, pkg := range i.manifest.Dependencies { | ||
pc, lp, err := i.convertOne(pkg) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
manifest.Constraints[pc.Ident.ProjectRoot] = gps.ProjectProperties{Source: pc.Ident.Source, Constraint: pc.Constraint} | ||
lock.P = append(lock.P, lp) | ||
} | ||
|
||
return manifest, lock, nil | ||
} | ||
|
||
func (i *gbImporter) convertOne(pkg gbDependency) (pc gps.ProjectConstraint, lp gps.LockedProject, err error) { | ||
if pkg.Importpath == "" { | ||
err = errors.New("Invalid gb configuration, package import path is required") | ||
return | ||
} | ||
|
||
/* | ||
gb's vendor plugin (gb vendor), which manages the vendor tree and manifest | ||
file, supports fetching by a specific tag or revision, but if you specify | ||
either of those it's a detached checkout and the "branch" field is HEAD. | ||
The only time the "branch" field is not "HEAD" is if you do not specify a | ||
tag or revision, otherwise it's either "master" or the value of the -branch | ||
flag | ||
This means that, generally, the only possible "constraint" we can really specify is | ||
the branch name if the branch name is not HEAD. Otherwise, it's a specific revision. | ||
However, if we can infer a tag that points to the revision or the branch, we may be able | ||
to use that as the constraint | ||
*/ | ||
|
||
pc.Ident = gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot(pkg.Importpath), Source: pkg.Repository} | ||
|
||
// Generally, gb tracks revisions | ||
var revision = gps.Revision(pkg.Revision) | ||
|
||
// But if the branch field is not "HEAD", we can use that as the initial constraint | ||
var constraint gps.Constraint | ||
if pkg.Branch != "HEAD" { | ||
constraint = gps.NewBranch(pkg.Branch) | ||
} | ||
|
||
// See if we can get a version from that constraint | ||
version, err := lookupVersionForLockedProject(pc.Ident, constraint, revision, i.sm) | ||
if err != nil { | ||
// Log the error, but don't fail it. It's okay if we can't find a version | ||
i.logger.Println(err.Error()) | ||
} | ||
|
||
// And now try to infer a constraint from the returned version | ||
pc.Constraint, err = i.sm.InferConstraint(version.String(), pc.Ident) | ||
if err != nil { | ||
return | ||
} | ||
|
||
lp = gps.NewLockedProject(pc.Ident, version, nil) | ||
|
||
fb.NewConstraintFeedback(pc, fb.DepTypeImported).LogFeedback(i.logger) | ||
fb.NewLockedProjectFeedback(lp, fb.DepTypeImported).LogFeedback(i.logger) | ||
|
||
return | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
// 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/gps" | ||
"github.com/golang/dep/internal/test" | ||
"github.com/pkg/errors" | ||
) | ||
|
||
const testGbProjectRoot = "github.com/golang/notexist" | ||
|
||
func TestGbConfig_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", testGbProjectRoot, "vendor")) | ||
h.TempCopy(filepath.Join(testGbProjectRoot, "vendor", "manifest"), "gb/manifest") | ||
projectRoot := h.Path(testGbProjectRoot) | ||
|
||
// Capture stderr so we can verify output | ||
verboseOutput := &bytes.Buffer{} | ||
ctx.Err = log.New(verboseOutput, "", 0) | ||
|
||
g := newGbImporter(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 gb manifest file") | ||
} | ||
|
||
m, l, err := g.Import(projectRoot, testGbProjectRoot) | ||
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 := "gb/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 TestGbConfig_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" | ||
repo := "https://github.com/sdboyer/deptest.git" | ||
|
||
g := newGbImporter(ctx.Err, true, sm) | ||
g.manifest = gbManifest{ | ||
Dependencies: []gbDependency{ | ||
{ | ||
Importpath: pkg, | ||
Repository: repo, | ||
Revision: "ff2948a2ac8f538c4ecd55962e919d1e13e74baf", | ||
}, | ||
}, | ||
} | ||
|
||
manifest, lock, err := g.convert(testGbProjectRoot) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
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) | ||
} | ||
|
||
gotS := d.Source | ||
if gotS != repo { | ||
t.Fatalf("Expected manifest source to be %s, got %s", repo, gotS) | ||
} | ||
|
||
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) | ||
} | ||
|
||
gotS = p.Ident().Source | ||
if gotS != repo { | ||
t.Fatalf("Expected locked source to be %s, got '%s'", repo, gotS) | ||
} | ||
|
||
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 TestGbConfig_Convert_BadInput_EmptyPackageName(t *testing.T) { | ||
h := test.NewHelper(t) | ||
defer h.Cleanup() | ||
|
||
ctx := newTestContext(h) | ||
sm, err := ctx.SourceManager() | ||
h.Must(err) | ||
defer sm.Release() | ||
|
||
g := newGbImporter(ctx.Err, true, sm) | ||
g.manifest = gbManifest{ | ||
Dependencies: []gbDependency{{Importpath: ""}}, | ||
} | ||
|
||
_, _, err = g.convert(testGbProjectRoot) | ||
if err == nil { | ||
t.Fatal("Expected conversion to fail because the package name is empty") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
Detected gb manifest file... | ||
Converting from gb manifest... | ||
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 | ||
Using ^1.0.0 as initial constraint for imported dep github.com/sdboyer/deptest | ||
Trying v1.0.0 (ff2948a) as initial lock for imported dep github.com/sdboyer/deptest |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
{ | ||
"version": 0, | ||
"dependencies": [ | ||
{ | ||
"importpath": "github.com/sdboyer/deptestdos", | ||
"repository": "https://github.com/sdboyer/deptestdos", | ||
"revision": "5c607206be5decd28e6263ffffdcee067266015e", | ||
"branch": "master" | ||
}, | ||
{ | ||
"importpath": "github.com/sdboyer/deptest", | ||
"repository": "https://github.com/sdboyer/deptest", | ||
"revision": "ff2948a2ac8f538c4ecd55962e919d1e13e74baf", | ||
"branch": "HEAD" | ||
} | ||
] | ||
} |
23 changes: 23 additions & 0 deletions
23
cmd/dep/testdata/harness_tests/init/gb/case1/final/Gopkg.lock
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Oops, something went wrong.