"os"
"path"
"path/filepath"
+ "runtime"
+ "sort"
"strings"
+ "sync"
"cmd/go/internal/cfg"
"cmd/go/internal/fsys"
"cmd/go/internal/imports"
"cmd/go/internal/modindex"
+ "cmd/go/internal/par"
"cmd/go/internal/search"
"golang.org/x/mod/module"
treeCanMatch = search.TreeCanMatchPattern(m.Pattern())
}
+ var mu sync.Mutex
have := map[string]bool{
"builtin": true, // ignore pseudo-package that exists only for documentation
}
+ addPkg := func(p string) {
+ mu.Lock()
+ m.Pkgs = append(m.Pkgs, p)
+ mu.Unlock()
+ }
if !cfg.BuildContext.CgoEnabled {
have["runtime/cgo"] = true // ignore during walk
}
pruneGoMod
)
+ q := par.NewQueue(runtime.GOMAXPROCS(0))
+
walkPkgs := func(root, importPathRoot string, prune pruning) {
root = filepath.Clean(root)
err := fsys.Walk(root, func(path string, fi fs.FileInfo, err error) error {
if !have[name] {
have[name] = true
if isMatch(name) {
- if _, _, err := scanDir(root, path, tags); err != imports.ErrNoGo {
- m.Pkgs = append(m.Pkgs, name)
- }
+ q.Add(func() {
+ if _, _, err := scanDir(root, path, tags); err != imports.ErrNoGo {
+ addPkg(name)
+ }
+ })
}
}
}
}
+ // Wait for all in-flight operations to complete before returning.
+ defer func() {
+ <-q.Idle()
+ sort.Strings(m.Pkgs) // sort everything we added for determinism
+ }()
+
if filter == includeStd {
walkPkgs(cfg.GOROOTsrc, "", pruneGoMod)
if treeCanMatch("cmd") {
modPrefix = mod.Path
}
if mi, err := modindex.Get(root); err == nil {
- walkFromIndex(ctx, m, tags, root, mi, have, modPrefix)
+ walkFromIndex(mi, modPrefix, isMatch, treeCanMatch, tags, have, addPkg)
continue
} else if !errors.Is(err, modindex.ErrNotIndexed) {
m.AddError(err)
// walkFromIndex matches packages in a module using the module index. modroot
// is the module's root directory on disk, index is the ModuleIndex for the
// module, and importPathRoot is the module's path prefix.
-func walkFromIndex(ctx context.Context, m *search.Match, tags map[string]bool, modroot string, index *modindex.ModuleIndex, have map[string]bool, importPathRoot string) {
- isMatch := func(string) bool { return true }
- treeCanMatch := func(string) bool { return true }
- if !m.IsMeta() {
- isMatch = search.MatchPattern(m.Pattern())
- treeCanMatch = search.TreeCanMatchPattern(m.Pattern())
- }
+func walkFromIndex(index *modindex.ModuleIndex, importPathRoot string, isMatch, treeCanMatch func(string) bool, tags, have map[string]bool, addPkg func(string)) {
loopPackages:
for _, reldir := range index.Packages() {
// Avoid .foo, _foo, and testdata subdirectory trees.
have[name] = true
if isMatch(name) {
if _, _, err := index.ScanDir(reldir, tags); err != imports.ErrNoGo {
- m.Pkgs = append(m.Pkgs, name)
+ addPkg(name)
}
}
}