]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/go: display helpful error when module cache can't be created
authorJulie Qiu <julie@golang.org>
Wed, 24 Mar 2021 20:24:38 +0000 (16:24 -0400)
committerJulie Qiu <julie@golang.org>
Mon, 12 Apr 2021 15:51:43 +0000 (15:51 +0000)
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>
src/cmd/go/internal/modfetch/cache.go
src/cmd/go/testdata/script/mod_gomodcache.txt

index c1303502e5526c4ed354a2e7e384ff2924577834..f3b58a172a6fc2808776c8ca63515dc4502d1540 100644 (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
 }
index b2143e2093989719a2d000b12c415b5030a6c97e..74a3c79622f1f5ff916edd64cb39facd386edee4 100644 (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 --