]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/go: inject State parameter into `toolchain.Select`
authorIan Alexander <jitsu@google.com>
Fri, 3 Oct 2025 01:45:53 +0000 (21:45 -0400)
committerIan Alexander <jitsu@google.com>
Mon, 20 Oct 2025 19:56:03 +0000 (12:56 -0700)
This command modifies the call tree starting at `toolchain.Select` to
inject a `State` parameter to every function that is currently using
the global `modload.LoaderState` variable.  By explicilty passing a
`State` parameter, we can begin to eliminate the usage of the global
`modload.LoaderState`.

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

[git-generate]
cd src/cmd/go/internal/toolchain
rf '
  inject modload.LoaderState Select
  add select.go var moduleLoaderState *modload.State
  ex {
    import "cmd/go/internal/modload";
    modload.LoaderState -> moduleLoaderState
  }
  add Select://+0 moduleLoaderState := modload.NewState()
  rm select.go:/var moduleLoaderState \*modload.State/
'
cd ..
./rf-cleanup.zsh

Change-Id: I759439a47e2b1aaa01a0a800bc18596dd7ce4983
Reviewed-on: https://go-review.googlesource.com/c/go/+/709988
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>

src/cmd/go/internal/modcmd/download.go
src/cmd/go/internal/modcmd/graph.go
src/cmd/go/internal/modcmd/tidy.go
src/cmd/go/internal/modget/get.go
src/cmd/go/internal/modload/init.go
src/cmd/go/internal/telemetrystats/telemetrystats.go
src/cmd/go/internal/toolchain/select.go
src/cmd/go/internal/toolchain/switch.go
src/cmd/go/internal/workcmd/sync.go

index 0d223b382692f645c9deca40ac931b88395ef379..63eb6886a1a15786084f4db31dc40aa2a76c63ce 100644 (file)
@@ -158,7 +158,7 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
                                        // 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(ctx, err)
