Skip to content
This repository has been archived by the owner on Sep 9, 2020. It is now read-only.

Commit

Permalink
import gvt manifest on init
Browse files Browse the repository at this point in the history
  • Loading branch information
michael-go committed Sep 10, 2017
1 parent 16990a1 commit e4bce9d
Show file tree
Hide file tree
Showing 6 changed files with 559 additions and 0 deletions.
117 changes: 117 additions & 0 deletions cmd/dep/gvt_importer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// 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"
"github.com/golang/dep/internal/gps"
"github.com/pkg/errors"
)

const gvtPath = "vendor" + string(os.PathSeparator) + "manifest"

type gvtImporter struct {
*baseImporter
gvtConfig gvtManifest
}

func newGvtImporter(logger *log.Logger, verbose bool, sm gps.SourceManager) *gvtImporter {
return &gvtImporter{baseImporter: newBaseImporter(logger, verbose, sm)}
}

type gvtManifest struct {
Deps []gvtPkg `json:"dependencies"`
}

type gvtPkg struct {
ImportPath string
Repository string
Revision string
Branch string
}

func (g *gvtImporter) Name() string {
return "gvt"
}

func (g *gvtImporter) HasDepMetadata(dir string) bool {
y := filepath.Join(dir, gvtPath)
if _, err := os.Stat(y); err != nil {
return false
}

return true
}

func (g *gvtImporter) 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 *gvtImporter) load(projectDir string) error {
g.logger.Println("Detected gvt configuration files...")
j := filepath.Join(projectDir, gvtPath)
if g.verbose {
g.logger.Printf(" Loading %s", j)
}
jb, err := ioutil.ReadFile(j)
if err != nil {
return errors.Wrapf(err, "unable to read %s", j)
}
err = json.Unmarshal(jb, &g.gvtConfig)
if err != nil {
return errors.Wrapf(err, "unable to parse %s", j)
}

return nil
}

func (g *gvtImporter) convert(pr gps.ProjectRoot) (*dep.Manifest, *dep.Lock, error) {
g.logger.Println("Converting from vendor/manifest ...")

packages := make([]importedPackage, 0, len(g.gvtConfig.Deps))
for _, pkg := range g.gvtConfig.Deps {
// Validate
if pkg.ImportPath == "" {
err := errors.New("invalid gvt configuration, ImportPath is required")
return nil, nil, err
}

if pkg.Revision == "" {
err := errors.New("invalid gvt configuration, Revision is required")
return nil, nil, err
}

var contstraintHint = ""
if pkg.Branch != "master" {
contstraintHint = pkg.Branch
}

ip := importedPackage{
Name: pkg.ImportPath,
//TODO: Source: pkg.Repository,
LockHint: pkg.Revision,
ConstraintHint: contstraintHint,
}
packages = append(packages, ip)
}

err := g.importPackages(packages, true)
if err != nil {
return nil, nil, err
}

return g.manifest, g.lock, nil
}
209 changes: 209 additions & 0 deletions cmd/dep/gvt_importer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
// 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"
"github.com/golang/dep/internal/gps"
"github.com/golang/dep/internal/test"
"github.com/pkg/errors"
)

func TestGvtConfig_Convert(t *testing.T) {
testCases := map[string]struct {
convertTestCase
gvtConfig gvtManifest
}{
"package without comment": {
convertTestCase{
wantConstraint: importerTestV1Constraint,
wantRevision: importerTestV1Rev,
wantVersion: importerTestV1Tag,
},
gvtManifest{
Deps: []gvtPkg{
{
ImportPath: importerTestProject,
Revision: importerTestV1Rev,
},
},
},
},
"package with non-master branch": {
convertTestCase{
wantConstraint: importerTestV2Branch,
wantRevision: importerTestV2PatchRev,
wantVersion: importerTestV2PatchTag,
},
gvtManifest{
Deps: []gvtPkg{
{
ImportPath: importerTestProject,
Revision: importerTestV2PatchRev,
Branch: importerTestV2Branch,
},
},
},
},
"missing package name": {
convertTestCase{
wantConvertErr: true,
},
gvtManifest{
Deps: []gvtPkg{{ImportPath: ""}},
},
},
"missing revision": {
convertTestCase{
wantConvertErr: true,
},
gvtManifest{
Deps: []gvtPkg{
{
ImportPath: importerTestProject,
},
},
},
},
}

for name, testCase := range testCases {
name := name
testCase := testCase
t.Run(name, func(t *testing.T) {
t.Parallel()

err := testCase.Exec(t, func(logger *log.Logger, sm gps.SourceManager) (*dep.Manifest, *dep.Lock, error) {
g := newGvtImporter(logger, true, sm)
g.gvtConfig = testCase.gvtConfig
return g.convert(testProjectRoot)
})
if err != nil {
t.Fatalf("%#v", err)
}
})
}
}

