Skip to content

Commit 2d2bcdd

Browse files
committed
cmd/go: upgrade go install pkg@version's go using local mod, work
This CL changes the toolchain selection behavior for go install pkg@v and go run pkg@v to also take into account the go and toolchain version lines in the containing go.mod and go.work file. Before this change, the go command would detect that go install pkg@version or go run pkg@version was being run and skip the standard behavior that would select the toolchain based on the go version in the go.mod or go.work file. It would instead check the go line of the module being downloaded and switch to that version if necessary. With this change, the go command does not skip the standard behavior. It proceeds to determine if an upgrade is required based on the containing go.mod or go.work file's go and toolchain lines. Then, it checks the module being installed to see if it would require a higher version than the determined upgrade (or the local version if no upgrade was determined). If it does require a higher version, then a switch happens to that version, and if not the upgrade logic proceeds as usual doing the upgrade if one was determined. Fixes #66518 Change-Id: I00d96170e8713c451cc0fd2203be521585418842 Reviewed-on: https://go-review.googlesource.com/c/go/+/660035 Reviewed-by: Junyang Shao <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent 7372b64 commit 2d2bcdd

File tree

3 files changed

+53
-22
lines changed

3 files changed

+53
-22
lines changed

src/cmd/go/internal/toolchain/select.go

+16-17
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ func Select() {
169169
}
170170

171171
gotoolchain = minToolchain
172-
if (mode == "auto" || mode == "path") && !goInstallVersion(minVers) {
172+
if mode == "auto" || mode == "path" {
173173
// Read go.mod to find new minimum and suggested toolchain.
174174
file, goVers, toolchain := modGoToolchain()
175175
gover.Startup.AutoFile = file
@@ -212,6 +212,7 @@ func Select() {
212212
}
213213
if gover.Compare(goVers, minVers) > 0 {
214214
gotoolchain = "go" + goVers
215+
minVers = goVers
215216
// Starting with Go 1.21, the first released version has a .0 patch version suffix.
216217
// Don't try to download a language version (sans patch component), such as go1.22.
217218
// Instead, use the first toolchain of that language version, such as 1.22.0.
@@ -230,6 +231,7 @@ func Select() {
230231
}
231232
}
232233
}
234+
maybeSwitchForGoInstallVersion(minVers)
233235
}
234236

235237
// If we are invoked as a target toolchain, confirm that
@@ -547,21 +549,21 @@ func modGoToolchain() (file, goVers, toolchain string) {
547549
return file, gover.GoModLookup(data, "go"), gover.GoModLookup(data, "toolchain")
548550
}
549551

