From e646d07329e7edc56c8cf3284c729937979dae4a Mon Sep 17 00:00:00 2001 From: Dmitri Shuralyov Date: Fri, 11 Nov 2016 20:49:41 -0800 Subject: [PATCH] go/build: fix lack of error for Import of nonexistent local import path When calling build.Import, normally, an error is returned if the directory doesn't exist. However, that didn't happen for local import paths when build.FindOnly ImportMode was used. This change fixes that, and adds tests. It also makes the error value more consistent in all scenarios where it occurs. When calling build.Import with a local import path, the package can only exist in a single deterministic directory. That makes it possible verify that directory exists earlier in the path, and return a "cannot find package" error if it doesn't. Previously, this occurred only when build.FindOnly ImportMode was not set. It occurred quite late, after getting past Found label, to line that calls ctxt.readDir. Doing so would return an error like "no such file or directory" when the directory does not exist. Fixes #17863. Updates #17888 (relevant issue I ran into while working on this CL). Change-Id: If6a6996ac6176ac203a88bd31419748f88d89d7c Reviewed-on: https://go-review.googlesource.com/33158 Reviewed-by: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot --- src/go/build/build.go | 5 +++++ src/go/build/build_test.go | 24 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/src/go/build/build.go b/src/go/build/build.go index 27bd802317b..5ced41ce45c 100644 --- a/src/go/build/build.go +++ b/src/go/build/build.go @@ -155,6 +155,7 @@ func (ctxt *Context) hasSubdir(root, dir string) (rel string, ok bool) { return hasSubdir(rootSym, dirSym) } +// hasSubdir reports if dir is within root by performing lexical analysis only. func hasSubdir(root, dir string) (rel string, ok bool) { const sep = string(filepath.Separator) root = filepath.Clean(root) @@ -528,6 +529,10 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa if !ctxt.isAbsPath(path) { p.Dir = ctxt.joinPath(srcDir, path) } + if !ctxt.isDir(p.Dir) { + // package was not found + return p, fmt.Errorf("cannot find package %q in:\n\t%s", path, p.Dir) + } // Determine canonical import path, if any. // Exclude results where the import path would include /testdata/. inTestdata := func(sub string) bool { diff --git a/src/go/build/build_test.go b/src/go/build/build_test.go index a9972416ef2..9b50efe2534 100644 --- a/src/go/build/build_test.go +++ b/src/go/build/build_test.go @@ -300,6 +300,30 @@ func TestShellSafety(t *testing.T) { } } +// Want to get a "cannot find package" error when directory for package does not exist. +func TestImportDirNotExist(t *testing.T) { + testenv.MustHaveGoBuild(t) // really must just have source + ctxt := Default + ctxt.GOPATH = "" + + tests := []struct { + label string + path, srcDir string + mode ImportMode + }{ + {"Import(full, 0)", "go/build/doesnotexist", "", 0}, + {"Import(local, 0)", "./doesnotexist", filepath.Join(ctxt.GOROOT, "src/go/build"), 0}, + {"Import(full, FindOnly)", "go/build/doesnotexist", "", FindOnly}, + {"Import(local, FindOnly)", "./doesnotexist", filepath.Join(ctxt.GOROOT, "src/go/build"), FindOnly}, + } + for _, test := range tests { + _, err := ctxt.Import(test.path, test.srcDir, test.mode) + if err == nil || !strings.HasPrefix(err.Error(), "cannot find package") { + t.Errorf(`%s got error: %q, want "cannot find package" error`, test.label, err) + } + } +} + func TestImportVendor(t *testing.T) { testenv.MustHaveGoBuild(t) // really must just have source ctxt := Default