cmd/go: display helpful error when module cache can't be created

Previously when the module cache specified by GOMODCACHE could not be
created an unhelpful message would be printed multiple times.

This happened because we were fetching several things in parallel then
failing to write them because we can't create the module cache.

We now check if the module cache can be created before fetching.

If not, the following message is printed:

go: could not create module cache

Fixes #45113

Change-Id: Ic9cec787411335edc7f4d0614fde7eaa8a957fb5
Reviewed-on: https://go-review.googlesource.com/c/go/+/304571
Trust: Julie Qiu <julie@golang.org>
Run-TryBot: Julie Qiu <julie@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Jay Conrod <jayconrod@google.com>
This commit is contained in:
Julie Qiu 2021-03-24 16:24:38 -04:00
parent 117b1c84d3
commit 51a47b7ff2
2 changed files with 39 additions and 2 deletions

View file

@ -347,6 +347,9 @@ func GoMod(path, rev string) ([]byte, error) {
if _, info, err := readDiskStat(path, rev); err == nil {
rev = info.Version
} else {
if errors.Is(err, statCacheErr) {
return nil, err
}
err := TryProxies(func(proxy string) error {
info, err := Lookup(proxy, path).Stat(rev)
if err == nil {
@ -706,15 +709,42 @@ func rewriteVersionList(dir string) (err error) {
return nil
}
var (
statCacheOnce sync.Once
statCacheErr error
)
// checkCacheDir checks if the directory specified by GOMODCACHE exists. An
// error is returned if it does not.
func checkCacheDir() error {
if cfg.GOMODCACHE == "" {
// modload.Init exits if GOPATH[0] is empty, and cfg.GOMODCACHE
// is set to GOPATH[0]/pkg/mod if GOMODCACHE is empty, so this should never happen.
return fmt.Errorf("internal error: cfg.GOMODCACHE not set")
}
if !filepath.IsAbs(cfg.GOMODCACHE) {
return fmt.Errorf("GOMODCACHE entry is relative; must be absolute path: %q.\n", cfg.GOMODCACHE)
}
return nil
// os.Stat is slow on Windows, so we only call it once to prevent unnecessary
// I/O every time this function is called.
statCacheOnce.Do(func() {
fi, err := os.Stat(cfg.GOMODCACHE)
if err != nil {
if !os.IsNotExist(err) {
statCacheErr = fmt.Errorf("could not create module cache: %w", err)
return
}
if err := os.MkdirAll(cfg.GOMODCACHE, 0777); err != nil {
statCacheErr = fmt.Errorf("could not create module cache: %w", err)
return
}
return
}
if !fi.IsDir() {
statCacheErr = fmt.Errorf("could not create module cache: %q is not a directory", cfg.GOMODCACHE)
return
}
})
return statCacheErr
}

View file

@ -47,6 +47,11 @@ env GOMODCACHE=$WORK/modcache
go mod download rsc.io/quote@v1.0.0
exists $WORK/modcache/cache/download/rsc.io/quote/@v/v1.0.0.info
# Test error when cannot create GOMODCACHE directory
env GOMODCACHE=$WORK/modcachefile
! go install example.com/cmd/a@v1.0.0
stderr 'go: could not create module cache'
# Test that the following work even with GO111MODULE=off
env GO111MODULE=off
@ -58,3 +63,5 @@ go clean -modcache
-- go.mod --
module m
-- $WORK/modcachefile --