550-
// goInstallVersion reports whether the command line is go install m@v or go run m@v.
551-
// If so, Select must not read the go.mod or go.work file in "auto" or "path" mode.
552-
func goInstallVersion(minVers string) bool {
552+
// maybeSwitchForGoInstallVersion reports whether the command line is go install m@v or go run m@v.
553+
// If so, switch to the go version required to build m@v if it's higher than minVers.
554+
func maybeSwitchForGoInstallVersion(minVers string) {
553555
// Note: We assume there are no flags between 'go' and 'install' or 'run'.
554556
// During testing there are some debugging flags that are accepted
555557
// in that position, but in production go binaries there are not.
556558
if len(os.Args) < 3 {
557-
return false
559+
return
558560
}
559561

560562
var cmdFlags *flag.FlagSet
561563
switch os.Args[1] {
562564
default:
563565
// Command doesn't support a pkg@version as the main module.
564-
return false
566+
return
565567
case "install":
566568
cmdFlags = &work.CmdInstall.Flag
567569
case "run":
@@ -595,7 +597,7 @@ func goInstallVersion(minVers string) bool {
595597
args = args[1:]
596598
if a == "--" {
597599
if len(args) == 0 {
598-
return false
600+
return
599601
}
600602
pkgArg = args[0]
601603
break
@@ -616,7 +618,7 @@ func goInstallVersion(minVers string) bool {
616618
val = "true"
617619
}
618620
if err := modcacherwVal.Set(val); err != nil {
619-
return false
621+
return
620622
}
621623
modcacherwSeen = true
622624
continue
@@ -636,8 +638,8 @@ func goInstallVersion(minVers string) bool {
636638
// because it is preceded by run flags and followed by arguments to the
637639
// program being run. Since we don't know whether this flag takes
638640
// an argument, we can't reliably identify the end of the run flags.
639-
// Just give up and let the user clarify using the "=" form..
640-
return false
641+
// Just give up and let the user clarify using the "=" form.
642+
return
641643
}
642644

643645
// We would like to let 'go install -newflag pkg@version' work even
@@ -666,11 +668,11 @@ func goInstallVersion(minVers string) bool {
666668
}
667669

668670
if !strings.Contains(pkgArg, "@") || build.IsLocalImport(pkgArg) || filepath.IsAbs(pkgArg) {
669-
return false
671+
return
670672
}
671673
path, version, _ := strings.Cut(pkgArg, "@")
672674
if path == "" || version == "" || gover.IsToolchain(path) {
673-
return false
675+
return
674676
}
675677

676678
if !modcacherwSeen && base.InGOFLAGS("-modcacherw") {
@@ -679,9 +681,8 @@ func goInstallVersion(minVers string) bool {
679681
base.SetFromGOFLAGS(fs)
680682
}
681683

682-
// It would be correct to simply return true here, bypassing use
683-
// of the current go.mod or go.work, and let "go run" or "go install"
684-
// do the rest, including a toolchain switch.
684+
// It would be correct to do nothing here, and let "go run" or "go install"
685+
// do the toolchain switch.
685686
// Our goal instead is, since we have gone to the trouble of handling
686687
// unknown flags to some degree, to run the switch now, so that
687688
// these commands can switch to a newer toolchain directed by the
@@ -714,6 +715,4 @@ func goInstallVersion(minVers string) bool {
714715
SwitchOrFatal(ctx, err)
715716
}
716717
}
717-
718-
return true // pkg@version found
719718
}

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

+35-3
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,8 @@ go mod edit -go=1.501 -toolchain=none
197197
go version
198198
stdout go1.501
199199

200+
go mod edit -go=1.21
201+
200202
# avoid two-step switch, first from install target requirement, then from GOTOOLCHAIN min
201203
# instead, just jump directly to GOTOOLCHAIN min
202204
env TESTGO_VERSION=go1.2.3
@@ -205,21 +207,49 @@ env GOTOOLCHAIN=go1.23.0+auto
205207
! go install rsc.io/fortune/[email protected]
206208
! stderr 'switching to go1.22.9'
207209
stderr 'using go1.23.0'
208-
env GODEBUG=
209210
env GOTOOLCHAIN=auto
210211

211-
# go install m@v and go run m@v should ignore go.mod and use m@v
212+
# go install m@v and go run m@v should use the go directive from m@v,
213+
# or the go directive in go.mod, whichever is higher.
212214
env TESTGO_VERSION=go1.2.3
213-
go mod edit -go=1.999 -toolchain=go1.998
215+
go mod edit -go=1.1.1 -toolchain=go1.1.1
214216

215217
! go install rsc.io/fortune/[email protected]
216218
stderr '^go: rsc.io/[email protected] requires go >= 1.21rc999; switching to go1.22.9$'
219+
! stderr 'upgrading toolchain'
217220
stderr '^go: rsc.io/fortune/[email protected]: module rsc.io/[email protected] found, but does not contain package rsc.io/fortune/nonexist'
218221

219222
! go run rsc.io/fortune/[email protected]
220223
stderr '^go: rsc.io/[email protected] requires go >= 1.21rc999; switching to go1.22.9$'
224+
! stderr 'upgrading toolchain'
225+
stderr '^go: rsc.io/fortune/[email protected]: module rsc.io/[email protected] found, but does not contain package rsc.io/fortune/nonexist'
226+
227+
go mod edit -go=1.23rc1 -toolchain=go1.1.1
228+
229+
! go install rsc.io/fortune/[email protected]
230+
stderr '^go: upgrading toolchain to go1.23rc1 \(required by go line in go.mod; upgrade allowed by GOTOOLCHAIN=auto\)'
231+
! stderr 'switching to'
221232
stderr '^go: rsc.io/fortune/[email protected]: module rsc.io/[email protected] found, but does not contain package rsc.io/fortune/nonexist'
222233

234+
! go run rsc.io/fortune/[email protected]
235+
stderr '^go: upgrading toolchain to go1.23rc1 \(required by go line in go.mod; upgrade allowed by GOTOOLCHAIN=auto\)'
236+
! stderr 'switching to'
237+
stderr '^go: rsc.io/fortune/[email protected]: module rsc.io/[email protected] found, but does not contain package rsc.io/fortune/nonexist'
238+
239+
go mod edit -go=1.23rc1 -toolchain=go1.998
240+
241+
! go install rsc.io/fortune/[email protected]
242+
stderr '^go: upgrading toolchain to go1.998 \(required by toolchain line in go.mod; upgrade allowed by GOTOOLCHAIN=auto\)'
243+
! stderr 'switching to'
244+
stderr '^go: rsc.io/fortune/[email protected]: module rsc.io/[email protected] found, but does not contain package rsc.io/fortune/nonexist'
245+
246+
! go run rsc.io/fortune/[email protected]
247+
stderr '^go: upgrading toolchain to go1.998 \(required by toolchain line in go.mod; upgrade allowed by GOTOOLCHAIN=auto\)'
248+
! stderr 'switching to'
249+
stderr '^go: rsc.io/fortune/[email protected]: module rsc.io/[email protected] found, but does not contain package rsc.io/fortune/nonexist'
250+
251+
go mod edit -go=1.1.1 -toolchain=go1.1.1
252+
223253
# go install should handle unknown flags to find m@v
224254
! go install -unknownflag rsc.io/fortune/[email protected]
225255
stderr '^go: rsc.io/[email protected] requires go >= 1.21rc999; switching to go1.22.9$'
@@ -229,6 +259,8 @@ stderr '^flag provided but not defined: -unknownflag'
229259
stderr '^go: rsc.io/[email protected] requires go >= 1.21rc999; switching to go1.22.9$'
230260
stderr '^flag provided but not defined: -unknownflag'
231261

262+
env GODEBUG=
263+
232264
# go run cannot handle unknown boolean flags
233265
! go run -unknownflag rsc.io/fortune/[email protected]
234266
! stderr switching

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ stderr 'running go1.50.0 from PATH'
5959

6060
# NewerToolchain should find Go 1.50.0.
6161
env GOTOOLCHAIN=local
62-
go mod edit -toolchain=none -go=1.22
63-
grep 'go 1.22$' go.mod
62+
go mod edit -toolchain=none -go=1.21
63+
grep 'go 1.21$' go.mod
6464
! grep toolchain go.mod
6565
env GOTOOLCHAIN=path
6666
! go run rsc.io/[email protected]

0 commit comments

Comments
 (0)