Skip to content

Commit b864818

Browse files
committed
cmd/api: read std package info once, not per goos-goarch-cgo
Cuts api test time from 12.7r 26.2u 14.2s to 7.5r 12.1u 2.2s. After this change, all.bash runs in ~4:36 on my laptop. For #26473. Change-Id: I4211e6afcd7ab61a4ed2c9a2aa5ac1ea04982695 Reviewed-on: https://go-review.googlesource.com/c/go/+/177597 Run-TryBot: Russ Cox <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Brad Fitzpatrick <[email protected]>
1 parent 2d357d8 commit b864818

File tree

1 file changed

+58
-43
lines changed

1 file changed

+58
-43
lines changed

src/cmd/api/goapi.go

+58-43
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ func main() {
144144
} else {
145145
stds, err := exec.Command(goCmd(), "list", "std").Output()
146146
if err != nil {
147-
log.Fatal(err)
147+
log.Fatalf("go list std: %v\n%s", err, stds)
148148
}
149149
for _, pkg := range strings.Fields(string(stds)) {
150150
if !internalPkg.MatchString(pkg) {
@@ -153,10 +153,25 @@ func main() {
153153
}
154154
}
155155

156+
importDir, importMap := loadImports()
157+
158+
// The code below assumes that the import map can vary
159+
// by package, so that an import in one package (directory) might mean
160+
// something different from the same import in another.
161+
// While this can happen in GOPATH mode with vendoring,
162+
// it is not possible in the standard library: the one importMap
163+
// returned by loadImports applies to all packages.
164+
// Construct a per-directory importMap that resolves to
165+
// that single map for all packages.
166+
importMapForDir := make(map[string]map[string]string)
167+
for _, dir := range importDir {
168+
importMapForDir[dir] = importMap
169+
}
156170
var featureCtx = make(map[string]map[string]bool) // feature -> context name -> true
157171
for _, context := range contexts {
158172
w := NewWalker(context, filepath.Join(build.Default.GOROOT, "src"))
159-
w.loadImports(pkgNames, w.context)
173+
w.importDir = importDir
174+
w.importMap = importMapForDir
160175

161176
for _, name := range pkgNames {
162177
// Vendored packages do not contribute to our
@@ -440,58 +455,58 @@ func tagKey(dir string, context *build.Context, tags []string) string {
440455
return key
441456
}
442457

443-
func (w *Walker) loadImports(paths []string, context *build.Context) {
444-
if context == nil {
445-
context = &build.Default
446-
}
447-
448-
var (
449-
tags = context.BuildTags
450-
cgoEnabled = "0"
451-
)
452-
if context.CgoEnabled {
453-
tags = append(tags[:len(tags):len(tags)], "cgo")
454-
cgoEnabled = "1"
455-
}
456-
457-
// TODO(golang.org/issue/29666): Request only the fields that we need.
458-
cmd := exec.Command(goCmd(), "list", "-e", "-deps", "-json")
459-
if len(tags) > 0 {
460-
cmd.Args = append(cmd.Args, "-tags", strings.Join(tags, " "))
461-
}
462-
cmd.Args = append(cmd.Args, paths...)
463-
464-
cmd.Env = append(os.Environ(),
465-
"GOOS="+context.GOOS,
466-
"GOARCH="+context.GOARCH,
467-
"CGO_ENABLED="+cgoEnabled,
468-
)
469-
470-
stdout := new(bytes.Buffer)
471-
cmd.Stdout = stdout
472-
cmd.Stderr = new(strings.Builder)
473-
err := cmd.Run()
458+
// loadImports returns information about the packages in the standard library
459+
// and the packages they themselves import.
460+
// importDir maps expanded import path to the directory containing that package.
461+
// importMap maps source import path to expanded import path.
462+
// The source import path and expanded import path are identical except for vendored packages.
463+
// For example, on return:
464+
//
465+
// importMap["math"] = "math"
466+
// importDir["math"] = "<goroot>/src/math"
467+
//
468+
// importMap["golang.org/x/net/route"] = "vendor/golang.org/x/net/route"
469+
// importDir["vendor/golang.org/x/net/route"] = "<goroot>/src/vendor/golang.org/x/net/route"
470+
//
471+
// There are a few imports that only appear on certain platforms,
472+
// including it turns out x/net/route, and we add those explicitly.
473+
func loadImports() (importDir map[string]string, importMap map[string]string) {
474+
out, err := exec.Command(goCmd(), "list", "-e", "-deps", "-json", "std").CombinedOutput()
474475
if err != nil {
475-
log.Fatalf("%s failed: %v\n%s", strings.Join(cmd.Args, " "), err, cmd.Stderr)
476+
log.Fatalf("loading imports: %v\n%s", err, out)
476477
}
477478

478-
w.importDir = make(map[string]string)
479-
w.importMap = make(map[string]map[string]string)
480-
dec := json.NewDecoder(stdout)
479+
importDir = make(map[string]string)
480+
importMap = make(map[string]string)
481+
dec := json.NewDecoder(bytes.NewReader(out))
481482
for {
482483
var pkg struct {
483484
ImportPath, Dir string
484485
ImportMap map[string]string
485486
}
486-
if err := dec.Decode(&pkg); err == io.EOF {
487+
err := dec.Decode(&pkg)
488+
if err == io.EOF {
487489
break
488-
} else if err != nil {
489-
log.Fatalf("%s: invalid output: %v", strings.Join(cmd.Args, " "), err)
490+
}
491+
if err != nil {
492+
log.Fatalf("go list: invalid output: %v", err)
490493
}
491494

492-
w.importDir[pkg.ImportPath] = pkg.Dir
493-
w.importMap[pkg.Dir] = pkg.ImportMap
495+
importDir[pkg.ImportPath] = pkg.Dir
496+
for k, v := range pkg.ImportMap {
497+
importMap[k] = v
498+
}
494499
}
500+
501+
// Fixup for vendor packages listed in args above.
502+
fixup := []string{
503+
"vendor/golang.org/x/net/route",
504+
}
505+
for _, pkg := range fixup {
506+
importDir[pkg] = filepath.Join(build.Default.GOROOT, "src", pkg)
507+
importMap[strings.TrimPrefix(pkg, "vendor/")] = pkg
508+
}
509+
return
495510
}
496511

497512
// Importing is a sentinel taking the place in Walker.imported
@@ -523,7 +538,7 @@ func (w *Walker) ImportFrom(fromPath, fromDir string, mode types.ImportMode) (*t
523538
dir = filepath.Join(w.root, filepath.FromSlash(name))
524539
}
525540
if fi, err := os.Stat(dir); err != nil || !fi.IsDir() {
526-
log.Fatalf("no source in tree for import %q: %v", name, err)
541+
log.Fatalf("no source in tree for import %q (from import %s in %s): %v", name, fromPath, fromDir, err)
527542
}
528543

529544
context := w.context

0 commit comments

Comments
 (0)