]> 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         "context"
9         "fmt"
10         "os"
11         "path/filepath"
12         "strings"
13
14         "cmd/go/internal/cfg"
15         "cmd/go/internal/imports"
16         "cmd/go/internal/search"
17
18         "golang.org/x/mod/module"
19 )
20
21 type stdFilter int8
22
23 const (
24         omitStd = stdFilter(iota)
25         includeStd
26 )
27
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) {
32         m.Pkgs = []string{}
33
34         isMatch := func(string) bool { return true }
35         treeCanMatch := func(string) bool { return true }
36         if !m.IsMeta() {
37                 isMatch = search.MatchPattern(m.Pattern())
38                 treeCanMatch = search.TreeCanMatchPattern(m.Pattern())
39         }
40
41         have := map[string]bool{
42                 "builtin": true, // ignore pseudo-package that exists only for documentation
43         }
44         if !cfg.BuildContext.CgoEnabled {
45                 have["runtime/cgo"] = true // ignore during walk
46         }
47
48         type pruning int8
49         const (
50                 pruneVendor = pruning(1 << iota)
51                 pruneGoMod
52         )
53
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 {
57                         if err != nil {
58                                 m.AddError(err)
59                                 return nil
60                         }
61
62                         want := true
63                         elem := ""
64
65                         // Don't use GOROOT/src but do walk down into it.
66                         if path == root {
67                                 if importPathRoot == "" {
68                                         return nil
69                                 }
70                         } else {
71                                 // Avoid .foo, _foo, and testdata subdirectory trees.
72                                 _, elem = filepath.Split(path)
73                                 if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
74                                         want = false
75                                 }
76                         }
77
78                         name := importPathRoot + filepath.ToSlash(path[len(root):])
79                         if importPathRoot == "" {
80                                 name = name[1:] // cut leading slash
81                         }
82                         if !treeCanMatch(name) {
83                                 want = false
84                         }
85
86                         if !fi.IsDir() {
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)
90                                         }
91                                 }
92                                 return nil
93                         }
94
95                         if !want {
96                                 return filepath.SkipDir
97                         }
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
102                                 }
103                         }
104
105                         if !have[name] {
106                                 have[name] = true
107                                 if isMatch(name) {
108                                         if _, _, err := scanDir(path, tags); err != imports.ErrNoGo {
109                                                 m.Pkgs = append(m.Pkgs, name)
110                                         }
111                                 }
112                         }
113
114                         if elem == "vendor" && (prune&pruneVendor != 0) {
115                                 return filepath.SkipDir
116                         }
117                         return nil
118                 })
119                 if err != nil {
120                         m.AddError(err)
121                 }
122         }
123
124         if filter == includeStd {
125                 walkPkgs(cfg.GOROOTsrc, "", pruneGoMod)
126                 if treeCanMatch("cmd") {
127                         walkPkgs(filepath.Join(cfg.GOROOTsrc, "cmd"), "cmd", pruneGoMod)
128                 }
129         }
130
131         if cfg.BuildMod == "vendor" {
132                 if HasModRoot() {
133                         walkPkgs(ModRoot(), targetPrefix, pruneGoMod|pruneVendor)
134                         walkPkgs(filepath.Join(ModRoot(), "vendor"), "", pruneVendor)
135                 }
136                 return
137         }
138
139         for _, mod := range modules {
140                 if !treeCanMatch(mod.Path) {
141                         continue
142                 }
143
144                 var (
145                         root, modPrefix string
146                         isLocal         bool
147                 )
148                 if mod == Target {
149                         if !HasModRoot() {
150                                 continue // If there is no main module, we can't search in it.
151                         }
152                         root = ModRoot()
153                         modPrefix = targetPrefix
154                         isLocal = true
155                 } else {
156                         var err error
157                         root, isLocal, err = fetch(ctx, mod)
158                         if err != nil {
159                                 m.AddError(err)
160                                 continue
161                         }
162                         modPrefix = mod.Path
163                 }
164
165                 prune := pruneVendor
166                 if isLocal {
167                         prune |= pruneGoMod
168                 }
169                 walkPkgs(root, modPrefix, prune)
170         }
171
172         return
173 }