Implement vendoring support in ParseImports
Updates #27
diff --git a/gbvendor/_testdata/copyfile/a/rick b/gbvendor/_testdata/copyfile/a/rick
deleted file mode 120000
index 0db35ec..0000000
--- a/gbvendor/_testdata/copyfile/a/rick
+++ /dev/null
@@ -1 +0,0 @@
-/never/going/to/give/you/up
\ No newline at end of file
diff --git a/gbvendor/_testdata/src/github.com/foo/bar/main.go b/gbvendor/_testdata/src/github.com/foo/bar/main.go
deleted file mode 100644
index 399afdd..0000000
--- a/gbvendor/_testdata/src/github.com/foo/bar/main.go
+++ /dev/null
@@ -1,17 +0,0 @@
-package main
-
-import (
- "fmt"
-
- "github.com/quux/flobble"
- // "bitbucket.org/fwoop/ftang" // commented out, this is deliberate
- moo "github.com/lypo/moopo"
-)
-
-import "github.com/hoo/wuu"
-
-func main() {
- fmt.Println(flobble.Q)
- fmt.Prinln(moo.Q)
- fmt.Println(wuu.Q)
-}
diff --git a/gbvendor/_testdata/vendor/src/bitbucket.org/fwoop/ftang/kthulu.go b/gbvendor/_testdata/vendor/src/bitbucket.org/fwoop/ftang/kthulu.go
deleted file mode 100644
index baa83bb..0000000
--- a/gbvendor/_testdata/vendor/src/bitbucket.org/fwoop/ftang/kthulu.go
+++ /dev/null
@@ -1,3 +0,0 @@
-package ftang
-
-const CAT = "ack!"
diff --git a/gbvendor/_testdata/vendor/src/github.com/hoo/wuu/goo.go b/gbvendor/_testdata/vendor/src/github.com/hoo/wuu/goo.go
deleted file mode 100644
index fd4d087..0000000
--- a/gbvendor/_testdata/vendor/src/github.com/hoo/wuu/goo.go
+++ /dev/null
@@ -1,3 +0,0 @@
-package wuu
-
-const Q = "hey"
diff --git a/gbvendor/_testdata/vendor/src/github.com/lypo/moopo/tropo.go b/gbvendor/_testdata/vendor/src/github.com/lypo/moopo/tropo.go
deleted file mode 100644
index 834ab54..0000000
--- a/gbvendor/_testdata/vendor/src/github.com/lypo/moopo/tropo.go
+++ /dev/null
@@ -1,3 +0,0 @@
-package moopo
-
-const Q = "hi"
diff --git a/gbvendor/_testdata/vendor/src/github.com/quux/flobble/wobble.go b/gbvendor/_testdata/vendor/src/github.com/quux/flobble/wobble.go
deleted file mode 100644
index fa9e631..0000000
--- a/gbvendor/_testdata/vendor/src/github.com/quux/flobble/wobble.go
+++ /dev/null
@@ -1,3 +0,0 @@
-package flobble
-
-const Q = "hello"
diff --git a/gbvendor/imports.go b/gbvendor/imports.go
index 0124483..373e3f9 100644
--- a/gbvendor/imports.go
+++ b/gbvendor/imports.go
@@ -5,17 +5,22 @@
"go/parser"
"go/token"
"io"
+ "io/ioutil"
+ "log"
"net/http"
"os"
+ "path"
"path/filepath"
"strings"
)
// ParseImports parses Go packages from a specific root returning a set of import paths.
-func ParseImports(root string) (map[string]bool, error) {
+// vendorRoot is how deep to go looking for vendor folders, usually the repo root.
+// vendorPrefix is the vendorRoot import path.
+func ParseImports(root, vendorRoot, vendorPrefix string) (map[string]bool, error) {
pkgs := make(map[string]bool)
- var walkFn = func(path string, info os.FileInfo, err error) error {
+ var walkFn = func(p string, info os.FileInfo, err error) error {
if info.IsDir() {
name := info.Name()
if strings.HasPrefix(name, ".") || strings.HasPrefix(name, "_") || name == "testdata" {
@@ -23,19 +28,22 @@
}
return nil
}
- if filepath.Ext(path) != ".go" { // Parse only go source files
+ if filepath.Ext(p) != ".go" { // Parse only go source files
return nil
}
fs := token.NewFileSet()
- f, err := parser.ParseFile(fs, path, nil, parser.ImportsOnly)
+ f, err := parser.ParseFile(fs, p, nil, parser.ImportsOnly)
if err != nil {
return err
}
for _, s := range f.Imports {
- p := strings.Replace(s.Path.Value, "\"", "", -1)
- pkgs[p] = true
+ pkg := strings.Replace(s.Path.Value, "\"", "", -1)
+ if vp := findVendor(vendorRoot, filepath.Dir(p), pkg); vp != "" {
+ pkg = path.Join(vendorPrefix, vp)
+ }
+ pkgs[pkg] = true
}
return nil
}
@@ -44,6 +52,44 @@
return pkgs, err
}
+// findVendor looks for pkgName in a vendor folder at start/vendor or deeper, stopping
+// at root. start is expected to match or be a subfolder of root.
+//
+// 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)
+ }
+
+ 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)
+
+ files, err := ioutil.ReadDir(candidate)
+ if err != nil {
+ files = nil
+ }
+ isPackage := false
+ for _, f := range files {
+ if !f.IsDir() && filepath.Ext(f.Name()) == ".go" {
+ isPackage = true
+ break
+ }
+ }
+
+ if isPackage {
+ return strings.TrimPrefix(candidate, root)
+ }
+
+ if len(levels) == 0 {
+ return ""
+ }
+ levels = levels[:len(levels)-1]
+ }
+}
+
// FetchMetadata fetchs the remote metadata for path.
func FetchMetadata(path string, insecure bool) (rc io.ReadCloser, err error) {
defer func() {
diff --git a/gbvendor/imports_test.go b/gbvendor/imports_test.go
index bdde910..d43e315 100644
--- a/gbvendor/imports_test.go
+++ b/gbvendor/imports_test.go
@@ -4,26 +4,10 @@
"bytes"
"fmt"
"io"
- "os"
- "path/filepath"
"reflect"
"testing"
)
-func TestParseImports(t *testing.T) {
- root := filepath.Join(getwd(t), "_testdata", "src")
-
- got, err := ParseImports(root)
- if err != nil {
- t.Fatalf("ParseImports(%q): %v", root, err)
- }
-
- want := set("fmt", "github.com/quux/flobble", "github.com/lypo/moopo", "github.com/hoo/wuu")
- if !reflect.DeepEqual(got, want) {
- t.Fatalf("ParseImports(%q): want: %v, got %v", root, want, got)
- }
-}
-
func TestFetchMetadata(t *testing.T) {
if testing.Short() {
t.Skipf("skipping network tests in -short mode")
@@ -151,11 +135,3 @@
}
}
}
-
-func getwd(t *testing.T) string {
- cwd, err := os.Getwd()
- if err != nil {
- t.Fatal(err)
- }
- return cwd
-}