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)
}