in internal/symbol/generate.go [181:286]
func (w *Walker) loadImports(pkgPath string) {
if w.context == nil {
return // test-only Walker; does not use the import map
}
generateOutput := func() ([]byte, error) {
cmd := exec.Command(goCmd(), "list", "-e", "-deps", "-json")
cmd.Env = listEnv(w.context)
if w.context.Dir != "" {
cmd.Dir = w.context.Dir
}
return cmd.CombinedOutput()
}
goModDownload := func(out []byte) ([]byte, error) {
words := strings.Fields(string(out))
modPath := words[len(words)-1]
cmd := exec.Command("go", "mod", "download", modPath)
if w.context.Dir != "" {
cmd.Dir = w.context.Dir
}
return cmd.CombinedOutput()
}
retryOrFail := func(out []byte, err error) {
if strings.Contains(string(out), "missing go.sum entry") {
out2, err2 := goModDownload(out)
if err2 != nil {
log.Fatalf("loadImports: initial error: %v\n%s \n\n error running go mod download: %v\n%s",
err, string(out), err2, string(out2))
}
return
}
log.Fatalf("loadImports: %v\n%s", err, out)
}
name := contextName(w.context)
imports, ok := listCache.Load(name)
if !ok {
listSem <- semToken{}
defer func() { <-listSem }()
out, err := generateOutput()
if err != nil {
retryOrFail(out, err)
}
if strings.HasPrefix(string(out), "go: downloading") {
// If a module was downloaded, we will see "go: downloading
// <module> ..." in the JSON output.
// This causes an error in json.NewDecoder below, so run
// generateOutput again to avoid that error.
out, err = generateOutput()
if err != nil {
retryOrFail(out, err)
}
}
var packages []string
importMap := make(map[string]map[string]string)
importDir := make(map[string]string)
dec := json.NewDecoder(bytes.NewReader(out))
for {
var pkg struct {
ImportPath, Dir string
ImportMap map[string]string
Standard bool
}
err := dec.Decode(&pkg)
if err == io.EOF {
break
}
if err != nil {
log.Fatalf("loadImports: go list: invalid output: %v", err)
}
// - Package "unsafe" contains special signatures requiring
// extra care when printing them - ignore since it is not
// going to change w/o a language change.
// - Internal and vendored packages do not contribute to our
// API surface. (If we are running within the "std" module,
// vendored dependencies appear as themselves instead of
// their "vendor/" standard-library copies.)
// - 'go list std' does not include commands, which cannot be
// imported anyway.
if ip := pkg.ImportPath; pkg.ImportPath == pkgPath ||
(pkg.Standard && ip != "unsafe" && !strings.HasPrefix(ip, "vendor/") && !internalPkg.MatchString(ip)) {
packages = append(packages, ip)
}
importDir[pkg.ImportPath] = pkg.Dir
if len(pkg.ImportMap) > 0 {
importMap[pkg.Dir] = make(map[string]string, len(pkg.ImportMap))
}
for k, v := range pkg.ImportMap {
importMap[pkg.Dir][k] = v
}
}
sort.Strings(packages)
imports = listImports{
packages: packages,
importMap: importMap,
importDir: importDir,
}
imports, _ = listCache.LoadOrStore(name, imports)
}
li := imports.(listImports)
w.packages = li.packages
w.importDir = li.importDir
w.importMap = li.importMap
}