]> 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/base"
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 // 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)
29         }
30
31         have := map[string]bool{
32                 "builtin": true, // ignore pseudo-package that exists only for documentation
33         }
34         if !cfg.BuildContext.CgoEnabled {
35                 have["runtime/cgo"] = true // ignore during walk
36         }
37         var pkgs []string
38
39         type pruning int8
40         const (
41                 pruneVendor = pruning(1 << iota)
42                 pruneGoMod
43         )
44
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 {
48                         if err != nil {
49                                 return nil
50                         }
51
52                         want := true
53                         elem := ""
54
55                         // Don't use GOROOT/src but do walk down into it.
56                         if path == root {
57                                 if importPathRoot == "" {
58                                         return nil
59                                 }
60                         } else {
61                                 // Avoid .foo, _foo, and testdata subdirectory trees.
62                                 _, elem = filepath.Split(path)
63                                 if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
64                                         want = false
65                                 }
66                         }
67
68                         name := importPathRoot + filepath.ToSlash(path[len(root):])
69                         if importPathRoot == "" {
70                                 name = name[1:] // cut leading slash
71                         }
72                         if !treeCanMatch(name) {
73                                 want = false
74                         }
75
76                         if !fi.IsDir() {
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)
80                                         }
81                                 }
82                                 return nil
83                         }
84
85                         if !want {
86                                 return filepath.SkipDir
87                         }
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
92                                 }
93                         }
94
95                         if !have[name] {
96                                 have[name] = true
97                                 if match(name) {
98                                         if _, _, err := scanDir(path, tags); err != imports.ErrNoGo {
99                                                 pkgs = append(pkgs, name)
100                                         }
101                                 }
102                         }
103
104                         if elem == "vendor" && (prune&pruneVendor != 0) {
105                                 return filepath.SkipDir
106                         }
107                         return nil
108                 })
109         }
110
111         if useStd {
112                 walkPkgs(cfg.GOROOTsrc, "", pruneGoMod)
113                 if treeCanMatch("cmd") {
114                         walkPkgs(filepath.Join(cfg.GOROOTsrc, "cmd"), "cmd", pruneGoMod)
115                 }
116         }
117
118         if cfg.BuildMod == "vendor" {
119                 if HasModRoot() {
120                         walkPkgs(ModRoot(), targetPrefix, pruneGoMod|pruneVendor)
121                         walkPkgs(filepath.Join(ModRoot(), "vendor"), "", pruneVendor)
122                 }
123                 return pkgs
124         }
125
126         for _, mod := range modules {
127                 if !treeCanMatch(mod.Path) {
128                         continue
129                 }
130
131                 var (
132                         root, modPrefix string
133                         isLocal         bool
134                 )
135                 if mod == Target {
136                         if !HasModRoot() {
137                                 continue // If there is no main module, we can't search in it.
138                         }
139                         root = ModRoot()
140                         modPrefix = targetPrefix
141                         isLocal = true
142                 } else {
143                         var err error
144                         root, isLocal, err = fetch(mod)
145                         if err != nil {
146                                 base.Errorf("go: %v", err)
147                                 continue
148                         }
149                         modPrefix = mod.Path
150                 }
151
152                 prune := pruneVendor
153                 if isLocal {
154                         prune |= pruneGoMod
155                 }
156                 walkPkgs(root, modPrefix, prune)
157         }
158
159         return pkgs
160 }