aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/api
diff options
context:
space:
mode:
authorBryan C. Mills <bcmills@google.com>2019-03-05 16:52:48 -0500
committerBryan C. Mills <bcmills@google.com>2019-03-08 15:14:27 +0000
commit361a01983f01790694d5c7773d56a560c01b96cb (patch)
tree7ab534679f0a05d64e769b854009c77963ecf8c3 /src/cmd/api
parent49662bc6b02810389c66b6b24576f6a5b217d471 (diff)
downloadgo-361a01983f01790694d5c7773d56a560c01b96cb.tar.xz
cmd/api: use 'go list' to locate transitive dependencies of std
With standard-library modules and vendoring, the mapping from import path to directory within the standard library is no longer entirely trivial. Fortunately, 'go list' makes that mapping straightforward to compute. Updates #30241 Updates #30228 Change-Id: Iddd77c21a527b7acdb30c17bec8b4bbd43e23756 Reviewed-on: https://go-review.googlesource.com/c/go/+/165497 Run-TryBot: Bryan C. Mills <bcmills@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Jay Conrod <jayconrod@google.com>
Diffstat (limited to 'src/cmd/api')
-rw-r--r--src/cmd/api/goapi.go84
1 files changed, 77 insertions, 7 deletions
diff --git a/src/cmd/api/goapi.go b/src/cmd/api/goapi.go
index 60359229de..1a0242f60c 100644
--- a/src/cmd/api/goapi.go
+++ b/src/cmd/api/goapi.go
@@ -8,6 +8,7 @@ package main
import (
"bufio"
"bytes"
+ "encoding/json"
"flag"
"fmt"
"go/ast"
@@ -153,6 +154,7 @@ func main() {
var featureCtx = make(map[string]map[string]bool) // feature -> context name -> true
for _, context := range contexts {
w := NewWalker(context, filepath.Join(build.Default.GOROOT, "src"))
+ w.loadImports(pkgNames, w.context)
for _, name := range pkgNames {
// Vendored packages do not contribute to our
@@ -349,12 +351,14 @@ func fileFeatures(filename string) []string {
var fset = token.NewFileSet()
type Walker struct {
- context *build.Context
- root string
- scope []string
- current *types.Package
- features map[string]bool // set
- imported map[string]*types.Package // packages already imported
+ context *build.Context
+ root string
+ scope []string
+ current *types.Package
+ features map[string]bool // set
+ imported map[string]*types.Package // packages already imported
+ importMap map[string]map[string]string // importer dir -> import path -> canonical path
+ importDir map[string]string // canonical import path -> dir
}
func NewWalker(context *build.Context, root string) *Walker {
@@ -434,11 +438,74 @@ func tagKey(dir string, context *build.Context, tags []string) string {
return key
}
+func (w *Walker) loadImports(paths []string, context *build.Context) {
+ if context == nil {
+ context = &build.Default
+ }
+
+ var (
+ tags = context.BuildTags
+ cgoEnabled = "0"
+ )
+ if context.CgoEnabled {
+ tags = append(tags[:len(tags):len(tags)], "cgo")
+ cgoEnabled = "1"
+ }
+
+ // TODO(golang.org/issue/29666): Request only the fields that we need.
+ cmd := exec.Command(goCmd(), "list", "-e", "-deps", "-json")
+ if len(tags) > 0 {
+ cmd.Args = append(cmd.Args, "-tags", strings.Join(tags, " "))
+ }
+ cmd.Args = append(cmd.Args, paths...)
+
+ cmd.Env = append(os.Environ(),
+ "GOOS="+context.GOOS,
+ "GOARCH="+context.GOARCH,
+ "CGO_ENABLED="+cgoEnabled,
+ )
+
+ stdout := new(bytes.Buffer)
+ cmd.Stdout = stdout
+ cmd.Stderr = new(strings.Builder)
+ err := cmd.Run()
+ if err != nil {
+ log.Fatalf("%s failed: %v\n%s", strings.Join(cmd.Args, " "), err, cmd.Stderr)
+ }
+
+ w.importDir = make(map[string]string)
+ w.importMap = make(map[string]map[string]string)
+ dec := json.NewDecoder(stdout)
+ for {
+ var pkg struct {
+ ImportPath, Dir string
+ ImportMap map[string]string
+ }
+ if err := dec.Decode(&pkg); err == io.EOF {
+ break
+ } else if err != nil {
+ log.Fatalf("%s: invalid output: %v", strings.Join(cmd.Args, " "), err)
+ }
+
+ w.importDir[pkg.ImportPath] = pkg.Dir
+ w.importMap[pkg.Dir] = pkg.ImportMap
+ }
+}
+
// Importing is a sentinel taking the place in Walker.imported
// for a package that is in the process of being imported.
var importing types.Package
func (w *Walker) Import(name string) (*types.Package, error) {
+ return w.ImportFrom(name, "", 0)
+}
+
+func (w *Walker) ImportFrom(fromPath, fromDir string, mode types.ImportMode) (*types.Package, error) {
+ name := fromPath
+ if canonical, ok := w.importMap[fromDir][fromPath]; ok {
+ name = canonical
+ }
+
pkg := w.imported[name]
if pkg != nil {
if pkg == &importing {
@@ -449,7 +516,10 @@ func (w *Walker) Import(name string) (*types.Package, error) {
w.imported[name] = &importing
// Determine package files.
- dir := filepath.Join(w.root, filepath.FromSlash(name))
+ dir := w.importDir[name]
+ if dir == "" {
+ dir = filepath.Join(w.root, filepath.FromSlash(name))
+ }
if fi, err := os.Stat(dir); err != nil || !fi.IsDir() {
log.Fatalf("no source in tree for import %q: %v", name, err)
}