Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sync match.go with upstream changes #8

Merged
merged 1 commit into from Jul 9, 2016
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 79 additions & 9 deletions match.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,10 @@ func matchPattern(pattern string) func(name string) bool {

func (c Context) matchPackages(pattern string) []string {
match := func(string) bool { return true }
if pattern != "all" && pattern != "std" {
treeCanMatch := func(string) bool { return true }
if !isMetaPackage(pattern) {
match = matchPattern(pattern)
treeCanMatch = treeCanMatchPattern(pattern)
}

have := map[string]bool{
Expand All @@ -80,11 +82,15 @@ func (c Context) matchPackages(pattern string) []string {
var pkgs []string

for _, src := range c.BuildContext.SrcDirs() {
if pattern == "std" && src != gorootSrcPkg {
if (pattern == "std" || pattern == "cmd") && src != gorootSrcPkg {
continue
}
src = filepath.Clean(src) + string(filepath.Separator)
filepath.Walk(src, func(path string, fi os.FileInfo, err error) error {
root := src
if pattern == "cmd" {
root += "cmd" + string(filepath.Separator)
}
filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
if err != nil || !fi.IsDir() || path == src {
return nil
}
Expand All @@ -96,7 +102,12 @@ func (c Context) matchPackages(pattern string) []string {
}

name := filepath.ToSlash(path[len(src):])
if pattern == "std" && strings.Contains(name, ".") {
if pattern == "std" && (!isStandardImportPath(name) || name == "cmd") {
// The name "std" is only the standard library.
// If the name is cmd, it's the root of the command tree.
return filepath.SkipDir
}
if !treeCanMatch(name) {
return filepath.SkipDir
}
if have[name] {
Expand Down Expand Up @@ -129,7 +140,7 @@ func (c Context) importPathsNoDotExpansion(args []string) []string {
for _, a := range args {
// Arguments are supposed to be import paths, but
// as a courtesy to Windows developers, rewrite \ to /
// in command-line arguments. Handles .\... and so on.
// in command-line arguments. Handles .\... and so on.
if filepath.Separator == '\\' {
a = strings.Replace(a, `\`, `/`, -1)
}
Expand All @@ -143,8 +154,8 @@ func (c Context) importPathsNoDotExpansion(args []string) []string {
} else {
a = path.Clean(a)
}
if a == "all" || a == "std" {
out = append(out, c.allPackages(a)...)
if isMetaPackage(a) {
out = append(out, allPackages(a)...)
continue
}
out = append(out, a)
Expand Down Expand Up @@ -227,7 +238,7 @@ func matchPackagesInFS(pattern string) []string {
// The initial case is not Cleaned, though, so we do this explicitly.
//
// This converts a path like "./io/" to "io". Without this step, running
// "cd $GOROOT/src/pkg; go list ./io/..." would incorrectly skip the io
// "cd $GOROOT/src; go list ./io/..." would incorrectly skip the io
// package, because prepending the prefix "./" to the unclean path would
// result in "././io", and match("././io") returns false.
path = filepath.Clean(path)
Expand All @@ -244,11 +255,70 @@ func matchPackagesInFS(pattern string) []string {
if !match(name) {
return nil
}
if _, err = build.ImportDir(path, 0); err != nil {

// We keep the directory if we can import it, or if we can't import it
// due to invalid Go source files. This means that directories containing
// parse errors will be built (and fail) instead of being silently skipped
// as not matching the pattern. Go 1.5 and earlier skipped, but that
// behavior means people miss serious mistakes.
// See golang.org/issue/11407.
if p, err := c.BuildContext.ImportDir(path, 0); err != nil && (p == nil || len(p.InvalidGoFiles) == 0) {
if _, noGo := err.(*build.NoGoError); !noGo {
log.Print(err)
}
return nil
}
pkgs = append(pkgs, name)
return nil
})
return pkgs
}

// isMetaPackage checks if name is a reserved package name that expands to multiple packages
func isMetaPackage(name string) bool {
return name == "std" || name == "cmd" || name == "all"
}

// isStandardImportPath reports whether $GOROOT/src/path should be considered
// part of the standard distribution. For historical reasons we allow people to add
// their own code to $GOROOT instead of using $GOPATH, but we assume that
// code will start with a domain name (dot in the first element).
func isStandardImportPath(path string) bool {
i := strings.Index(path, "/")
if i < 0 {
i = len(path)
}
elem := path[:i]
return !strings.Contains(elem, ".")
}

// hasPathPrefix reports whether the path s begins with the
// elements in prefix.
func hasPathPrefix(s, prefix string) bool {
switch {
default:
return false
case len(s) == len(prefix):
return s == prefix
case len(s) > len(prefix):
if prefix != "" && prefix[len(prefix)-1] == '/' {
return strings.HasPrefix(s, prefix)
}
return s[len(prefix)] == '/' && s[:len(prefix)] == prefix
}
}

// treeCanMatchPattern(pattern)(name) reports whether
// name or children of name can possibly match pattern.
// Pattern is the same limited glob accepted by matchPattern.
func treeCanMatchPattern(pattern string) func(name string) bool {
wildCard := false
if i := strings.Index(pattern, "..."); i >= 0 {
wildCard = true
pattern = pattern[:i]
}
return func(name string) bool {
return len(name) <= len(pattern) && hasPathPrefix(pattern, name) ||
wildCard && strings.HasPrefix(name, pattern)
}
}