Skip to content

Commit c71b5ff

Browse files
committed
cmd/go: print toolchain switching with GODEBUG=toolchaintrace
This CL introduces the ability to print information about the toolchain switch used in the go command, controlled by the `toolchaintrace` setting. This setting defaults to `toolchaintrace=0`, meaning no information is printed. Setting it to `toolchaintrace=1` will cause the go command to print a message indicating the toolchain used and where it was found. Fixes: golang#63939 Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest,gotip-windows-amd64-longtest Change-Id: Idc58e3d5bc76573aa48e1f7df352caa13004c25e Reviewed-on: https://go-review.googlesource.com/c/go/+/610235 Reviewed-by: Michael Matloob <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent e190638 commit c71b5ff

File tree

3 files changed

+160
-0
lines changed

3 files changed

+160
-0
lines changed

src/cmd/go/internal/toolchain/exec.go

+8
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ package toolchain
88

99
import (
1010
"cmd/go/internal/base"
11+
"fmt"
1112
"internal/godebug"
1213
"os"
1314
"os/exec"
@@ -26,6 +27,13 @@ func execGoToolchain(gotoolchain, dir, exe string) {
2627
} else {
2728
os.Setenv("GOROOT", dir)
2829
}
30+
if toolchainTrace {
31+
if dir == "" {
32+
fmt.Fprintf(os.Stderr, "go: using %s toolchain located in system PATH (%s)\n", gotoolchain, exe)
33+
} else {
34+
fmt.Fprintf(os.Stderr, "go: using %s toolchain from cache located at %s\n", gotoolchain, exe)
35+
}
36+
}
2937

3038
// On Windows, there is no syscall.Exec, so the best we can do
3139
// is run a subprocess and exit with the same status.

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

+30
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,14 @@
66
package toolchain
77

88
import (
9+
"bytes"
910
"context"
1011
"errors"
1112
"flag"
1213
"fmt"
1314
"go/build"
15+
"internal/godebug"
16+
"io"
1417
"io/fs"
1518
"log"
1619
"os"
@@ -84,6 +87,7 @@ func FilterEnv(env []string) []string {
8487
}
8588

8689
var counterErrorsInvalidToolchainInFile = counter.New("go/errors:invalid-toolchain-in-file")
90+
var toolchainTrace = godebug.New("#toolchaintrace").Value() == "1"
8791

8892
// Select invokes a different Go toolchain if directed by
8993
// the GOTOOLCHAIN environment variable or the user's configuration
@@ -137,6 +141,7 @@ func Select() {
137141
minToolchain := gover.LocalToolchain()
138142
minVers := gover.Local()
139143
var mode string
144+
var toolchainTraceBuffer bytes.Buffer
140145
if gotoolchain == "auto" {
141146
mode = "auto"
142147
} else if gotoolchain == "path" {
@@ -158,6 +163,9 @@ func Select() {
158163
base.Fatalf("invalid GOTOOLCHAIN %q: only version suffixes are +auto and +path", gotoolchain)
159164
}
160165
mode = suffix
166+
if toolchainTrace {
167+
fmt.Fprintf(&toolchainTraceBuffer, "go: default toolchain set to %s from GOTOOLCHAIN=%s\n", minToolchain, gotoolchain)
168+
}
161169
}
162170

163171
gotoolchain = minToolchain
@@ -190,6 +198,13 @@ func Select() {
190198
base.Fatalf("invalid toolchain %q in %s", toolchain, base.ShortPath(file))
191199
}
192200
if gover.Compare(toolVers, minVers) > 0 {
201+
if toolchainTrace {
202+
modeFormat := mode
203+
if strings.Contains(cfg.Getenv("GOTOOLCHAIN"), "+") { // go1.2.3+auto
204+
modeFormat = fmt.Sprintf("<name>+%s", mode)
205+
}
206+
fmt.Fprintf(&toolchainTraceBuffer, "go: upgrading toolchain to %s (required by toolchain line in %s; upgrade allowed by GOTOOLCHAIN=%s)\n", toolchain, base.ShortPath(file), modeFormat)
207+
}
193208
gotoolchain = toolchain
194209
minVers = toolVers
195210
gover.Startup.AutoToolchain = toolchain
@@ -206,6 +221,13 @@ func Select() {
206221
}
207222
gover.Startup.AutoGoVersion = goVers
208223
gover.Startup.AutoToolchain = "" // in case we are overriding it for being too old
224+
if toolchainTrace {
225+
modeFormat := mode
226+
if strings.Contains(cfg.Getenv("GOTOOLCHAIN"), "+") { // go1.2.3+auto
227+
modeFormat = fmt.Sprintf("<name>+%s", mode)
228+
}
229+
fmt.Fprintf(&toolchainTraceBuffer, "go: upgrading toolchain to %s (required by go line in %s; upgrade allowed by GOTOOLCHAIN=%s)\n", gotoolchain, base.ShortPath(file), modeFormat)
230+
}
209231
}
210232
}
211233
}
@@ -237,8 +259,16 @@ func Select() {
237259
return
238260
}
239261

262+
if toolchainTrace {
263+
// Flush toolchain tracing buffer only in the parent process (targetEnv is unset).
264+
io.Copy(os.Stderr, &toolchainTraceBuffer)
265+
}
266+
240267
if gotoolchain == "local" || gotoolchain == gover.LocalToolchain() {
241268
// Let the current binary handle the command.
269+
if toolchainTrace {
270+
fmt.Fprintf(os.Stderr, "go: using local toolchain %s\n", gover.LocalToolchain())
271+
}
242272
return
243273
}
244274

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
# Test the GODEBUG=toolchaintrace behavior
2+
# See https://go.dev/issue/63939
3+
env GODEBUG=toolchaintrace=1
4+
env TESTGO_VERSION=go1.21.0
5+
env TESTGO_VERSION_SWITCH=switch
6+
env GOTOOLCHAIN=auto
7+
8+
# Go line is newer than local go version.
9+
go mod init m
10+
go mod edit -go=1.21.1
11+
go version
12+
stderr -count=1 'go: upgrading toolchain to go1.21.1 \(required by go line in go.mod; upgrade allowed by GOTOOLCHAIN=auto\)'
13+
stderr -count=1 'go: using go1.21.1 toolchain from cache located at .*'
14+
stdout 'go version go1.21.1'
15+
rm go.mod
16+
17+
# Toolchain line is newer than go line.
18+
go mod init m
19+
go mod edit -go=1.21.1 -toolchain=go1.21.2
20+
go version
21+
stderr -count=1 'go: upgrading toolchain to go1.21.2 \(required by toolchain line in go.mod; upgrade allowed by GOTOOLCHAIN=auto\)'
22+
stderr -count=1 'go: using go1.21.2 toolchain from cache located at .*'
23+
stdout 'go version go1.21.2'
24+
rm go.mod
25+
26+
# Go line is newer than local go version and toolchain line.
27+
go mod init m
28+
go mod edit -go=1.22 -toolchain=go1.21.2
29+
go version
30+
stderr -count=1 'go: upgrading toolchain to go1.21.2 \(required by toolchain line in go.mod; upgrade allowed by GOTOOLCHAIN=auto\)'
31+
stderr -count=1 'go: upgrading toolchain to go1.22.0 \(required by go line in go.mod; upgrade allowed by GOTOOLCHAIN=auto\)'
32+
stderr -count=1 'go: using go1.22.0 toolchain from cache located at .*'
33+
stdout 'go version go1.22.0'
34+
rm go.mod
35+
36+
# No switch.
37+
go mod init m
38+
go mod edit -go=1.21.0 -toolchain=go1.21.0
39+
go version
40+
stderr -count=1 'go: using local toolchain go1.21.0'
41+
! stderr 'go: upgrading toolchain'
42+
stdout 'go version go1.21.0'
43+
rm go.mod
44+
45+
# GOTOOLCHAIN+auto is older than go line and toolchain line.
46+
go mod init m
47+
go mod edit -go=1.22 -toolchain=go1.21.2
48+
env GOTOOLCHAIN=go1.21.0+auto
49+
go version
50+
stderr -count=1 'go: default toolchain set to go1.21.0 from GOTOOLCHAIN=go1.21.0\+auto'
51+
stderr -count=1 'go: upgrading toolchain to go1.21.2 \(required by toolchain line in go.mod; upgrade allowed by GOTOOLCHAIN=<name>\+auto\)'
52+
stderr -count=1 'go: upgrading toolchain to go1.22.0 \(required by go line in go.mod; upgrade allowed by GOTOOLCHAIN=<name>\+auto\)'
53+
stderr -count=1 'go: using go1.22.0 toolchain from cache located at .*'
54+
stdout 'go version go1.22.0'
55+
rm go.mod
56+
57+
# GOTOOLCHAIN is older than go line and toolchain line.
58+
go mod init m
59+
go mod edit -go=1.22 -toolchain=go1.21.2
60+
env GOTOOLCHAIN=go1.21.1
61+
go version
62+
stderr -count=1 'go: default toolchain set to go1.21.1 from GOTOOLCHAIN=go1.21.1'
63+
stderr -count=1 'go: using go1.21.1 toolchain from cache located at .*'
64+
! stderr 'go: upgrading toolchain'
65+
stdout 'go version go1.21.1'
66+
rm go.mod
67+
env GOTOOLCHAIN=auto
68+
69+
# GOTOOLCHAIN+auto is newer than go line and toolchain line.
70+
go mod init m
71+
go mod edit -go=1.21.1 -toolchain=go1.21.2
72+
env GOTOOLCHAIN=go1.22.0+auto
73+
go version
74+
stderr -count=1 'go: default toolchain set to go1.22.0 from GOTOOLCHAIN=go1.22.0\+auto'
75+
stderr -count=1 'go: using go1.22.0 toolchain from cache located at .*'
76+
stdout 'go version go1.22.0'
77+
rm go.mod
78+
79+
# GOTOOLCHAIN=local
80+
env GOTOOLCHAIN=local
81+
go mod init m
82+
go mod edit -go=1.21.1 -toolchain=go1.21.2
83+
go version
84+
stderr -count=1 'go: default toolchain set to go1.21.0 from GOTOOLCHAIN=local'
85+
stderr -count=1 'go: using local toolchain go1.21.0'
86+
stdout 'go version go1.21.0'
87+
rm go.mod
88+
89+
[short] stop 'requires build'
90+
# If toolchain found in PATH, ensure we print that.
91+
env GOTOOLCHAIN=auto
92+
env TESTGO_VERSION_SWITCH=
93+
mkdir $WORK/bin
94+
go build -o $WORK/bin/go1.22.0$GOEXE ./fake/fakego.go # adds .exe extension implicitly on Windows
95+
[!GOOS:plan9] env PATH=$WORK/bin
96+
[GOOS:plan9] env path=$WORK/bin
97+
go mod init m
98+
go mod edit -go=1.22.0
99+
! go version
100+
stderr -count=1 'go: upgrading toolchain to go1.22.0 \(required by go line in go.mod; upgrade allowed by GOTOOLCHAIN=auto\)'
101+
stderr -count=1 'go: using go1.22.0 toolchain located in system PATH \('$WORK'[/\\]bin[/\\]go1.22.0'$GOEXE'\)'
102+
stderr 'running go1.22.0 from PATH'
103+
rm go.mod
104+
105+
106+
-- fake/fakego.go --
107+
package main
108+
109+
import (
110+
"fmt"
111+
"os"
112+
"path/filepath"
113+
"strings"
114+
)
115+
116+
func main() {
117+
exe, _ := os.Executable()
118+
name := filepath.Base(exe)
119+
name = strings.TrimSuffix(name, ".exe")
120+
fmt.Fprintf(os.Stderr, "running %s from PATH\n", name)
121+
os.Exit(1) // fail in case we are running this accidentally (like in "go mod edit")
122+
}

0 commit comments

Comments
 (0)