in cmd/gorelease/gorelease.go [1055:1205]
func prepareLoadDir(ctx context.Context, modFile *modfile.File, modPath, modRoot, version string, cached bool) (dir string, goModData, goSumData []byte, pkgPaths []string, diagnostics []string, err error) {
defer func() {
if err != nil {
if cached {
err = fmt.Errorf("preparing to load packages for %s@%s: %w", modPath, version, err)
} else {
err = fmt.Errorf("preparing to load packages for %s: %w", modPath, err)
}
}
}()
if module.Check(modPath, version) != nil {
// If no version is proposed or if the version isn't valid, use a fake
// version that matches the module's major version suffix. If the version
// is invalid, that will be reported elsewhere.
version = "v0.0.0-gorelease"
if _, pathMajor, _ := module.SplitPathVersion(modPath); pathMajor != "" {
version = pathMajor[1:] + ".0.0-gorelease"
}
}
dir, err = ioutil.TempDir("", "gorelease-load")
if err != nil {
return "", nil, nil, nil, nil, err
}
f := &modfile.File{}
f.AddModuleStmt("gorelease-load-module")
f.AddRequire(modPath, version)
if !cached {
f.AddReplace(modPath, version, modRoot, "")
}
if modFile != nil {
if modFile.Go != nil {
f.AddGoStmt(modFile.Go.Version)
}
for _, r := range modFile.Require {
f.AddRequire(r.Mod.Path, r.Mod.Version)
}
}
goModData, err = f.Format()
if err != nil {
return "", nil, nil, nil, nil, err
}
if err := ioutil.WriteFile(filepath.Join(dir, "go.mod"), goModData, 0666); err != nil {
return "", nil, nil, nil, nil, err
}
goSumData, err = ioutil.ReadFile(filepath.Join(modRoot, "go.sum"))
if err != nil && !os.IsNotExist(err) {
return "", nil, nil, nil, nil, err
}
if err := ioutil.WriteFile(filepath.Join(dir, "go.sum"), goSumData, 0666); err != nil {
return "", nil, nil, nil, nil, err
}
// Add a .go file with requirements, so that `go get` won't blat
// requirements.
fakeImports := &strings.Builder{}
fmt.Fprint(fakeImports, "package tmp\n")
imps, err := collectImportPaths(modPath, modRoot)
if err != nil {
return "", nil, nil, nil, nil, err
}
for _, imp := range imps {
fmt.Fprintf(fakeImports, "import _ %q\n", imp)
}
if err := ioutil.WriteFile(filepath.Join(dir, "tmp.go"), []byte(fakeImports.String()), 0666); err != nil {
return "", nil, nil, nil, nil, err
}
// Add missing requirements.
cmd := exec.CommandContext(ctx, "go", "get", "-d", ".")
cmd.Env = copyEnv(ctx, cmd.Env)
cmd.Dir = dir
if _, err := cmd.Output(); err != nil {
return "", nil, nil, nil, nil, fmt.Errorf("looking for missing dependencies: %w", cleanCmdError(err))
}
// Report new requirements in go.mod.
goModPath := filepath.Join(dir, "go.mod")
loadReqs := func(data []byte) (reqs []module.Version, err error) {
modFile, err := modfile.ParseLax(goModPath, data, nil)
if err != nil {
return nil, err
}
for _, r := range modFile.Require {
reqs = append(reqs, r.Mod)
}
return reqs, nil
}
oldReqs, err := loadReqs(goModData)
if err != nil {
return "", nil, nil, nil, nil, err
}
newGoModData, err := ioutil.ReadFile(goModPath)
if err != nil {
return "", nil, nil, nil, nil, err
}
newReqs, err := loadReqs(newGoModData)
if err != nil {
return "", nil, nil, nil, nil, err
}
oldMap := make(map[module.Version]bool)
for _, req := range oldReqs {
oldMap[req] = true
}
var missing []module.Version
for _, req := range newReqs {
// Ignore cyclic imports, since a module never needs to require itself.
if req.Path == modPath {
continue
}
if !oldMap[req] {
missing = append(missing, req)
}
}
if len(missing) > 0 {
var missingReqs []string
for _, m := range missing {
missingReqs = append(missingReqs, m.String())
}
diagnostics = append(diagnostics, fmt.Sprintf("go.mod: the following requirements are needed\n\t%s\nRun 'go mod tidy' to add missing requirements.", strings.Join(missingReqs, "\n\t")))
return dir, goModData, goSumData, imps, diagnostics, nil
}
// Cached modules may have no go.sum.
// We skip comparison because a downloaded module is outside the user's
// control.
if !cached {
// Check if 'go get' added new hashes to go.sum.
goSumPath := filepath.Join(dir, "go.sum")
newGoSumData, err := ioutil.ReadFile(goSumPath)
if err != nil {
if !os.IsNotExist(err) {
return "", nil, nil, nil, nil, err
}
// If the sum doesn't exist, that's ok: we'll treat "no go.sum" like
// "empty go.sum".
}
if !sumsMatchIgnoringPath(string(goSumData), string(newGoSumData), modPath) {
diagnostics = append(diagnostics, "go.sum: one or more sums are missing. Run 'go mod tidy' to add missing sums.")
}
}
return dir, goModData, goSumData, imps, diagnostics, nil
}