Skip to content

Commit 81fcb18

Browse files
author
Bryan C. Mills
committed
cmd/go: make Tidy an option in PackageOpts rather than a separate call
This eliminates some awkwardly-stateful outside calls to modload.{Disallow,Allow,}WriteGoMod. Perhaps more importantly, it gives the loader the opportunity to reload packages and revise dependencies after the tidied requirements are computed. With lazy loading, dropping an irrelevant requirement from the main module's go.mod file may (rarely) cause other test dependencies for packages outside the main module to become unresolved, which may require the loader to re-resolve those dependencies, which may in turn add new roots and increase the selected versions of modules providing other packages. This refactoring allows the loader to iterate between tidying the build list and reloading packages as needed, making the exact sequencing of loading and tidying an implementation detail of the modload package. For #36460 For #40775 Change-Id: Ib6da3672f32153d5bd7d653d85e3672ab96cbe36 Reviewed-on: https://go-review.googlesource.com/c/go/+/310181 Trust: Bryan C. Mills <[email protected]> Run-TryBot: Bryan C. Mills <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Michael Matloob <[email protected]> Reviewed-by: Jay Conrod <[email protected]>
1 parent c33ced6 commit 81fcb18

File tree

4 files changed

+51
-50
lines changed

4 files changed

+51
-50
lines changed

src/cmd/go/internal/modcmd/tidy.go

+1-13
Original file line numberDiff line numberDiff line change
@@ -60,26 +60,14 @@ func runTidy(ctx context.Context, cmd *base.Command, args []string) {
6060
// request that their test dependencies be included.
6161
modload.ForceUseModules = true
6262
modload.RootMode = modload.NeedRoot
63-
modload.DisallowWriteGoMod() // Suppress writing until we've tidied the file.
6463

6564
modload.LoadPackages(ctx, modload.PackageOpts{
6665
Tags: imports.AnyTags(),
66+
Tidy: true,
6767
VendorModulesInGOROOTSrc: true,
6868
ResolveMissingImports: true,
6969
LoadTests: true,
7070
AllowErrors: tidyE,
7171
SilenceMissingStdImports: true,
7272
}, "all")
73-
74-
modload.TidyBuildList(ctx)
75-
modload.TrimGoSum(ctx)
76-
77-
modload.AllowWriteGoMod()
78-
79-
// TODO(#40775): Toggling global state via AllowWriteGoMod makes the
80-
// invariants for go.mod cleanliness harder to reason about. Instead, either
81-
// make DisallowWriteGoMod an explicit PackageOpts field, or add a Tidy
82-
// argument to modload.LoadPackages so that Tidy is just one call into the
83-
// module loader, or perhaps both.
84-
modload.WriteGoMod(ctx)
8573
}

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

