Commit 14b5b4a2 authored by Bryan C. Mills's avatar Bryan C. Mills

cmd/go/internal/modload: fix boundary conditions in matchPackages

This makes the boundary logic of matchPackages consistent with
modload.dirInModule.

Previously, matchPackages always stopped at go.mod file, even within
the vendor tree. However, we do not guarantee that the vendor tree is
free of such files in general.

matchPackages also issued needless stat operations for modules in the
module cach, which we already know to be free of nested modules. On
systems with slow filesystems (such as macOS), those extra calls could
potentially slow package matching considerably.

Change-Id: I71979ab752e1d3971b370b37085d30502690413b
Reviewed-on: https://go-review.googlesource.com/c/go/+/172985
Run-TryBot: Bryan C. Mills <bcmills@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarJay Conrod <jayconrod@google.com>
parent dbe32284
...@@ -35,7 +35,13 @@ func matchPackages(pattern string, tags map[string]bool, useStd bool, modules [] ...@@ -35,7 +35,13 @@ func matchPackages(pattern string, tags map[string]bool, useStd bool, modules []
} }
var pkgs []string var pkgs []string
walkPkgs := func(root, importPathRoot string, includeVendor bool) { type pruning int8
const (
pruneVendor = pruning(1 << iota)
pruneGoMod
)
walkPkgs := func(root, importPathRoot string, prune pruning) {
root = filepath.Clean(root) root = filepath.Clean(root)
filepath.Walk(root, func(path string, fi os.FileInfo, err error) error { filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
if err != nil { if err != nil {
...@@ -75,7 +81,7 @@ func matchPackages(pattern string, tags map[string]bool, useStd bool, modules [] ...@@ -75,7 +81,7 @@ func matchPackages(pattern string, tags map[string]bool, useStd bool, modules []
return filepath.SkipDir return filepath.SkipDir
} }
// Stop at module boundaries. // Stop at module boundaries.
if path != root { if (prune&pruneGoMod != 0) && path != root {
if fi, err := os.Stat(filepath.Join(path, "go.mod")); err == nil && !fi.IsDir() { if fi, err := os.Stat(filepath.Join(path, "go.mod")); err == nil && !fi.IsDir() {
return filepath.SkipDir return filepath.SkipDir
} }
...@@ -90,7 +96,7 @@ func matchPackages(pattern string, tags map[string]bool, useStd bool, modules [] ...@@ -90,7 +96,7 @@ func matchPackages(pattern string, tags map[string]bool, useStd bool, modules []
} }
} }
if elem == "vendor" && !includeVendor { if elem == "vendor" && (prune&pruneVendor != 0) {
return filepath.SkipDir return filepath.SkipDir
} }
return nil return nil
...@@ -98,16 +104,16 @@ func matchPackages(pattern string, tags map[string]bool, useStd bool, modules [] ...@@ -98,16 +104,16 @@ func matchPackages(pattern string, tags map[string]bool, useStd bool, modules []
} }
if useStd { if useStd {
walkPkgs(cfg.GOROOTsrc, "", true) walkPkgs(cfg.GOROOTsrc, "", pruneGoMod)
if treeCanMatch("cmd") { if treeCanMatch("cmd") {
walkPkgs(filepath.Join(cfg.GOROOTsrc, "cmd"), "cmd", true) walkPkgs(filepath.Join(cfg.GOROOTsrc, "cmd"), "cmd", pruneGoMod)
} }
} }
if cfg.BuildMod == "vendor" { if cfg.BuildMod == "vendor" {
if HasModRoot() { if HasModRoot() {
walkPkgs(ModRoot(), targetPrefix, false) walkPkgs(ModRoot(), targetPrefix, pruneGoMod|pruneVendor)
walkPkgs(filepath.Join(ModRoot(), "vendor"), "", false) walkPkgs(filepath.Join(ModRoot(), "vendor"), "", pruneVendor)
} }
return pkgs return pkgs
} }
...@@ -116,23 +122,33 @@ func matchPackages(pattern string, tags map[string]bool, useStd bool, modules [] ...@@ -116,23 +122,33 @@ func matchPackages(pattern string, tags map[string]bool, useStd bool, modules []
if !treeCanMatch(mod.Path) { if !treeCanMatch(mod.Path) {
continue continue
} }
var root, modPrefix string
var (
root, modPrefix string
isLocal bool
)
if mod == Target { if mod == Target {
if !HasModRoot() { if !HasModRoot() {
continue // If there is no main module, we can't search in it. continue // If there is no main module, we can't search in it.
} }
root = ModRoot() root = ModRoot()
modPrefix = targetPrefix modPrefix = targetPrefix
isLocal = true
} else { } else {
var err error var err error
root, _, err = fetch(mod) root, isLocal, err = fetch(mod)
if err != nil { if err != nil {
base.Errorf("go: %v", err) base.Errorf("go: %v", err)
continue continue
} }
modPrefix = mod.Path modPrefix = mod.Path
} }
walkPkgs(root, modPrefix, false)
prune := pruneVendor
if isLocal {
prune |= pruneGoMod
}
walkPkgs(root, modPrefix, prune)
} }
return pkgs return pkgs
......
env GO111MODULE=on
go list -mod=vendor example.com/...
stdout ^example.com/x$
stdout ^example.com/x/y$
! stdout ^example.com/x/vendor
-- go.mod --
module example.com/m
-- vendor/modules.txt --
# example.com/x v0.0.0
example.com/x
# example.com/x/y v0.1.0
example.com/x/y
-- vendor/example.com/x/go.mod --
module example.com/x
-- vendor/example.com/x/x.go --
package x
-- vendor/example.com/x/y/go.mod --
module example.com/x/y
-- vendor/example.com/x/y/y.go --
package y
-- vendor/example.com/x/vendor/z/z.go --
package z
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment