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