]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/go/internal/modload/search.go
cmd/go/internal/modload: fix boundary conditions in matchPackages
[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/module"
17         "cmd/go/internal/search"
18 )
19
20 // matchPackages returns a list of packages in the list of modules
21 // matching the pattern. Package loading assumes the given set of tags.
22 func matchPackages(pattern string, tags map[string]bool, useStd bool, modules []module.Version) []string {
23         match := func(string) bool { return true }
24         treeCanMatch := func(string) bool { return true }
25         if !search.IsMetaPackage(pattern) {
26                 match = search.MatchPattern(pattern)
27                 treeCanMatch = search.TreeCanMatchPattern(pattern)
28         }
29
30         have := map[string]bool{
31                 "builtin": true, // ignore pseudo-package that exists only for documentation
32         }
33         if !cfg.BuildContext.CgoEnabled {
34                 have["runtime/cgo"] = true // ignore during walk
35         }
36         var pkgs []string
37
38         type pruning int8
39         const (
40                 pruneVendor = pruning(1 << iota)
41                 pruneGoMod
42         )
43
44         walkPkgs := func(root, importPathRoot string, prune pruning) {
45                 root = filepath.Clean(root)
46                 filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
47                         if err != nil {
48                                 return nil
49                         }
50
51                         // Don't use GOROOT/src but do walk down into it.
52                         if path == root && importPathRoot == "" {
53                                 return nil
54                         }
55
56                         want := true
57                         // Avoid .foo, _foo, and testdata directory trees.
58                         _, elem := filepath.Split(path)
59                         if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
60                                 want = false
61                         }
62
63                         name := importPathRoot + filepath.ToSlash(path[len(root):])
64                         if importPathRoot == "" {
65                                 name = name[1:] // cut leading slash
66                         }
67                         if !treeCanMatch(name) {
68                                 want = false
69                         }
70
71                         if !fi.IsDir() {
72                                 if fi.Mode()&os.ModeSymlink != 0 && want {
73                                         if target, err := os.Stat(path); err == nil && target.IsDir() {
74                                                 fmt.Fprintf(os.Stderr, "warning: ignoring symlink %s\n", path)
75                                         }
76                                 }
77                                 return nil
78                         }
79
80                         if !want {
81                                 return filepath.SkipDir
82                         }
83                         // Stop at module boundaries.
84                         if (prune&pruneGoMod != 0) && path != root {
85                                 if fi, err := os.Stat(filepath.Join(path, "go.mod")); err == nil && !fi.IsDir() {
86                                         return filepath.SkipDir
87                                 }
88                         }
89
90                         if !have[name] {
91                                 have[name] = true
92                                 if match(name) {
93                                         if _, _, err := scanDir(path, tags); err != imports.ErrNoGo {
94                                                 pkgs = append(pkgs, name)
95                                         }
96                                 }
97                         }
98
99                         if elem == "vendor" && (prune&pruneVendor != 0) {
100                                 return filepath.SkipDir
101                         }
102                         return nil
103                 })
104         }
105
106         if useStd {
107                 walkPkgs(cfg.GOROOTsrc, "", pruneGoMod)
108                 if treeCanMatch("cmd") {
109                         walkPkgs(filepath.Join(cfg.GOROOTsrc, "cmd"), "cmd", pruneGoMod)
110                 }
111         }
112
113         if cfg.BuildMod == "vendor" {
114                 if HasModRoot() {
115                         walkPkgs(ModRoot(), targetPrefix, pruneGoMod|pruneVendor)
116                         walkPkgs(filepath.Join(ModRoot(), "vendor"), "", pruneVendor)
117                 }
118                 return pkgs
119         }
120
121         for _, mod := range modules {
122                 if !treeCanMatch(mod.Path) {
123                         continue
124                 }
125
126                 var (
127                         root, modPrefix string
128                         isLocal         bool
129                 )
130                 if mod == Target {
131                         if !HasModRoot() {
132                                 continue // If there is no main module, we can't search in it.
133                         }
134                         root = ModRoot()
135                         modPrefix = targetPrefix
136                         isLocal = true
137                 } else {
138                         var err error
139                         root, isLocal, err = fetch(mod)
140                         if err != nil {
141                                 base.Errorf("go: %v", err)
142                                 continue
143                         }
144                         modPrefix = mod.Path
145                 }
146
147                 prune := pruneVendor
148                 if isLocal {
149                         prune |= pruneGoMod
150                 }
151                 walkPkgs(root, modPrefix, prune)
152         }
153
154         return pkgs
155 }