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.
13 "cmd/go/internal/base"
15 "cmd/go/internal/imports"
16 "cmd/go/internal/search"
18 "golang.org/x/mod/module"
21 // matchPackages returns a list of packages in the list of modules
22 // matching the pattern. Package loading assumes the given set of tags.
23 func matchPackages(pattern string, tags map[string]bool, useStd bool, modules []module.Version) []string {
24 match := func(string) bool { return true }
25 treeCanMatch := func(string) bool { return true }
26 if !search.IsMetaPackage(pattern) {
27 match = search.MatchPattern(pattern)
28 treeCanMatch = search.TreeCanMatchPattern(pattern)
31 have := map[string]bool{
32 "builtin": true, // ignore pseudo-package that exists only for documentation
34 if !cfg.BuildContext.CgoEnabled {
35 have["runtime/cgo"] = true // ignore during walk
41 pruneVendor = pruning(1 << iota)
45 walkPkgs := func(root, importPathRoot string, prune pruning) {
46 root = filepath.Clean(root)
47 filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
55 // Don't use GOROOT/src but do walk down into it.
57 if importPathRoot == "" {
61 // Avoid .foo, _foo, and testdata subdirectory trees.
62 _, elem = filepath.Split(path)
63 if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
68 name := importPathRoot + filepath.ToSlash(path[len(root):])
69 if importPathRoot == "" {
70 name = name[1:] // cut leading slash
72 if !treeCanMatch(name) {
77 if fi.Mode()&os.ModeSymlink != 0 && want {
78 if target, err := os.Stat(path); err == nil && target.IsDir() {
79 fmt.Fprintf(os.Stderr, "warning: ignoring symlink %s\n", path)
86 return filepath.SkipDir
88 // Stop at module boundaries.
89 if (prune&pruneGoMod != 0) && path != root {
90 if fi, err := os.Stat(filepath.Join(path, "go.mod")); err == nil && !fi.IsDir() {
91 return filepath.SkipDir
98 if _, _, err := scanDir(path, tags); err != imports.ErrNoGo {
99 pkgs = append(pkgs, name)
104 if elem == "vendor" && (prune&pruneVendor != 0) {
105 return filepath.SkipDir
112 walkPkgs(cfg.GOROOTsrc, "", pruneGoMod)
113 if treeCanMatch("cmd") {
114 walkPkgs(filepath.Join(cfg.GOROOTsrc, "cmd"), "cmd", pruneGoMod)
118 if cfg.BuildMod == "vendor" {
120 walkPkgs(ModRoot(), targetPrefix, pruneGoMod|pruneVendor)
121 walkPkgs(filepath.Join(ModRoot(), "vendor"), "", pruneVendor)
126 for _, mod := range modules {
127 if !treeCanMatch(mod.Path) {
132 root, modPrefix string
137 continue // If there is no main module, we can't search in it.
140 modPrefix = targetPrefix
144 root, isLocal, err = fetch(mod)
146 base.Errorf("go: %v", err)
156 walkPkgs(root, modPrefix, prune)