import (
"context"
+ "errors"
"fmt"
"io/fs"
"os"
+ "path"
"path/filepath"
"strings"
"cmd/go/internal/cfg"
"cmd/go/internal/fsys"
"cmd/go/internal/imports"
+ "cmd/go/internal/modindex"
"cmd/go/internal/search"
"golang.org/x/mod/module"
}
modPrefix = mod.Path
}
+ if mi, err := modindex.Get(root); err == nil {
+ walkFromIndex(ctx, m, tags, root, mi, have, modPrefix)
+ continue
+ } else if !errors.Is(err, modindex.ErrNotIndexed) {
+ m.AddError(err)
+ }
prune := pruneVendor
if isLocal {
return
}
+// 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())
+ }
+loopPackages:
+ for _, reldir := range index.Packages() {
+ // Avoid .foo, _foo, and testdata subdirectory trees.
+ p := reldir
+ for {
+ elem, rest, found := strings.Cut(p, string(filepath.Separator))
+ if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
+ continue loopPackages
+ }
+ if found && elem == "vendor" {
+ // Ignore this path if it contains the element "vendor" anywhere
+ // except for the last element (packages named vendor are allowed
+ // for historical reasons). Note that found is true when this
+ // isn't the last path element.
+ continue loopPackages
+ }
+ if !found {
+ // Didn't find the separator, so we're considering the last element.
+ break
+ }
+ p = rest
+ }
+
+ // Don't use GOROOT/src.
+ if reldir == "" && importPathRoot == "" {
+ continue
+ }
+
+ name := path.Join(importPathRoot, filepath.ToSlash(reldir))
+ if !treeCanMatch(name) {
+ continue
+ }
+
+ if !have[name] {
+ have[name] = true
+ if isMatch(name) {
+ if _, _, err := index.ScanDir(reldir, tags); err != imports.ErrNoGo {
+ m.Pkgs = append(m.Pkgs, name)
+ }
+ }
+ }
+ }
+}
+
// MatchInModule identifies the packages matching the given pattern within the
// given module version, which does not need to be in the build list or module
// requirement graph.