Skip to content

Commit 288a83d

Browse files
committed
[dev.cmdgo] cmd/go: maintain a go.work.sum file
This change causes the go command to maintain a separate go.work.sum file when in workspace mode rather than using the go.sum files from the individual modules. This isn't quite what the proposal spec specifies, which is that the sums that don't exist in any of the workspace modules are added to go.work.sum rather than the necessary sums. That will be done in a future change. Change-Id: I528b9b153a93a4cd67c5af471ad6d5bd3628578b Reviewed-on: https://go-review.googlesource.com/c/go/+/334939 Trust: Michael Matloob <[email protected]> Run-TryBot: Michael Matloob <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Jay Conrod <[email protected]>
1 parent 2c8acf6 commit 288a83d

File tree

8 files changed

+113
-19
lines changed

8 files changed

+113
-19
lines changed

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

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -681,19 +681,21 @@ func isValidSum(data []byte) bool {
681681
return true
682682
}
683683

684+
var ErrGoSumDirty = errors.New("updates to go.sum needed, disabled by -mod=readonly")
685+
684686
// WriteGoSum writes the go.sum file if it needs to be updated.
685687
//
686688
// keep is used to check whether a newly added sum should be saved in go.sum.
687689
// It should have entries for both module content sums and go.mod sums
688690
// (version ends with "/go.mod"). Existing sums will be preserved unless they
689691
// have been marked for deletion with TrimGoSum.
690-
func WriteGoSum(keep map[module.Version]bool) {
692+
func WriteGoSum(keep map[module.Version]bool, readonly bool) error {
691693
goSum.mu.Lock()
692694
defer goSum.mu.Unlock()
693695

694696
// If we haven't read the go.sum file yet, don't bother writing it.
695697
if !goSum.enabled {
696-
return
698+
return nil
697699
}
698700

699701
// Check whether we need to add sums for which keep[m] is true or remove
@@ -711,10 +713,10 @@ Outer:
711713
}
712714
}
713715
if !dirty {
714-
return
716+
return nil
715717
}
716-
if cfg.BuildMod == "readonly" {
717-
base.Fatalf("go: updates to go.sum needed, disabled by -mod=readonly")
718+
if readonly {
719+
return ErrGoSumDirty
718720
}
719721

720722
// Make a best-effort attempt to acquire the side lock, only to exclude
@@ -759,11 +761,12 @@ Outer:
759761
})
760762

761763
if err != nil {
762-
base.Fatalf("go: updating go.sum: %v", err)
764+
return fmt.Errorf("updating go.sum: %w", err)
763765
}
764766

765767
goSum.status = make(map[modSum]modSumStatus)
766768
goSum.overwrite = false
769+
return nil
767770
}
768771

769772
// TrimGoSum trims go.sum to contain only the modules needed for reproducible

