func fetchModule()

in cmd/fetch_repo/module.go [32:118]


func fetchModule(dest, importpath, version, sum string) error {
	// Check that version is a complete semantic version or pseudo-version.
	if _, ok := parse(version); !ok {
		return fmt.Errorf("%q is not a valid semantic version", version)
	} else if isSemverPrefix(version) {
		return fmt.Errorf("-version must be a complete semantic version. %q is a prefix.", version)
	}

	// Locate the go binary. If GOROOT is set, we'll use that one; otherwise,
	// we'll use PATH.
	goPath := "go"
	if runtime.GOOS == "windows" {
		goPath += ".exe"
	}
	if goroot, ok := os.LookupEnv("GOROOT"); ok {
		goPath = filepath.Join(goroot, "bin", goPath)
	}

	// Check whether -modcacherw is supported.
	// Assume that fetch_repo was built with the same version of Go we're running.
	modcacherw := false
	for _, tag := range build.Default.ReleaseTags {
		if tag == "go1.14" {
			modcacherw = true
			break
		}
	}

	// Download the module. In Go 1.11, this command must be run in a module,
	// so we create a dummy module in the current directory (which should be
	// empty).
	w, err := os.OpenFile("go.mod", os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0666)
	if err != nil {
		return fmt.Errorf("error creating temporary go.mod: %v", err)
	}
	_, err = fmt.Fprintln(w, "module example.com/temporary/module/for/fetch_repo/download")
	if err != nil {
		w.Close()
		return fmt.Errorf("error writing temporary go.mod: %v", err)
	}
	if err := w.Close(); err != nil {
		return fmt.Errorf("error closing temporary go.mod: %v", err)
	}

	buf := &bytes.Buffer{}
	bufErr := &bytes.Buffer{}
	cmd := exec.Command(goPath, "mod", "download", "-json")
	if modcacherw {
		cmd.Args = append(cmd.Args, "-modcacherw")
	}
	cmd.Args = append(cmd.Args, importpath+"@"+version)
	cmd.Stdout = buf
	cmd.Stderr = bufErr
	dlErr := cmd.Run()
	os.Remove("go.mod")
	if dlErr != nil {
		if _, ok := dlErr.(*exec.ExitError); !ok {
			if bufErr.Len() > 0 {
				return fmt.Errorf("%s %s: %s", cmd.Path, strings.Join(cmd.Args, " "), bufErr.Bytes())
			} else {
				return fmt.Errorf("%s %s: %v", cmd.Path, strings.Join(cmd.Args, " "), dlErr)
			}
		}
	}

	// Parse the JSON output.
	var dl struct{ Dir, Sum, Error string }
	if err := json.Unmarshal(buf.Bytes(), &dl); err != nil {
		if bufErr.Len() > 0 {
			return fmt.Errorf("%s %s: %s", cmd.Path, strings.Join(cmd.Args, " "), bufErr.Bytes())
		} else {
			return fmt.Errorf("%s %s: %v", cmd.Path, strings.Join(cmd.Args, " "), err)
		}
	}
	if dl.Error != "" {
		return errors.New(dl.Error)
	}
	if dlErr != nil {
		return dlErr
	}
	if dl.Sum != sum {
		return fmt.Errorf("downloaded module with sum %s; expected sum %s", dl.Sum, sum)
	}

	// Copy the module to the destination.
	return copyTree(dest, dl.Dir)
}