Otherwise it is impossible to vendor a/b/c without hiding the real a/b.
I also updated golang.org/s/go15vendor.
Fixes #13832.
Change-Id: Iee3d53c11ea870721803f6e8e67845b405686e79
Reviewed-on: https://go-review.googlesource.com/18644
Reviewed-by: Andrew Gerrand <adg@golang.org>
continue
}
targ := filepath.Join(dir[:i], vpath)
- if isDir(targ) {
+ if isDir(targ) && hasGoFiles(targ) {
// We started with parent's dir c:\gopath\src\foo\bar\baz\quux\xyzzy.
// We know the import path for parent's dir.
// We chopped off some number of path elements and
return path
}
+// hasGoFiles reports whether dir contains any files with names ending in .go.
+// For a vendor check we must exclude directories that contain no .go files.
+// Otherwise it is not possible to vendor just a/b/c and still import the
+// non-vendored a/b. See golang.org/issue/13832.
+func hasGoFiles(dir string) bool {
+ fis, _ := ioutil.ReadDir(dir)
+ for _, fi := range fis {
+ if !fi.IsDir() && strings.HasSuffix(fi.Name(), ".go") {
+ return true
+ }
+ }
+ return false
+}
+
// reusePackage reuses package p to satisfy the import at the top
// of the import stack stk. If this use causes an import loop,
// reusePackage updates p's error information to record the loop.
--- /dev/null
+package dir1
--- /dev/null
+package dir2
import _ "p"
import _ "q"
import _ "r"
+import _ "vend/dir1" // not vendored
+import _ "vend/dir1/dir2" // vendored
tg.run("list", "-f", "{{.ImportPath}} {{.Imports}}", "vend/...")
want := `
vend [vend/vendor/p r]
+ vend/dir1 []
vend/hello [fmt vend/vendor/strings]
vend/subdir [vend/vendor/p r]
vend/vendor/p []
vend/vendor/q []
vend/vendor/strings []
- vend/x [vend/x/vendor/p vend/vendor/q vend/x/vendor/r]
+ vend/vendor/vend/dir1/dir2 []
+ vend/x [vend/x/vendor/p vend/vendor/q vend/x/vendor/r vend/dir1 vend/vendor/vend/dir1/dir2]
vend/x/invalid [vend/x/invalid/vendor/foo]
vend/x/vendor/p []
vend/x/vendor/p/p [notfound]
}
}
+func TestVendorBuild(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+ tg.setenv("GO15VENDOREXPERIMENT", "1")
+ tg.run("build", "vend/x")
+}
+
func TestVendorRun(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
vendor := ctxt.joinPath(root, sub, "vendor")
if ctxt.isDir(vendor) {
dir := ctxt.joinPath(vendor, path)
- if ctxt.isDir(dir) {
+ if ctxt.isDir(dir) && hasGoFiles(ctxt, dir) {
p.Dir = dir
p.ImportPath = strings.TrimPrefix(pathpkg.Join(sub, "vendor", path), "src/")
p.Goroot = isGoroot
return p, pkgerr
}
+// hasGoFiles reports whether dir contains any files with names ending in .go.
+// For a vendor check we must exclude directories that contain no .go files.
+// Otherwise it is not possible to vendor just a/b/c and still import the
+// non-vendored a/b. See golang.org/issue/13832.
+func hasGoFiles(ctxt *Context, dir string) bool {
+ ents, _ := ctxt.readDir(dir)
+ for _, ent := range ents {
+ if !ent.IsDir() && strings.HasSuffix(ent.Name(), ".go") {
+ return true
+ }
+ }
+ return false
+}
+
func findImportComment(data []byte) (s string, line int) {
// expect keyword package
word, data := parseWord(data)
t.Fatalf("error on failed import does not mention GOROOT/src/vendor directory:\n%s", e)
}
}
+
+func TestImportVendorParentFailure(t *testing.T) {
+ testenv.MustHaveGoBuild(t) // really must just have source
+ ctxt := Default
+ ctxt.GOPATH = ""
+ // This import should fail because the vendor/golang.org/x/net/http2 directory has no source code.
+ p, err := ctxt.Import("golang.org/x/net/http2", filepath.Join(ctxt.GOROOT, "src/net/http"), 0)
+ if err == nil {
+ t.Fatalf("found empty parent in %s", p.Dir)
+ }
+ if p != nil && p.Dir != "" {
+ t.Fatalf("decided to use %s", p.Dir)
+ }
+ e := err.Error()
+ if !strings.Contains(e, " (vendor tree)") {
+ t.Fatalf("error on failed import does not mention GOROOT/src/vendor directory:\n%s", e)
+ }
+}