forked from ebhomengo/niki
1
0
Fork 0
niki/vendor/golang.org/x/tools/go/buildutil/allpackages.go

338 lines
5.1 KiB
Go
Raw Normal View History

2024-05-14 13:07:09 +00:00
// Copyright 2014 The Go Authors. All rights reserved.
2024-05-14 13:07:09 +00:00
// Use of this source code is governed by a BSD-style
2024-05-14 13:07:09 +00:00
// license that can be found in the LICENSE file.
// Package buildutil provides utilities related to the go/build
2024-05-14 13:07:09 +00:00
// package in the standard library.
2024-05-14 13:07:09 +00:00
//
2024-05-14 13:07:09 +00:00
// All I/O is done via the build.Context file system interface, which must
2024-05-14 13:07:09 +00:00
// be concurrency-safe.
2024-05-14 13:07:09 +00:00
package buildutil // import "golang.org/x/tools/go/buildutil"
import (
"go/build"
"os"
"path/filepath"
"sort"
"strings"
"sync"
)
// AllPackages returns the package path of each Go package in any source
2024-05-14 13:07:09 +00:00
// directory of the specified build context (e.g. $GOROOT or an element
2024-05-14 13:07:09 +00:00
// of $GOPATH). Errors are ignored. The results are sorted.
2024-05-14 13:07:09 +00:00
// All package paths are canonical, and thus may contain "/vendor/".
2024-05-14 13:07:09 +00:00
//
2024-05-14 13:07:09 +00:00
// The result may include import paths for directories that contain no
2024-05-14 13:07:09 +00:00
// *.go files, such as "archive" (in $GOROOT/src).
2024-05-14 13:07:09 +00:00
//
2024-05-14 13:07:09 +00:00
// All I/O is done via the build.Context file system interface,
2024-05-14 13:07:09 +00:00
// which must be concurrency-safe.
2024-05-14 13:07:09 +00:00
func AllPackages(ctxt *build.Context) []string {
2024-05-14 13:07:09 +00:00
var list []string
2024-05-14 13:07:09 +00:00
ForEachPackage(ctxt, func(pkg string, _ error) {
2024-05-14 13:07:09 +00:00
list = append(list, pkg)
2024-05-14 13:07:09 +00:00
})
2024-05-14 13:07:09 +00:00
sort.Strings(list)
2024-05-14 13:07:09 +00:00
return list
2024-05-14 13:07:09 +00:00
}
// ForEachPackage calls the found function with the package path of
2024-05-14 13:07:09 +00:00
// each Go package it finds in any source directory of the specified
2024-05-14 13:07:09 +00:00
// build context (e.g. $GOROOT or an element of $GOPATH).
2024-05-14 13:07:09 +00:00
// All package paths are canonical, and thus may contain "/vendor/".
2024-05-14 13:07:09 +00:00
//
2024-05-14 13:07:09 +00:00
// If the package directory exists but could not be read, the second
2024-05-14 13:07:09 +00:00
// argument to the found function provides the error.
2024-05-14 13:07:09 +00:00
//
2024-05-14 13:07:09 +00:00
// All I/O is done via the build.Context file system interface,
2024-05-14 13:07:09 +00:00
// which must be concurrency-safe.
2024-05-14 13:07:09 +00:00
func ForEachPackage(ctxt *build.Context, found func(importPath string, err error)) {
2024-05-14 13:07:09 +00:00
ch := make(chan item)
var wg sync.WaitGroup
2024-05-14 13:07:09 +00:00
for _, root := range ctxt.SrcDirs() {
2024-05-14 13:07:09 +00:00
root := root
2024-05-14 13:07:09 +00:00
wg.Add(1)
2024-05-14 13:07:09 +00:00
go func() {
2024-05-14 13:07:09 +00:00
allPackages(ctxt, root, ch)
2024-05-14 13:07:09 +00:00
wg.Done()
2024-05-14 13:07:09 +00:00
}()
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
go func() {
2024-05-14 13:07:09 +00:00
wg.Wait()
2024-05-14 13:07:09 +00:00
close(ch)
2024-05-14 13:07:09 +00:00
}()
// All calls to found occur in the caller's goroutine.
2024-05-14 13:07:09 +00:00
for i := range ch {
2024-05-14 13:07:09 +00:00
found(i.importPath, i.err)
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
}
type item struct {
importPath string
err error // (optional)
2024-05-14 13:07:09 +00:00
}
// We use a process-wide counting semaphore to limit
2024-05-14 13:07:09 +00:00
// the number of parallel calls to ReadDir.
2024-05-14 13:07:09 +00:00
var ioLimit = make(chan bool, 20)
func allPackages(ctxt *build.Context, root string, ch chan<- item) {
2024-05-14 13:07:09 +00:00
root = filepath.Clean(root) + string(os.PathSeparator)
var wg sync.WaitGroup
var walkDir func(dir string)
2024-05-14 13:07:09 +00:00
walkDir = func(dir string) {
2024-05-14 13:07:09 +00:00
// Avoid .foo, _foo, and testdata directory trees.
2024-05-14 13:07:09 +00:00
base := filepath.Base(dir)
2024-05-14 13:07:09 +00:00
if base == "" || base[0] == '.' || base[0] == '_' || base == "testdata" {
2024-05-14 13:07:09 +00:00
return
2024-05-14 13:07:09 +00:00
}
pkg := filepath.ToSlash(strings.TrimPrefix(dir, root))
// Prune search if we encounter any of these import paths.
2024-05-14 13:07:09 +00:00
switch pkg {
2024-05-14 13:07:09 +00:00
case "builtin":
2024-05-14 13:07:09 +00:00
return
2024-05-14 13:07:09 +00:00
}
ioLimit <- true
2024-05-14 13:07:09 +00:00
files, err := ReadDir(ctxt, dir)
2024-05-14 13:07:09 +00:00
<-ioLimit
2024-05-14 13:07:09 +00:00
if pkg != "" || err != nil {
2024-05-14 13:07:09 +00:00
ch <- item{pkg, err}
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
for _, fi := range files {
2024-05-14 13:07:09 +00:00
fi := fi
2024-05-14 13:07:09 +00:00
if fi.IsDir() {
2024-05-14 13:07:09 +00:00
wg.Add(1)
2024-05-14 13:07:09 +00:00
go func() {
2024-05-14 13:07:09 +00:00
walkDir(filepath.Join(dir, fi.Name()))
2024-05-14 13:07:09 +00:00
wg.Done()
2024-05-14 13:07:09 +00:00
}()
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
}
walkDir(root)
2024-05-14 13:07:09 +00:00
wg.Wait()
2024-05-14 13:07:09 +00:00
}
// ExpandPatterns returns the set of packages matched by patterns,
2024-05-14 13:07:09 +00:00
// which may have the following forms:
2024-05-14 13:07:09 +00:00
//
2024-05-14 13:07:09 +00:00
// golang.org/x/tools/cmd/guru # a single package
2024-05-14 13:07:09 +00:00
// golang.org/x/tools/... # all packages beneath dir
2024-05-14 13:07:09 +00:00
// ... # the entire workspace.
2024-05-14 13:07:09 +00:00
//
2024-05-14 13:07:09 +00:00
// Order is significant: a pattern preceded by '-' removes matching
2024-05-14 13:07:09 +00:00
// packages from the set. For example, these patterns match all encoding
2024-05-14 13:07:09 +00:00
// packages except encoding/xml:
2024-05-14 13:07:09 +00:00
//
2024-05-14 13:07:09 +00:00
// encoding/... -encoding/xml
2024-05-14 13:07:09 +00:00
//
2024-05-14 13:07:09 +00:00
// A trailing slash in a pattern is ignored. (Path components of Go
2024-05-14 13:07:09 +00:00
// package names are separated by slash, not the platform's path separator.)
2024-05-14 13:07:09 +00:00
func ExpandPatterns(ctxt *build.Context, patterns []string) map[string]bool {
2024-05-14 13:07:09 +00:00
// TODO(adonovan): support other features of 'go list':
2024-05-14 13:07:09 +00:00
// - "std"/"cmd"/"all" meta-packages
2024-05-14 13:07:09 +00:00
// - "..." not at the end of a pattern
2024-05-14 13:07:09 +00:00
// - relative patterns using "./" or "../" prefix
pkgs := make(map[string]bool)
2024-05-14 13:07:09 +00:00
doPkg := func(pkg string, neg bool) {
2024-05-14 13:07:09 +00:00
if neg {
2024-05-14 13:07:09 +00:00
delete(pkgs, pkg)
2024-05-14 13:07:09 +00:00
} else {
2024-05-14 13:07:09 +00:00
pkgs[pkg] = true
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
}
// Scan entire workspace if wildcards are present.
2024-05-14 13:07:09 +00:00
// TODO(adonovan): opt: scan only the necessary subtrees of the workspace.
2024-05-14 13:07:09 +00:00
var all []string
2024-05-14 13:07:09 +00:00
for _, arg := range patterns {
2024-05-14 13:07:09 +00:00
if strings.HasSuffix(arg, "...") {
2024-05-14 13:07:09 +00:00
all = AllPackages(ctxt)
2024-05-14 13:07:09 +00:00
break
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
}
for _, arg := range patterns {
2024-05-14 13:07:09 +00:00
if arg == "" {
2024-05-14 13:07:09 +00:00
continue
2024-05-14 13:07:09 +00:00
}
neg := arg[0] == '-'
2024-05-14 13:07:09 +00:00
if neg {
2024-05-14 13:07:09 +00:00
arg = arg[1:]
2024-05-14 13:07:09 +00:00
}
if arg == "..." {
2024-05-14 13:07:09 +00:00
// ... matches all packages
2024-05-14 13:07:09 +00:00
for _, pkg := range all {
2024-05-14 13:07:09 +00:00
doPkg(pkg, neg)
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
} else if dir := strings.TrimSuffix(arg, "/..."); dir != arg {
2024-05-14 13:07:09 +00:00
// dir/... matches all packages beneath dir
2024-05-14 13:07:09 +00:00
for _, pkg := range all {
2024-05-14 13:07:09 +00:00
if strings.HasPrefix(pkg, dir) &&
2024-05-14 13:07:09 +00:00
(len(pkg) == len(dir) || pkg[len(dir)] == '/') {
2024-05-14 13:07:09 +00:00
doPkg(pkg, neg)
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
} else {
2024-05-14 13:07:09 +00:00
// single package
2024-05-14 13:07:09 +00:00
doPkg(strings.TrimSuffix(arg, "/"), neg)
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
}
return pkgs
2024-05-14 13:07:09 +00:00
}