+8-13
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@ type cachedGraph struct {
7979
//
8080
// It is always non-nil if the main module's go.mod file has been loaded.
8181
//
82-
// This variable should only be read from the LoadModFile function,
83-
// and should only be written in the writeGoMod function.
82+
// This variable should only be read from the loadModFile function, and should
83+
// only be written in the loadModFile and commitRequirements functions.
8484
// All other functions that need or produce a *Requirements should
8585
// accept and/or return an explicit parameter.
8686
var requirements *Requirements
@@ -538,14 +538,9 @@ type Conflict struct {
538538
Constraint module.Version
539539
}
540540

541-
// TidyBuildList trims the build list to the minimal requirements needed to
542-
// retain the same versions of all packages from the preceding call to
543-
// LoadPackages.
544-
func TidyBuildList(ctx context.Context) {
545-
if loaded == nil {
546-
panic("internal error: TidyBuildList called when no packages have been loaded")
547-
}
548-
541+
// tidyBuildList trims the build list to the minimal requirements needed to
542+
// retain the same versions of all packages loaded by ld.
543+
func tidyBuildList(ctx context.Context, ld *loader, initialRS *Requirements) *Requirements {
549544
if go117LazyTODO {
550545
// Tidy needs to maintain the lazy-loading invariants for lazy modules.
551546
// The implementation for eager modules should be factored out into a function.
@@ -557,15 +552,15 @@ func TidyBuildList(ctx context.Context) {
557552
// changed after loading packages.
558553
}
559554

560-
tidy, err := updateRoots(ctx, depth, loaded.requirements.direct, loaded.pkgs, nil)
555+
tidy, err := updateRoots(ctx, depth, ld.requirements.direct, ld.pkgs, nil)
561556
if err != nil {
562557
base.Fatalf("go: %v", err)
563558
}
564559

565560
if cfg.BuildV {
566561
mg, _ := tidy.Graph(ctx)
567562

568-
for _, m := range LoadModFile(ctx).rootModules {
563+
for _, m := range initialRS.rootModules {
569564
if mg.Selected(m.Path) == "none" {
570565
fmt.Fprintf(os.Stderr, "unused %s\n", m.Path)
571566
} else if go117LazyTODO {
@@ -575,7 +570,7 @@ func TidyBuildList(ctx context.Context) {
575570
}
576571
}
577572

578-
commitRequirements(ctx, tidy)
573+
return tidy
579574
}
580575

581576
// updateRoots returns a set of root requirements that includes the selected

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

+22-14
Original file line numberDiff line numberDiff line change
@@ -365,8 +365,8 @@ var errGoModDirty error = goModDirtyError{}
365365
// build list from its go.mod file.
366366
//
367367
// LoadModFile may make changes in memory, like adding a go directive and
368-
// ensuring requirements are consistent. WriteGoMod should be called later to
369-
// write changes out to disk or report errors in readonly mode.
368+
// ensuring requirements are consistent, and will write those changes back to
369+
// disk unless DisallowWriteGoMod is in effect.
370370
//
371371
// As a side-effect, LoadModFile may change cfg.BuildMod to "vendor" if
372372
// -mod wasn't set explicitly and automatic vendoring should be enabled.
@@ -379,17 +379,31 @@ var errGoModDirty error = goModDirtyError{}
379379
// it for global consistency. Most callers outside of the modload package should
380380
// use LoadModGraph instead.
381381
func LoadModFile(ctx context.Context) *Requirements {
382+
rs, needCommit := loadModFile(ctx)
383+
if needCommit {
384+
commitRequirements(ctx, rs)
385+
}
386+
return rs
387+
}
388+
389+
// loadModFile is like LoadModFile, but does not implicitly commit the
390+
// requirements back to disk after fixing inconsistencies.
391+
//
392+
// If needCommit is true, after the caller makes any other needed changes to the
393+
// returned requirements they should invoke commitRequirements to fix any
394+
// inconsistencies that may be present in the on-disk go.mod file.
395+
func loadModFile(ctx context.Context) (rs *Requirements, needCommit bool) {
382396
if requirements != nil {
383-
return requirements
397+
return requirements, false
384398
}
385399

386400
Init()
387401
if modRoot == "" {
388402
Target = module.Version{Path: "command-line-arguments"}
389403
targetPrefix = "command-line-arguments"
390404
rawGoVersion.Store(Target, latestGoVersion())
391-
commitRequirements(ctx, newRequirements(index.depth(), nil, nil))
392-
return requirements
405+
requirements = newRequirements(index.depth(), nil, nil)
406+
return requirements, false
393407
}
394408

395409
gomod := ModFilePath()
@@ -418,7 +432,7 @@ func LoadModFile(ctx context.Context) *Requirements {
418432
}
419433

420434
setDefaultBuildMod() // possibly enable automatic vendoring
421-
rs := requirementsFromModFile(ctx, f)
435+
rs = requirementsFromModFile(ctx, f)
422436

423437
if cfg.BuildMod == "vendor" {
424438
readVendorList()
@@ -450,9 +464,8 @@ func LoadModFile(ctx context.Context) *Requirements {
450464
}
451465
}
452466

453-
// Fix up roots if inconsistent.
454-
commitRequirements(ctx, rs)
455-
return requirements
467+
requirements = rs
468+
return requirements, true
456469
}
457470

458471
// CreateModFile initializes a new module by creating a go.mod file.
@@ -1136,8 +1149,3 @@ const (
11361149
func modkey(m module.Version) module.Version {
11371150
return module.Version{Path: m.Path, Version: m.Version + "/go.mod"}
11381151
}
1139-
1140-
func TrimGoSum(ctx context.Context) {
1141-
rs := LoadModFile(ctx)
1142-
modfetch.TrimGoSum(keepSums(ctx, loaded, rs, loadedZipSumsOnly))
1143-
}

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

+20-10
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,11 @@ type PackageOpts struct {
138138
// If nil, treated as equivalent to imports.Tags().
139139
Tags map[string]bool
140140

141+
// Tidy, if true, requests that the build list and go.sum file be reduced to
142+
// the minimial dependencies needed to reproducibly reload the requested
143+
// packages.
144+
Tidy bool
145+
141146
// VendorModulesInGOROOTSrc indicates that if we are within a module in
142147
// GOROOT/src, packages in the module's vendor directory should be resolved as
143148
// actual module dependencies (instead of standard-library packages).
@@ -202,8 +207,6 @@ type PackageOpts struct {
202207
// LoadPackages identifies the set of packages matching the given patterns and
203208
// loads the packages in the import graph rooted at that set.
204209
func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (matches []*search.Match, loadedPackages []string) {
205-
rs := LoadModFile(ctx)
206-
207210
if opts.Tags == nil {
208211
opts.Tags = imports.Tags()
209212
}
@@ -218,7 +221,7 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
218221
}
219222
}
220223

221-
updateMatches := func(ld *loader) {
224+
updateMatches := func(rs *Requirements, ld *loader) {
222225
for _, m := range matches {
223226
switch {
224227
case m.IsLocal():
@@ -293,15 +296,17 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
293296
}
294297
}
295298

299+
initialRS, _ := loadModFile(ctx) // Ignore needCommit — we're going to commit at the end regardless.
300+
296301
ld := loadFromRoots(ctx, loaderParams{
297302
PackageOpts: opts,
298-
requirements: rs,
303+
requirements: initialRS,
299304

300305
allClosesOverTests: index.allPatternClosesOverTests() && !opts.UseVendorAll,
301306
allPatternIsRoot: allPatternIsRoot,
302307

303-
listRoots: func() (roots []string) {
304-
updateMatches(nil)
308+
listRoots: func(rs *Requirements) (roots []string) {
309+
updateMatches(rs, nil)
305310
for _, m := range matches {
306311
roots = append(roots, m.Pkgs...)
307312
}
@@ -310,7 +315,7 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
310315
})
311316

312317
// One last pass to finalize wildcards.
313-
updateMatches(ld)
318+
updateMatches(ld.requirements, ld)
314319

315320
// Report errors, if any.
316321
checkMultiplePaths(ld.requirements)
@@ -365,6 +370,11 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
365370
search.WarnUnmatched(matches)
366371
}
367372

373+
if ld.Tidy {
374+
ld.requirements = tidyBuildList(ctx, ld, initialRS)
375+
modfetch.TrimGoSum(keepSums(ctx, ld, ld.requirements, loadedZipSumsOnly))
376+
}
377+
368378
// Success! Update go.mod (if needed) and return the results.
369379
loaded = ld
370380
commitRequirements(ctx, loaded.requirements)
@@ -588,7 +598,7 @@ func ImportFromFiles(ctx context.Context, gofiles []string) {
588598
},
589599
requirements: rs,
590600
allClosesOverTests: index.allPatternClosesOverTests(),
591-
listRoots: func() (roots []string) {
601+
listRoots: func(*Requirements) (roots []string) {
592602
roots = append(roots, imports...)
593603
roots = append(roots, testImports...)
594604
return roots
@@ -747,7 +757,7 @@ type loaderParams struct {
747757
allClosesOverTests bool // Does the "all" pattern include the transitive closure of tests of packages in "all"?
748758
allPatternIsRoot bool // Is the "all" pattern an additional root?
749759

750-
listRoots func() []string
760+
listRoots func(rs *Requirements) []string
751761
}
752762

753763
func (ld *loader) reset() {
@@ -876,7 +886,7 @@ func loadFromRoots(ctx context.Context, params loaderParams) *loader {
876886
// Note: the returned roots can change on each iteration,
877887
// since the expansion of package patterns depends on the
878888
// build list we're using.
879-
rootPkgs := ld.listRoots()
889+
rootPkgs := ld.listRoots(ld.requirements)
880890

881891
if go117LazyTODO {
882892
// Before we start loading transitive imports of packages, locate all of

0 commit comments

Comments
 (0)