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 14, 2017
1 parent d62440d commit a7103ca
Show file tree
Hide file tree
Showing 5 changed files with 360 additions and 0 deletions.
124 changes: 124 additions & 0 deletions internal/importers/gvt/importer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// 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 gvt

import (
"encoding/json"
"io/ioutil"
"log"
"os"
"path/filepath"

"github.com/golang/dep"
"github.com/golang/dep/internal/gps"
"github.com/golang/dep/internal/importers/base"
"github.com/pkg/errors"
)

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

// Importer imports gvt configuration into the dep configuration format.
type Importer struct {
*base.Importer
gvtConfig gvtManifest
}

// NewImporter for gvt.
func NewImporter(logger *log.Logger, verbose bool, sm gps.SourceManager) *Importer {
return &Importer{Importer: base.NewImporter(logger, verbose, sm)}
}

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

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

// Name of the importer.
func (g *Importer) Name() string {
return "gvt"
}

// HasDepMetadata checks if a directory contains config that the importer can handle.
func (g *Importer) HasDepMetadata(dir string) bool {
y := filepath.Join(dir, gvtPath)
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 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 *Importer) convert(pr gps.ProjectRoot) (*dep.Manifest, *dep.Lock, error) {
g.Logger.Println("Converting from vendor/manifest ...")

packages := make([]base.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 := base.ImportedPackage{
Name: pkg.ImportPath,
//TODO: temporarly ignore .Repository. see https://github.com/golang/dep/pull/1166
// 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 internal/importers/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 gvt

import (
"bytes"
"log"
"path/filepath"
"testing"

"github.com/golang/dep"
"github.com/golang/dep/internal/gps"
"github.com/golang/dep/internal/importers/importertest"
"github.com/golang/dep/internal/test"
"github.com/pkg/errors"
)

func TestGvtConfig_Convert(t *testing.T) {
testCases := map[string]struct {
importertest.TestCase
gvtConfig gvtManifest
}{
"package with master branch": {
importertest.TestCase{
WantConstraint: importertest.V1Constraint,
WantRevision: importertest.V1Rev,
WantVersion: importertest.V1Tag,
},
gvtManifest{
Deps: []gvtPkg{
{
ImportPath: importertest.Project,
Revision: importertest.V1Rev,
Branch: "master",
},
},
},
},
"package with non-master branch": {
importertest.TestCase{
WantConstraint: importertest.V2Branch,
WantRevision: importertest.V2PatchRev,
WantVersion: importertest.V2PatchTag,
},
gvtManifest{
Deps: []gvtPkg{
{
ImportPath: importertest.Project,
Revision: importertest.V2PatchRev,
Branch: importertest.V2Branch,
},
},
},
},
"missing package name": {
importertest.TestCase{
WantConvertErr: true,
},
gvtManifest{
Deps: []gvtPkg{{ImportPath: ""}},
},
},
"missing revision": {
importertest.TestCase{
WantConvertErr: true,
},
gvtManifest{
Deps: []gvtPkg{
{
ImportPath: importertest.Project,
},
},
},
},
}

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.gvtConfig = testCase.gvtConfig
return g.convert(importertest.RootProject)
})
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", importertest.RootProject))
h.TempCopy(filepath.Join(importertest.RootProject, gvtPath), "manifest")

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

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

g := NewImporter(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, importertest.RootProject)
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("want %s, got %s", want, got)
}
}
}

func TestGvtConfig_JsonLoad(t *testing.T) {
// This is same as testdata/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 := importertest.NewTestContext(h)

h.TempCopy(filepath.Join(importertest.RootProject, gvtPath), "manifest")

projectRoot := h.Path(importertest.RootProject)

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

if !equalImports(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)
}
}

// equalImports compares two slices of gvtPkg and checks if they are
// equal.
func equalImports(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
}
8 changes: 8 additions & 0 deletions internal/importers/gvt/testdata/golden.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Detected gvt configuration files...
Converting from vendor/manifest ...
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
Using v2 as initial constraint for imported dep github.com/carolynvs/deptest-importers
Trying v2 (b79bc94) as initial lock for imported dep github.com/carolynvs/deptest-importers
17 changes: 17 additions & 0 deletions internal/importers/gvt/testdata/manifest
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"dependencies": [
{
"importpath": "github.com/sdboyer/deptest",
"revision": "3f4c3bea144e112a69bbe5d8d01c1b09a544253f"
},
{
"importpath": "github.com/sdboyer/deptestdos",
"revision": "5c607206be5decd28e6263ffffdcee067266015e"
},
{
"importpath": "github.com/carolynvs/deptest-importers",
"revision": "b79bc9482da8bb7402cdc3e3fd984db250718dd7",
"branch": "v2"
}
]
}
2 changes: 2 additions & 0 deletions internal/importers/importers.go
Original file line number Diff line number Diff line change
Expand Up @@ -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/gvt"
"github.com/golang/dep/internal/importers/vndr"
)

Expand All @@ -35,5 +36,6 @@ func BuildAll(logger *log.Logger, verbose bool, sm gps.SourceManager) []Importer
godep.NewImporter(logger, verbose, sm),
vndr.NewImporter(logger, verbose, sm),
govend.NewImporter(logger, verbose, sm),
gvt.NewImporter(logger, verbose, sm),
}
}

0 comments on commit a7103ca

Please sign in to comment.