src/cmd/go/internal/modload/buildlist.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -807,7 +807,7 @@ func updateLazyRoots(ctx context.Context, direct map[string]bool, rs *Requiremen
807807
// We've added or upgraded one or more roots, so load the full module
808808
// graph so that we can update those roots to be consistent with other
809809
// requirements.
810-
if cfg.BuildMod != "mod" {
810+
if mustHaveCompleteRequirements() {
811811
// Our changes to the roots may have moved dependencies into or out of
812812
// the lazy-loading horizon, which could in turn change the selected
813813
// versions of other modules. (Unlike for eager modules, for lazy
@@ -1007,7 +1007,7 @@ func updateEagerRoots(ctx context.Context, direct map[string]bool, rs *Requireme
10071007
return rs, err
10081008
}
10091009

1010-
if cfg.BuildMod != "mod" {
1010+
if mustHaveCompleteRequirements() {
10111011
// Instead of actually updating the requirements, just check that no updates
10121012
// are needed.
10131013
if rs == nil {

src/cmd/go/internal/modload/import.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ type ImportMissingError struct {
3232
Module module.Version
3333
QueryErr error
3434

35+
ImportingModule module.Version
36+
3537
// isStd indicates whether we would expect to find the package in the standard
3638
// library. This is normally true for all dotless import paths, but replace
3739
// directives can cause us to treat the replaced paths as also being in
@@ -673,7 +675,7 @@ func fetch(ctx context.Context, mod module.Version, needSum bool) (dir string, i
673675
mod = r
674676
}
675677

676-
if HasModRoot() && cfg.BuildMod == "readonly" && needSum && !modfetch.HaveSum(mod) {
678+
if HasModRoot() && cfg.BuildMod == "readonly" && !inWorkspaceMode() && needSum && !modfetch.HaveSum(mod) {
677679
return "", false, module.VersionError(mod, &sumMissingError{})
678680
}
679681

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

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,7 @@ func Init() {
367367
if err != nil {
368368
base.Fatalf("reading go.work: %v", err)
369369
}
370+
modfetch.GoSumFile = workFilePath + ".sum"
370371
// TODO(matloob) should workRoot just be workFile?
371372
} else if modRoots == nil {
372373
// We're in module mode, but not inside a module.
@@ -1009,6 +1010,10 @@ func setDefaultBuildMod() {
10091010
cfg.BuildMod = "readonly"
10101011
}
10111012

1013+
func mustHaveCompleteRequirements() bool {
1014+
return cfg.BuildMod != "mod" && !inWorkspaceMode()
1015+
}
1016+
10121017
// convertLegacyConfig imports module requirements from a legacy vendoring
10131018
// configuration file, if one is present.
10141019
func convertLegacyConfig(modFile *modfile.File, modPath string) (from string, err error) {
@@ -1306,10 +1311,17 @@ func commitRequirements(ctx context.Context, goVersion string, rs *Requirements)
13061311
return
13071312
}
13081313

1314+
if inWorkspaceMode() {
1315+
// go.mod files aren't updated in workspace mode, but we still want to
1316+
// update the go.work.sum file.
1317+
if err := modfetch.WriteGoSum(keepSums(ctx, loaded, rs, addBuildListZipSums), mustHaveCompleteRequirements()); err != nil {
1318+
base.Fatalf("go: %v", err)
1319+
}
1320+
return
1321+
}
1322+
13091323
if MainModules.Len() != 1 || MainModules.ModRoot(MainModules.Versions()[0]) == "" {
1310-
_ = TODOWorkspaces("also check that workspace mode is off")
13111324
// We aren't in a module, so we don't have anywhere to write a go.mod file.
1312-
_ = TODOWorkspaces("also check that workspace mode is off")
13131325
return
13141326
}
13151327
mainModule := MainModules.Versions()[0]
@@ -1346,7 +1358,9 @@ func commitRequirements(ctx context.Context, goVersion string, rs *Requirements)
13461358
// Don't write go.mod, but write go.sum in case we added or trimmed sums.
13471359
// 'go mod init' shouldn't write go.sum, since it will be incomplete.
13481360
if cfg.CmdName != "mod init" {
1349-
modfetch.WriteGoSum(keepSums(ctx, loaded, rs, addBuildListZipSums))
1361+
if err := modfetch.WriteGoSum(keepSums(ctx, loaded, rs, addBuildListZipSums), mustHaveCompleteRequirements()); err != nil {
1362+
base.Fatalf("go: %v", err)
1363+
}
13501364
}
13511365
return
13521366
}
@@ -1368,7 +1382,9 @@ func commitRequirements(ctx context.Context, goVersion string, rs *Requirements)
13681382
// Update go.sum after releasing the side lock and refreshing the index.
13691383
// 'go mod init' shouldn't write go.sum, since it will be incomplete.
13701384
if cfg.CmdName != "mod init" {
1371-
modfetch.WriteGoSum(keepSums(ctx, loaded, rs, addBuildListZipSums))
1385+
if err := modfetch.WriteGoSum(keepSums(ctx, loaded, rs, addBuildListZipSums), mustHaveCompleteRequirements()); err != nil {
1386+
base.Fatalf("go: %v", err)
1387+
}
13721388
}
13731389
}()
13741390

src/cmd/go/internal/modload/load.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,9 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
403403
// loaded.requirements, but here we may have also loaded (and want to
404404
// preserve checksums for) additional entities from compatRS, which are
405405
// only needed for compatibility with ld.TidyCompatibleVersion.
406-
modfetch.WriteGoSum(keep)
406+
if err := modfetch.WriteGoSum(keep, mustHaveCompleteRequirements()); err != nil {
407+
base.Fatalf("go: %v", err)
408+
}
407409
}
408410
}
409411

src/cmd/go/internal/modload/modfile.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,7 @@ func goModSummary(m module.Version) (*modFileSummary, error) {
532532
}
533533

534534
actual := resolveReplacement(m)
535-
if HasModRoot() && cfg.BuildMod == "readonly" && actual.Version != "" {
535+
if HasModRoot() && cfg.BuildMod == "readonly" && !inWorkspaceMode() && actual.Version != "" {
536536
key := module.Version{Path: actual.Path, Version: actual.Version + "/go.mod"}
537537
if !modfetch.HaveSum(key) {
538538
suggestion := fmt.Sprintf("; to add it:\n\tgo mod download %s", m.Path)

src/cmd/go/testdata/script/work.txt

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
go mod initwork ./a ./b
22
cmp go.work go.work.want
33

4+
! go run example.com/b
5+
stderr 'a(\\|/)a.go:4:8: no required module provides package rsc.io/quote; to add it:\n\tgo get rsc.io/quote'
6+
cd a
7+
go get rsc.io/quote
8+
go env GOMOD # go env GOMOD reports the module in a single module context
9+
stdout $GOPATH(\\|/)src(\\|/)a(\\|/)go.mod
10+
cd ..
411
go run example.com/b
5-
stdout 'Hello from module A'
12+
stdout 'Hello, world.'
613

714
# And try from a different directory
815
cd c
9-
go run example.com/b
10-
stdout 'Hello from module A'
16+
go run example.com/b
17+
stdout 'Hello, world.'
1118
cd $GOPATH/src
1219

1320
go list all # all includes both modules
@@ -26,6 +33,9 @@ cp go.work.dup go.work
2633
stderr 'reading go.work: path .* appears multiple times in workspace'
2734
cp go.work.backup go.work
2835

36+
cp go.work.d go.work
37+
go run example.com/d
38+
2939
-- go.work.dup --
3040
go 1.17
3141

@@ -41,6 +51,14 @@ directory (
4151
./a
4252
./b
4353
)
54+
-- go.work.d --
55+
go 1.17
56+
57+
directory (
58+
a
59+
b
60+
d
61+
)
4462
-- a/go.mod --
4563

4664
module example.com/a
@@ -49,9 +67,10 @@ module example.com/a
4967
package a
5068

5169
import "fmt"
70+
import "rsc.io/quote"
5271

5372
func HelloFromA() {
54-
fmt.Println("Hello from module A")
73+
fmt.Println(quote.Hello())
5574
}
5675

5776
-- b/go.mod --
@@ -66,8 +85,27 @@ import "example.com/a"
6685
func main() {
6786
a.HelloFromA()
6887
}
88+
-- b/lib/hello.go --
89+
package lib
90+
91+
import "example.com/a"
92+
93+
func Hello() {
94+
a.HelloFromA()
95+
}
6996

7097
-- c/README --
7198
Create this directory so we can cd to
7299
it and make sure paths are interpreted
73100
relative to the go.work, not the cwd.
101+
-- d/go.mod --
102+
module example.com/d
103+
104+
-- d/main.go --
105+
package main
106+
107+
import "example.com/b/lib"
108+
109+
func main() {
110+
lib.Hello()
111+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Test adding sums to go.work.sum when sum isn't in go.mod.
2+
3+
go run .
4+
cmp go.work.sum want.sum
5+
6+
-- want.sum --
7+
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:pvCbr/wm8HzDD3fVywevekufpn6tCGPY3spdHeZJEsw=
8+
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
9+
rsc.io/quote v1.5.2 h1:3fEykkD9k7lYzXqCYrwGAf7iNhbk4yCjHmKBN9td4L0=
10+
rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0=
11+
rsc.io/sampler v1.3.0 h1:HLGR/BgEtI3r0uymSP/nl2uPLsUnNJX8toRyhfpBTII=
12+
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
13+
-- go.work --
14+
go 1.18
15+
16+
directory .
17+
-- go.mod --
18+
go 1.18
19+
20+
module example.com/hi
21+
22+
require "rsc.io/quote" v1.5.2
23+
-- main.go --
24+
package main
25+
26+
import (
27+
"fmt"
28+
"rsc.io/quote"
29+
)
30+
31+
func main() {
32+
fmt.Println(quote.Hello())
33+
}

0 commit comments

Comments
 (0)