Skip to content

Commit

Permalink
[cmd/fetch_repo] make cache corruption failures more clear (#1782)
Browse files Browse the repository at this point in the history
This failure was confusing to our users. We should make more clear error messages in cases when a `GOMODCACHE` might be corrupt.

Resolves #1774

Example failure:
```
ERROR: /home/user/go-code/WORKSPACE:69:26: fetching go_repository rule //external:com_github_bazelbuild_remote_apis: Traceback (most recent call last):
        File "/home/user/.cache/bazel/_bazel_tfrench/b97476d719d716accead0f2d5b93104f/external/bazel_gazelle/internal/go_repository.bzl", line 263, column 17, in _go_repository_impl
                fail("failed to fetch %s: %s" % (ctx.name, result.stderr))
Error in fail: failed to fetch com_github_bazelbuild_remote_apis: fetch_repo: resulting module with sum h1:xhO5v3Ac039HesaPqoVUwOy4WhRRJbmo9om245kp+AY=; expected sum h1:xhO5v3Ac039HesaPqoVUwOy4WhRRJbmo9om245kp+AY=, Please try clearing your module cache directory "/home/user/go-code/pkg/mod"
ERROR: Error computing the main repository mapping: no such package '@@com_github_bazelbuild_remote_apis//': failed to fetch com_github_bazelbuild_remote_apis: fetch_repo: resulting module with sum h1:xhO5v3Ac039HesaPqoVUwOy4WhRRJbmo9om245kp+AY=; expected sum h1:xhO5v3Ac039HesaPqoVUwOy4WhRRJbmo9om245kp+AY=, Please try clearing your module cache directory "/home/user/go-code/pkg/mod"
INFO: Build Event Protocol files produced successfully.
Computing main repo mapping: 
WARNING:Bazel failed with exit code 1
```
  • Loading branch information
tyler-french authored Apr 12, 2024
1 parent 26bb2ac commit cc40a33
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 33 deletions.
32 changes: 16 additions & 16 deletions cmd/fetch_repo/copy_tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,23 +37,23 @@ func copyTree(destRoot, srcRoot string) error {

if info.IsDir() {
return os.Mkdir(dest, 0o777)
} else {
r, err := os.Open(src)
if err != nil {
return err
}
defer r.Close()
w, err := os.Create(dest)
if err != nil {
return err
}
defer func() {
if cerr := w.Close(); err == nil && cerr != nil {
err = cerr
}
}()
_, err = io.Copy(w, r)
}

r, err := os.Open(src)
if err != nil {
return err
}
defer r.Close()
w, err := os.Create(dest)
if err != nil {
return err
}
defer func() {
if cerr := w.Close(); err == nil && cerr != nil {
err = cerr
}
}()
_, err = io.Copy(w, r)
return err
})
}
20 changes: 7 additions & 13 deletions cmd/fetch_repo/go_mod_download.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ func findGoPath() string {
}

func runGoModDownload(dl *GoModDownloadResult, dest string, importpath string, version string) error {
buf := &bytes.Buffer{}
bufErr := &bytes.Buffer{}
buf := bytes.NewBuffer(nil)
bufErr := bytes.NewBuffer(nil)
cmd := exec.Command(findGoPath(), "mod", "download", "-json")
cmd.Dir = dest
cmd.Args = append(cmd.Args, "-modcacherw")
Expand All @@ -44,34 +44,28 @@ func runGoModDownload(dl *GoModDownloadResult, dest string, importpath string, v

cmd.Stdout = buf
cmd.Stderr = bufErr
fmt.Printf("Running: %s %s\n", cmd.Path, strings.Join(cmd.Args, " "))
dlErr := cmd.Run()
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)
return fmt.Errorf("go mod download exec error: %s %q: %s, %w", cmd.Path, strings.Join(cmd.Args, " "), bufErr.String(), dlErr)
}
return fmt.Errorf("go mod download exec error: %s %s: %v", cmd.Path, strings.Join(cmd.Args, " "), dlErr)
}
}

// Parse the JSON output.
if err := json.Unmarshal(buf.Bytes(), &dl); err != nil {
if bufErr.Len() > 0 {
return fmt.Errorf("3%s %s: %s", cmd.Path, strings.Join(cmd.Args, " "), bufErr.Bytes())
} else {
return fmt.Errorf("4%s %s: error parsing JSON: %v error: %v", cmd.Path, strings.Join(cmd.Args, " "), buf, err)
return fmt.Errorf("go mod download output format: `%s %s`: parsing JSON: %q stderr: %q error: %w", cmd.Path, strings.Join(cmd.Args, " "), buf.String(), bufErr.String(), err)
}
return fmt.Errorf("go mod download output format: `%s %s`: parsing JSON: %q error: %w", cmd.Path, strings.Join(cmd.Args, " "), buf.String(), err)
}
if dl.Error != "" {
return errors.New(dl.Error)
return errors.Join(errors.New(dl.Error), dlErr)
}
if dlErr != nil {
return dlErr
}

fmt.Printf("Downloaded: %s\n", dl.Dir)

return nil
}
9 changes: 5 additions & 4 deletions cmd/fetch_repo/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,24 +49,25 @@ func fetchModule(dest, importpath, version, sum string) error {
var dl = GoModDownloadResult{}
err = runGoModDownload(&dl, dest, importpath, version)
os.Remove("go.mod")

if err != nil {
return err
}

// Copy the module to the destination.
err = copyTree(dest, dl.Dir)
if err != nil {
if err := copyTree(dest, dl.Dir); err != nil {
return fmt.Errorf("failed copying repo: %w", err)
}

// Verify sum
// Verify sum of the directory itself against the go.sum.
repoSum, err := dirhash.HashDir(dest, importpath+"@"+version, dirhash.Hash1)
if err != nil {
return fmt.Errorf("failed computing sum: %w", err)
}

if repoSum != sum {
if goModCache := os.Getenv("GOMODCACHE"); goModCache != "" {
return fmt.Errorf("resulting module with sum %s; expected sum %s, Please try clearing your module cache directory %q", repoSum, sum, goModCache)
}
return fmt.Errorf("resulting module with sum %s; expected sum %s", repoSum, sum)
}

Expand Down

0 comments on commit cc40a33

Please sign in to comment.