func TestGvtConfig_Import(t *testing.T) {
h := test.NewHelper(t)
defer h.Cleanup()

cacheDir := "gps-repocache"
h.TempDir(cacheDir)
h.TempDir("src")
h.TempDir(filepath.Join("src", testProjectRoot))
h.TempCopy(filepath.Join(testProjectRoot, gvtPath), "init/gvt/manifest")

projectRoot := h.Path(testProjectRoot)
sm, err := gps.NewSourceManager(gps.SourceManagerConfig{
Cachedir: h.Path(cacheDir),
Logger: log.New(test.Writer{t}, "", 0),
})
h.Must(err)
defer sm.Release()

// Capture stderr so we can verify output
verboseOutput := &bytes.Buffer{}
logger := log.New(verboseOutput, "", 0)

g := newGvtImporter(logger, 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 gvt configuration file")
}

m, l, err := g.Import(projectRoot, testProjectRoot)
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 := "init/gvt/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("want %s, got %s", want, got)
}
}
}

func TestGvtConfig_JsonLoad(t *testing.T) {
// This is same as cmd/dep/testdata/init/gvt/manifest
wantConfig := gvtManifest{
Deps: []gvtPkg{
{
ImportPath: "github.com/sdboyer/deptest",
Revision: "3f4c3bea144e112a69bbe5d8d01c1b09a544253f",
},
{
ImportPath: "github.com/sdboyer/deptestdos",
Revision: "5c607206be5decd28e6263ffffdcee067266015e",
},
{
ImportPath: "github.com/carolynvs/deptest-importers",
Revision: "b79bc9482da8bb7402cdc3e3fd984db250718dd7",
Branch: "v2",
},
},
}

h := test.NewHelper(t)
defer h.Cleanup()

ctx := newTestContext(h)

h.TempCopy(filepath.Join(testProjectRoot, gvtPath), "init/gvt/manifest")

projectRoot := h.Path(testProjectRoot)

g := newGvtImporter(ctx.Err, true, nil)
err := g.load(projectRoot)
if err != nil {
t.Fatalf("Error while loading... %v", err)
}

if !gvtEqualImports(g.gvtConfig.Deps, wantConfig.Deps) {
t.Fatalf("Expected imports to be equal. \n\t(GOT): %v\n\t(WNT): %v", g.gvtConfig.Deps, wantConfig.Deps)
}
}

// gvtEqualImports compares two slices of gvtPkg and checks if they are
// equal.
func gvtEqualImports(a, b []gvtPkg) bool {
if a == nil && b == nil {
return true
}

if a == nil || b == nil {
return false
}

if len(a) != len(b) {
return false
}

for i := range a {
if a[i] != b[i] {
return false
}
}

return true
}
1 change: 1 addition & 0 deletions cmd/dep/root_analyzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ func (a *rootAnalyzer) importManifestAndLock(dir string, pr gps.ProjectRoot, sup
newGodepImporter(logger, a.ctx.Verbose, a.sm),
newVndrImporter(logger, a.ctx.Verbose, a.sm),
newGovendImporter(logger, a.ctx.Verbose, a.sm),
newGvtImporter(logger, a.ctx.Verbose, a.sm),
}

for _, i := range importers {
Expand Down
Loading

0 comments on commit e4bce9d

Please sign in to comment.