+                                       toolchain.SwitchOrFatal(modload.LoaderState, ctx, err)
                                }
 
                                for _, m := range modFile.Require {
index 3bc6009b57b59552683e075bc6f672d514c97a7a..aa3c9f45405240a0df60ecf009698b13c1e2c512 100644 (file)
@@ -62,7 +62,7 @@ func runGraph(ctx context.Context, cmd *base.Command, args []string) {
 
        goVersion := graphGo.String()
        if goVersion != "" && gover.Compare(gover.Local(), goVersion) < 0 {
-               toolchain.SwitchOrFatal(ctx, &gover.TooNewError{
+               toolchain.SwitchOrFatal(modload.LoaderState, ctx, &gover.TooNewError{
                        What:      "-go flag",
                        GoVersion: goVersion,
                })
index 8a8b4e34c0cf7169b15d3f11b9c307dad7e86384..fb66bbcda3a17300ed186747e47d5c3ec9599aed 100644 (file)
@@ -124,7 +124,7 @@ func runTidy(ctx context.Context, cmd *base.Command, args []string) {
 
        goVersion := tidyGo.String()
        if goVersion != "" && gover.Compare(gover.Local(), goVersion) < 0 {
-               toolchain.SwitchOrFatal(ctx, &gover.TooNewError{
+               toolchain.SwitchOrFatal(modload.LoaderState, ctx, &gover.TooNewError{
                        What:      "-go flag",
                        GoVersion: goVersion,
                })
index 8972e4152e077986411dc2b9ec6bf9a6a5030e64..9de24c4508a5ee5fe1aa4237bda3721833bf0879 100644 (file)
@@ -418,7 +418,7 @@ func runGet(ctx context.Context, cmd *base.Command, args []string) {
                // but the command line is not.
                // TODO(bcmills): modload.EditBuildList should catch this instead,
                // and then this can be changed to base.Fatal(err).
-               toolchain.SwitchOrFatal(ctx, err)
+               toolchain.SwitchOrFatal(modload.LoaderState, ctx, err)
        }
 
        newReqs := reqsFromGoMod(modload.ModFile())
@@ -558,7 +558,7 @@ func newResolver(ctx context.Context, queries []*query) *resolver {
        // methods.
        mg, err := modload.LoadModGraph(ctx, "")
        if err != nil {
-               toolchain.SwitchOrFatal(ctx, err)
+               toolchain.SwitchOrFatal(modload.LoaderState, ctx, err)
        }
 
        buildList := mg.BuildList()
@@ -1619,7 +1619,7 @@ func (r *resolver) checkPackageProblems(ctx context.Context, pkgPatterns []strin
                        // are old enough but the go command itself is not new
                        // enough. See the related comment on the SwitchOrFatal
                        // in runGet when WriteGoMod returns an error.
-                       toolchain.SwitchOrFatal(ctx, err)
+                       toolchain.SwitchOrFatal(modload.LoaderState, ctx, err)
                }
        }
 
@@ -1989,7 +1989,7 @@ func (r *resolver) updateBuildList(ctx context.Context, additions []module.Versi
        changed, err := modload.EditBuildList(modload.LoaderState, ctx, additions, resolved)
        if err != nil {
                if errors.Is(err, gover.ErrTooNew) {
-                       toolchain.SwitchOrFatal(ctx, err)
+                       toolchain.SwitchOrFatal(modload.LoaderState, ctx, err)
                }
 
                constraint, ok := errors.AsType[*modload.ConstraintError](err)
@@ -2035,7 +2035,7 @@ func (r *resolver) updateBuildList(ctx context.Context, additions []module.Versi
 
        mg, err := modload.LoadModGraph(ctx, "")
        if err != nil {
-               toolchain.SwitchOrFatal(ctx, err)
+               toolchain.SwitchOrFatal(modload.LoaderState, ctx, err)
        }
 
        r.buildList = mg.BuildList()
index 9e07c72aa6583c5feeba25aa748be4e1957ace9b..9182f60ee7b1bbd12f4f197184357d7d4b844247 100644 (file)
@@ -570,12 +570,12 @@ func Init(loaderstate *State) {
 // of 'go get', but Init reads the -modfile flag in 'go get', so it shouldn't
 // be called until the command is installed and flags are parsed. Instead of
 // calling Init and Enabled, the main package can call this function.
-func WillBeEnabled() bool {
-       if LoaderState.modRoots != nil || cfg.ModulesEnabled {
+func WillBeEnabled(loaderstate *State) bool {
+       if loaderstate.modRoots != nil || cfg.ModulesEnabled {
                // Already enabled.
                return true
        }
-       if LoaderState.initialized {
+       if loaderstate.initialized {
                // Initialized, not enabled.
                return false
        }
index 9586324551dfc95b80d151d938c39195331ec778..077c2d817f0e144d2d134db5a2162eb73d4c0494 100644 (file)
@@ -22,7 +22,7 @@ func Increment() {
 // incrementConfig increments counters for the configuration
 // the command is running in.
 func incrementConfig() {
-       if !modload.WillBeEnabled() {
+       if !modload.WillBeEnabled(modload.LoaderState) {
                counter.Inc("go/mode:gopath")
        } else if workfile := modload.FindGoWork(modload.LoaderState, base.Cwd()); workfile != "" {
                counter.Inc("go/mode:workspace")
index 8a7e51c1437557bad465a6feefa07c99eebc1f46..5a0600a9654ce081502d9b09bae3684bb1e40ab4 100644 (file)
@@ -95,10 +95,11 @@ var toolchainTrace = godebug.New("#toolchaintrace").Value() == "1"
 // It must be called early in startup.
 // See https://go.dev/doc/toolchain#select.
 func Select() {
+       moduleLoaderState := modload.NewState()
        log.SetPrefix("go: ")
        defer log.SetPrefix("")
 
-       if !modload.WillBeEnabled() {
+       if !modload.WillBeEnabled(moduleLoaderState) {
                return
        }
 
@@ -171,7 +172,7 @@ func Select() {
        gotoolchain = minToolchain
        if mode == "auto" || mode == "path" {
                // Read go.mod to find new minimum and suggested toolchain.
-               file, goVers, toolchain := modGoToolchain()
+               file, goVers, toolchain := modGoToolchain(moduleLoaderState)
                gover.Startup.AutoFile = file
                if toolchain == "default" {
                        // "default" means always use the default toolchain,
@@ -231,7 +232,7 @@ func Select() {
                                }
                        }
                }
-               maybeSwitchForGoInstallVersion(minVers)
+               maybeSwitchForGoInstallVersion(moduleLoaderState, minVers)
        }
 
        // If we are invoked as a target toolchain, confirm that
@@ -283,7 +284,7 @@ func Select() {
        }
 
        counterSelectExec.Inc()
-       Exec(modload.LoaderState, gotoolchain)
+       Exec(moduleLoaderState, gotoolchain)
 }
 
 var counterSelectExec = counter.New("go/toolchain/select-exec")
@@ -527,9 +528,9 @@ func raceSafeCopy(old, new string) error {
 // modGoToolchain finds the enclosing go.work or go.mod file
 // and returns the go version and toolchain lines from the file.
 // The toolchain line overrides the version line
-func modGoToolchain() (file, goVers, toolchain string) {
+func modGoToolchain(loaderstate *modload.State) (file, goVers, toolchain string) {
        wd := base.UncachedCwd()
-       file = modload.FindGoWork(modload.LoaderState, wd)
+       file = modload.FindGoWork(loaderstate, wd)
        // $GOWORK can be set to a file that does not yet exist, if we are running 'go work init'.
        // Do not try to load the file in that case
        if _, err := os.Stat(file); err != nil {
@@ -551,7 +552,7 @@ func modGoToolchain() (file, goVers, toolchain string) {
 
 // maybeSwitchForGoInstallVersion reports whether the command line is go install m@v or go run m@v.
 // If so, switch to the go version required to build m@v if it's higher than minVers.
-func maybeSwitchForGoInstallVersion(minVers string) {
+func maybeSwitchForGoInstallVersion(loaderstate *modload.State, minVers string) {
        // Note: We assume there are no flags between 'go' and 'install' or 'run'.
        // During testing there are some debugging flags that are accepted
        // in that position, but in production go binaries there are not.
@@ -692,10 +693,10 @@ func maybeSwitchForGoInstallVersion(minVers string) {
        // command lines if we add new flags in the future.
 
        // Set up modules without an explicit go.mod, to download go.mod.
-       modload.LoaderState.ForceUseModules = true
-       modload.LoaderState.RootMode = modload.NoRoot
-       modload.Init(modload.LoaderState)
-       defer modload.LoaderState.Reset()
+       loaderstate.ForceUseModules = true
+       loaderstate.RootMode = modload.NoRoot
+       modload.Init(loaderstate)
+       defer loaderstate.Reset()
 
        // See internal/load.PackagesAndErrorsOutsideModule
        ctx := context.Background()
@@ -705,14 +706,14 @@ func maybeSwitchForGoInstallVersion(minVers string) {
                allowed = nil
        }
        noneSelected := func(path string) (version string) { return "none" }
-       _, err := modload.QueryPackages(modload.LoaderState, ctx, path, version, noneSelected, allowed)
+       _, err := modload.QueryPackages(loaderstate, ctx, path, version, noneSelected, allowed)
        if errors.Is(err, gover.ErrTooNew) {
                // Run early switch, same one go install or go run would eventually do,
                // if it understood all the command-line flags.
-               s := NewSwitcher(modload.LoaderState)
+               s := NewSwitcher(loaderstate)
                s.Error(err)
                if s.TooNew != nil && gover.Compare(s.TooNew.GoVersion, minVers) > 0 {
-                       SwitchOrFatal(ctx, err)
+                       SwitchOrFatal(loaderstate, ctx, err)
                }
        }
 }
index 9fedea3abbf4b77fc1ad267d0eeea76f4b71e833..76b608fdef415798e652283c288aeb7925ddc0af 100644 (file)
@@ -116,8 +116,8 @@ var counterSwitchExec = counter.New("go/toolchain/switch-exec")
 
 // SwitchOrFatal attempts a toolchain switch based on the information in err
 // and otherwise falls back to base.Fatal(err).
-func SwitchOrFatal(ctx context.Context, err error) {
-       s := NewSwitcher(modload.LoaderState)
+func SwitchOrFatal(loaderstate *modload.State, ctx context.Context, err error) {
+       s := NewSwitcher(loaderstate)
        s.Error(err)
        s.Switch(ctx)
        base.Exit()
index c58cd55ceee39246a4ddd63c050d9efaab86bdf3..dfff0c29d227b1f5064ca63c13000d0b15764720 100644 (file)
@@ -56,7 +56,7 @@ func runSync(ctx context.Context, cmd *base.Command, args []string) {
 
        _, err := modload.LoadModGraph(ctx, "")
        if err != nil {
-               toolchain.SwitchOrFatal(ctx, err)
+               toolchain.SwitchOrFatal(modload.LoaderState, ctx, err)
        }
        mustSelectFor := map[module.Version][]module.Version{}