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 -}