]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/go: print toolchain switching with GODEBUG=toolchaintrace
authorSam Thanawalla <samthanawalla@google.com>
Tue, 3 Sep 2024 14:51:01 +0000 (14:51 +0000)
committerSam Thanawalla <samthanawalla@google.com>
Wed, 18 Sep 2024 19:48:13 +0000 (19:48 +0000)
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: #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 <matloob@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>

src/cmd/go/internal/toolchain/exec.go
src/cmd/go/internal/toolchain/select.go
src/cmd/go/testdata/script/gotoolchain_godebug_trace.txt [new file with mode: 0644]

index 820fe93e87c377e770b7fe1573de50a74f12dc3d..df385e7b4712e346063cb0bd7319af5a81e2191e 100644 (file)
@@ -8,6 +8,7 @@ package toolchain
 
 import (
        "cmd/go/internal/base"
+       "fmt"
        "internal/godebug"
        "os"
        "os/exec"
@@ -26,6 +27,13 @@ func execGoToolchain(gotoolchain, dir, exe string) {
        } else {
                os.Setenv("GOROOT", dir)
        }
+       if toolchainTrace {
+               if dir == "" {
+                       fmt.Fprintf(os.Stderr, "go: using %s toolchain located in system PATH (%s)\n", gotoolchain, exe)
+               } else {
+                       fmt.Fprintf(os.Stderr, "go: using %s toolchain from cache located at %s\n", gotoolchain, exe)
+               }
+       }
 
        // On Windows, there is no syscall.Exec, so the best we can do
        // is run a subprocess and exit with the same status.
index 8925c6bd51ec8d5294f78b613d4c39aeba1dbb37..cbdd7a2418e1f07b8dae7e89336587ccfcadeaf7 100644 (file)
@@ -6,11 +6,14 @@
 package toolchain
 
 import (
+       "bytes"
        "context"
        "errors"
        "flag"
        "fmt"
        "go/build"
+       "internal/godebug"
+       "io"
        "io/fs"
        "log"
        "os"
@@ -84,6 +87,7 @@ func FilterEnv(env []string) []string {
 }
 
 var counterErrorsInvalidToolchainInFile = counter.New("go/errors:invalid-toolchain-in-file")
+var toolchainTrace = godebug.New("#toolchaintrace").Value() == "1"
 
 // Select invokes a different Go toolchain if directed by
 // the GOTOOLCHAIN environment variable or the user's configuration
@@ -137,6 +141,7 @@ func Select() {
        minToolchain := gover.LocalToolchain()
        minVers := gover.Local()
        var mode string
+       var toolchainTraceBuffer bytes.Buffer
        if gotoolchain == "auto" {
                mode = "auto"
        } else if gotoolchain == "path" {
@@ -158,6 +163,9 @@ func Select() {
                        base.Fatalf("invalid GOTOOLCHAIN %q: only version suffixes are +auto and +path", gotoolchain)
                }
                mode = suffix
+               if toolchainTrace {
+                       fmt.Fprintf(&toolchainTraceBuffer, "go: default toolchain set to %s from GOTOOLCHAIN=%s\n", minToolchain, gotoolchain)
+               }
        }
 
        gotoolchain = minToolchain
@@ -190,6 +198,13 @@ func Select() {
                                        base.Fatalf("invalid toolchain %q in %s", toolchain, base.ShortPath(file))
                                }
                                if gover.Compare(toolVers, minVers) > 0 {
+                                       if toolchainTrace {
+                                               modeFormat := mode
+                                               if strings.Contains(cfg.Getenv("GOTOOLCHAIN"), "+") { // go1.2.3+auto
+                                                       modeFormat = fmt.Sprintf("<name>+%s", mode)
+                                               }
+                                               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)
+                                       }
                                        gotoolchain = toolchain
                                        minVers = toolVers
                                        gover.Startup.AutoToolchain = toolchain
@@ -206,6 +221,13 @@ func Select() {
                                }
                                gover.Startup.AutoGoVersion = goVers
                                gover.Startup.AutoToolchain = "" // in case we are overriding it for being too old
+                               if toolchainTrace {
+                                       modeFormat := mode
+                                       if strings.Contains(cfg.Getenv("GOTOOLCHAIN"), "+") { // go1.2.3+auto
+                                               modeFormat = fmt.Sprintf("<name>+%s", mode)
+                                       }
+                                       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)
+                               }
                        }
                }
        }
@@ -237,8 +259,16 @@ func Select() {
                return
        }
 
+       if toolchainTrace {
+               // Flush toolchain tracing buffer only in the parent process (targetEnv is unset).
+               io.Copy(os.Stderr, &toolchainTraceBuffer)
+       }
+
        if gotoolchain == "local" || gotoolchain == gover.LocalToolchain() {
                // Let the current binary handle the command.
+               if toolchainTrace {
+                       fmt.Fprintf(os.Stderr, "go: using local toolchain %s\n", gover.LocalToolchain())
+               }
                return
        }
 
