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