From a68bf75d3402412a1946fe1df67f57ca923f1507 Mon Sep 17 00:00:00 2001 From: Michael Matloob Date: Mon, 10 Mar 2025 13:32:23 -0400 Subject: [PATCH] cmd/go: don't write own toolchain line when updating go line The Go command had a behavior of writing its own toolchain name when updating the go line in a go.mod (for example when a user runs go get go@version). This behavior was often undesirable and the toolchain line was often removed by users before checking in go.mod files (including in the x/ repos). It also led to user confusion. This change removes that behavior. A toolchain line will not be added if one wasn't present before. The toolchain line can still be removed though: the toolchain line must be at least the go version, so if the go version is increased above the toolchain version, the toolchain version will be bumped up to that go version. Then the toolchain line will then be dropped because go implies toolchain . Making this change slightly hurts reproducability because future go commands run on the go.mod file may be run with a different toolchain than the one that used it, but that doesn't seem to be worth the confusion the behavior resulted in. We expect this change will not have negative consequences, but it could be possible, and we would like to hear from any users that depended on the previous behavior in case we need to roll it back before the release. Fixes #65847 Change-Id: Id795b7f762e4f90ba0fa8c7935d03f32dfc8590e Reviewed-on: https://go-review.googlesource.com/c/go/+/656835 Reviewed-by: Alan Donovan LUCI-TryBot-Result: Go LUCI --- src/cmd/go/internal/modload/init.go | 50 +++++-------------- .../testdata/script/gotoolchain_modcmds.txt | 2 +- .../script/mod_download_exec_toolchain.txt | 2 - .../script/mod_get_exec_toolchain.txt | 16 +++--- .../go/testdata/script/mod_get_toolchain.txt | 17 ++++--- .../testdata/script/mod_import_toolchain.txt | 8 +-- .../go/testdata/script/mod_tidy_version.txt | 4 +- src/cmd/go/testdata/script/mod_toolchain.txt | 9 +++- .../go/testdata/script/work_get_toolchain.txt | 6 +-- .../testdata/script/work_sync_toolchain.txt | 4 +- .../go/testdata/script/work_use_toolchain.txt | 8 +-- 11 files changed, 52 insertions(+), 74 deletions(-) diff --git a/src/cmd/go/internal/modload/init.go b/src/cmd/go/internal/modload/init.go index 5d01aedc2f..1ffe5052fb 100644 --- a/src/cmd/go/internal/modload/init.go +++ b/src/cmd/go/internal/modload/init.go @@ -745,34 +745,25 @@ func UpdateWorkGoVersion(wf *modfile.WorkFile, goVers string) (changed bool) { wf.AddGoStmt(goVers) - // We wrote a new go line. For reproducibility, - // if the toolchain running right now is newer than the new toolchain line, - // update the toolchain line to record the newer toolchain. - // The user never sets the toolchain explicitly in a 'go work' command, - // so this is only happening as a result of a go or toolchain line found - // in a module. - // If the toolchain running right now is a dev toolchain (like "go1.21") - // writing 'toolchain go1.21' will not be useful, since that's not an actual - // toolchain you can download and run. In that case fall back to at least - // checking that the toolchain is new enough for the Go version. - toolchain := "go" + old - if wf.Toolchain != nil { - toolchain = wf.Toolchain.Name - } - if gover.IsLang(gover.Local()) { - toolchain = gover.ToolchainMax(toolchain, "go"+goVers) - } else { - toolchain = gover.ToolchainMax(toolchain, "go"+gover.Local()) + if wf.Toolchain == nil { + return true } - // Drop the toolchain line if it is implied by the go line + // Drop the toolchain line if it is implied by the go line, + // if its version is older than the version in the go line, // or if it is asking for a toolchain older than Go 1.21, // which will not understand the toolchain line. - if toolchain == "go"+goVers || gover.Compare(gover.FromToolchain(toolchain), gover.GoStrictVersion) < 0 { + // Previously, a toolchain line set to the local toolchain + // version was added so that future operations on the go file + // would use the same toolchain logic for reproducibility. + // This behavior seemed to cause user confusion without much + // benefit so it was removed. See #65847. + toolchain := wf.Toolchain.Name + toolVers := gover.FromToolchain(toolchain) + if toolchain == "go"+goVers || gover.Compare(toolVers, goVers) < 0 || gover.Compare(toolVers, gover.GoStrictVersion) < 0 { wf.DropToolchainStmt() - } else { - wf.AddToolchainStmt(toolchain) } + return true } @@ -1833,22 +1824,7 @@ func UpdateGoModFromReqs(ctx context.Context, opts WriteOpts) (before, after []b toolchain = "go" + goVersion } - // For reproducibility, if we are writing a new go line, - // and we're not explicitly modifying the toolchain line with 'go get toolchain@something', - // and the go version is one that supports switching toolchains, - // and the toolchain running right now is newer than the current toolchain line, - // then update the toolchain line to record the newer toolchain. - // - // TODO(#57001): This condition feels too complicated. Can we simplify it? - // TODO(#57001): Add more tests for toolchain lines. toolVers := gover.FromToolchain(toolchain) - if wroteGo && !opts.DropToolchain && !opts.ExplicitToolchain && - gover.Compare(goVersion, gover.GoStrictVersion) >= 0 && - (gover.Compare(gover.Local(), toolVers) > 0 && !gover.IsLang(gover.Local())) { - toolchain = "go" + gover.Local() - toolVers = gover.FromToolchain(toolchain) - } - if opts.DropToolchain || toolchain == "go"+goVersion || (gover.Compare(toolVers, gover.GoStrictVersion) < 0 && !opts.ExplicitToolchain) { // go get toolchain@none or toolchain matches go line or isn't valid; drop it. // TODO(#57001): 'go get' should reject explicit toolchains below GoStrictVersion. diff --git a/src/cmd/go/testdata/script/gotoolchain_modcmds.txt b/src/cmd/go/testdata/script/gotoolchain_modcmds.txt index 1edd6d85a5..e6a45533bc 100644 --- a/src/cmd/go/testdata/script/gotoolchain_modcmds.txt +++ b/src/cmd/go/testdata/script/gotoolchain_modcmds.txt @@ -21,7 +21,7 @@ stderr '^go: rsc.io/future@v1.0.0: module rsc.io/future@v1.0.0 requires go >= 1. go get . stderr '^go: module rsc.io/future@v1.0.0 requires go >= 1.999; switching to go1.999testmod$' stderr '^go: upgraded go 1.21 => 1.999$' -stderr '^go: added toolchain go1.999testmod$' +! stderr '^go: added toolchain' # Now, the various 'go mod' subcommands should succeed. diff --git a/src/cmd/go/testdata/script/mod_download_exec_toolchain.txt b/src/cmd/go/testdata/script/mod_download_exec_toolchain.txt index 6cf863b28a..78b62aa7f0 100644 --- a/src/cmd/go/testdata/script/mod_download_exec_toolchain.txt +++ b/src/cmd/go/testdata/script/mod_download_exec_toolchain.txt @@ -102,6 +102,4 @@ module example go 1.23 -toolchain go1.23.9 - require rsc.io/needall v0.0.1 diff --git a/src/cmd/go/testdata/script/mod_get_exec_toolchain.txt b/src/cmd/go/testdata/script/mod_get_exec_toolchain.txt index 497fe36f40..79df80e841 100644 --- a/src/cmd/go/testdata/script/mod_get_exec_toolchain.txt +++ b/src/cmd/go/testdata/script/mod_get_exec_toolchain.txt @@ -9,7 +9,7 @@ stderr '^go: rsc.io/needall@v0.0.1 requires go >= 1.23; switching to go1.23.9$' ! stderr '\(running' stderr '^go: added rsc.io/needall v0.0.1' grep 'go 1.23' go.mod -grep 'toolchain go1.23.9' go.mod +! grep toolchain go.mod # GOTOOLCHAIN=min+auto should run the newer toolchain env GOTOOLCHAIN=go1.21+auto @@ -19,7 +19,7 @@ stderr '^go: rsc.io/needall@v0.0.1 requires go >= 1.23; switching to go1.23.9$' ! stderr '\(running' stderr '^go: added rsc.io/needall v0.0.1' grep 'go 1.23' go.mod -grep 'toolchain go1.23.9' go.mod +! grep toolchain go.mod # GOTOOLCHAIN=go1.21 should NOT run the newer toolchain env GOTOOLCHAIN=go1.21 @@ -67,7 +67,7 @@ cp go.mod.new go.mod go get go@1.22rc1 stderr '^go: updating go.mod requires go >= 1.22rc1; switching to go1.22.9$' stderr '^go: upgraded go 1.1 => 1.22rc1$' -stderr '^go: added toolchain go1.22.9$' +! stderr '^go: added toolchain$' # go get go@1.22.1 should use 1.22.1 exactly, not a later release. env GOTOOLCHAIN=local @@ -80,7 +80,7 @@ cp go.mod.new go.mod go get go@1.22.1 stderr '^go: updating go.mod requires go >= 1.22.1; switching to go1.22.9$' stderr '^go: upgraded go 1.1 => 1.22.1$' -stderr '^go: added toolchain go1.22.9$' +! stderr '^go: added toolchain$' # go get needgo122 (says 'go 1.22') should use 1.22.0, the earliest release we have available # (ignoring prereleases). @@ -94,7 +94,7 @@ cp go.mod.new go.mod go get rsc.io/needgo122 stderr '^go: upgraded go 1.1 => 1.22$' stderr '^go: rsc.io/needgo122@v0.0.1 requires go >= 1.22; switching to go1.22.9$' -stderr '^go: added toolchain go1.22.9$' +! stderr '^go: added toolchain$' # go get needgo1223 (says 'go 1.22.3') should use go 1.22.3 env GOTOOLCHAIN=local @@ -107,7 +107,7 @@ cp go.mod.new go.mod go get rsc.io/needgo1223 stderr '^go: upgraded go 1.1 => 1.22.3$' stderr '^go: rsc.io/needgo1223@v0.0.1 requires go >= 1.22.3; switching to go1.22.9$' -stderr '^go: added toolchain go1.22.9$' +! stderr '^go: added toolchain$' # go get needgo124 (says 'go 1.24') should use go 1.24rc1, the only version available env GOTOOLCHAIN=local @@ -120,7 +120,7 @@ cp go.mod.new go.mod go get rsc.io/needgo124 stderr '^go: rsc.io/needgo124@v0.0.1 requires go >= 1.24; switching to go1.24rc1$' stderr '^go: upgraded go 1.1 => 1.24$' -stderr '^go: added toolchain go1.24rc1$' +! stderr '^go: added toolchain$' # The -C flag should not happen more than once due to switching. mkdir dir dir/dir @@ -132,7 +132,7 @@ cp p.go dir/dir/p.go go get -C dir rsc.io/needgo124 stderr '^go: rsc.io/needgo124@v0.0.1 requires go >= 1.24; switching to go1.24rc1$' stderr '^go: upgraded go 1.1 => 1.24$' -stderr '^go: added toolchain go1.24rc1$' +! stderr '^go: added toolchain1$' cmp go.mod.new go.mod cmp go.mod.new dir/dir/go.mod grep 'go 1.24$' dir/go.mod diff --git a/src/cmd/go/testdata/script/mod_get_toolchain.txt b/src/cmd/go/testdata/script/mod_get_toolchain.txt index 758142d668..87e84ae15e 100644 --- a/src/cmd/go/testdata/script/mod_get_toolchain.txt +++ b/src/cmd/go/testdata/script/mod_get_toolchain.txt @@ -7,28 +7,28 @@ cp go.mod.orig go.mod go get go stderr '^go: upgraded go 1.21 => 1.23.9$' grep 'go 1.23.9' go.mod -grep 'toolchain go1.99rc1' go.mod +! grep toolchain go.mod # go get go@1.23 should use the latest Go 1.23 cp go.mod.orig go.mod go get go@1.23 stderr '^go: upgraded go 1.21 => 1.23.9$' grep 'go 1.23.9' go.mod -grep 'toolchain go1.99rc1' go.mod +! grep toolchain go.mod # go get go@1.22 should use the latest Go 1.22 cp go.mod.orig go.mod go get go@1.22 stderr '^go: upgraded go 1.21 => 1.22.9$' grep 'go 1.22.9' go.mod -grep 'toolchain go1.99rc1' go.mod +! grep toolchain1 go.mod # go get go@patch should use the latest patch release go get go@1.22.1 go get go@patch stderr '^go: upgraded go 1.22.1 => 1.22.9$' grep 'go 1.22.9' go.mod -grep 'toolchain go1.99rc1' go.mod +! grep toolchain go.mod # go get go@1.24 does NOT find the release candidate cp go.mod.orig go.mod @@ -40,17 +40,22 @@ cp go.mod.orig go.mod go get go@1.24rc1 stderr '^go: upgraded go 1.21 => 1.24rc1$' grep 'go 1.24rc1' go.mod -grep 'toolchain go1.99rc1' go.mod +! grep toolchain go.mod # go get go@latest finds the latest Go 1.23 cp go.mod.orig go.mod go get go@latest stderr '^go: upgraded go 1.21 => 1.23.9$' grep 'go 1.23.9' go.mod -grep 'toolchain go1.99rc1' go.mod +! grep toolchain go.mod # Again, with toolchains. +go get toolchain@go1.99rc1 +stderr '^go: added toolchain go1.99rc1$' +grep 'go 1.23.9' go.mod +grep 'toolchain go1.99rc1' go.mod + # go get toolchain should find go1.999testmod. go get toolchain stderr '^go: upgraded toolchain go1.99rc1 => go1.999testmod$' diff --git a/src/cmd/go/testdata/script/mod_import_toolchain.txt b/src/cmd/go/testdata/script/mod_import_toolchain.txt index 42c12c1e2a..d19b93d932 100644 --- a/src/cmd/go/testdata/script/mod_import_toolchain.txt +++ b/src/cmd/go/testdata/script/mod_import_toolchain.txt @@ -1,5 +1,5 @@ # This test verifies that 'go get' and 'go mod tidy' switch to a newer toolchain -# if needed to process newly-reolved imports. +# if needed to process newly-resolved imports. env TESTGO_VERSION=go1.21.0 env TESTGO_VERSION_SWITCH=switch @@ -46,7 +46,6 @@ go: trying upgrade to example.net/b@v0.1.0 go: accepting indirect upgrade from go@1.20 to 1.22.0 go: trying upgrade to example.net/c@v0.1.0 go: upgraded go 1.20 => 1.22.0 -go: added toolchain go1.22.9 go: added example.net/b v0.1.0 go: added example.net/c v0.1.0 go: added example.net/d v0.1.0 @@ -67,7 +66,6 @@ go: trying upgrade to example.net/c@v0.1.0 go: trying upgrade to example.net/d@v0.2.0 go: accepting indirect upgrade from go@1.22.0 to 1.23.0 go: upgraded go 1.20 => 1.23.0 -go: added toolchain go1.23.9 go: upgraded example.net/a v0.1.0 => v0.2.0 go: added example.net/b v0.1.0 go: added example.net/c v0.1.0 @@ -92,8 +90,6 @@ module example go 1.22.0 -toolchain go1.22.9 - require ( example.net/a v0.1.0 example.net/b v0.1.0 @@ -117,8 +113,6 @@ module example go 1.23.0 -toolchain go1.23.9 - require ( example.net/a v0.2.0 example.net/b v0.1.0 diff --git a/src/cmd/go/testdata/script/mod_tidy_version.txt b/src/cmd/go/testdata/script/mod_tidy_version.txt index e3f2561f5e..e86a9d9cbf 100644 --- a/src/cmd/go/testdata/script/mod_tidy_version.txt +++ b/src/cmd/go/testdata/script/mod_tidy_version.txt @@ -131,7 +131,7 @@ cmpenv go.mod go.mod.latest cp go.mod.117 go.mod go mod tidy -go=1.21.0 # lower than $goversion -cmpenv go.mod go.mod.121toolchain +cmp go.mod go.mod.121toolchain -- go.mod -- @@ -334,8 +334,6 @@ module example.com/m go 1.21.0 -toolchain $TESTGO_VERSION - require example.net/a v0.1.0 require ( diff --git a/src/cmd/go/testdata/script/mod_toolchain.txt b/src/cmd/go/testdata/script/mod_toolchain.txt index c771cae0a1..e96dfbcd84 100644 --- a/src/cmd/go/testdata/script/mod_toolchain.txt +++ b/src/cmd/go/testdata/script/mod_toolchain.txt @@ -18,9 +18,12 @@ grep 'toolchain go1.22.1' go.mod go get go@1.22.3 stderr '^go: upgraded go 1.10 => 1.22.3$' -stderr '^go: upgraded toolchain go1.22.1 => go1.100.0$' +! stderr '^go: upgraded toolchain$' grep 'go 1.22.3' go.mod +go get toolchain@go1.100.0 +stderr '^go: added toolchain go1.100.0$' + go get go@1.22.3 toolchain@1.22.3 stderr '^go: removed toolchain go1.100.0$' ! grep toolchain go.mod @@ -65,6 +68,10 @@ stderr '^go: removed toolchain go1.23.9' ! stderr ' go 1' grep 'go 1.23.5' go.mod +go get toolchain@go1.23.0 go@1.22.0 +go get go@1.24.0 +! grep toolchain go.mod + -- go.mod -- module m go 1.10 diff --git a/src/cmd/go/testdata/script/work_get_toolchain.txt b/src/cmd/go/testdata/script/work_get_toolchain.txt index 5a851bb774..6548860ac9 100644 --- a/src/cmd/go/testdata/script/work_get_toolchain.txt +++ b/src/cmd/go/testdata/script/work_get_toolchain.txt @@ -1,4 +1,4 @@ -# go get should update the go and toolchain lines in go.work +# go get should update the go line in go.work env TESTGO_VERSION=go1.21 env TESTGO_VERSION_SWITCH=switch env GOTOOLCHAIN=auto @@ -9,8 +9,8 @@ stderr '^go: rsc.io/needall@v0.0.1 requires go >= 1.23; switching to go1.23.9$' stderr '^go: added rsc.io/needall v0.0.1' grep 'go 1.23$' go.mod grep 'go 1.23$' go.work -grep 'toolchain go1.23.9' go.mod -grep 'toolchain go1.23.9' go.work +! grep toolchain go.mod +! grep toolchain go.work -- go.mod.new -- module m diff --git a/src/cmd/go/testdata/script/work_sync_toolchain.txt b/src/cmd/go/testdata/script/work_sync_toolchain.txt index b752462727..989d6bb792 100644 --- a/src/cmd/go/testdata/script/work_sync_toolchain.txt +++ b/src/cmd/go/testdata/script/work_sync_toolchain.txt @@ -34,7 +34,7 @@ env GOTOOLCHAIN=auto go work sync stderr '^go: m1_22_1'${/}'go.mod requires go >= 1.22.1; switching to go1.22.9$' grep '^go 1.22.1$' go.work -grep '^toolchain go1.22.9$' go.work +! grep toolchain go.work # work sync with newer modules should update go 1.22.1 -> 1.24rc1 and drop toolchain go work edit -use=./m1_24_rc0 @@ -42,4 +42,4 @@ go work sync stderr '^go: m1_24_rc0'${/}'go.mod requires go >= 1.24rc0; switching to go1.24rc1$' cat go.work grep '^go 1.24rc0$' go.work -grep '^toolchain go1.24rc1$' go.work +! grep toolchain go.work diff --git a/src/cmd/go/testdata/script/work_use_toolchain.txt b/src/cmd/go/testdata/script/work_use_toolchain.txt index bb3db9cf90..d81e4a4c3e 100644 --- a/src/cmd/go/testdata/script/work_use_toolchain.txt +++ b/src/cmd/go/testdata/script/work_use_toolchain.txt @@ -32,13 +32,13 @@ env GOTOOLCHAIN=auto go work use ./m1_22_0 stderr '^go: m1_22_0'${/}'go.mod requires go >= 1.22.0; switching to go1.22.9$' grep '^go 1.22.0$' go.work -grep '^toolchain go1.22.9$' go.work +! grep toolchain go.work # work use with an even newer module should bump go again. go work use ./m1_22_1 -! stderr switching +stderr '^go: m1_22_1'${/}'go.mod requires go >= 1.22.1; switching to go1.22.9$' grep '^go 1.22.1$' go.work -grep '^toolchain go1.22.9$' go.work # unchanged +! grep toolchain go.work # work use with an even newer module should bump go and toolchain again. env GOTOOLCHAIN=go1.22.9 @@ -48,4 +48,4 @@ env GOTOOLCHAIN=auto go work use ./m1_24_rc0 stderr '^go: m1_24_rc0'${/}'go.mod requires go >= 1.24rc0; switching to go1.24rc1$' grep '^go 1.24rc0$' go.work -grep '^toolchain go1.24rc1$' go.work +! grep 'toolchain' go.work -- 2.51.0