aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/go/internal/modload/load.go
diff options
context:
space:
mode:
authorBryan C. Mills <bcmills@google.com>2019-07-09 17:41:37 -0400
committerBryan C. Mills <bcmills@google.com>2019-07-15 16:53:05 +0000
commitb9edee32e15eb2ea66fe96563088520fff6f2535 (patch)
treef7848138da39e95bebffd96df3bcbe023cce6293 /src/cmd/go/internal/modload/load.go
parent4b3658880752ca30a2ad5f2dc33a9bee9ff91de4 (diff)
downloadgo-b9edee32e15eb2ea66fe96563088520fff6f2535.tar.gz
go-b9edee32e15eb2ea66fe96563088520fff6f2535.zip
cmd/go: check for source files in relative paths before attempting to determine the package path
This is a more minimial fix for the immediate symptom of 32917 and 30590, but does not improve 'list -e' behavior or error messages resulting from other package loading issues. Fixes #32917 Fixes #30590 Change-Id: I6088d14d864410159ebf228d9392d186322fd2a5 Reviewed-on: https://go-review.googlesource.com/c/go/+/185417 Run-TryBot: Bryan C. Mills <bcmills@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Jay Conrod <jayconrod@google.com>
Diffstat (limited to 'src/cmd/go/internal/modload/load.go')
-rw-r--r--src/cmd/go/internal/modload/load.go66
1 files changed, 54 insertions, 12 deletions
diff --git a/src/cmd/go/internal/modload/load.go b/src/cmd/go/internal/modload/load.go
index 992fa70b79..81fb8b346f 100644
--- a/src/cmd/go/internal/modload/load.go
+++ b/src/cmd/go/internal/modload/load.go
@@ -100,11 +100,31 @@ func ImportPathsQuiet(patterns []string, tags map[string]bool) []*search.Match {
dir = filepath.Clean(dir)
}
+ // golang.org/issue/32917: We should resolve a relative path to a
+ // package path only if the relative path actually contains the code
+ // for that package.
+ if !dirContainsPackage(dir) {
+ // If we're outside of a module, ensure that the failure mode
+ // indicates that.
+ ModRoot()
+
+ // If the directory is local but does not exist, don't return it
+ // while loader is iterating, since this might trigger a fetch.
+ // After loader is done iterating, we still need to return the
+ // path, so that "go list -e" produces valid output.
+ if !iterating {
+ // We don't have a valid path to resolve to, so report the
+ // unresolved path.
+ m.Pkgs = append(m.Pkgs, pkg)
+ }
+ continue
+ }
+
// Note: The checks for @ here are just to avoid misinterpreting
// the module cache directories (formerly GOPATH/src/mod/foo@v1.5.2/bar).
// It's not strictly necessary but helpful to keep the checks.
if modRoot != "" && dir == modRoot {
- pkg = Target.Path
+ pkg = targetPrefix
} else if modRoot != "" && strings.HasPrefix(dir, modRoot+string(filepath.Separator)) && !strings.Contains(dir[len(modRoot):], "@") {
suffix := filepath.ToSlash(dir[len(modRoot):])
if strings.HasPrefix(suffix, "/vendor/") {
@@ -121,7 +141,13 @@ func ImportPathsQuiet(patterns []string, tags map[string]bool) []*search.Match {
continue
}
} else {
- pkg = Target.Path + suffix
+ modPkg := targetPrefix + suffix
+ if _, ok := dirInModule(modPkg, targetPrefix, modRoot, true); ok {
+ pkg = modPkg
+ } else if !iterating {
+ ModRoot()
+ base.Errorf("go: directory %s is outside main module", base.ShortPath(dir))
+ }
}
} else if sub := search.InDir(dir, cfg.GOROOTsrc); sub != "" && sub != "." && !strings.Contains(sub, "@") {
pkg = filepath.ToSlash(sub)
@@ -134,16 +160,6 @@ func ImportPathsQuiet(patterns []string, tags map[string]bool) []*search.Match {
base.Errorf("go: directory %s outside available modules", base.ShortPath(dir))
}
}
- info, err := os.Stat(dir)
- if err != nil || !info.IsDir() {
- // If the directory is local but does not exist, don't return it
- // while loader is iterating, since this would trigger a fetch.
- // After loader is done iterating, we still need to return the
- // path, so that "go list -e" produces valid output.
- if iterating {
- continue
- }
- }
m.Pkgs = append(m.Pkgs, pkg)
}
@@ -247,6 +263,32 @@ func pathInModuleCache(dir string) string {
return ""
}
+var dirContainsPackageCache sync.Map // absolute dir → bool
+
+func dirContainsPackage(dir string) bool {
+ isPkg, ok := dirContainsPackageCache.Load(dir)
+ if !ok {
+ _, err := cfg.BuildContext.ImportDir(dir, 0)
+ if err == nil {
+ isPkg = true
+ } else {
+ if fi, statErr := os.Stat(dir); statErr != nil || !fi.IsDir() {
+ // A non-directory or inaccessible directory is not a Go package.
+ isPkg = false
+ } else if _, noGo := err.(*build.NoGoError); noGo {
+ // A directory containing no Go source files is not a Go package.
+ isPkg = false
+ } else {
+ // An error other than *build.NoGoError indicates that the package exists
+ // but has some other problem (such as a syntax error).
+ isPkg = true
+ }
+ }
+ isPkg, _ = dirContainsPackageCache.LoadOrStore(dir, isPkg)
+ }
+ return isPkg.(bool)
+}
+
// ImportFromFiles adds modules to the build list as needed
// to satisfy the imports in the named Go source files.
func ImportFromFiles(gofiles []string) {