Update upstream source from tag 'upstream/1.0.0'
Update to upstream version '1.0.0'
with Debian dir 719aaffd5790890bd5f60dead69fd9d6a217d48f
Shengjing Zhu
3 years ago
0 | sudo: false | |
0 | 1 | language: go |
1 | sudo: false | |
2 | ||
2 | go: | |
3 | - 1.2 | |
4 | - 1.3 | |
5 | - 1.4 | |
6 | - 1.5 | |
7 | - 1.6 | |
8 | - 1.7 | |
9 | - 1.8 | |
10 | - 1.9 | |
11 | - master | |
3 | 12 | matrix: |
4 | include: | |
5 | - go: 1.2 | |
6 | - go: 1.3 | |
7 | - go: 1.4 | |
8 | - go: 1.5 | |
9 | - go: 1.6 | |
10 | - go: tip | |
11 | ||
13 | allow_failures: | |
14 | - go: master | |
15 | fast_finish: true | |
12 | 16 | install: |
13 | - # Skip | |
14 | ||
17 | - # Skip. | |
15 | 18 | script: |
16 | 19 | - go get -t -v ./... |
17 | 20 | - diff -u <(echo -n) <(gofmt -d .) |
0 | // +build go1.6,!go1.9 | |
1 | ||
2 | package gotool | |
3 | ||
4 | import ( | |
5 | "go/build" | |
6 | "path/filepath" | |
7 | "runtime" | |
8 | ) | |
9 | ||
10 | var gorootSrc = filepath.Join(runtime.GOROOT(), "src") | |
11 | ||
12 | func shouldIgnoreImport(p *build.Package) bool { | |
13 | return p == nil || len(p.InvalidGoFiles) == 0 | |
14 | } |
0 | // +build go1.6 | |
1 | ||
2 | package gotool | |
3 | ||
4 | import ( | |
5 | "go/build" | |
6 | "path/filepath" | |
7 | "runtime" | |
8 | ) | |
9 | ||
10 | var gorootSrc = filepath.Join(runtime.GOROOT(), "src") | |
11 | ||
12 | func shouldIgnoreImport(p *build.Package) bool { | |
13 | return p == nil || len(p.InvalidGoFiles) == 0 | |
14 | } |
0 | // Copyright 2012 The Go Authors. All rights reserved. | |
1 | // Use of this source code is governed by a BSD-style | |
2 | // license that can be found in the LICENSE file. | |
3 | ||
4 | // +build go1.9 | |
5 | ||
6 | package load | |
7 | ||
8 | import ( | |
9 | "strings" | |
10 | "testing" | |
11 | ) | |
12 | ||
13 | var matchPatternTests = ` | |
14 | pattern ... | |
15 | match foo | |
16 | ||
17 | pattern net | |
18 | match net | |
19 | not net/http | |
20 | ||
21 | pattern net/http | |
22 | match net/http | |
23 | not net | |
24 | ||
25 | pattern net... | |
26 | match net net/http netchan | |
27 | not not/http not/net/http | |
28 | ||
29 | # Special cases. Quoting docs: | |
30 | ||
31 | # First, /... at the end of the pattern can match an empty string, | |
32 | # so that net/... matches both net and packages in its subdirectories, like net/http. | |
33 | pattern net/... | |
34 | match net net/http | |
35 | not not/http not/net/http netchan | |
36 | ||
37 | # Second, any slash-separted pattern element containing a wildcard never | |
38 | # participates in a match of the "vendor" element in the path of a vendored | |
39 | # package, so that ./... does not match packages in subdirectories of | |
40 | # ./vendor or ./mycode/vendor, but ./vendor/... and ./mycode/vendor/... do. | |
41 | # Note, however, that a directory named vendor that itself contains code | |
42 | # is not a vendored package: cmd/vendor would be a command named vendor, | |
43 | # and the pattern cmd/... matches it. | |
44 | pattern ./... | |
45 | match ./vendor ./mycode/vendor | |
46 | not ./vendor/foo ./mycode/vendor/foo | |
47 | ||
48 | pattern ./vendor/... | |
49 | match ./vendor/foo ./vendor/foo/vendor | |
50 | not ./vendor/foo/vendor/bar | |
51 | ||
52 | pattern mycode/vendor/... | |
53 | match mycode/vendor mycode/vendor/foo mycode/vendor/foo/vendor | |
54 | not mycode/vendor/foo/vendor/bar | |
55 | ||
56 | pattern x/vendor/y | |
57 | match x/vendor/y | |
58 | not x/vendor | |
59 | ||
60 | pattern x/vendor/y/... | |
61 | match x/vendor/y x/vendor/y/z x/vendor/y/vendor x/vendor/y/z/vendor | |
62 | not x/vendor/y/vendor/z | |
63 | ||
64 | pattern .../vendor/... | |
65 | match x/vendor/y x/vendor/y/z x/vendor/y/vendor x/vendor/y/z/vendor | |
66 | ` | |
67 | ||
68 | func TestMatchPattern(t *testing.T) { | |
69 | testPatterns(t, "matchPattern", matchPatternTests, func(pattern, name string) bool { | |
70 | return matchPattern(pattern)(name) | |
71 | }) | |
72 | } | |
73 | ||
74 | var treeCanMatchPatternTests = ` | |
75 | pattern ... | |
76 | match foo | |
77 | ||
78 | pattern net | |
79 | match net | |
80 | not net/http | |
81 | ||
82 | pattern net/http | |
83 | match net net/http | |
84 | ||
85 | pattern net... | |
86 | match net netchan net/http | |
87 | not not/http not/net/http | |
88 | ||
89 | pattern net/... | |
90 | match net net/http | |
91 | not not/http netchan | |
92 | ||
93 | pattern abc.../def | |
94 | match abcxyz | |
95 | not xyzabc | |
96 | ||
97 | pattern x/y/z/... | |
98 | match x x/y x/y/z x/y/z/w | |
99 | ||
100 | pattern x/y/z | |
101 | match x x/y x/y/z | |
102 | not x/y/z/w | |
103 | ||
104 | pattern x/.../y/z | |
105 | match x/a/b/c | |
106 | not y/x/a/b/c | |
107 | ` | |
108 | ||
109 | func TestTreeCanMatchPattern(t *testing.T) { | |
110 | testPatterns(t, "treeCanMatchPattern", treeCanMatchPatternTests, func(pattern, name string) bool { | |
111 | return treeCanMatchPattern(pattern)(name) | |
112 | }) | |
113 | } | |
114 | ||
115 | var hasPathPrefixTests = []stringPairTest{ | |
116 | {"abc", "a", false}, | |
117 | {"a/bc", "a", true}, | |
118 | {"a", "a", true}, | |
119 | {"a/bc", "a/", true}, | |
120 | } | |
121 | ||
122 | func TestHasPathPrefix(t *testing.T) { | |
123 | testStringPairs(t, "hasPathPrefix", hasPathPrefixTests, hasPathPrefix) | |
124 | } | |
125 | ||
126 | type stringPairTest struct { | |
127 | in1 string | |
128 | in2 string | |
129 | out bool | |
130 | } | |
131 | ||
132 | func testStringPairs(t *testing.T, name string, tests []stringPairTest, f func(string, string) bool) { | |
133 | for _, tt := range tests { | |
134 | if out := f(tt.in1, tt.in2); out != tt.out { | |
135 | t.Errorf("%s(%q, %q) = %v, want %v", name, tt.in1, tt.in2, out, tt.out) | |
136 | } | |
137 | } | |
138 | } | |
139 | ||
140 | func testPatterns(t *testing.T, name, tests string, fn func(string, string) bool) { | |
141 | var patterns []string | |
142 | for _, line := range strings.Split(tests, "\n") { | |
143 | if i := strings.Index(line, "#"); i >= 0 { | |
144 | line = line[:i] | |
145 | } | |
146 | f := strings.Fields(line) | |
147 | if len(f) == 0 { | |
148 | continue | |
149 | } | |
150 | switch f[0] { | |
151 | default: | |
152 | t.Fatalf("unknown directive %q", f[0]) | |
153 | case "pattern": | |
154 | patterns = f[1:] | |
155 | case "match", "not": | |
156 | want := f[0] == "match" | |
157 | for _, pattern := range patterns { | |
158 | for _, in := range f[1:] { | |
159 | if fn(pattern, in) != want { | |
160 | t.Errorf("%s(%q, %q) = %v, want %v", name, pattern, in, !want, want) | |
161 | } | |
162 | } | |
163 | } | |
164 | } | |
165 | } | |
166 | } |
0 | // Copyright 2017 The Go Authors. All rights reserved. | |
1 | // Use of this source code is governed by a BSD-style | |
2 | // license that can be found in the LICENSE file. | |
3 | ||
4 | // +build go1.9 | |
5 | ||
6 | package load | |
7 | ||
8 | import ( | |
9 | "strings" | |
10 | ) | |
11 | ||
12 | // hasPathPrefix reports whether the path s begins with the | |
13 | // elements in prefix. | |
14 | func hasPathPrefix(s, prefix string) bool { | |
15 | switch { | |
16 | default: | |
17 | return false | |
18 | case len(s) == len(prefix): | |
19 | return s == prefix | |
20 | case len(s) > len(prefix): | |
21 | if prefix != "" && prefix[len(prefix)-1] == '/' { | |
22 | return strings.HasPrefix(s, prefix) | |
23 | } | |
24 | return s[len(prefix)] == '/' && s[:len(prefix)] == prefix | |
25 | } | |
26 | } |
0 | // Copyright 2011 The Go Authors. All rights reserved. | |
1 | // Use of this source code is governed by a BSD-style | |
2 | // license that can be found in the LICENSE file. | |
3 | ||
4 | // +build go1.9 | |
5 | ||
6 | // Package load loads packages. | |
7 | package load | |
8 | ||
9 | import ( | |
10 | "strings" | |
11 | ) | |
12 | ||
13 | // isStandardImportPath reports whether $GOROOT/src/path should be considered | |
14 | // part of the standard distribution. For historical reasons we allow people to add | |
15 | // their own code to $GOROOT instead of using $GOPATH, but we assume that | |
16 | // code will start with a domain name (dot in the first element). | |
17 | func isStandardImportPath(path string) bool { | |
18 | i := strings.Index(path, "/") | |
19 | if i < 0 { | |
20 | i = len(path) | |
21 | } | |
22 | elem := path[:i] | |
23 | return !strings.Contains(elem, ".") | |
24 | } |
0 | // Copyright 2017 The Go Authors. All rights reserved. | |
1 | // Use of this source code is governed by a BSD-style | |
2 | // license that can be found in the LICENSE file. | |
3 | ||
4 | // +build go1.9 | |
5 | ||
6 | package load | |
7 | ||
8 | import ( | |
9 | "fmt" | |
10 | "go/build" | |
11 | "log" | |
12 | "os" | |
13 | "path" | |
14 | "path/filepath" | |
15 | "regexp" | |
16 | "strings" | |
17 | ) | |
18 | ||
19 | // Context specifies values for operation of ImportPaths that would | |
20 | // otherwise come from cmd/go/internal/cfg package. | |
21 | // | |
22 | // This is a construct added for gotool purposes and doesn't have | |
23 | // an equivalent upstream in cmd/go. | |
24 | type Context struct { | |
25 | // BuildContext is the build context to use. | |
26 | BuildContext build.Context | |
27 | ||
28 | // GOROOTsrc is the location of the src directory in GOROOT. | |
29 | // At this time, it's used only in MatchPackages to skip | |
30 | // GOOROOT/src entry from BuildContext.SrcDirs output. | |
31 | GOROOTsrc string | |
32 | } | |
33 | ||
34 | // allPackages returns all the packages that can be found | |
35 | // under the $GOPATH directories and $GOROOT matching pattern. | |
36 | // The pattern is either "all" (all packages), "std" (standard packages), | |
37 | // "cmd" (standard commands), or a path including "...". | |
38 | func (c *Context) allPackages(pattern string) []string { | |
39 | pkgs := c.MatchPackages(pattern) | |
40 | if len(pkgs) == 0 { | |
41 | fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern) | |
42 | } | |
43 | return pkgs | |
44 | } | |
45 | ||
46 | // allPackagesInFS is like allPackages but is passed a pattern | |
47 | // beginning ./ or ../, meaning it should scan the tree rooted | |
48 | // at the given directory. There are ... in the pattern too. | |
49 | func (c *Context) allPackagesInFS(pattern string) []string { | |
50 | pkgs := c.MatchPackagesInFS(pattern) | |
51 | if len(pkgs) == 0 { | |
52 | fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern) | |
53 | } | |
54 | return pkgs | |
55 | } | |
56 | ||
57 | // MatchPackages returns a list of package paths matching pattern | |
58 | // (see go help packages for pattern syntax). | |
59 | func (c *Context) MatchPackages(pattern string) []string { | |
60 | match := func(string) bool { return true } | |
61 | treeCanMatch := func(string) bool { return true } | |
62 | if !IsMetaPackage(pattern) { | |
63 | match = matchPattern(pattern) | |
64 | treeCanMatch = treeCanMatchPattern(pattern) | |
65 | } | |
66 | ||
67 | have := map[string]bool{ | |
68 | "builtin": true, // ignore pseudo-package that exists only for documentation | |
69 | } | |
70 | if !c.BuildContext.CgoEnabled { | |
71 | have["runtime/cgo"] = true // ignore during walk | |
72 | } | |
73 | var pkgs []string | |
74 | ||
75 | for _, src := range c.BuildContext.SrcDirs() { | |
76 | if (pattern == "std" || pattern == "cmd") && src != c.GOROOTsrc { | |
77 | continue | |
78 | } | |
79 | src = filepath.Clean(src) + string(filepath.Separator) | |
80 | root := src | |
81 | if pattern == "cmd" { | |
82 | root += "cmd" + string(filepath.Separator) | |
83 | } | |
84 | filepath.Walk(root, func(path string, fi os.FileInfo, err error) error { | |
85 | if err != nil || path == src { | |
86 | return nil | |
87 | } | |
88 | ||
89 | want := true | |
90 | // Avoid .foo, _foo, and testdata directory trees. | |
91 | _, elem := filepath.Split(path) | |
92 | if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" { | |
93 | want = false | |
94 | } | |
95 | ||
96 | name := filepath.ToSlash(path[len(src):]) | |
97 | if pattern == "std" && (!isStandardImportPath(name) || name == "cmd") { | |
98 | // The name "std" is only the standard library. | |
99 | // If the name is cmd, it's the root of the command tree. | |
100 | want = false | |
101 | } | |
102 | if !treeCanMatch(name) { | |
103 | want = false | |
104 | } | |
105 | ||
106 | if !fi.IsDir() { | |
107 | if fi.Mode()&os.ModeSymlink != 0 && want { | |
108 | if target, err := os.Stat(path); err == nil && target.IsDir() { | |
109 | fmt.Fprintf(os.Stderr, "warning: ignoring symlink %s\n", path) | |
110 | } | |
111 | } | |
112 | return nil | |
113 | } | |
114 | if !want { | |
115 | return filepath.SkipDir | |
116 | } | |
117 | ||
118 | if have[name] { | |
119 | return nil | |
120 | } | |
121 | have[name] = true | |
122 | if !match(name) { | |
123 | return nil | |
124 | } | |
125 | pkg, err := c.BuildContext.ImportDir(path, 0) | |
126 | if err != nil { | |
127 | if _, noGo := err.(*build.NoGoError); noGo { | |
128 | return nil | |
129 | } | |
130 | } | |
131 | ||
132 | // If we are expanding "cmd", skip main | |
133 | // packages under cmd/vendor. At least as of | |
134 | // March, 2017, there is one there for the | |
135 | // vendored pprof tool. | |
136 | if pattern == "cmd" && strings.HasPrefix(pkg.ImportPath, "cmd/vendor") && pkg.Name == "main" { | |
137 | return nil | |
138 | } | |
139 | ||
140 | pkgs = append(pkgs, name) | |
141 | return nil | |
142 | }) | |
143 | } | |
144 | return pkgs | |
145 | } | |
146 | ||
147 | // MatchPackagesInFS returns a list of package paths matching pattern, | |
148 | // which must begin with ./ or ../ | |
149 | // (see go help packages for pattern syntax). | |
150 | func (c *Context) MatchPackagesInFS(pattern string) []string { | |
151 | // Find directory to begin the scan. | |
152 | // Could be smarter but this one optimization | |
153 | // is enough for now, since ... is usually at the | |
154 | // end of a path. | |
155 | i := strings.Index(pattern, "...") | |
156 | dir, _ := path.Split(pattern[:i]) | |
157 | ||
158 | // pattern begins with ./ or ../. | |
159 | // path.Clean will discard the ./ but not the ../. | |
160 | // We need to preserve the ./ for pattern matching | |
161 | // and in the returned import paths. | |
162 | prefix := "" | |
163 | if strings.HasPrefix(pattern, "./") { | |
164 | prefix = "./" | |
165 | } | |
166 | match := matchPattern(pattern) | |
167 | ||
168 | var pkgs []string | |
169 | filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error { | |
170 | if err != nil || !fi.IsDir() { | |
171 | return nil | |
172 | } | |
173 | if path == dir { | |
174 | // filepath.Walk starts at dir and recurses. For the recursive case, | |
175 | // the path is the result of filepath.Join, which calls filepath.Clean. | |
176 | // The initial case is not Cleaned, though, so we do this explicitly. | |
177 | // | |
178 | // This converts a path like "./io/" to "io". Without this step, running | |
179 | // "cd $GOROOT/src; go list ./io/..." would incorrectly skip the io | |
180 | // package, because prepending the prefix "./" to the unclean path would | |
181 | // result in "././io", and match("././io") returns false. | |
182 | path = filepath.Clean(path) | |
183 | } | |
184 | ||
185 | // Avoid .foo, _foo, and testdata directory trees, but do not avoid "." or "..". | |
186 | _, elem := filepath.Split(path) | |
187 | dot := strings.HasPrefix(elem, ".") && elem != "." && elem != ".." | |
188 | if dot || strings.HasPrefix(elem, "_") || elem == "testdata" { | |
189 | return filepath.SkipDir | |
190 | } | |
191 | ||
192 | name := prefix + filepath.ToSlash(path) | |
193 | if !match(name) { | |
194 | return nil | |
195 | } | |
196 | ||
197 | // We keep the directory if we can import it, or if we can't import it | |
198 | // due to invalid Go source files. This means that directories containing | |
199 | // parse errors will be built (and fail) instead of being silently skipped | |
200 | // as not matching the pattern. Go 1.5 and earlier skipped, but that | |
201 | // behavior means people miss serious mistakes. | |
202 | // See golang.org/issue/11407. | |
203 | if p, err := c.BuildContext.ImportDir(path, 0); err != nil && (p == nil || len(p.InvalidGoFiles) == 0) { | |
204 | if _, noGo := err.(*build.NoGoError); !noGo { | |
205 | log.Print(err) | |
206 | } | |
207 | return nil | |
208 | } | |
209 | pkgs = append(pkgs, name) | |
210 | return nil | |
211 | }) | |
212 | return pkgs | |
213 | } | |
214 | ||
215 | // treeCanMatchPattern(pattern)(name) reports whether | |
216 | // name or children of name can possibly match pattern. | |
217 | // Pattern is the same limited glob accepted by matchPattern. | |
218 | func treeCanMatchPattern(pattern string) func(name string) bool { | |
219 | wildCard := false | |
220 | if i := strings.Index(pattern, "..."); i >= 0 { | |
221 | wildCard = true | |
222 | pattern = pattern[:i] | |
223 | } | |
224 | return func(name string) bool { | |
225 | return len(name) <= len(pattern) && hasPathPrefix(pattern, name) || | |
226 | wildCard && strings.HasPrefix(name, pattern) | |
227 | } | |
228 | } | |
229 | ||
230 | // matchPattern(pattern)(name) reports whether | |
231 | // name matches pattern. Pattern is a limited glob | |
232 | // pattern in which '...' means 'any string' and there | |
233 | // is no other special syntax. | |
234 | // Unfortunately, there are two special cases. Quoting "go help packages": | |
235 | // | |
236 | // First, /... at the end of the pattern can match an empty string, | |
237 | // so that net/... matches both net and packages in its subdirectories, like net/http. | |
238 | // Second, any slash-separted pattern element containing a wildcard never | |
239 | // participates in a match of the "vendor" element in the path of a vendored | |
240 | // package, so that ./... does not match packages in subdirectories of | |
241 | // ./vendor or ./mycode/vendor, but ./vendor/... and ./mycode/vendor/... do. | |
242 | // Note, however, that a directory named vendor that itself contains code | |
243 | // is not a vendored package: cmd/vendor would be a command named vendor, | |
244 | // and the pattern cmd/... matches it. | |
245 | func matchPattern(pattern string) func(name string) bool { | |
246 | // Convert pattern to regular expression. | |
247 | // The strategy for the trailing /... is to nest it in an explicit ? expression. | |
248 | // The strategy for the vendor exclusion is to change the unmatchable | |
249 | // vendor strings to a disallowed code point (vendorChar) and to use | |
250 | // "(anything but that codepoint)*" as the implementation of the ... wildcard. | |
251 | // This is a bit complicated but the obvious alternative, | |
252 | // namely a hand-written search like in most shell glob matchers, | |
253 | // is too easy to make accidentally exponential. | |
254 | // Using package regexp guarantees linear-time matching. | |
255 | ||
256 | const vendorChar = "\x00" | |
257 | ||
258 | if strings.Contains(pattern, vendorChar) { | |
259 | return func(name string) bool { return false } | |
260 | } | |
261 | ||
262 | re := regexp.QuoteMeta(pattern) | |
263 | re = replaceVendor(re, vendorChar) | |
264 | switch { | |
265 | case strings.HasSuffix(re, `/`+vendorChar+`/\.\.\.`): | |
266 | re = strings.TrimSuffix(re, `/`+vendorChar+`/\.\.\.`) + `(/vendor|/` + vendorChar + `/\.\.\.)` | |
267 | case re == vendorChar+`/\.\.\.`: | |
268 | re = `(/vendor|/` + vendorChar + `/\.\.\.)` | |
269 | case strings.HasSuffix(re, `/\.\.\.`): | |
270 | re = strings.TrimSuffix(re, `/\.\.\.`) + `(/\.\.\.)?` | |
271 | } | |
272 | re = strings.Replace(re, `\.\.\.`, `[^`+vendorChar+`]*`, -1) | |
273 | ||
274 | reg := regexp.MustCompile(`^` + re + `$`) | |
275 | ||
276 | return func(name string) bool { | |
277 | if strings.Contains(name, vendorChar) { | |
278 | return false | |
279 | } | |
280 | return reg.MatchString(replaceVendor(name, vendorChar)) | |
281 | } | |
282 | } | |
283 | ||
284 | // replaceVendor returns the result of replacing | |
285 | // non-trailing vendor path elements in x with repl. | |
286 | func replaceVendor(x, repl string) string { | |
287 | if !strings.Contains(x, "vendor") { | |
288 | return x | |
289 | } | |
290 | elem := strings.Split(x, "/") | |
291 | for i := 0; i < len(elem)-1; i++ { | |
292 | if elem[i] == "vendor" { | |
293 | elem[i] = repl | |
294 | } | |
295 | } | |
296 | return strings.Join(elem, "/") | |
297 | } | |
298 | ||
299 | // ImportPaths returns the import paths to use for the given command line. | |
300 | func (c *Context) ImportPaths(args []string) []string { | |
301 | args = c.ImportPathsNoDotExpansion(args) | |
302 | var out []string | |
303 | for _, a := range args { | |
304 | if strings.Contains(a, "...") { | |
305 | if build.IsLocalImport(a) { | |
306 | out = append(out, c.allPackagesInFS(a)...) | |
307 | } else { | |
308 | out = append(out, c.allPackages(a)...) | |
309 | } | |
310 | continue | |
311 | } | |
312 | out = append(out, a) | |
313 | } | |
314 | return out | |
315 | } | |
316 | ||
317 | // ImportPathsNoDotExpansion returns the import paths to use for the given | |
318 | // command line, but it does no ... expansion. | |
319 | func (c *Context) ImportPathsNoDotExpansion(args []string) []string { | |
320 | if len(args) == 0 { | |
321 | return []string{"."} | |
322 | } | |
323 | var out []string | |
324 | for _, a := range args { | |
325 | // Arguments are supposed to be import paths, but | |
326 | // as a courtesy to Windows developers, rewrite \ to / | |
327 | // in command-line arguments. Handles .\... and so on. | |
328 | if filepath.Separator == '\\' { | |
329 | a = strings.Replace(a, `\`, `/`, -1) | |
330 | } | |
331 | ||
332 | // Put argument in canonical form, but preserve leading ./. | |
333 | if strings.HasPrefix(a, "./") { | |
334 | a = "./" + path.Clean(a) | |
335 | if a == "./." { | |
336 | a = "." | |
337 | } | |
338 | } else { | |
339 | a = path.Clean(a) | |
340 | } | |
341 | if IsMetaPackage(a) { | |
342 | out = append(out, c.allPackages(a)...) | |
343 | continue | |
344 | } | |
345 | out = append(out, a) | |
346 | } | |
347 | return out | |
348 | } | |
349 | ||
350 | // IsMetaPackage checks if name is a reserved package name that expands to multiple packages. | |
351 | func IsMetaPackage(name string) bool { | |
352 | return name == "std" || name == "cmd" || name == "all" | |
353 | } |
25 | 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
26 | 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | 27 | |
28 | // +build go1.9 | |
29 | ||
28 | 30 | package gotool |
29 | 31 | |
30 | 32 | import ( |
31 | "fmt" | |
32 | "go/build" | |
33 | "log" | |
34 | "os" | |
35 | "path" | |
36 | 33 | "path/filepath" |
37 | "regexp" | |
38 | "strings" | |
34 | ||
35 | "github.com/kisielk/gotool/internal/load" | |
39 | 36 | ) |
40 | ||
41 | // This file contains code from the Go distribution. | |
42 | ||
43 | // matchPattern(pattern)(name) reports whether | |
44 | // name matches pattern. Pattern is a limited glob | |
45 | // pattern in which '...' means 'any string' and there | |
46 | // is no other special syntax. | |
47 | func matchPattern(pattern string) func(name string) bool { | |
48 | re := regexp.QuoteMeta(pattern) | |
49 | re = strings.Replace(re, `\.\.\.`, `.*`, -1) | |
50 | // Special case: foo/... matches foo too. | |
51 | if strings.HasSuffix(re, `/.*`) { | |
52 | re = re[:len(re)-len(`/.*`)] + `(/.*)?` | |
53 | } | |
54 | reg := regexp.MustCompile(`^` + re + `$`) | |
55 | return reg.MatchString | |
56 | } | |
57 | ||
58 | func (c *Context) matchPackages(pattern string) []string { | |
59 | match := func(string) bool { return true } | |
60 | treeCanMatch := func(string) bool { return true } | |
61 | if !isMetaPackage(pattern) { | |
62 | match = matchPattern(pattern) | |
63 | treeCanMatch = treeCanMatchPattern(pattern) | |
64 | } | |
65 | ||
66 | have := map[string]bool{ | |
67 | "builtin": true, // ignore pseudo-package that exists only for documentation | |
68 | } | |
69 | if !c.BuildContext.CgoEnabled { | |
70 | have["runtime/cgo"] = true // ignore during walk | |
71 | } | |
72 | var pkgs []string | |
73 | ||
74 | for _, src := range c.BuildContext.SrcDirs() { | |
75 | if (pattern == "std" || pattern == "cmd") && src != gorootSrc { | |
76 | continue | |
77 | } | |
78 | src = filepath.Clean(src) + string(filepath.Separator) | |
79 | root := src | |
80 | if pattern == "cmd" { | |
81 | root += "cmd" + string(filepath.Separator) | |
82 | } | |
83 | filepath.Walk(root, func(path string, fi os.FileInfo, err error) error { | |
84 | if err != nil || !fi.IsDir() || path == src { | |
85 | return nil | |
86 | } | |
87 | ||
88 | // Avoid .foo, _foo, and testdata directory trees. | |
89 | _, elem := filepath.Split(path) | |
90 | if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" { | |
91 | return filepath.SkipDir | |
92 | } | |
93 | ||
94 | name := filepath.ToSlash(path[len(src):]) | |
95 | if pattern == "std" && (!isStandardImportPath(name) || name == "cmd") { | |
96 | // The name "std" is only the standard library. | |
97 | // If the name is cmd, it's the root of the command tree. | |
98 | return filepath.SkipDir | |
99 | } | |
100 | if !treeCanMatch(name) { | |
101 | return filepath.SkipDir | |
102 | } | |
103 | if have[name] { | |
104 | return nil | |
105 | } | |
106 | have[name] = true | |
107 | if !match(name) { | |
108 | return nil | |
109 | } | |
110 | _, err = c.BuildContext.ImportDir(path, 0) | |
111 | if err != nil { | |
112 | if _, noGo := err.(*build.NoGoError); noGo { | |
113 | return nil | |
114 | } | |
115 | } | |
116 | pkgs = append(pkgs, name) | |
117 | return nil | |
118 | }) | |
119 | } | |
120 | return pkgs | |
121 | } | |
122 | ||
123 | // importPathsNoDotExpansion returns the import paths to use for the given | |
124 | // command line, but it does no ... expansion. | |
125 | func (c *Context) importPathsNoDotExpansion(args []string) []string { | |
126 | if len(args) == 0 { | |
127 | return []string{"."} | |
128 | } | |
129 | var out []string | |
130 | for _, a := range args { | |
131 | // Arguments are supposed to be import paths, but | |
132 | // as a courtesy to Windows developers, rewrite \ to / | |
133 | // in command-line arguments. Handles .\... and so on. | |
134 | if filepath.Separator == '\\' { | |
135 | a = strings.Replace(a, `\`, `/`, -1) | |
136 | } | |
137 | ||
138 | // Put argument in canonical form, but preserve leading ./. | |
139 | if strings.HasPrefix(a, "./") { | |
140 | a = "./" + path.Clean(a) | |
141 | if a == "./." { | |
142 | a = "." | |
143 | } | |
144 | } else { | |
145 | a = path.Clean(a) | |
146 | } | |
147 | if isMetaPackage(a) { | |
148 | out = append(out, c.allPackages(a)...) | |
149 | continue | |
150 | } | |
151 | out = append(out, a) | |
152 | } | |
153 | return out | |
154 | } | |
155 | 37 | |
156 | 38 | // importPaths returns the import paths to use for the given command line. |
157 | 39 | func (c *Context) importPaths(args []string) []string { |
158 | args = c.importPathsNoDotExpansion(args) | |
159 | var out []string | |
160 | for _, a := range args { | |
161 | if strings.Contains(a, "...") { | |
162 | if build.IsLocalImport(a) { | |
163 | out = append(out, c.allPackagesInFS(a)...) | |
164 | } else { | |
165 | out = append(out, c.allPackages(a)...) | |
166 | } | |
167 | continue | |
168 | } | |
169 | out = append(out, a) | |
40 | lctx := load.Context{ | |
41 | BuildContext: c.BuildContext, | |
42 | GOROOTsrc: c.joinPath(c.BuildContext.GOROOT, "src"), | |
170 | 43 | } |
171 | return out | |
44 | return lctx.ImportPaths(args) | |
172 | 45 | } |
173 | 46 | |
174 | // allPackages returns all the packages that can be found | |
175 | // under the $GOPATH directories and $GOROOT matching pattern. | |
176 | // The pattern is either "all" (all packages), "std" (standard packages), | |
177 | // "cmd" (standard commands), or a path including "...". | |
178 | func (c *Context) allPackages(pattern string) []string { | |
179 | pkgs := c.matchPackages(pattern) | |
180 | if len(pkgs) == 0 { | |
181 | fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern) | |
47 | // joinPath calls c.BuildContext.JoinPath (if not nil) or else filepath.Join. | |
48 | // | |
49 | // It's a copy of the unexported build.Context.joinPath helper. | |
50 | func (c *Context) joinPath(elem ...string) string { | |
51 | if f := c.BuildContext.JoinPath; f != nil { | |
52 | return f(elem...) | |
182 | 53 | } |
183 | return pkgs | |
54 | return filepath.Join(elem...) | |
184 | 55 | } |
185 | ||
186 | // allPackagesInFS is like allPackages but is passed a pattern | |
187 | // beginning ./ or ../, meaning it should scan the tree rooted | |
188 | // at the given directory. There are ... in the pattern too. | |
189 | func (c *Context) allPackagesInFS(pattern string) []string { | |
190 | pkgs := c.matchPackagesInFS(pattern) | |
191 | if len(pkgs) == 0 { | |
192 | fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern) | |
193 | } | |
194 | return pkgs | |
195 | } | |
196 | ||
197 | func (c *Context) matchPackagesInFS(pattern string) []string { | |
198 | // Find directory to begin the scan. | |
199 | // Could be smarter but this one optimization | |
200 | // is enough for now, since ... is usually at the | |
201 | // end of a path. | |
202 | i := strings.Index(pattern, "...") | |
203 | dir, _ := path.Split(pattern[:i]) | |
204 | ||
205 | // pattern begins with ./ or ../. | |
206 | // path.Clean will discard the ./ but not the ../. | |
207 | // We need to preserve the ./ for pattern matching | |
208 | // and in the returned import paths. | |
209 | prefix := "" | |
210 | if strings.HasPrefix(pattern, "./") { | |
211 | prefix = "./" | |
212 | } | |
213 | match := matchPattern(pattern) | |
214 | ||
215 | var pkgs []string | |
216 | filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error { | |
217 | if err != nil || !fi.IsDir() { | |
218 | return nil | |
219 | } | |
220 | if path == dir { | |
221 | // filepath.Walk starts at dir and recurses. For the recursive case, | |
222 | // the path is the result of filepath.Join, which calls filepath.Clean. | |
223 | // The initial case is not Cleaned, though, so we do this explicitly. | |
224 | // | |
225 | // This converts a path like "./io/" to "io". Without this step, running | |
226 | // "cd $GOROOT/src; go list ./io/..." would incorrectly skip the io | |
227 | // package, because prepending the prefix "./" to the unclean path would | |
228 | // result in "././io", and match("././io") returns false. | |
229 | path = filepath.Clean(path) | |
230 | } | |
231 | ||
232 | // Avoid .foo, _foo, and testdata directory trees, but do not avoid "." or "..". | |
233 | _, elem := filepath.Split(path) | |
234 | dot := strings.HasPrefix(elem, ".") && elem != "." && elem != ".." | |
235 | if dot || strings.HasPrefix(elem, "_") || elem == "testdata" { | |
236 | return filepath.SkipDir | |
237 | } | |
238 | ||
239 | name := prefix + filepath.ToSlash(path) | |
240 | if !match(name) { | |
241 | return nil | |
242 | } | |
243 | ||
244 | // We keep the directory if we can import it, or if we can't import it | |
245 | // due to invalid Go source files. This means that directories containing | |
246 | // parse errors will be built (and fail) instead of being silently skipped | |
247 | // as not matching the pattern. Go 1.5 and earlier skipped, but that | |
248 | // behavior means people miss serious mistakes. | |
249 | // See golang.org/issue/11407. | |
250 | if p, err := c.BuildContext.ImportDir(path, 0); err != nil && shouldIgnoreImport(p) { | |
251 | if _, noGo := err.(*build.NoGoError); !noGo { | |
252 | log.Print(err) | |
253 | } | |
254 | return nil | |
255 | } | |
256 | pkgs = append(pkgs, name) | |
257 | return nil | |
258 | }) | |
259 | return pkgs | |
260 | } | |
261 | ||
262 | // isMetaPackage checks if name is a reserved package name that expands to multiple packages | |
263 | func isMetaPackage(name string) bool { | |
264 | return name == "std" || name == "cmd" || name == "all" | |
265 | } | |
266 | ||
267 | // isStandardImportPath reports whether $GOROOT/src/path should be considered | |
268 | // part of the standard distribution. For historical reasons we allow people to add | |
269 | // their own code to $GOROOT instead of using $GOPATH, but we assume that | |
270 | // code will start with a domain name (dot in the first element). | |
271 | func isStandardImportPath(path string) bool { | |
272 | i := strings.Index(path, "/") | |
273 | if i < 0 { | |
274 | i = len(path) | |
275 | } | |
276 | elem := path[:i] | |
277 | return !strings.Contains(elem, ".") | |
278 | } | |
279 | ||
280 | // hasPathPrefix reports whether the path s begins with the | |
281 | // elements in prefix. | |
282 | func hasPathPrefix(s, prefix string) bool { | |
283 | switch { | |
284 | default: | |
285 | return false | |
286 | case len(s) == len(prefix): | |
287 | return s == prefix | |
288 | case len(s) > len(prefix): | |
289 | if prefix != "" && prefix[len(prefix)-1] == '/' { | |
290 | return strings.HasPrefix(s, prefix) | |
291 | } | |
292 | return s[len(prefix)] == '/' && s[:len(prefix)] == prefix | |
293 | } | |
294 | } | |
295 | ||
296 | // treeCanMatchPattern(pattern)(name) reports whether | |
297 | // name or children of name can possibly match pattern. | |
298 | // Pattern is the same limited glob accepted by matchPattern. | |
299 | func treeCanMatchPattern(pattern string) func(name string) bool { | |
300 | wildCard := false | |
301 | if i := strings.Index(pattern, "..."); i >= 0 { | |
302 | wildCard = true | |
303 | pattern = pattern[:i] | |
304 | } | |
305 | return func(name string) bool { | |
306 | return len(name) <= len(pattern) && hasPathPrefix(pattern, name) || | |
307 | wildCard && strings.HasPrefix(name, pattern) | |
308 | } | |
309 | } |
0 | // Copyright (c) 2009 The Go Authors. All rights reserved. | |
1 | // | |
2 | // Redistribution and use in source and binary forms, with or without | |
3 | // modification, are permitted provided that the following conditions are | |
4 | // met: | |
5 | // | |
6 | // * Redistributions of source code must retain the above copyright | |
7 | // notice, this list of conditions and the following disclaimer. | |
8 | // * Redistributions in binary form must reproduce the above | |
9 | // copyright notice, this list of conditions and the following disclaimer | |
10 | // in the documentation and/or other materials provided with the | |
11 | // distribution. | |
12 | // * Neither the name of Google Inc. nor the names of its | |
13 | // contributors may be used to endorse or promote products derived from | |
14 | // this software without specific prior written permission. | |
15 | // | |
16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
17 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
18 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
19 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
20 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
21 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
22 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
23 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
27 | ||
28 | // +build !go1.9 | |
29 | ||
30 | package gotool | |
31 | ||
32 | import ( | |
33 | "fmt" | |
34 | "go/build" | |
35 | "log" | |
36 | "os" | |
37 | "path" | |
38 | "path/filepath" | |
39 | "regexp" | |
40 | "strings" | |
41 | ) | |
42 | ||
43 | // This file contains code from the Go distribution. | |
44 | ||
45 | // matchPattern(pattern)(name) reports whether | |
46 | // name matches pattern. Pattern is a limited glob | |
47 | // pattern in which '...' means 'any string' and there | |
48 | // is no other special syntax. | |
49 | func matchPattern(pattern string) func(name string) bool { | |
50 | re := regexp.QuoteMeta(pattern) | |
51 | re = strings.Replace(re, `\.\.\.`, `.*`, -1) | |
52 | // Special case: foo/... matches foo too. | |
53 | if strings.HasSuffix(re, `/.*`) { | |
54 | re = re[:len(re)-len(`/.*`)] + `(/.*)?` | |
55 | } | |
56 | reg := regexp.MustCompile(`^` + re + `$`) | |
57 | return reg.MatchString | |
58 | } | |
59 | ||
60 | // matchPackages returns a list of package paths matching pattern | |
61 | // (see go help packages for pattern syntax). | |
62 | func (c *Context) matchPackages(pattern string) []string { | |
63 | match := func(string) bool { return true } | |
64 | treeCanMatch := func(string) bool { return true } | |
65 | if !isMetaPackage(pattern) { | |
66 | match = matchPattern(pattern) | |
67 | treeCanMatch = treeCanMatchPattern(pattern) | |
68 | } | |
69 | ||
70 | have := map[string]bool{ | |
71 | "builtin": true, // ignore pseudo-package that exists only for documentation | |
72 | } | |
73 | if !c.BuildContext.CgoEnabled { | |
74 | have["runtime/cgo"] = true // ignore during walk | |
75 | } | |
76 | var pkgs []string | |
77 | ||
78 | for _, src := range c.BuildContext.SrcDirs() { | |
79 | if (pattern == "std" || pattern == "cmd") && src != gorootSrc { | |
80 | continue | |
81 | } | |
82 | src = filepath.Clean(src) + string(filepath.Separator) | |
83 | root := src | |
84 | if pattern == "cmd" { | |
85 | root += "cmd" + string(filepath.Separator) | |
86 | } | |
87 | filepath.Walk(root, func(path string, fi os.FileInfo, err error) error { | |
88 | if err != nil || !fi.IsDir() || path == src { | |
89 | return nil | |
90 | } | |
91 | ||
92 | // Avoid .foo, _foo, and testdata directory trees. | |
93 | _, elem := filepath.Split(path) | |
94 | if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" { | |
95 | return filepath.SkipDir | |
96 | } | |
97 | ||
98 | name := filepath.ToSlash(path[len(src):]) | |
99 | if pattern == "std" && (!isStandardImportPath(name) || name == "cmd") { | |
100 | // The name "std" is only the standard library. | |
101 | // If the name is cmd, it's the root of the command tree. | |
102 | return filepath.SkipDir | |
103 | } | |
104 | if !treeCanMatch(name) { | |
105 | return filepath.SkipDir | |
106 | } | |
107 | if have[name] { | |
108 | return nil | |
109 | } | |
110 | have[name] = true | |
111 | if !match(name) { | |
112 | return nil | |
113 | } | |
114 | _, err = c.BuildContext.ImportDir(path, 0) | |
115 | if err != nil { | |
116 | if _, noGo := err.(*build.NoGoError); noGo { | |
117 | return nil | |
118 | } | |
119 | } | |
120 | pkgs = append(pkgs, name) | |
121 | return nil | |
122 | }) | |
123 | } | |
124 | return pkgs | |
125 | } | |
126 | ||
127 | // importPathsNoDotExpansion returns the import paths to use for the given | |
128 | // command line, but it does no ... expansion. | |
129 | func (c *Context) importPathsNoDotExpansion(args []string) []string { | |
130 | if len(args) == 0 { | |
131 | return []string{"."} | |
132 | } | |
133 | var out []string | |
134 | for _, a := range args { | |
135 | // Arguments are supposed to be import paths, but | |
136 | // as a courtesy to Windows developers, rewrite \ to / | |
137 | // in command-line arguments. Handles .\... and so on. | |
138 | if filepath.Separator == '\\' { | |
139 | a = strings.Replace(a, `\`, `/`, -1) | |
140 | } | |
141 | ||
142 | // Put argument in canonical form, but preserve leading ./. | |
143 | if strings.HasPrefix(a, "./") { | |
144 | a = "./" + path.Clean(a) | |
145 | if a == "./." { | |
146 | a = "." | |
147 | } | |
148 | } else { | |
149 | a = path.Clean(a) | |
150 | } | |
151 | if isMetaPackage(a) { | |
152 | out = append(out, c.allPackages(a)...) | |
153 | continue | |
154 | } | |
155 | out = append(out, a) | |
156 | } | |
157 | return out | |
158 | } | |
159 | ||
160 | // importPaths returns the import paths to use for the given command line. | |
161 | func (c *Context) importPaths(args []string) []string { | |
162 | args = c.importPathsNoDotExpansion(args) | |
163 | var out []string | |
164 | for _, a := range args { | |
165 | if strings.Contains(a, "...") { | |
166 | if build.IsLocalImport(a) { | |
167 | out = append(out, c.allPackagesInFS(a)...) | |
168 | } else { | |
169 | out = append(out, c.allPackages(a)...) | |
170 | } | |
171 | continue | |
172 | } | |
173 | out = append(out, a) | |
174 | } | |
175 | return out | |
176 | } | |
177 | ||
178 | // allPackages returns all the packages that can be found | |
179 | // under the $GOPATH directories and $GOROOT matching pattern. | |
180 | // The pattern is either "all" (all packages), "std" (standard packages), | |
181 | // "cmd" (standard commands), or a path including "...". | |
182 | func (c *Context) allPackages(pattern string) []string { | |
183 | pkgs := c.matchPackages(pattern) | |
184 | if len(pkgs) == 0 { | |
185 | fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern) | |
186 | } | |
187 | return pkgs | |
188 | } | |
189 | ||
190 | // allPackagesInFS is like allPackages but is passed a pattern | |
191 | // beginning ./ or ../, meaning it should scan the tree rooted | |
192 | // at the given directory. There are ... in the pattern too. | |
193 | func (c *Context) allPackagesInFS(pattern string) []string { | |
194 | pkgs := c.matchPackagesInFS(pattern) | |
195 | if len(pkgs) == 0 { | |
196 | fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern) | |
197 | } | |
198 | return pkgs | |
199 | } | |
200 | ||
201 | // matchPackagesInFS returns a list of package paths matching pattern, | |
202 | // which must begin with ./ or ../ | |
203 | // (see go help packages for pattern syntax). | |
204 | func (c *Context) matchPackagesInFS(pattern string) []string { | |
205 | // Find directory to begin the scan. | |
206 | // Could be smarter but this one optimization | |
207 | // is enough for now, since ... is usually at the | |
208 | // end of a path. | |
209 | i := strings.Index(pattern, "...") | |
210 | dir, _ := path.Split(pattern[:i]) | |
211 | ||
212 | // pattern begins with ./ or ../. | |
213 | // path.Clean will discard the ./ but not the ../. | |
214 | // We need to preserve the ./ for pattern matching | |
215 | // and in the returned import paths. | |
216 | prefix := "" | |
217 | if strings.HasPrefix(pattern, "./") { | |
218 | prefix = "./" | |
219 | } | |
220 | match := matchPattern(pattern) | |
221 | ||
222 | var pkgs []string | |
223 | filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error { | |
224 | if err != nil || !fi.IsDir() { | |
225 | return nil | |
226 | } | |
227 | if path == dir { | |
228 | // filepath.Walk starts at dir and recurses. For the recursive case, | |
229 | // the path is the result of filepath.Join, which calls filepath.Clean. | |
230 | // The initial case is not Cleaned, though, so we do this explicitly. | |
231 | // | |
232 | // This converts a path like "./io/" to "io". Without this step, running | |
233 | // "cd $GOROOT/src; go list ./io/..." would incorrectly skip the io | |
234 | // package, because prepending the prefix "./" to the unclean path would | |
235 | // result in "././io", and match("././io") returns false. | |
236 | path = filepath.Clean(path) | |
237 | } | |
238 | ||
239 | // Avoid .foo, _foo, and testdata directory trees, but do not avoid "." or "..". | |
240 | _, elem := filepath.Split(path) | |
241 | dot := strings.HasPrefix(elem, ".") && elem != "." && elem != ".." | |
242 | if dot || strings.HasPrefix(elem, "_") || elem == "testdata" { | |
243 | return filepath.SkipDir | |
244 | } | |
245 | ||
246 | name := prefix + filepath.ToSlash(path) | |
247 | if !match(name) { | |
248 | return nil | |
249 | } | |
250 | ||
251 | // We keep the directory if we can import it, or if we can't import it | |
252 | // due to invalid Go source files. This means that directories containing | |
253 | // parse errors will be built (and fail) instead of being silently skipped | |
254 | // as not matching the pattern. Go 1.5 and earlier skipped, but that | |
255 | // behavior means people miss serious mistakes. | |
256 | // See golang.org/issue/11407. | |
257 | if p, err := c.BuildContext.ImportDir(path, 0); err != nil && shouldIgnoreImport(p) { | |
258 | if _, noGo := err.(*build.NoGoError); !noGo { | |
259 | log.Print(err) | |
260 | } | |
261 | return nil | |
262 | } | |
263 | pkgs = append(pkgs, name) | |
264 | return nil | |
265 | }) | |
266 | return pkgs | |
267 | } | |
268 | ||
269 | // isMetaPackage checks if name is a reserved package name that expands to multiple packages. | |
270 | func isMetaPackage(name string) bool { | |
271 | return name == "std" || name == "cmd" || name == "all" | |
272 | } | |
273 | ||
274 | // isStandardImportPath reports whether $GOROOT/src/path should be considered | |
275 | // part of the standard distribution. For historical reasons we allow people to add | |
276 | // their own code to $GOROOT instead of using $GOPATH, but we assume that | |
277 | // code will start with a domain name (dot in the first element). | |
278 | func isStandardImportPath(path string) bool { | |
279 | i := strings.Index(path, "/") | |
280 | if i < 0 { | |
281 | i = len(path) | |
282 | } | |
283 | elem := path[:i] | |
284 | return !strings.Contains(elem, ".") | |
285 | } | |
286 | ||
287 | // hasPathPrefix reports whether the path s begins with the | |
288 | // elements in prefix. | |
289 | func hasPathPrefix(s, prefix string) bool { | |
290 | switch { | |
291 | default: | |
292 | return false | |
293 | case len(s) == len(prefix): | |
294 | return s == prefix | |
295 | case len(s) > len(prefix): | |
296 | if prefix != "" && prefix[len(prefix)-1] == '/' { | |
297 | return strings.HasPrefix(s, prefix) | |
298 | } | |
299 | return s[len(prefix)] == '/' && s[:len(prefix)] == prefix | |
300 | } | |
301 | } | |
302 | ||
303 | // treeCanMatchPattern(pattern)(name) reports whether | |
304 | // name or children of name can possibly match pattern. | |
305 | // Pattern is the same limited glob accepted by matchPattern. | |
306 | func treeCanMatchPattern(pattern string) func(name string) bool { | |
307 | wildCard := false | |
308 | if i := strings.Index(pattern, "..."); i >= 0 { | |
309 | wildCard = true | |
310 | pattern = pattern[:i] | |
311 | } | |
312 | return func(name string) bool { | |
313 | return len(name) <= len(pattern) && hasPathPrefix(pattern, name) || | |
314 | wildCard && strings.HasPrefix(name, pattern) | |
315 | } | |
316 | } |
0 | // Copyright (c) 2009 The Go Authors. All rights reserved. | |
1 | // | |
2 | // Redistribution and use in source and binary forms, with or without | |
3 | // modification, are permitted provided that the following conditions are | |
4 | // met: | |
5 | // | |
6 | // * Redistributions of source code must retain the above copyright | |
7 | // notice, this list of conditions and the following disclaimer. | |
8 | // * Redistributions in binary form must reproduce the above | |
9 | // copyright notice, this list of conditions and the following disclaimer | |
10 | // in the documentation and/or other materials provided with the | |
11 | // distribution. | |
12 | // * Neither the name of Google Inc. nor the names of its | |
13 | // contributors may be used to endorse or promote products derived from | |
14 | // this software without specific prior written permission. | |
15 | // | |
16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
17 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
18 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
19 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
20 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
21 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
22 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
23 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
27 | ||
28 | // +build !go1.9 | |
29 | ||
30 | package gotool | |
31 | ||
32 | import ( | |
33 | "sort" | |
34 | "testing" | |
35 | ) | |
36 | ||
37 | // This file contains code from the Go distribution. | |
38 | ||
39 | var matchPatternTests = []stringPairTest{ | |
40 | {"...", "foo", true}, | |
41 | {"net", "net", true}, | |
42 | {"net", "net/http", false}, | |
43 | {"net/http", "net", false}, | |
44 | {"net/http", "net/http", true}, | |
45 | {"net...", "netchan", true}, | |
46 | {"net...", "net", true}, | |
47 | {"net...", "net/http", true}, | |
48 | {"net...", "not/http", false}, | |
49 | {"net/...", "netchan", false}, | |
50 | {"net/...", "net", true}, | |
51 | {"net/...", "net/http", true}, | |
52 | {"net/...", "not/http", false}, | |
53 | } | |
54 | ||
55 | func TestMatchPattern(t *testing.T) { | |
56 | testStringPairs(t, "matchPattern", matchPatternTests, func(pattern, name string) bool { | |
57 | return matchPattern(pattern)(name) | |
58 | }) | |
59 | } | |
60 | ||
61 | var treeCanMatchPatternTests = []stringPairTest{ | |
62 | {"...", "foo", true}, | |
63 | {"net", "net", true}, | |
64 | {"net", "net/http", false}, | |
65 | {"net/http", "net", true}, | |
66 | {"net/http", "net/http", true}, | |
67 | {"net...", "netchan", true}, | |
68 | {"net...", "net", true}, | |
69 | {"net...", "net/http", true}, | |
70 | {"net...", "not/http", false}, | |
71 | {"net/...", "netchan", false}, | |
72 | {"net/...", "net", true}, | |
73 | {"net/...", "net/http", true}, | |
74 | {"net/...", "not/http", false}, | |
75 | {"abc.../def", "abcxyz", true}, | |
76 | {"abc.../def", "xyxabc", false}, | |
77 | {"x/y/z/...", "x", true}, | |
78 | {"x/y/z/...", "x/y", true}, | |
79 | {"x/y/z/...", "x/y/z", true}, | |
80 | {"x/y/z/...", "x/y/z/w", true}, | |
81 | {"x/y/z", "x", true}, | |
82 | {"x/y/z", "x/y", true}, | |
83 | {"x/y/z", "x/y/z", true}, | |
84 | {"x/y/z", "x/y/z/w", false}, | |
85 | {"x/.../y/z", "x/a/b/c", true}, | |
86 | {"x/.../y/z", "y/x/a/b/c", false}, | |
87 | } | |
88 | ||
89 | func TestChildrenCanMatchPattern(t *testing.T) { | |
90 | testStringPairs(t, "treeCanMatchPattern", treeCanMatchPatternTests, func(pattern, name string) bool { | |
91 | return treeCanMatchPattern(pattern)(name) | |
92 | }) | |
93 | } | |
94 | ||
95 | var hasPathPrefixTests = []stringPairTest{ | |
96 | {"abc", "a", false}, | |
97 | {"a/bc", "a", true}, | |
98 | {"a", "a", true}, | |
99 | {"a/bc", "a/", true}, | |
100 | } | |
101 | ||
102 | func TestHasPathPrefix(t *testing.T) { | |
103 | testStringPairs(t, "hasPathPrefix", hasPathPrefixTests, hasPathPrefix) | |
104 | } | |
105 | ||
106 | type stringPairTest struct { | |
107 | in1 string | |
108 | in2 string | |
109 | out bool | |
110 | } | |
111 | ||
112 | func testStringPairs(t *testing.T, name string, tests []stringPairTest, f func(string, string) bool) { | |
113 | for _, tt := range tests { | |
114 | if out := f(tt.in1, tt.in2); out != tt.out { | |
115 | t.Errorf("%s(%q, %q) = %v, want %v", name, tt.in1, tt.in2, out, tt.out) | |
116 | } | |
117 | } | |
118 | } | |
119 | ||
120 | // containsString reports whether strings contains x. strings is assumed to be sorted. | |
121 | func containsString(strings []string, x string) bool { | |
122 | return strings[sort.SearchStrings(strings, x)] == x | |
123 | } | |
124 | ||
125 | func TestMatchStdPackages(t *testing.T) { | |
126 | packages := DefaultContext.matchPackages("std") | |
127 | sort.Strings(packages) | |
128 | // some common packages all Go versions should have | |
129 | commonPackages := []string{"bufio", "bytes", "crypto", "fmt", "io", "os"} | |
130 | for _, p := range commonPackages { | |
131 | if !containsString(packages, p) { | |
132 | t.Errorf("std package set doesn't contain expected package %s", p) | |
133 | } | |
134 | } | |
135 | } |
0 | // Copyright (c) 2009 The Go Authors. All rights reserved. | |
1 | // | |
2 | // Redistribution and use in source and binary forms, with or without | |
3 | // modification, are permitted provided that the following conditions are | |
4 | // met: | |
5 | // | |
6 | // * Redistributions of source code must retain the above copyright | |
7 | // notice, this list of conditions and the following disclaimer. | |
8 | // * Redistributions in binary form must reproduce the above | |
9 | // copyright notice, this list of conditions and the following disclaimer | |
10 | // in the documentation and/or other materials provided with the | |
11 | // distribution. | |
12 | // * Neither the name of Google Inc. nor the names of its | |
13 | // contributors may be used to endorse or promote products derived from | |
14 | // this software without specific prior written permission. | |
15 | // | |
16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
17 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
18 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
19 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
20 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
21 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
22 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
23 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
27 | ||
28 | package gotool | |
29 | ||
30 | import ( | |
31 | "sort" | |
32 | "testing" | |
33 | ) | |
34 | ||
35 | // This file contains code from the Go distribution. | |
36 | ||
37 | var matchPatternTests = []stringPairTest{ | |
38 | {"...", "foo", true}, | |
39 | {"net", "net", true}, | |
40 | {"net", "net/http", false}, | |
41 | {"net/http", "net", false}, | |
42 | {"net/http", "net/http", true}, | |
43 | {"net...", "netchan", true}, | |
44 | {"net...", "net", true}, | |
45 | {"net...", "net/http", true}, | |
46 | {"net...", "not/http", false}, | |
47 | {"net/...", "netchan", false}, | |
48 | {"net/...", "net", true}, | |
49 | {"net/...", "net/http", true}, | |
50 | {"net/...", "not/http", false}, | |
51 | } | |
52 | ||
53 | func TestMatchPattern(t *testing.T) { | |
54 | testStringPairs(t, "matchPattern", matchPatternTests, func(pattern, name string) bool { | |
55 | return matchPattern(pattern)(name) | |
56 | }) | |
57 | } | |
58 | ||
59 | var treeCanMatchPatternTests = []stringPairTest{ | |
60 | {"...", "foo", true}, | |
61 | {"net", "net", true}, | |
62 | {"net", "net/http", false}, | |
63 | {"net/http", "net", true}, | |
64 | {"net/http", "net/http", true}, | |
65 | {"net...", "netchan", true}, | |
66 | {"net...", "net", true}, | |
67 | {"net...", "net/http", true}, | |
68 | {"net...", "not/http", false}, | |
69 | {"net/...", "netchan", false}, | |
70 | {"net/...", "net", true}, | |
71 | {"net/...", "net/http", true}, | |
72 | {"net/...", "not/http", false}, | |
73 | {"abc.../def", "abcxyz", true}, | |
74 | {"abc.../def", "xyxabc", false}, | |
75 | {"x/y/z/...", "x", true}, | |
76 | {"x/y/z/...", "x/y", true}, | |
77 | {"x/y/z/...", "x/y/z", true}, | |
78 | {"x/y/z/...", "x/y/z/w", true}, | |
79 | {"x/y/z", "x", true}, | |
80 | {"x/y/z", "x/y", true}, | |
81 | {"x/y/z", "x/y/z", true}, | |
82 | {"x/y/z", "x/y/z/w", false}, | |
83 | {"x/.../y/z", "x/a/b/c", true}, | |
84 | {"x/.../y/z", "y/x/a/b/c", false}, | |
85 | } | |
86 | ||
87 | func TestChildrenCanMatchPattern(t *testing.T) { | |
88 | testStringPairs(t, "treeCanMatchPattern", treeCanMatchPatternTests, func(pattern, name string) bool { | |
89 | return treeCanMatchPattern(pattern)(name) | |
90 | }) | |
91 | } | |
92 | ||
93 | var hasPathPrefixTests = []stringPairTest{ | |
94 | {"abc", "a", false}, | |
95 | {"a/bc", "a", true}, | |
96 | {"a", "a", true}, | |
97 | {"a/bc", "a/", true}, | |
98 | } | |
99 | ||
100 | func TestHasPathPrefix(t *testing.T) { | |
101 | testStringPairs(t, "hasPathPrefix", hasPathPrefixTests, hasPathPrefix) | |
102 | } | |
103 | ||
104 | type stringPairTest struct { | |
105 | in1 string | |
106 | in2 string | |
107 | out bool | |
108 | } | |
109 | ||
110 | func testStringPairs(t *testing.T, name string, tests []stringPairTest, f func(string, string) bool) { | |
111 | for _, tt := range tests { | |
112 | if out := f(tt.in1, tt.in2); out != tt.out { | |
113 | t.Errorf("%s(%q, %q) = %v, want %v", name, tt.in1, tt.in2, out, tt.out) | |
114 | } | |
115 | } | |
116 | } | |
117 | ||
118 | // containsString reports whether strings contains x. strings is assumed to be sorted. | |
119 | func containsString(strings []string, x string) bool { | |
120 | return strings[sort.SearchStrings(strings, x)] == x | |
121 | } | |
122 | ||
123 | func TestMatchStdPackages(t *testing.T) { | |
124 | packages := DefaultContext.matchPackages("std") | |
125 | sort.Strings(packages) | |
126 | // some common packages all Go versions should have | |
127 | commonPackages := []string{"bufio", "bytes", "crypto", "fmt", "io", "os"} | |
128 | for _, p := range commonPackages { | |
129 | if !containsString(packages, p) { | |
130 | t.Errorf("std package set doesn't contain expected package %s", p) | |
131 | } | |
132 | } | |
133 | } |