cmd/go: use local state object in pkg modcmd

This commit modifies `modcmd.runDownload` to construct a new
modload.State object using the new constructor instead of the current
global `modload.LoaderState` variable.

This commit is part of the overall effort to eliminate global
modloader state.

[git-generate]
cd src/cmd/go/internal/modcmd
rf '
  add download.go:/func runDownload\(/-0 var moduleLoaderState *modload.State
  ex {
    import "cmd/go/internal/modload";
    modload.LoaderState -> moduleLoaderState
  }
  add runDownload://+0 moduleLoaderState := modload.NewState()
  add runEdit://+0 moduleLoaderState := modload.NewState()
  add runGraph://+0 moduleLoaderState := modload.NewState()
  add runInit://+0 moduleLoaderState := modload.NewState()
  add runTidy://+0 moduleLoaderState := modload.NewState()
  add runVendor://+0 moduleLoaderState := modload.NewState()
  add runVerify://+0 moduleLoaderState := modload.NewState()
  add runWhy://+0 moduleLoaderState := modload.NewState()
  rm download.go:/var moduleLoaderState \*modload.State/
'

Change-Id: Id69deba173032a4d6da228eae28e38bd87176db5
Reviewed-on: https://go-review.googlesource.com/c/go/+/711125
Reviewed-by: Michael Matloob <matloob@google.com>
Reviewed-by: Michael Matloob <matloob@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
Ian Alexander 2025-10-08 20:03:54 -04:00
parent ea9cf26aa1
commit d312e27e8b
8 changed files with 56 additions and 48 deletions

View file

@ -109,18 +109,19 @@ type ModuleJSON struct {
}
func runDownload(ctx context.Context, cmd *base.Command, args []string) {
modload.InitWorkfile(modload.LoaderState)
moduleLoaderState := modload.NewState()
modload.InitWorkfile(moduleLoaderState)
// Check whether modules are enabled and whether we're in a module.
modload.LoaderState.ForceUseModules = true
moduleLoaderState.ForceUseModules = true
modload.ExplicitWriteGoMod = true
haveExplicitArgs := len(args) > 0
if modload.HasModRoot(modload.LoaderState) || modload.WorkFilePath(modload.LoaderState) != "" {
modload.LoadModFile(modload.LoaderState, ctx) // to fill MainModules
if modload.HasModRoot(moduleLoaderState) || modload.WorkFilePath(moduleLoaderState) != "" {
modload.LoadModFile(moduleLoaderState, ctx) // to fill MainModules
if haveExplicitArgs {
for _, mainModule := range modload.LoaderState.MainModules.Versions() {
for _, mainModule := range moduleLoaderState.MainModules.Versions() {
targetAtUpgrade := mainModule.Path + "@upgrade"
targetAtPatch := mainModule.Path + "@patch"
for _, arg := range args {
@ -130,14 +131,14 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
}
}
}
} else if modload.WorkFilePath(modload.LoaderState) != "" {
} else if modload.WorkFilePath(moduleLoaderState) != "" {
// TODO(#44435): Think about what the correct query is to download the
// right set of modules. Also see code review comment at
// https://go-review.googlesource.com/c/go/+/359794/comments/ce946a80_6cf53992.
args = []string{"all"}
} else {
mainModule := modload.LoaderState.MainModules.Versions()[0]
modFile := modload.LoaderState.MainModules.ModFile(mainModule)
mainModule := moduleLoaderState.MainModules.Versions()[0]
modFile := moduleLoaderState.MainModules.ModFile(mainModule)
if modFile.Go == nil || gover.Compare(modFile.Go.Version, gover.ExplicitIndirectVersion) < 0 {
if len(modFile.Require) > 0 {
args = []string{"all"}
@ -153,12 +154,12 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
// However, we also need to load the full module graph, to ensure that
// we have downloaded enough of the module graph to run 'go list all',
// 'go mod graph', and similar commands.
_, err := modload.LoadModGraph(modload.LoaderState, ctx, "")
_, err := modload.LoadModGraph(moduleLoaderState, ctx, "")
if err != nil {
// TODO(#64008): call base.Fatalf instead of toolchain.SwitchOrFatal
// here, since we can only reach this point with an outdated toolchain
// if the go.mod file is inconsistent.
toolchain.SwitchOrFatal(modload.LoaderState, ctx, err)
toolchain.SwitchOrFatal(moduleLoaderState, ctx, err)
}
for _, m := range modFile.Require {
@ -169,7 +170,7 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
}
if len(args) == 0 {
if modload.HasModRoot(modload.LoaderState) {
if modload.HasModRoot(moduleLoaderState) {
os.Stderr.WriteString("go: no module dependencies to download\n")
} else {
base.Errorf("go: no modules specified (see 'go help mod download')")
@ -177,14 +178,14 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
base.Exit()
}
if *downloadReuse != "" && modload.HasModRoot(modload.LoaderState) {
if *downloadReuse != "" && modload.HasModRoot(moduleLoaderState) {
base.Fatalf("go mod download -reuse cannot be used inside a module")
}
var mods []*ModuleJSON
type token struct{}
sem := make(chan token, runtime.GOMAXPROCS(0))
infos, infosErr := modload.ListModules(modload.LoaderState, ctx, args, 0, *downloadReuse)
infos, infosErr := modload.ListModules(moduleLoaderState, ctx, args, 0, *downloadReuse)
// There is a bit of a chicken-and-egg problem here: ideally we need to know
// which Go version to switch to download the requested modules, but if we
@ -211,7 +212,7 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
// toolchain version) or only one module (as is used by the Go Module Proxy).
if infosErr != nil {
sw := toolchain.NewSwitcher(modload.LoaderState)
sw := toolchain.NewSwitcher(moduleLoaderState)
sw.Error(infosErr)
if sw.NeedSwitch() {
sw.Switch(ctx)
@ -220,7 +221,7 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
// when we can.
}
if !haveExplicitArgs && modload.WorkFilePath(modload.LoaderState) == "" {
if !haveExplicitArgs && modload.WorkFilePath(moduleLoaderState) == "" {
// 'go mod download' is sometimes run without arguments to pre-populate the
// module cache. In modules that aren't at go 1.17 or higher, it may fetch
// modules that aren't needed to build packages in the main module. This is
@ -231,7 +232,7 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
// TODO(#64008): In the future, report an error if go.mod or go.sum need to
// be updated after loading the build list. This may require setting
// the mode to "mod" or "readonly" depending on haveExplicitArgs.
if err := modload.WriteGoMod(modload.LoaderState, ctx, modload.WriteOpts{}); err != nil {
if err := modload.WriteGoMod(moduleLoaderState, ctx, modload.WriteOpts{}); err != nil {
base.Fatal(err)
}
}
@ -291,8 +292,8 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
// with no arguments we download the module pattern "all",
// which may include dependencies that are normally pruned out
// of the individual modules in the workspace.
if haveExplicitArgs || modload.WorkFilePath(modload.LoaderState) != "" {
sw := toolchain.NewSwitcher(modload.LoaderState)
if haveExplicitArgs || modload.WorkFilePath(moduleLoaderState) != "" {
sw := toolchain.NewSwitcher(moduleLoaderState)
// Add errors to the Switcher in deterministic order so that they will be
// logged deterministically.
for _, m := range mods {
@ -347,8 +348,8 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
//
// Don't save sums for 'go mod download' without arguments unless we're in
// workspace mode; see comment above.
if haveExplicitArgs || modload.WorkFilePath(modload.LoaderState) != "" {
if err := modload.WriteGoMod(modload.LoaderState, ctx, modload.WriteOpts{}); err != nil {
if haveExplicitArgs || modload.WorkFilePath(moduleLoaderState) != "" {
if err := modload.WriteGoMod(moduleLoaderState, ctx, modload.WriteOpts{}); err != nil {
base.Error(err)
}
}

View file

@ -209,6 +209,7 @@ func init() {
}
func runEdit(ctx context.Context, cmd *base.Command, args []string) {
moduleLoaderState := modload.NewState()
anyFlags := *editModule != "" ||
*editGo != "" ||
*editToolchain != "" ||
@ -232,7 +233,7 @@ func runEdit(ctx context.Context, cmd *base.Command, args []string) {
if len(args) == 1 {
gomod = args[0]
} else {
gomod = modload.ModFilePath(modload.LoaderState)
gomod = modload.ModFilePath(moduleLoaderState)
}
if *editModule != "" {

View file

@ -52,23 +52,24 @@ func init() {
}
func runGraph(ctx context.Context, cmd *base.Command, args []string) {
modload.InitWorkfile(modload.LoaderState)
moduleLoaderState := modload.NewState()
modload.InitWorkfile(moduleLoaderState)
if len(args) > 0 {
base.Fatalf("go: 'go mod graph' accepts no arguments")
}
modload.LoaderState.ForceUseModules = true
modload.LoaderState.RootMode = modload.NeedRoot
moduleLoaderState.ForceUseModules = true
moduleLoaderState.RootMode = modload.NeedRoot
goVersion := graphGo.String()
if goVersion != "" && gover.Compare(gover.Local(), goVersion) < 0 {
toolchain.SwitchOrFatal(modload.LoaderState, ctx, &gover.TooNewError{
toolchain.SwitchOrFatal(moduleLoaderState, ctx, &gover.TooNewError{
What: "-go flag",
GoVersion: goVersion,
})
}
mg, err := modload.LoadModGraph(modload.LoaderState, ctx, goVersion)
mg, err := modload.LoadModGraph(moduleLoaderState, ctx, goVersion)
if err != nil {
base.Fatal(err)
}

View file

@ -35,6 +35,7 @@ func init() {
}
func runInit(ctx context.Context, cmd *base.Command, args []string) {
moduleLoaderState := modload.NewState()
if len(args) > 1 {
base.Fatalf("go: 'go mod init' accepts at most one argument")
}
@ -43,6 +44,6 @@ func runInit(ctx context.Context, cmd *base.Command, args []string) {
modPath = args[0]
}
modload.LoaderState.ForceUseModules = true
modload.CreateModFile(modload.LoaderState, ctx, modPath) // does all the hard work
moduleLoaderState.ForceUseModules = true
modload.CreateModFile(moduleLoaderState, ctx, modPath) // does all the hard work
}

View file

@ -105,6 +105,7 @@ func (f *goVersionFlag) Set(s string) error {
}
func runTidy(ctx context.Context, cmd *base.Command, args []string) {
moduleLoaderState := modload.NewState()
if len(args) > 0 {
base.Fatalf("go: 'go mod tidy' accepts no arguments")
}
@ -119,18 +120,18 @@ func runTidy(ctx context.Context, cmd *base.Command, args []string) {
// those packages. In order to make 'go test' reproducible for the packages
// that are in 'all' but outside of the main module, we must explicitly
// request that their test dependencies be included.
modload.LoaderState.ForceUseModules = true
modload.LoaderState.RootMode = modload.NeedRoot
moduleLoaderState.ForceUseModules = true
moduleLoaderState.RootMode = modload.NeedRoot
goVersion := tidyGo.String()
if goVersion != "" && gover.Compare(gover.Local(), goVersion) < 0 {
toolchain.SwitchOrFatal(modload.LoaderState, ctx, &gover.TooNewError{
toolchain.SwitchOrFatal(moduleLoaderState, ctx, &gover.TooNewError{
What: "-go flag",
GoVersion: goVersion,
})
}
modload.LoadPackages(modload.LoaderState, ctx, modload.PackageOpts{
modload.LoadPackages(moduleLoaderState, ctx, modload.PackageOpts{
TidyGoVersion: tidyGo.String(),
Tags: imports.AnyTags(),
Tidy: true,
@ -141,6 +142,6 @@ func runTidy(ctx context.Context, cmd *base.Command, args []string) {
LoadTests: true,
AllowErrors: tidyE,
SilenceMissingStdImports: true,
Switcher: toolchain.NewSwitcher(modload.LoaderState),
Switcher: toolchain.NewSwitcher(moduleLoaderState),
}, "all")
}

View file

@ -66,11 +66,12 @@ func init() {
}
func runVendor(ctx context.Context, cmd *base.Command, args []string) {
modload.InitWorkfile(modload.LoaderState)
if modload.WorkFilePath(modload.LoaderState) != "" {
moduleLoaderState := modload.NewState()
modload.InitWorkfile(moduleLoaderState)
if modload.WorkFilePath(moduleLoaderState) != "" {
base.Fatalf("go: 'go mod vendor' cannot be run in workspace mode. Run 'go work vendor' to vendor the workspace or set 'GOWORK=off' to exit workspace mode.")
}
RunVendor(modload.LoaderState, ctx, vendorE, vendorO, args)
RunVendor(moduleLoaderState, ctx, vendorE, vendorO, args)
}
func RunVendor(loaderstate *modload.State, ctx context.Context, vendorE bool, vendorO string, args []string) {

View file

@ -44,20 +44,21 @@ func init() {
}
func runVerify(ctx context.Context, cmd *base.Command, args []string) {
modload.InitWorkfile(modload.LoaderState)
moduleLoaderState := modload.NewState()
modload.InitWorkfile(moduleLoaderState)
if len(args) != 0 {
// NOTE(rsc): Could take a module pattern.
base.Fatalf("go: verify takes no arguments")
}
modload.LoaderState.ForceUseModules = true
modload.LoaderState.RootMode = modload.NeedRoot
moduleLoaderState.ForceUseModules = true
moduleLoaderState.RootMode = modload.NeedRoot
// Only verify up to GOMAXPROCS zips at once.
type token struct{}
sem := make(chan token, runtime.GOMAXPROCS(0))
mg, err := modload.LoadModGraph(modload.LoaderState, ctx, "")
mg, err := modload.LoadModGraph(moduleLoaderState, ctx, "")
if err != nil {
base.Fatal(err)
}
@ -71,7 +72,7 @@ func runVerify(ctx context.Context, cmd *base.Command, args []string) {
errsChans[i] = errsc
mod := mod // use a copy to avoid data races
go func() {
errsc <- verifyMod(modload.LoaderState, ctx, mod)
errsc <- verifyMod(moduleLoaderState, ctx, mod)
<-sem
}()
}

View file

@ -63,9 +63,10 @@ func init() {
}
func runWhy(ctx context.Context, cmd *base.Command, args []string) {
modload.InitWorkfile(modload.LoaderState)
modload.LoaderState.ForceUseModules = true
modload.LoaderState.RootMode = modload.NeedRoot
moduleLoaderState := modload.NewState()
modload.InitWorkfile(moduleLoaderState)
moduleLoaderState.ForceUseModules = true
moduleLoaderState.RootMode = modload.NeedRoot
modload.ExplicitWriteGoMod = true // don't write go.mod in ListModules
loadOpts := modload.PackageOpts{
@ -83,13 +84,13 @@ func runWhy(ctx context.Context, cmd *base.Command, args []string) {
}
}
mods, err := modload.ListModules(modload.LoaderState, ctx, args, 0, "")
mods, err := modload.ListModules(moduleLoaderState, ctx, args, 0, "")
if err != nil {
base.Fatal(err)
}
byModule := make(map[string][]string)
_, pkgs := modload.LoadPackages(modload.LoaderState, ctx, loadOpts, "all")
_, pkgs := modload.LoadPackages(moduleLoaderState, ctx, loadOpts, "all")
for _, path := range pkgs {
m := modload.PackageModule(path)
if m.Path != "" {
@ -120,9 +121,9 @@ func runWhy(ctx context.Context, cmd *base.Command, args []string) {
}
} else {
// Resolve to packages.
matches, _ := modload.LoadPackages(modload.LoaderState, ctx, loadOpts, args...)
matches, _ := modload.LoadPackages(moduleLoaderState, ctx, loadOpts, args...)
modload.LoadPackages(modload.LoaderState, ctx, loadOpts, "all") // rebuild graph, from main module (not from named packages)
modload.LoadPackages(moduleLoaderState, ctx, loadOpts, "all") // rebuild graph, from main module (not from named packages)
sep := ""
for _, m := range matches {