]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/go/internal/modload/search.go
[dev.boringcrypto] all: merge master into dev.boringcrypto
[gostls13.git] / src / cmd / go / internal / modload / search.go
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.
4
5 package modload
6
7 import (
8         "fmt"
9         "os"
10         "path/filepath"
11         "strings"
12
13         "cmd/go/internal/cfg"
14         "cmd/go/internal/imports"
15         "cmd/go/internal/search"
16
17         "golang.org/x/mod/module"
18 )
19
20 type stdFilter int8
21
22 const (
23         omitStd = stdFilter(iota)
24         includeStd
25 )
26
27 // matchPackages is like m.MatchPackages, but uses a local variable (rather than
28 // a global) for tags, can include or exclude packages in the standard library,
29 // and is restricted to the given list of modules.
30 func matchPackages(m *search.Match, tags map[string]bool, filter stdFilter, modules []module.Version) {
31         m.Pkgs = []string{}
32
33         isMatch := func(string) bool { return true }
34         treeCanMatch := func(string) bool { return true }
35         if !m.IsMeta() {
36                 isMatch = search.MatchPattern(m.Pattern())
37                 treeCanMatch = search.TreeCanMatchPattern(m.Pattern())
38         }
39
40         have := map[string]bool{
41                 "builtin": true, // ignore pseudo-package that exists only for documentation
42         }
43         if !cfg.BuildContext.CgoEnabled {
44                 have["runtime/cgo"] = true // ignore during walk
45         }
46
47         type pruning int8
48         const (
49                 pruneVendor = pruning(1 << iota)
50                 pruneGoMod
51         )
52
53         walkPkgs := func(root, importPathRoot string, prune pruning) {
54                 root = filepath.Clean(root)
55                 err := filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
56                         if err != nil {
57                                 m.AddError(err)
58                                 return nil
59                         }
60
61                         want := true
62                         elem := ""
63
64                         // Don't use GOROOT/src but do walk down into it.
65                         if path == root {
66                                 if importPathRoot == "" {
67                                         return nil
68                                 }
69                         } else {
70                                 // Avoid .foo, _foo, and testdata subdirectory trees.
71                                 _, elem = filepath.Split(path)
72                                 if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
73                                         want = false
74                                 }
75                         }
76
77                         name := importPathRoot + filepath.ToSlash(path[len(root):])
78                         if importPathRoot == "" {
79                                 name = name[1:] // cut leading slash
80                         }
81                         if !treeCanMatch(name) {
82                                 want = false
83                         }
84
85                         if !fi.IsDir() {
86                                 if fi.Mode()&os.ModeSymlink != 0 && want {
87                                         if target, err := os.Stat(path); err == nil && target.IsDir() {
88                                                 fmt.Fprintf(os.Stderr, "warning: ignoring symlink %s\n", path)
89                                         }
90                                 }
91                                 return nil
92                         }
93
94                         if !want {
95                                 return filepath.SkipDir
96                         }
97                         // Stop at module boundaries.
98                         if (prune&pruneGoMod != 0) && path != root {
99                                 if fi, err := os.Stat(filepath.Join(path, "go.mod")); err == nil && !fi.IsDir() {
100                                         return filepath.SkipDir
101                                 }
102                         }
103
104                         if !have[name] {
105                                 have[name] = true
106                                 if isMatch(name) {
107                                         if _, _, err := scanDir(path, tags); err != imports.ErrNoGo {
108                                                 m.Pkgs = append(m.Pkgs, name)
109                                         }
110                                 }
111                         }
112
113                         if elem == "vendor" && (prune&pruneVendor != 0) {
114                                 return filepath.SkipDir
115                         }
116                         return nil
117                 })
118                 if err != nil {
119                         m.AddError(err)
120                 }
121         }
122
123         if filter == includeStd {
124                 walkPkgs(cfg.GOROOTsrc, "", pruneGoMod)
125                 if treeCanMatch("cmd") {
126                         walkPkgs(filepath.Join(cfg.GOROOTsrc, "cmd"), "cmd", pruneGoMod)
127                 }
128         }
129
130         if cfg.BuildMod == "vendor" {
131                 if HasModRoot() {
132                         walkPkgs(ModRoot(), targetPrefix, pruneGoMod|pruneVendor)
133                         walkPkgs(filepath.Join(ModRoot(), "vendor"), "", pruneVendor)
134                 }
135                 return
136         }
137
138         for _, mod := range modules {
139                 if !treeCanMatch(mod.Path) {
140                         continue
141                 }
142
143                 var (
144                         root, modPrefix string
145                         isLocal         bool
146                 )
147                 if mod == Target {
148                         if !HasModRoot() {
149                                 continue // If there is no main module, we can't search in it.
150                         }
151                         root = ModRoot()
152                         modPrefix = targetPrefix
153                         isLocal = true
154                 } else {
155                         var err error
156                         root, isLocal, err = fetch(mod)
157                         if err != nil {
158                                 m.AddError(err)
159                                 continue
160                         }
161                         modPrefix = mod.Path
162                 }
163
164                 prune := pruneVendor
165                 if isLocal {
166                         prune |= pruneGoMod
167                 }
168                 walkPkgs(root, modPrefix, prune)
169         }
170
171         return
172 }