/
search.go
137 lines (120 loc) · 3.19 KB
/
search.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package modload
import (
"fmt"
"os"
"path/filepath"
"strings"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/imports"
"cmd/go/internal/module"
"cmd/go/internal/search"
)
// matchPackages returns a list of packages in the list of modules
// matching the pattern. Package loading assumes the given set of tags.
func matchPackages(pattern string, tags map[string]bool, useStd bool, modules []module.Version) []string {
match := func(string) bool { return true }
treeCanMatch := func(string) bool { return true }
if !search.IsMetaPackage(pattern) {
match = search.MatchPattern(pattern)
treeCanMatch = search.TreeCanMatchPattern(pattern)
}
have := map[string]bool{
"builtin": true, // ignore pseudo-package that exists only for documentation
}
if !cfg.BuildContext.CgoEnabled {
have["runtime/cgo"] = true // ignore during walk
}
var pkgs []string
walkPkgs := func(root, importPathRoot string) {
root = filepath.Clean(root)
var cmd string
if root == cfg.GOROOTsrc {
cmd = filepath.Join(root, "cmd")
}
filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
if err != nil {
return nil
}
// Don't use GOROOT/src but do walk down into it.
if path == root && importPathRoot == "" {
return nil
}
// GOROOT/src/cmd makes use of GOROOT/src/cmd/vendor,
// which module mode can't deal with. Eventually we'll stop using
// that vendor directory, and then we can remove this exclusion.
// golang.org/issue/26924.
if path == cmd {
return filepath.SkipDir
}
want := true
// Avoid .foo, _foo, and testdata directory trees.
_, elem := filepath.Split(path)
if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
want = false
}
name := importPathRoot + filepath.ToSlash(path[len(root):])
if importPathRoot == "" {
name = name[1:] // cut leading slash
}
if !treeCanMatch(name) {
want = false
}
if !fi.IsDir() {
if fi.Mode()&os.ModeSymlink != 0 && want {
if target, err := os.Stat(path); err == nil && target.IsDir() {
fmt.Fprintf(os.Stderr, "warning: ignoring symlink %s\n", path)
}
}
return nil
}
if !want {
return filepath.SkipDir
}
if path != root {
if _, err := os.Stat(filepath.Join(path, "go.mod")); err == nil {
return filepath.SkipDir
}
}
if !have[name] {
have[name] = true
if match(name) {
if _, _, err := scanDir(path, tags); err != imports.ErrNoGo {
pkgs = append(pkgs, name)
}
}
}
if elem == "vendor" {
return filepath.SkipDir
}
return nil
})
}
if useStd {
walkPkgs(cfg.GOROOTsrc, "")
}
for _, mod := range modules {
if !treeCanMatch(mod.Path) {
continue
}
var root string
if mod.Version == "" {
if !HasModRoot() {
continue // If there is no main module, we can't search in it.
}
root = ModRoot()
} else {
var err error
root, _, err = fetch(mod)
if err != nil {
base.Errorf("go: %v", err)
continue
}
}
walkPkgs(root, mod.Path)
}
return pkgs
}