Rewrite fetching and dependencies logic
The new code uses the parser to identify import statements, so ignores
build tags (fixes #34) and package validity (fixes #39). Critically,
the new code understand vendor folders (fixes #27).
The recursion logic is now smart about overlapping packages, ignoring
subpackages of existing ones and deleting subpackages when fetching the
parent (fixes #32).
diff --git a/alldocs.go b/alldocs.go
index f6727ea..149a698 100644
--- a/alldocs.go
+++ b/alldocs.go
@@ -25,6 +25,11 @@
fetch vendors an upstream import path.
+Recursive dependencies are fetched (at their master/tip/HEAD revision), unless they
+or their parent package are already present.
+
+If a subpackage of a dependency being fetched is already present, it will be deleted.
+
The import path may include a url scheme. This may be useful when fetching dependencies
from private repositories that cannot be probed.
diff --git a/delete.go b/delete.go
index 899a993..5f97f93 100644
--- a/delete.go
+++ b/delete.go
@@ -36,7 +36,7 @@
return fmt.Errorf("delete: you cannot specify path and --all flag at once")
}
- m, err := vendor.ReadManifest(manifestFile())
+ m, err := vendor.ReadManifest(manifestFile)
if err != nil {
return fmt.Errorf("could not load manifest: %v", err)
}
@@ -65,12 +65,12 @@
return fmt.Errorf("dependency could not be deleted: %v", err)
}
- if err := fileutils.RemoveAll(filepath.Join(vendorDir(), filepath.FromSlash(path))); err != nil {
+ if err := fileutils.RemoveAll(filepath.Join(vendorDir, filepath.FromSlash(path))); err != nil {
// TODO(dfc) need to apply vendor.cleanpath here to remove indermediate directories.
return fmt.Errorf("dependency could not be deleted: %v", err)
}
}
- return vendor.WriteManifest(manifestFile(), m)
+ return vendor.WriteManifest(manifestFile, m)
},
AddFlags: addDeleteFlags,
}
diff --git a/fetch.go b/fetch.go
index 89547a8..cb9814c 100644
--- a/fetch.go
+++ b/fetch.go
@@ -3,12 +3,11 @@
import (
"flag"
"fmt"
- "go/build"
"log"
"net/url"
+ "os"
"path/filepath"
- "runtime"
- "sort"
+ "strings"
"github.com/FiloSottile/gvt/fileutils"
"github.com/FiloSottile/gvt/gbvendor"
@@ -22,8 +21,6 @@
insecure bool // Allow the use of insecure protocols
tests bool
all bool
-
- recurse bool // should we fetch recursively
)
func addFetchFlags(fs *flag.FlagSet) {
@@ -42,8 +39,10 @@
Short: "fetch a remote dependency",
Long: `fetch vendors an upstream import path.
-Recursive dependencies are fetched at their master/tip/HEAD revision, unless they
-or their parent package is already present.
+Recursive dependencies are fetched (at their master/tip/HEAD revision), unless they
+or their parent package are already present.
+
+If a subpackage of a dependency being fetched is already present, it will be deleted.
The import path may include a url scheme. This may be useful when fetching dependencies
from private repositories that cannot be probed.
@@ -73,8 +72,7 @@
return fmt.Errorf("fetch: import path missing")
case 1:
path := args[0]
- recurse = !noRecurse
- return fetch(path, recurse)
+ return fetch(path)
default:
return fmt.Errorf("more than one import path supplied")
}
@@ -82,31 +80,102 @@
AddFlags: addFetchFlags,
}
-func fetch(path string, recurse bool) error {
- m, err := vendor.ReadManifest(manifestFile())
+var (
+ fetchRoot string // where the current session started
+ fetchedToday []string // packages fetched during this session
+)
+
+func fetch(path string) error {
+ m, err := vendor.ReadManifest(manifestFile)
if err != nil {
return fmt.Errorf("could not load manifest: %v", err)
}
- repo, extra, err := vendor.DeduceRemoteRepo(path, insecure)
- if err != nil {
- return err
+ fetchRoot = stripscheme(path)
+ return fetchRecursive(m, path, 0)
+}
+
+func fetchRecursive(m *vendor.Manifest, fullPath string, level int) error {
+ path := stripscheme(fullPath)
+
+ // Don't even bother the user about skipping packages we just fetched
+ for _, p := range fetchedToday {
+ if contains(p, path) {
+ return nil
+ }
}
- // strip of any scheme portion from the path, it is already
- // encoded in the repo.
- path = stripscheme(path)
-
+ // First, check if this or a parent is already vendored
if m.HasImportpath(path) {
- return fmt.Errorf("%s is already vendored", path)
+ if level == 0 {
+ return fmt.Errorf("%s or a parent of it is already vendored", path)
+ } else {
+ // TODO: print a different message for packages fetched during this session
+ logIndent(level, "Skipping (existing):", path)
+ return nil
+ }
}
- wc, err := GlobalDownloader.Get(repo, branch, tag, revision)
+ // Next, check if we are trying to vendor from the same repository we are in
+ if importPath != "" && contains(importPath, path) {
+ if level == 0 {
+ return fmt.Errorf("refusing to vendor a subpackage of \".\"")
+ } else {
+ logIndent(level, "Skipping (subpackage of \".\"):", path)
+ return nil
+ }
+ }
+ if level == 0 {
+ log.Println("Fetching:", path)
+ } else {
+ logIndent(level, "Fetching recursive dependency:", path)
+ }
+
+ // Finally, check if we already vendored a subpackage and remove it
+ parentOfRoot := false
+ for _, subp := range m.GetSubpackages(path) {
+ if contains(subp.Importpath, fetchRoot) {
+ // Through dependencies we ended up fetching a parent of the starting package
+ parentOfRoot = true // use the requested tag/branch/revision
+ } else {
+ ignore := false
+ for _, d := range fetchedToday {
+ if contains(d, subp.Importpath) {
+ ignore = true // No need to warn the user if we just downloaded it
+ }
+ }
+ if !ignore {
+ logIndent(level, "Deleting existing subpackage to prevent overlap:", subp.Importpath)
+ }
+ }
+ if err := m.RemoveDependency(subp); err != nil {
+ return fmt.Errorf("failed to remove subpackage: %v", err)
+ }
+ }
+ if err := fileutils.RemoveAll(filepath.Join(vendorDir, path)); err != nil && !os.IsNotExist(err) {
+ return fmt.Errorf("failed to remove existing folder: %v", err)
+ }
+
+ // Find and download the repository
+
+ repo, extra, err := vendor.DeduceRemoteRepo(fullPath, insecure)
if err != nil {
return err
}
+ var wc vendor.WorkingCopy
+ if level == 0 || parentOfRoot {
+ wc, err = GlobalDownloader.Get(repo, branch, tag, revision)
+ } else {
+ wc, err = GlobalDownloader.Get(repo, "", "", "")
+ }
+ if err != nil {
+ return err
+ }
+
+ // Add the dependency to the manifest
+
rev, err := wc.Revision()
if err != nil {
return err
@@ -132,7 +201,9 @@
return err
}
- dst := filepath.Join(vendorDir(), dep.Importpath)
+ // Copy the code to the vendor folder
+
+ dst := filepath.Join(vendorDir, dep.Importpath)
src := filepath.Join(wc.Dir(), dep.Path)
if err := fileutils.Copypath(dst, src, !dep.NoTests, dep.AllFiles); err != nil {
@@ -143,59 +214,36 @@
return err
}
- if err := vendor.WriteManifest(manifestFile(), m); err != nil {
+ if err := vendor.WriteManifest(manifestFile, m); err != nil {
return err
}
- if !recurse {
- return nil
- }
+ // Recurse
- // if we are recursing, overwrite branch, tag and revision
- // values so recursive fetching checks out from HEAD.
- branch = ""
- tag = ""
- revision = ""
+ fetchedToday = append(fetchedToday, path)
- for done := false; !done; {
-
- paths := []struct {
- Root, Prefix string
- }{
- {filepath.Join(runtime.GOROOT(), "src"), ""},
+ if !noRecurse {
+ // Look for dependencies in src, not going past wc.Dir() when looking for /vendor/,
+ // knowing that wc.Dir() corresponds to rootRepoPath
+ if !strings.HasSuffix(dep.Importpath, dep.Path) {
+ return fmt.Errorf("unable to derive the root repo import path")
}
- m, err := vendor.ReadManifest(manifestFile())
+ rootRepoPath := strings.TrimRight(strings.TrimSuffix(dep.Importpath, dep.Path), "/")
+ deps, err := vendor.ParseImports(src, wc.Dir(), rootRepoPath)
if err != nil {
- return err
- }
- for _, d := range m.Dependencies {
- paths = append(paths, struct{ Root, Prefix string }{filepath.Join(vendorDir(), filepath.FromSlash(d.Importpath)), filepath.FromSlash(d.Importpath)})
+ return fmt.Errorf("failed to parse imports: %s", err)
}
- dsm, err := vendor.LoadPaths(paths...)
- if err != nil {
- return err
- }
-
- is, ok := dsm[filepath.Join(vendorDir(), path)]
- if !ok {
- return fmt.Errorf("unable to locate depset for %q", path)
- }
-
- missing := findMissing(pkgs(is.Pkgs), dsm)
- switch len(missing) {
- case 0:
- done = true
- default:
-
- // sort keys in ascending order, so the shortest missing import path
- // with be fetched first.
- keys := keys(missing)
- sort.Strings(keys)
- pkg := keys[0]
- log.Printf("fetching recursive dependency %s", pkg)
- if err := fetch(pkg, false); err != nil {
- return err
+ for d := range deps {
+ if strings.Index(d, ".") == -1 { // TODO: replace this silly heuristic
+ continue
+ }
+ if err := fetchRecursive(m, d, level+1); err != nil {
+ if strings.HasPrefix(err.Error(), "error fetching") { // I know, ok?
+ return err
+ } else {
+ return fmt.Errorf("error fetching %s: %s", d, err)
+ }
}
}
}
@@ -203,88 +251,10 @@
return nil
}
-func keys(m map[string]bool) []string {
- var s []string
- for k := range m {
- s = append(s, k)
- }
- return s
-}
-
-func pkgs(m map[string]*vendor.Pkg) []*vendor.Pkg {
- var p []*vendor.Pkg
- for _, v := range m {
- p = append(p, v)
- }
- return p
-}
-
-func findMissing(pkgs []*vendor.Pkg, dsm map[string]*vendor.Depset) map[string]bool {
- missing := make(map[string]bool)
- imports := make(map[string]*vendor.Pkg)
- for _, s := range dsm {
- for _, p := range s.Pkgs {
- imports[p.ImportPath] = p
- }
- }
-
- // make fake C package for cgo
- imports["C"] = &vendor.Pkg{
- Depset: nil, // probably a bad idea
- Package: &build.Package{
- Name: "C",
- },
- }
- stk := make(map[string]bool)
- push := func(v string) {
- if stk[v] {
- panic(fmt.Sprintln("import loop:", v, stk))
- }
- stk[v] = true
- }
- pop := func(v string) {
- if !stk[v] {
- panic(fmt.Sprintln("impossible pop:", v, stk))
- }
- delete(stk, v)
- }
-
- // checked records import paths who's dependencies are all present
- checked := make(map[string]bool)
-
- var fn func(string)
- fn = func(importpath string) {
- p, ok := imports[importpath]
- if !ok {
- missing[importpath] = true
- return
- }
-
- // have we already walked this arm, if so, skip it
- if checked[importpath] {
- return
- }
-
- sz := len(missing)
- push(importpath)
- for _, i := range p.Imports {
- if i == importpath {
- continue
- }
- fn(i)
- }
-
- // if the size of the missing map has not changed
- // this entire subtree is complete, mark it as such
- if len(missing) == sz {
- checked[importpath] = true
- }
- pop(importpath)
- }
- for _, pkg := range pkgs {
- fn(pkg.ImportPath)
- }
- return missing
+func logIndent(level int, v ...interface{}) {
+ prefix := strings.Repeat("·", level)
+ v = append([]interface{}{prefix}, v...)
+ log.Println(v...)
}
// stripscheme removes any scheme components from url like paths.
@@ -295,3 +265,8 @@
}
return u.Host + u.Path
}
+
+// Package a contains package b?
+func contains(a, b string) bool {
+ return a == b || strings.HasPrefix(b, a+"/")
+}
diff --git a/gbvendor/depset.go b/gbvendor/depset.go
deleted file mode 100644
index b4c40d8..0000000
--- a/gbvendor/depset.go
+++ /dev/null
@@ -1,114 +0,0 @@
-package vendor
-
-import (
- "fmt"
- "go/build"
- "os"
- "path/filepath"
- "strings"
-)
-
-// Pkg describes a Go package.
-type Pkg struct {
- *Depset
- *build.Package
-}
-
-// Depset describes a set of related Go packages.
-type Depset struct {
- Root string
- Prefix string
- Pkgs map[string]*Pkg
-}
-
-// LoadPaths returns a map of paths to Depsets.
-func LoadPaths(paths ...struct{ Root, Prefix string }) (map[string]*Depset, error) {
- m := make(map[string]*Depset)
- for _, p := range paths {
- set, err := LoadTree(p.Root, p.Prefix)
- if err != nil {
- return nil, err
- }
- m[set.Root] = set
- }
- return m, nil
-}
-
-// LoadTree parses a tree of source files into a map of *pkgs.
-func LoadTree(root string, prefix string) (*Depset, error) {
- d := Depset{
- Root: root,
- Prefix: prefix,
- Pkgs: make(map[string]*Pkg),
- }
- fn := func(dir string, fi os.FileInfo) error {
- importpath := filepath.Join(prefix, dir[len(root)+1:])
-
- // if we're at the root of a tree, skip it
- if importpath == "" {
- return nil
- }
-
- p, err := loadPackage(&d, dir)
- if err != nil {
- if _, ok := err.(*build.NoGoError); ok {
- return nil
- }
- return fmt.Errorf("loadPackage(%q, %q): %v", dir, importpath, err)
- }
- p.ImportPath = filepath.ToSlash(importpath)
- if p != nil {
- d.Pkgs[p.ImportPath] = p
- }
- return nil
- }
-
- // handle root of the tree
- fi, err := os.Stat(root)
- if err != nil {
- return nil, err
- }
- if err := fn(root+string(filepath.Separator), fi); err != nil {
- return nil, err
- }
-
- // walk sub directories
- err = eachDir(root, fn)
- return &d, err
-}
-
-func loadPackage(d *Depset, dir string) (*Pkg, error) {
- p := Pkg{
- Depset: d,
- }
- var err error
-
- // expolit local import logic
- p.Package, err = build.ImportDir(dir, build.ImportComment)
- return &p, err
-}
-
-func eachDir(dir string, fn func(string, os.FileInfo) error) error {
- f, err := os.Open(dir)
- if err != nil {
- return err
- }
- defer f.Close()
- files, err := f.Readdir(-1)
- for _, fi := range files {
- if !fi.IsDir() {
- continue
- }
- if strings.HasPrefix(fi.Name(), "_") || strings.HasPrefix(fi.Name(), ".") || fi.Name() == "testdata" {
- continue
- }
- path := filepath.Join(dir, fi.Name())
- if err := fn(path, fi); err != nil {
- return err
- }
- if err := eachDir(path, fn); err != nil {
- return err
- }
- }
- return nil
-}
diff --git a/gbvendor/imports.go b/gbvendor/imports.go
index 373e3f9..db64a5b 100644
--- a/gbvendor/imports.go
+++ b/gbvendor/imports.go
@@ -57,15 +57,13 @@
//
// It returns the path to pkgName inside the vendor folder, relative to root.
func findVendor(root, start, pkgName string) string {
- if !strings.HasPrefix(root, start) {
- log.Fatal("Assertion failed:", root, "prefix of", start)
+ if !strings.HasPrefix(start, root) {
+ log.Fatalln("Assertion failed:", root, "prefix of", start)
}
levels := strings.Split(strings.TrimPrefix(start, root), string(filepath.Separator))
- log.Println(root, start, levels, pkgName)
for {
- candidate := filepath.Join(append(append([]string{root}, levels...), pkgName)...)
- log.Println(candidate)
+ candidate := filepath.Join(append(append([]string{root}, levels...), "vendor", pkgName)...)
files, err := ioutil.ReadDir(candidate)
if err != nil {
diff --git a/gbvendor/manifest.go b/gbvendor/manifest.go
index 6d68e74..0c3334b 100644
--- a/gbvendor/manifest.go
+++ b/gbvendor/manifest.go
@@ -6,6 +6,7 @@
"errors"
"fmt"
"io"
+ "log"
"os"
"reflect"
"sort"
@@ -24,19 +25,19 @@
}
var (
- depPresent = errors.New("dependency already present")
- depSubPkgPresent = errors.New("subpackages of this dependency are already present")
- depMissing = errors.New("dependency does not exist")
+ DepPresent = errors.New("dependency already present")
+ DepSubPkgPresent = errors.New("subpackages of this dependency are already present")
+ DepMissing = errors.New("dependency does not exist")
)
// AddDependency adds a Dependency to the current Manifest.
// If the dependency exists already then it returns and error.
func (m *Manifest) AddDependency(dep Dependency) error {
if m.HasImportpath(dep.Importpath) {
- return depPresent
+ return DepPresent
}
if m.GetSubpackages(dep.Importpath) != nil {
- return depSubPkgPresent
+ return DepSubPkgPresent
}
m.Dependencies = append(m.Dependencies, dep)
return nil
@@ -51,7 +52,7 @@
return nil
}
}
- return depMissing
+ return DepMissing
}
// HasImportpath reports whether the Manifest contains the import path,
@@ -66,7 +67,7 @@
// If the dependency does not exist it returns an error.
func (m *Manifest) GetDependencyForImportpath(path string) (Dependency, error) {
for _, d := range m.Dependencies {
- if strings.HasPrefix(path, d.Importpath) {
+ if path == d.Importpath || strings.HasPrefix(path, d.Importpath+"/") {
return d, nil
}
}
@@ -169,16 +170,18 @@
var m Manifest
d := json.NewDecoder(f)
- err = d.Decode(&m)
+ if err := d.Decode(&m); err != nil {
+ return nil, err
+ }
// Pass all dependencies through AddDependency to detect overlap
deps := m.Dependencies
m.Dependencies = nil
sort.Sort(byImportpath(deps)) // so that subpackages come after parents
for _, d := range deps {
- if err := m.AddDependency(d); err == depPresent {
- fmt.Fprintln(os.Stderr, "WARNING: overlapping dependency detected:", d.Importpath)
- fmt.Fprintln(os.Stderr, "The subpackage will be ignored to fix undefined behavior. See https://git.io/vwK4B")
+ if err := m.AddDependency(d); err == DepPresent {
+ log.Println("WARNING: overlapping dependency detected:", d.Importpath)
+ log.Println("The subpackage will be ignored to fix undefined behavior. See https://git.io/vwK4B")
} else if err != nil {
return nil, err
}
diff --git a/gbvendor/stringset.go b/gbvendor/stringset.go
deleted file mode 100644
index 007eae5..0000000
--- a/gbvendor/stringset.go
+++ /dev/null
@@ -1,52 +0,0 @@
-package vendor
-
-// union returns the union of a and b.
-func union(a, b map[string]bool) map[string]bool {
- r := make(map[string]bool)
- for k := range a {
- r[k] = true
- }
- for k := range b {
- r[k] = true
- }
- return r
-}
-
-// intersection returns the intersection of a and b.
-func intersection(a, b map[string]bool) map[string]bool {
- r := make(map[string]bool)
- for k := range a {
- if b[k] {
- r[k] = true
- }
- }
- return r
-}
-
-// difference returns the symetric difference of a and b.
-func difference(a, b map[string]bool) map[string]bool {
- r := make(map[string]bool)
- for k := range a {
- if !b[k] {
- r[k] = true
- }
- }
- for k := range b {
- if !a[k] {
- r[k] = true
- }
- }
- return r
-}
-
-// contains returns true if a contains all the elements in s.
-func contains(a map[string]bool, s ...string) bool {
- var r bool
- for _, e := range s {
- if !a[e] {
- return false
- }
- r = true
- }
- return r
-}
diff --git a/gbvendor/stringset_test.go b/gbvendor/stringset_test.go
deleted file mode 100644
index d8781a4..0000000
--- a/gbvendor/stringset_test.go
+++ /dev/null
@@ -1,147 +0,0 @@
-package vendor
-
-import "testing"
-import "reflect"
-
-func set(args ...string) map[string]bool {
- r := make(map[string]bool)
- for _, a := range args {
- r[a] = true
- }
- return r
-}
-
-func TestUnion(t *testing.T) {
- tests := []struct {
- a, b map[string]bool
- want map[string]bool
- }{{
- a: nil, b: nil,
- want: set(),
- }, {
- a: nil, b: set("b"),
- want: set("b"),
- }, {
- a: set("a"), b: nil,
- want: set("a"),
- }, {
- a: set("a"), b: set("b"),
- want: set("b", "a"),
- }, {
- a: set("c"), b: set("c"),
- want: set("c"),
- }}
-
- for _, tt := range tests {
- got := union(tt.a, tt.b)
- if !reflect.DeepEqual(tt.want, got) {
- t.Errorf("union(%v, %v) want: %v, got %v", tt.a, tt.b, tt.want, got)
- }
- }
-}
-
-func TestIntersection(t *testing.T) {
- tests := []struct {
- a, b map[string]bool
- want map[string]bool
- }{{
- a: nil, b: nil,
- want: set(),
- }, {
- a: nil, b: set("b"),
- want: set(),
- }, {
- a: set("a"), b: nil,
- want: set(),
- }, {
- a: set("a"), b: set("b"),
- want: set(),
- }, {
- a: set("c"), b: set("c"),
- want: set("c"),
- }, {
- a: set("a", "c"), b: set("b", "c"),
- want: set("c"),
- }}
-
- for _, tt := range tests {
- got := intersection(tt.a, tt.b)
- if !reflect.DeepEqual(tt.want, got) {
- t.Errorf("intersection(%v, %v) want: %v, got %v", tt.a, tt.b, tt.want, got)
- }
- }
-}
-
-func TestDifference(t *testing.T) {
- tests := []struct {
- a, b map[string]bool
- want map[string]bool
- }{{
- a: nil, b: nil,
- want: set(),
- }, {
- a: nil, b: set("b"),
- want: set("b"),
- }, {
- a: set("a"), b: nil,
- want: set("a"),
- }, {
- a: set("a"), b: set("b"),
- want: set("a", "b"),
- }, {
- a: set("c"), b: set("c"),
- want: set(),
- }, {
- a: set("a", "c"), b: set("b", "c"),
- want: set("a", "b"),
- }}
-
- for _, tt := range tests {
- got := difference(tt.a, tt.b)
- if !reflect.DeepEqual(tt.want, got) {
- t.Errorf("difference(%v, %v) want: %v, got %v", tt.a, tt.b, tt.want, got)
- }
- }
-}
-
-func TestContains(t *testing.T) {
- tests := []struct {
- a map[string]bool
- s []string
- want bool
- }{{
- a: nil, s: nil,
- want: false,
- }, {
- a: set("a"), s: nil,
- want: false,
- }, {
- a: set("a"), s: []string{"a"},
- want: true,
- }, {
- a: set("a"), s: []string{"b"},
- want: false,
- }, {
- a: set("a", "b"), s: []string{"b"},
- want: true,
- }, {
- a: set("a"), s: []string{"a", "b"},
- want: false,
- }, {
- a: set("a", "b", "c"), s: []string{"a", "b"},
- want: true,
- }, {
- a: set("a", "b", "c"), s: []string{"x", "b"},
- want: false,
- }, {
- a: set("a", "b", "c"), s: []string{"b", "c", "d"},
- want: false,
- }}
-
- for _, tt := range tests {
- got := contains(tt.a, tt.s...)
- if !reflect.DeepEqual(tt.want, got) {
- t.Errorf("contains(%v, %v) want: %v, got %v", tt.a, tt.s, tt.want, got)
- }
- }
-}
diff --git a/list.go b/list.go
index 49e7e89..95b50a9 100644
--- a/list.go
+++ b/list.go
@@ -31,7 +31,7 @@
`,
Run: func(args []string) error {
- m, err := vendor.ReadManifest(manifestFile())
+ m, err := vendor.ReadManifest(manifestFile)
if err != nil {
return fmt.Errorf("could not load manifest: %v", err)
}
diff --git a/main.go b/main.go
index 129b95b..c83d694 100644
--- a/main.go
+++ b/main.go
@@ -3,9 +3,11 @@
import (
"flag"
"fmt"
+ "go/build"
"log"
"os"
"path/filepath"
+ "strings"
)
var fs = flag.NewFlagSet(os.Args[0], flag.ContinueOnError)
@@ -78,16 +80,22 @@
os.Exit(3)
}
-const manifestfile = "manifest"
+var (
+ vendorDir, manifestFile string
+ importPath string
+)
-func vendorDir() string {
+func init() {
wd, err := os.Getwd()
if err != nil {
log.Fatal(err)
}
- return filepath.Join(wd, "vendor")
-}
-
-func manifestFile() string {
- return filepath.Join(vendorDir(), manifestfile)
+ vendorDir = filepath.Join(wd, "vendor")
+ manifestFile = filepath.Join(vendorDir, "manifest")
+ srcTree := filepath.Join(build.Default.GOPATH, "src") + string(filepath.Separator)
+ if build.Default.GOPATH == "" || !strings.HasPrefix(wd, srcTree) {
+ log.Println("WARNING: for go vendoring to work your project needs to be somewhere under $GOPATH/src/")
+ } else {
+ importPath = filepath.ToSlash(strings.TrimPrefix(wd, srcTree))
+ }
}
diff --git a/restore.go b/restore.go
index 3601291..dc0b1e3 100644
--- a/restore.go
+++ b/restore.go
@@ -47,7 +47,7 @@
Run: func(args []string) error {
switch len(args) {
case 0:
- return restore(manifestFile())
+ return restore(manifestFile)
default:
return fmt.Errorf("restore takes no arguments")
}
@@ -69,7 +69,7 @@
go func() {
defer wg.Done()
for d := range depC {
- if err := downloadDependency(d, &errors, vendorDir(), false); err != nil {
+ if err := downloadDependency(d, &errors, vendorDir, false); err != nil {
log.Printf("%s: %v", d.Importpath, err)
atomic.AddUint32(&errors, 1)
}
diff --git a/update.go b/update.go
index 8f6c6f1..9c73a49 100644
--- a/update.go
+++ b/update.go
@@ -46,7 +46,7 @@
return fmt.Errorf("update: you cannot specify path and -all flag at once")
}
- m, err := vendor.ReadManifest(manifestFile())
+ m, err := vendor.ReadManifest(manifestFile)
if err != nil {
return fmt.Errorf("could not load manifest: %v", err)
}
@@ -101,12 +101,12 @@
AllFiles: d.AllFiles,
}
- if err := fileutils.RemoveAll(filepath.Join(vendorDir(), filepath.FromSlash(d.Importpath))); err != nil {
+ if err := fileutils.RemoveAll(filepath.Join(vendorDir, filepath.FromSlash(d.Importpath))); err != nil {
// TODO(dfc) need to apply vendor.cleanpath here to remove intermediate directories.
return fmt.Errorf("dependency could not be deleted: %v", err)
}
- dst := filepath.Join(vendorDir(), filepath.FromSlash(dep.Importpath))
+ dst := filepath.Join(vendorDir, filepath.FromSlash(dep.Importpath))
src := filepath.Join(wc.Dir(), dep.Path)
if err := fileutils.Copypath(dst, src, !d.NoTests, d.AllFiles); err != nil {
@@ -121,7 +121,7 @@
return err
}
- if err := vendor.WriteManifest(manifestFile(), m); err != nil {
+ if err := vendor.WriteManifest(manifestFile, m); err != nil {
return err
}
}