Codebase list golang-github-kisielk-gotool / 9e21bc6
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
12 changed file(s) with 1072 addition(s) and 430 deletion(s). Raw diff Collapse all Expand all
0 sudo: false
01 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
312 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
1216 install:
13 - # Skip
14
17 - # Skip.
1518 script:
1619 - go get -t -v ./...
1720 - diff -u <(echo -n) <(gofmt -d .)
0 module "github.com/kisielk/gotool"
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
-15
go16.go less more
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 }
2525 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2626 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2727
28 // +build go1.9
29
2830 package gotool
2931
3032 import (
31 "fmt"
32 "go/build"
33 "log"
34 "os"
35 "path"
3633 "path/filepath"
37 "regexp"
38 "strings"
34
35 "github.com/kisielk/gotool/internal/load"
3936 )
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 }
15537
15638 // importPaths returns the import paths to use for the given command line.
15739 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"),
17043 }
171 return out
44 return lctx.ImportPaths(args)
17245 }
17346
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...)
18253 }
183 return pkgs
54 return filepath.Join(elem...)
18455 }
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
-134
match_test.go less more
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 }