1// Copyright 2017 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package cache 6 7import ( 8 "fmt" 9 "os" 10 "path/filepath" 11 "sync" 12 13 "cmd/go/internal/base" 14 "cmd/go/internal/cfg" 15 "internal/goexperiment" 16) 17 18// Default returns the default cache to use. 19// It never returns nil. 20func Default() Cache { 21 defaultOnce.Do(initDefaultCache) 22 return defaultCache 23} 24 25var ( 26 defaultOnce sync.Once 27 defaultCache Cache 28) 29 30// cacheREADME is a message stored in a README in the cache directory. 31// Because the cache lives outside the normal Go trees, we leave the 32// README as a courtesy to explain where it came from. 33const cacheREADME = `This directory holds cached build artifacts from the Go build system. 34Run "go clean -cache" if the directory is getting too large. 35Run "go clean -fuzzcache" to delete the fuzz cache. 36See golang.org to learn more about Go. 37` 38 39// initDefaultCache does the work of finding the default cache 40// the first time Default is called. 41func initDefaultCache() { 42 dir, _ := DefaultDir() 43 if dir == "off" { 44 if defaultDirErr != nil { 45 base.Fatalf("build cache is required, but could not be located: %v", defaultDirErr) 46 } 47 base.Fatalf("build cache is disabled by GOCACHE=off, but required as of Go 1.12") 48 } 49 if err := os.MkdirAll(dir, 0777); err != nil { 50 base.Fatalf("failed to initialize build cache at %s: %s\n", dir, err) 51 } 52 if _, err := os.Stat(filepath.Join(dir, "README")); err != nil { 53 // Best effort. 54 os.WriteFile(filepath.Join(dir, "README"), []byte(cacheREADME), 0666) 55 } 56 57 diskCache, err := Open(dir) 58 if err != nil { 59 base.Fatalf("failed to initialize build cache at %s: %s\n", dir, err) 60 } 61 62 if v := cfg.Getenv("GOCACHEPROG"); v != "" && goexperiment.CacheProg { 63 defaultCache = startCacheProg(v, diskCache) 64 } else { 65 defaultCache = diskCache 66 } 67} 68 69var ( 70 defaultDirOnce sync.Once 71 defaultDir string 72 defaultDirChanged bool // effective value differs from $GOCACHE 73 defaultDirErr error 74) 75 76// DefaultDir returns the effective GOCACHE setting. 77// It returns "off" if the cache is disabled, 78// and reports whether the effective value differs from GOCACHE. 79func DefaultDir() (string, bool) { 80 // Save the result of the first call to DefaultDir for later use in 81 // initDefaultCache. cmd/go/main.go explicitly sets GOCACHE so that 82 // subprocesses will inherit it, but that means initDefaultCache can't 83 // otherwise distinguish between an explicit "off" and a UserCacheDir error. 84 85 defaultDirOnce.Do(func() { 86 defaultDir = cfg.Getenv("GOCACHE") 87 if defaultDir != "" { 88 defaultDirChanged = true 89 if filepath.IsAbs(defaultDir) || defaultDir == "off" { 90 return 91 } 92 defaultDir = "off" 93 defaultDirErr = fmt.Errorf("GOCACHE is not an absolute path") 94 return 95 } 96 97 // Compute default location. 98 dir, err := os.UserCacheDir() 99 if err != nil { 100 defaultDir = "off" 101 defaultDirChanged = true 102 defaultDirErr = fmt.Errorf("GOCACHE is not defined and %v", err) 103 return 104 } 105 defaultDir = filepath.Join(dir, "go-build") 106 }) 107 108 return defaultDir, defaultDirChanged 109} 110