Skip to content

Commit c4f2a97

Browse files
committed
cmd/go: allow configuring module cache directory with GOMODCACHE
Adds a GOMODCACHE environment variable that's used by cmd/go to determine the location of the module cache. The default value of GOMODCACHE will be GOPATH[0]/pkg/mod, the default location of the module cache before this change. Replace the cmd/go/internal/modfetch.PkgMod variable which previously held the location of the module cache with the new cmd/go/internal/cfg.GOMODCACHE variable, for consistency with many of the other environment variables that affect the behavior of cmd/go. (Most of the changes in this CL are due to moving/renaming the variable.) The value of cfg.GOMODCACHE is now set using a variable initializer. It was previously set in cmd/go/internal/modload.Init. The location of GOPATH/pkg/sumdb is unchanged by this CL. While it was previously determined using the value of PkgMod, it now is determined independently dirctly from the value of GOPATH[0]. Fixes #34527 Change-Id: Id4d31d217b3507d6057c8ef7c52af1a0606603e4 Reviewed-on: https://go-review.googlesource.com/c/go/+/219538 Run-TryBot: Michael Matloob <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Bryan C. Mills <[email protected]> Reviewed-by: Jay Conrod <[email protected]>
1 parent 97711bf commit c4f2a97

File tree

15 files changed

+115
-61
lines changed

15 files changed

+115
-61
lines changed

src/cmd/go/internal/cfg/cfg.go

+11
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ var (
236236
GOROOTpkg = filepath.Join(GOROOT, "pkg")
237237
GOROOTsrc = filepath.Join(GOROOT, "src")
238238
GOROOT_FINAL = findGOROOT_FINAL()
239+
GOMODCACHE = envOr("GOMODCACHE", gopathDir("pkg/mod"))
239240

240241
// Used in envcmd.MkEnv and build ID computations.
241242
GOARM = envOr("GOARM", fmt.Sprint(objabi.GOARM))
@@ -253,6 +254,8 @@ var (
253254
GOINSECURE = Getenv("GOINSECURE")
254255
)
255256

257+
var SumdbDir = gopathDir("pkg/sumdb")
258+
256259
// GetArchEnv returns the name and setting of the
257260
// GOARCH-specific architecture environment variable.
258261
// If the current architecture has no GOARCH-specific variable,
@@ -364,3 +367,11 @@ func isGOROOT(path string) bool {
364367
}
365368
return stat.IsDir()
366369
}
370+
371+
func gopathDir(rel string) string {
372+
list := filepath.SplitList(BuildContext.GOPATH)
373+
if len(list) == 0 || list[0] == "" {
374+
return ""
375+
}
376+
return filepath.Join(list[0], rel)
377+
}

src/cmd/go/internal/clean/clean.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -186,14 +186,14 @@ func runClean(cmd *base.Command, args []string) {
186186
}
187187

