func()

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
}