1 // Copyright 2018 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
15 "cmd/go/internal/imports"
16 "cmd/go/internal/search"
18 "golang.org/x/mod/module"
24 omitStd = stdFilter(iota)
28 // matchPackages is like m.MatchPackages, but uses a local variable (rather than
29 // a global) for tags, can include or exclude packages in the standard library,
30 // and is restricted to the given list of modules.
31 func matchPackages(ctx context.Context, m *search.Match, tags map[string]bool, filter stdFilter, modules []module.Version) {
34 isMatch := func(string) bool { return true }
35 treeCanMatch := func(string) bool { return true }
37 isMatch = search.MatchPattern(m.Pattern())
38 treeCanMatch = search.TreeCanMatchPattern(m.Pattern())
41 have := map[string]bool{
42 "builtin": true, // ignore pseudo-package that exists only for documentation
44 if !cfg.BuildContext.CgoEnabled {
45 have["runtime/cgo"] = true // ignore during walk
50 pruneVendor = pruning(1 << iota)
54 walkPkgs := func(root, importPathRoot string, prune pruning) {
55 root = filepath.Clean(root)
56 err := filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
65 // Don't use GOROOT/src but do walk down into it.
67 if importPathRoot == "" {
71 // Avoid .foo, _foo, and testdata subdirectory trees.
72 _, elem = filepath.Split(path)
73 if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
78 name := importPathRoot + filepath.ToSlash(path[len(root):])
79 if importPathRoot == "" {
80 name = name[1:] // cut leading slash
82 if !treeCanMatch(name) {
87 if fi.Mode()&os.ModeSymlink != 0 && want {
88 if target, err := os.Stat(path); err == nil && target.IsDir() {
89 fmt.Fprintf(os.Stderr, "warning: ignoring symlink %s\n", path)
96 return filepath.SkipDir
98 // Stop at module boundaries.
99 if (prune&pruneGoMod != 0) && path != root {
100 if fi, err := os.Stat(filepath.Join(path, "go.mod")); err == nil && !fi.IsDir() {
101 return filepath.SkipDir
108 if _, _, err := scanDir(path, tags); err != imports.ErrNoGo {
109 m.Pkgs = append(m.Pkgs, name)
114 if elem == "vendor" && (prune&pruneVendor != 0) {
115 return filepath.SkipDir
124 if filter == includeStd {
125 walkPkgs(cfg.GOROOTsrc, "", pruneGoMod)
126 if treeCanMatch("cmd") {
127 walkPkgs(filepath.Join(cfg.GOROOTsrc, "cmd"), "cmd", pruneGoMod)
131 if cfg.BuildMod == "vendor" {
133 walkPkgs(ModRoot(), targetPrefix, pruneGoMod|pruneVendor)
134 walkPkgs(filepath.Join(ModRoot(), "vendor"), "", pruneVendor)
139 for _, mod := range modules {
140 if !treeCanMatch(mod.Path) {
145 root, modPrefix string
150 continue // If there is no main module, we can't search in it.
153 modPrefix = targetPrefix
157 root, isLocal, err = fetch(ctx, mod)
169 walkPkgs(root, modPrefix, prune)