188188
if cleanModcache {
189-
if modfetch.PkgMod == "" {
189+
if cfg.GOMODCACHE == "" {
190190
base.Fatalf("go clean -modcache: no module cache")
191191
}
192192
if cfg.BuildN || cfg.BuildX {
193-
b.Showcmd("", "rm -rf %s", modfetch.PkgMod)
193+
b.Showcmd("", "rm -rf %s", cfg.GOMODCACHE)
194194
}
195195
if !cfg.BuildN {
196-
if err := modfetch.RemoveAll(modfetch.PkgMod); err != nil {
196+
if err := modfetch.RemoveAll(cfg.GOMODCACHE); err != nil {
197197
base.Errorf("go clean -modcache: %v", err)
198198
}
199199
}

src/cmd/go/internal/envcmd/env.go

+1
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ func MkEnv() []cfg.EnvVar {
7777
{Name: "GOHOSTARCH", Value: runtime.GOARCH},
7878
{Name: "GOHOSTOS", Value: runtime.GOOS},
7979
{Name: "GOINSECURE", Value: cfg.GOINSECURE},
80+
{Name: "GOMODCACHE", Value: cfg.GOMODCACHE},
8081
{Name: "GONOPROXY", Value: cfg.GONOPROXY},
8182
{Name: "GONOSUMDB", Value: cfg.GONOSUMDB},
8283
{Name: "GOOS", Value: cfg.Goos},

src/cmd/go/internal/modconv/convert_test.go

+1-3
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import (
1818

1919
"cmd/go/internal/cfg"
2020
"cmd/go/internal/modfetch"
21-
"cmd/go/internal/modfetch/codehost"
2221

2322
"golang.org/x/mod/modfile"
2423
"golang.org/x/mod/module"
@@ -42,8 +41,7 @@ func testMain(m *testing.M) int {
4241
log.Fatal(err)
4342
}
4443
defer os.RemoveAll(dir)
45-
modfetch.PkgMod = filepath.Join(dir, "pkg/mod")
46-
codehost.WorkRoot = filepath.Join(dir, "codework")
44+
cfg.GOMODCACHE = filepath.Join(dir, "pkg/mod")
4745

4846
return m.Run()
4947
}

src/cmd/go/internal/modfetch/cache.go

+16-12
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,17 @@ import (
2626
"golang.org/x/mod/semver"
2727
)
2828

29-
var PkgMod string // $GOPATH/pkg/mod; set by package modload
30-
3129
func cacheDir(path string) (string, error) {
32-
if PkgMod == "" {
33-
return "", fmt.Errorf("internal error: modfetch.PkgMod not set")
30+
if cfg.GOMODCACHE == "" {
31+
// modload.Init exits if GOPATH[0] is empty, and cfg.GOMODCACHE
32+
// is set to GOPATH[0]/pkg/mod if GOMODCACHE is empty, so this should never happen.
33+
return "", fmt.Errorf("internal error: cfg.GOMODCACHE not set")
3434
}
3535
enc, err := module.EscapePath(path)
3636
if err != nil {
3737
return "", err
3838
}
39-
return filepath.Join(PkgMod, "cache/download", enc, "/@v"), nil
39+
return filepath.Join(cfg.GOMODCACHE, "cache/download", enc, "/@v"), nil
4040
}
4141

4242
func CachePath(m module.Version, suffix string) (string, error) {
@@ -63,8 +63,10 @@ func CachePath(m module.Version, suffix string) (string, error) {
6363
// along with the directory if the directory does not exist or if the directory
6464
// is not completely populated.
6565
func DownloadDir(m module.Version) (string, error) {
66-
if PkgMod == "" {
67-
return "", fmt.Errorf("internal error: modfetch.PkgMod not set")
66+
if cfg.GOMODCACHE == "" {
67+
// modload.Init exits if GOPATH[0] is empty, and cfg.GOMODCACHE
68+
// is set to GOPATH[0]/pkg/mod if GOMODCACHE is empty, so this should never happen.
69+
return "", fmt.Errorf("internal error: cfg.GOMODCACHE not set")
6870
}
6971
enc, err := module.EscapePath(m.Path)
7072
if err != nil {
@@ -81,7 +83,7 @@ func DownloadDir(m module.Version) (string, error) {
8183
return "", err
8284
}
8385

84-
dir := filepath.Join(PkgMod, enc+"@"+encVer)
86+
dir := filepath.Join(cfg.GOMODCACHE, enc+"@"+encVer)
8587
if fi, err := os.Stat(dir); os.IsNotExist(err) {
8688
return dir, err
8789
} else if err != nil {
@@ -131,11 +133,13 @@ func lockVersion(mod module.Version) (unlock func(), err error) {
131133
// user's working directory.
132134
// If err is nil, the caller MUST eventually call the unlock function.
133135
func SideLock() (unlock func(), err error) {
134-
if PkgMod == "" {
135-
base.Fatalf("go: internal error: modfetch.PkgMod not set")
136+
if cfg.GOMODCACHE == "" {
137+
// modload.Init exits if GOPATH[0] is empty, and cfg.GOMODCACHE
138+
// is set to GOPATH[0]/pkg/mod if GOMODCACHE is empty, so this should never happen.
139+
base.Fatalf("go: internal error: cfg.GOMODCACHE not set")
136140
}
137141

138-
path := filepath.Join(PkgMod, "cache", "lock")
142+
path := filepath.Join(cfg.GOMODCACHE, "cache", "lock")
139143
if err := os.MkdirAll(filepath.Dir(path), 0777); err != nil {
140144
return nil, fmt.Errorf("failed to create cache directory: %w", err)
141145
}
@@ -456,7 +460,7 @@ func readDiskStat(path, rev string) (file string, info *RevInfo, err error) {
456460
// just to find out about a commit we already know about
457461
// (and have cached under its pseudo-version).
458462
func readDiskStatByHash(path, rev string) (file string, info *RevInfo, err error) {
459-
if PkgMod == "" {
463+
if cfg.GOMODCACHE == "" {
460464
// Do not download to current directory.
461465
return "", nil, errNotCached
462466
}

src/cmd/go/internal/modfetch/codehost/codehost.go

+3-7
Original file line numberDiff line numberDiff line change
@@ -153,15 +153,11 @@ func ShortenSHA1(rev string) string {
153153
return rev
154154
}
155155

156-
// WorkRoot is the root of the cached work directory.
157-
// It is set by cmd/go/internal/modload.InitMod.
158-
var WorkRoot string
159-
160156
// WorkDir returns the name of the cached work directory to use for the
161157
// given repository type and name.
162158
func WorkDir(typ, name string) (dir, lockfile string, err error) {
163-
if WorkRoot == "" {
164-
return "", "", fmt.Errorf("codehost.WorkRoot not set")
159+
if cfg.GOMODCACHE == "" {
160+
return "", "", fmt.Errorf("neither GOPATH nor GOMODCACHE are set")
165161
}
166162

167163
// We name the work directory for the SHA256 hash of the type and name.
@@ -173,7 +169,7 @@ func WorkDir(typ, name string) (dir, lockfile string, err error) {
173169
return "", "", fmt.Errorf("codehost.WorkDir: type cannot contain colon")
174170
}
175171
key := typ + ":" + name
176-
dir = filepath.Join(WorkRoot, fmt.Sprintf("%x", sha256.Sum256([]byte(key))))
172+
dir = filepath.Join(cfg.GOMODCACHE, "cache/vcs", fmt.Sprintf("%x", sha256.Sum256([]byte(key))))
177173

178174
if cfg.BuildX {
179175
fmt.Fprintf(os.Stderr, "mkdir -p %s # %s %s\n", filepath.Dir(dir), typ, name)

src/cmd/go/internal/modfetch/codehost/git_test.go

-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ func testMain(m *testing.M) int {
5757
log.Fatal(err)
5858
}
5959
defer os.RemoveAll(dir)
60-
WorkRoot = dir
6160

6261
if testenv.HasExternalNetwork() && testenv.HasExec() {
6362
// Clone gitrepo1 into a local directory.

src/cmd/go/internal/modfetch/codehost/shell.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"strings"
2121
"time"
2222

23+
"cmd/go/internal/cfg"
2324
"cmd/go/internal/modfetch/codehost"
2425
)
2526

@@ -29,7 +30,7 @@ func usage() {
2930
}
3031

3132
func main() {
32-
codehost.WorkRoot = "/tmp/vcswork"
33+
cfg.GOMODCACHE = "/tmp/vcswork"
3334
log.SetFlags(0)
3435
log.SetPrefix("shell: ")
3536
flag.Usage = usage

src/cmd/go/internal/modfetch/coderepo_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ func testMain(m *testing.M) int {
4444
}
4545
defer os.RemoveAll(dir)
4646

47-
codehost.WorkRoot = dir
47+
cfg.GOMODCACHE = dir
4848
return m.Run()
4949
}
5050

src/cmd/go/internal/modfetch/fetch.go

+6-5
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,10 @@ var downloadCache par.Cache
3535
// local download cache and returns the name of the directory
3636
// corresponding to the root of the module's file tree.
3737
func Download(mod module.Version) (dir string, err error) {
38-
if PkgMod == "" {
39-
// Do not download to current directory.
40-
return "", fmt.Errorf("missing modfetch.PkgMod")
38+
if cfg.GOMODCACHE == "" {
39+
// modload.Init exits if GOPATH[0] is empty, and cfg.GOMODCACHE
40+
// is set to GOPATH[0]/pkg/mod if GOMODCACHE is empty, so this should never happen.
41+
base.Fatalf("go: internal error: cfg.GOMODCACHE not set")
4142
}
4243

4344
// The par.Cache here avoids duplicate work.
@@ -456,7 +457,7 @@ func readGoSum(dst map[module.Version][]string, file string, data []byte) error
456457

457458
// checkMod checks the given module's checksum.
458459
func checkMod(mod module.Version) {
459-
if PkgMod == "" {
460+
if cfg.GOMODCACHE == "" {
460461
// Do not use current directory.
461462
return
462463
}
@@ -593,7 +594,7 @@ func checkSumDB(mod module.Version, h string) error {
593594
// Sum returns the checksum for the downloaded copy of the given module,
594595
// if present in the download cache.
595596
func Sum(mod module.Version) string {
596-
if PkgMod == "" {
597+
if cfg.GOMODCACHE == "" {
597598
// Do not use current directory.
598599
return ""
599600
}

src/cmd/go/internal/modfetch/sumdb.go

+10-5
Original file line numberDiff line numberDiff line change
@@ -200,8 +200,10 @@ func (c *dbClient) ReadConfig(file string) (data []byte, err error) {
200200
return []byte(c.key), nil
201201
}
202202

203-
// GOPATH/pkg is PkgMod/..
204-
targ := filepath.Join(PkgMod, "../sumdb/"+file)
203+
if cfg.SumdbDir == "" {
204+
return nil, errors.New("could not locate sumdb file: missing $GOPATH")
205+
}
206+
targ := filepath.Join(cfg.SumdbDir, file)
205207
data, err = lockedfile.Read(targ)
206208
if errors.Is(err, os.ErrNotExist) {
207209
// Treat non-existent as empty, to bootstrap the "latest" file
@@ -217,7 +219,10 @@ func (*dbClient) WriteConfig(file string, old, new []byte) error {
217219
// Should not happen.
218220
return fmt.Errorf("cannot write key")
219221
}
220-
targ := filepath.Join(PkgMod, "../sumdb/"+file)
222+
if cfg.SumdbDir == "" {
223+
return errors.New("could not locate sumdb file: missing $GOPATH")
224+
}
225+
targ := filepath.Join(cfg.SumdbDir, file)
221226
os.MkdirAll(filepath.Dir(targ), 0777)
222227
f, err := lockedfile.Edit(targ)
223228
if err != nil {
@@ -247,7 +252,7 @@ func (*dbClient) WriteConfig(file string, old, new []byte) error {
247252
// GOPATH/pkg/mod/cache/download/sumdb,
248253
// which will be deleted by "go clean -modcache".
249254
func (*dbClient) ReadCache(file string) ([]byte, error) {
250-
targ := filepath.Join(PkgMod, "cache/download/sumdb", file)
255+
targ := filepath.Join(cfg.GOMODCACHE, "cache/download/sumdb", file)
251256
data, err := lockedfile.Read(targ)
252257
// lockedfile.Write does not atomically create the file with contents.
253258
// There is a moment between file creation and locking the file for writing,
@@ -261,7 +266,7 @@ func (*dbClient) ReadCache(file string) ([]byte, error) {
261266

262267
// WriteCache updates cached lookups or tiles.
263268
func (*dbClient) WriteCache(file string, data []byte) {
264-
targ := filepath.Join(PkgMod, "cache/download/sumdb", file)
269+
targ := filepath.Join(cfg.GOMODCACHE, "cache/download/sumdb", file)
265270
os.MkdirAll(filepath.Dir(targ), 0777)
266271
lockedfile.Write(targ, bytes.NewReader(data), 0666)
267272
}

src/cmd/go/internal/modload/init.go

-19
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import (
2626
"cmd/go/internal/lockedfile"
2727
"cmd/go/internal/modconv"
2828
"cmd/go/internal/modfetch"
29-
"cmd/go/internal/modfetch/codehost"
3029
"cmd/go/internal/mvs"
3130
"cmd/go/internal/search"
3231

@@ -178,17 +177,6 @@ func Init() {
178177
base.Fatalf("$GOPATH/go.mod exists but should not")
179178
}
180179

181-
oldSrcMod := filepath.Join(list[0], "src/mod")
182-
pkgMod := filepath.Join(list[0], "pkg/mod")
183-
infoOld, errOld := os.Stat(oldSrcMod)
184-
_, errMod := os.Stat(pkgMod)
185-
if errOld == nil && infoOld.IsDir() && errMod != nil && os.IsNotExist(errMod) {
186-
os.Rename(oldSrcMod, pkgMod)
187-
}
188-
189-
modfetch.PkgMod = pkgMod
190-
codehost.WorkRoot = filepath.Join(pkgMod, "cache/vcs")
191-
192180
cfg.ModulesEnabled = true
193181
load.ModBinDir = BinDir
194182
load.ModLookup = Lookup
@@ -225,13 +213,6 @@ func Init() {
225213

226214
func init() {
227215
load.ModInit = Init
228-
229-
// Set modfetch.PkgMod and codehost.WorkRoot unconditionally,
230-
// so that go clean -modcache and go mod download can run even without modules enabled.
231-
if list := filepath.SplitList(cfg.BuildContext.GOPATH); len(list) > 0 && list[0] != "" {
232-
modfetch.PkgMod = filepath.Join(list[0], "pkg/mod")
233-
codehost.WorkRoot = filepath.Join(list[0], "pkg/mod/cache/vcs")
234-
}
235216
}
236217

237218
// WillBeEnabled checks whether modules should be enabled but does not

src/cmd/go/internal/modload/query_test.go

+1-4
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ import (
1515
"testing"
1616

1717
"cmd/go/internal/cfg"
18-
"cmd/go/internal/modfetch"
19-
"cmd/go/internal/modfetch/codehost"
2018

2119
"golang.org/x/mod/module"
2220
)
@@ -36,8 +34,7 @@ func testMain(m *testing.M) int {
3634

3735
os.Setenv("GOPATH", dir)
3836
cfg.BuildContext.GOPATH = dir
39-
modfetch.PkgMod = filepath.Join(dir, "pkg/mod")
40-
codehost.WorkRoot = filepath.Join(dir, "codework")
37+
cfg.GOMODCACHE = filepath.Join(dir, "pkg/mod")
4138
return m.Run()
4239
}
4340

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Test GOMODCACHE
2+
env GO111MODULE=on
3+
4+
# Explicitly set GOMODCACHE
5+
env GOMODCACHE=$WORK/modcache
6+
go env GOMODCACHE
7+
stdout $WORK[/\\]modcache
8+
go get -d rsc.io/[email protected]
9+
exists $WORK/modcache/cache/download/rsc.io/quote/@v/v1.0.0.info
10+
grep '{"Version":"v1.0.0","Time":"2018-02-14T00:45:20Z"}' $WORK/modcache/cache/download/rsc.io/quote/@v/v1.0.0.info
11+
12+
# Ensure GOMODCACHE doesn't affect location of sumdb, but $GOMODCACHE/cache/download/sumdb is still written
13+
exists $GOPATH/pkg/sumdb
14+
! exists $WORK/modcache/sumdb
15+
exists $WORK/modcache/cache/download/sumdb
16+
17+
# Test that the default GOMODCACHE is $GOPATH[0]/pkg/mod
18+
env GOMODCACHE=
19+
go env GOMODCACHE
20+
stdout $GOPATH[/\\]pkg[/\\]mod
21+
go get -d rsc.io/[email protected]
22+
exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.0.0.info
23+
grep '{"Version":"v1.0.0","Time":"2018-02-14T00:45:20Z"}' $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.0.0.info
24+
25+
# If neither GOMODCACHE or GOPATH are set, GOPATH defaults to the user's $HOME/go, so GOMODCACHE becomes $HOME/go/pkg/mod
26+
[windows] env USERPROFILE=$WORK/home # Ensure USERPROFILE is a valid path (rather than /no-home/ so we don't run into the logic that "uninfers" GOPATH in cmd/go/main.go
27+
[!windows] env HOME=$WORK/home
28+
env GOMODCACHE=
29+
env GOPATH=
30+
go env GOMODCACHE
31+
stdout $HOME[/\\]go[/\\]pkg[/\\]mod
32+
33+
# If GOMODCACHE isn't set and GOPATH starts with the path list separator, it's an error.
34+
env GOMODCACHE=
35+
env GOPATH=${:}$WORK/this/is/ignored
36+
! go env GOMODCACHE
37+
stderr 'missing \$GOPATH'
38+
39+
# If GOMODCACHE isn't set and GOPATH has multiple elements only the first is used.
40+
env GOMODCACHE=
41+
env GOPATH=$WORK/first/path${:}$WORK/this/is/ignored
42+
go env GOMODCACHE
43+
stdout $WORK[/\\]first[/\\]path[/\\]pkg[/\\]mod
44+
45+
env GOMODCACHE=$WORK/modcache
46+
go mod download rsc.io/[email protected]
47+
exists $WORK/modcache/cache/download/rsc.io/quote/@v/v1.0.0.info
48+
49+
# Test that the following work even with GO111MODULE=off
50+
env GO111MODULE=off
51+
52+
# Cleaning modcache
53+
exists $WORK/modcache
54+
env GOMODCACHE=$WORK/modcache
55+
go clean -modcache
56+
! exists $WORK/modcache
57+
58+
-- go.mod --
59+
module m

0 commit comments

Comments
 (0)