diff --git a/src/cmd/go/testdata/script/gotoolchain_godebug_trace.txt b/src/cmd/go/testdata/script/gotoolchain_godebug_trace.txt
new file mode 100644 (file)
index 0000000..d98f62d
--- /dev/null
@@ -0,0 +1,122 @@
+# Test the GODEBUG=toolchaintrace behavior
+# See https://go.dev/issue/63939
+env GODEBUG=toolchaintrace=1
+env TESTGO_VERSION=go1.21.0
+env TESTGO_VERSION_SWITCH=switch
+env GOTOOLCHAIN=auto
+
+# Go line is newer than local go version.
+go mod init m
+go mod edit -go=1.21.1
+go version
+stderr -count=1 'go: upgrading toolchain to go1.21.1 \(required by go line in go.mod; upgrade allowed by GOTOOLCHAIN=auto\)'
+stderr -count=1 'go: using go1.21.1 toolchain from cache located at .*'
+stdout 'go version go1.21.1'
+rm go.mod
+
+# Toolchain line is newer than go line.
+go mod init m
+go mod edit -go=1.21.1 -toolchain=go1.21.2
+go version
+stderr -count=1 'go: upgrading toolchain to go1.21.2 \(required by toolchain line in go.mod; upgrade allowed by GOTOOLCHAIN=auto\)'
+stderr -count=1 'go: using go1.21.2 toolchain from cache located at .*'
+stdout 'go version go1.21.2'
+rm go.mod
+
+# Go line is newer than local go version and toolchain line.
+go mod init m
+go mod edit -go=1.22 -toolchain=go1.21.2
+go version
+stderr -count=1 'go: upgrading toolchain to go1.21.2 \(required by toolchain line in go.mod; upgrade allowed by GOTOOLCHAIN=auto\)'
+stderr -count=1 'go: upgrading toolchain to go1.22.0 \(required by go line in go.mod; upgrade allowed by GOTOOLCHAIN=auto\)'
+stderr -count=1 'go: using go1.22.0 toolchain from cache located at .*'
+stdout 'go version go1.22.0'
+rm go.mod
+
+# No switch.
+go mod init m
+go mod edit -go=1.21.0 -toolchain=go1.21.0
+go version
+stderr -count=1 'go: using local toolchain go1.21.0'
+! stderr 'go: upgrading toolchain'
+stdout 'go version go1.21.0'
+rm go.mod
+
+# GOTOOLCHAIN+auto is older than go line and toolchain line.
+go mod init m
+go mod edit -go=1.22 -toolchain=go1.21.2
+env GOTOOLCHAIN=go1.21.0+auto
+go version
+stderr -count=1 'go: default toolchain set to go1.21.0 from GOTOOLCHAIN=go1.21.0\+auto'
+stderr -count=1 'go: upgrading toolchain to go1.21.2 \(required by toolchain line in go.mod; upgrade allowed by GOTOOLCHAIN=<name>\+auto\)'
+stderr -count=1 'go: upgrading toolchain to go1.22.0 \(required by go line in go.mod; upgrade allowed by GOTOOLCHAIN=<name>\+auto\)'
+stderr -count=1 'go: using go1.22.0 toolchain from cache located at .*'
+stdout 'go version go1.22.0'
+rm go.mod
+
+# GOTOOLCHAIN is older than go line and toolchain line.
+go mod init m
+go mod edit -go=1.22 -toolchain=go1.21.2
+env GOTOOLCHAIN=go1.21.1
+go version
+stderr -count=1 'go: default toolchain set to go1.21.1 from GOTOOLCHAIN=go1.21.1'
+stderr -count=1 'go: using go1.21.1 toolchain from cache located at .*'
+! stderr 'go: upgrading toolchain'
+stdout 'go version go1.21.1'
+rm go.mod
+env GOTOOLCHAIN=auto
+
+# GOTOOLCHAIN+auto is newer than go line and toolchain line.
+go mod init m
+go mod edit -go=1.21.1 -toolchain=go1.21.2
+env GOTOOLCHAIN=go1.22.0+auto
+go version
+stderr -count=1 'go: default toolchain set to go1.22.0 from GOTOOLCHAIN=go1.22.0\+auto'
+stderr -count=1 'go: using go1.22.0 toolchain from cache located at .*'
+stdout 'go version go1.22.0'
+rm go.mod
+
+# GOTOOLCHAIN=local
+env GOTOOLCHAIN=local
+go mod init m
+go mod edit -go=1.21.1 -toolchain=go1.21.2
+go version
+stderr -count=1 'go: default toolchain set to go1.21.0 from GOTOOLCHAIN=local'
+stderr -count=1 'go: using local toolchain go1.21.0'
+stdout 'go version go1.21.0'
+rm go.mod
+
+[short] stop 'requires build'
+# If toolchain found in PATH, ensure we print that.
+env GOTOOLCHAIN=auto
+env TESTGO_VERSION_SWITCH=
+mkdir $WORK/bin
+go build -o $WORK/bin/go1.22.0$GOEXE ./fake/fakego.go  # adds .exe extension implicitly on Windows
+[!GOOS:plan9] env PATH=$WORK/bin
+[GOOS:plan9] env path=$WORK/bin
+go mod init m
+go mod edit -go=1.22.0
+! go version
+stderr -count=1 'go: upgrading toolchain to go1.22.0 \(required by go line in go.mod; upgrade allowed by GOTOOLCHAIN=auto\)'
+stderr -count=1 'go: using go1.22.0 toolchain located in system PATH \('$WORK'[/\\]bin[/\\]go1.22.0'$GOEXE'\)'
+stderr 'running go1.22.0 from PATH'
+rm go.mod
+
+
+-- fake/fakego.go --
+package main
+
+import (
+       "fmt"
+       "os"
+       "path/filepath"
+       "strings"
+)
+
+func main() {
+       exe, _ := os.Executable()
+       name := filepath.Base(exe)
+       name = strings.TrimSuffix(name, ".exe")
+       fmt.Fprintf(os.Stderr, "running %s from PATH\n", name)
+       os.Exit(1) // fail in case we are running this accidentally (like in "go mod edit")
+}