gotip: explicitly set GOTOOLCHAIN=auto Address issue 64665 by setting GOTOOLCHAIN=auto if GOTOOLCHAIN env var is not explicitly configured when invoking the real go binary from the gotip wrapper. This ensures that user's global GOTOOLCHAIN setting (set by `go env -w`) doesn't override gotip behavior. Other version wrappers' behavior is left unchanged. Fixes golang/go#64665 Change-Id: I076d34e88de8d149542085c494d4c1c31b7f379e Reviewed-on: https://go-review.googlesource.com/c/dl/+/763260 Reviewed-by: Michael Matloob <matloob@golang.org> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org> Reviewed-by: Michael Matloob <matloob@google.com>
diff --git a/gotip/main.go b/gotip/main.go index 2b98428..f7e593e 100644 --- a/gotip/main.go +++ b/gotip/main.go
@@ -14,6 +14,10 @@ // To update, run "gotip download" again. This will always download the main branch. // To download an alternative branch, run "gotip download BRANCH". // To download a specific CL, run "gotip download NUMBER". +// +// By default, gotip force sets GOTOOLCHAIN=auto to avoid the GOTOOLCHAIN value +// from go env -w interfere. Users can override this behavior by setting +// GOTOOLCHAIN in their environment var setting. package main import (
diff --git a/internal/version/gotip.go b/internal/version/gotip.go index 76ce7bb..764ddbe 100644 --- a/internal/version/gotip.go +++ b/internal/version/gotip.go
@@ -16,6 +16,8 @@ ) // RunTip runs the "go" tool from the development tree. +// It force sets GOTOOLCHAIN=auto to avoid the GOTOOLCHAIN value from go env -w interfere. +// Users can override this behavior by setting GOTOOLCHAIN in their environment var setting. func RunTip() { log.SetFlags(0) @@ -46,7 +48,11 @@ log.Fatalf("gotip: not downloaded. Run 'gotip download' to install to %v", root) } - runGo(root) + gotoolchain := "" + if _, ok := os.LookupEnv("GOTOOLCHAIN"); !ok { + gotoolchain = "auto" + } + runGo(root, gotoolchain) } func installTip(root, target string) error {
diff --git a/internal/version/version.go b/internal/version/version.go index 783a2c2..1876bfe 100644 --- a/internal/version/version.go +++ b/internal/version/version.go
@@ -51,20 +51,16 @@ log.Fatalf("%s: not downloaded. Run '%s download' to install to %v", version, version, root) } - runGo(root) + runGo(root, "") } -func runGo(root string) { +func runGo(root, gotoolchain string) { gobin := filepath.Join(root, "bin", "go"+exe()) cmd := exec.Command(gobin, os.Args[1:]...) cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr - newPath := filepath.Join(root, "bin") - if p := os.Getenv("PATH"); p != "" { - newPath += string(filepath.ListSeparator) + p - } - cmd.Env = dedupEnv(caseInsensitiveEnv, append(os.Environ(), "GOROOT="+root, "PATH="+newPath)) + cmd.Env = computeEnv(root, gotoolchain, os.Environ()) handleSignals() @@ -77,6 +73,18 @@ os.Exit(0) } +func computeEnv(root, gotoolchain string, baseEnv []string) []string { + newPath := filepath.Join(root, "bin") + if p := os.Getenv("PATH"); p != "" { + newPath += string(filepath.ListSeparator) + p + } + env := append(baseEnv, "GOROOT="+root, "PATH="+newPath) + if gotoolchain != "" { + env = append(env, "GOTOOLCHAIN="+gotoolchain) + } + return dedupEnv(caseInsensitiveEnv, env) +} + func fmtSize(size int64) string { const ( byte_unit = 1 << (10 * iota)
diff --git a/internal/version/version_test.go b/internal/version/version_test.go index 52545ca..e8f3b86 100644 --- a/internal/version/version_test.go +++ b/internal/version/version_test.go
@@ -65,3 +65,57 @@ total *= 1024 } } + +func TestComputeEnv(t *testing.T) { + tests := []struct { + name string + baseEnv []string + gotoolchain string + wantContain string + wantAbsent string + }{ + { + name: "not set, should use default", + baseEnv: []string{}, + gotoolchain: "auto", + wantContain: "GOTOOLCHAIN=auto", + }, + { + name: "already set, should override", + baseEnv: []string{"GOTOOLCHAIN=user-value"}, + gotoolchain: "auto", + wantContain: "GOTOOLCHAIN=auto", + wantAbsent: "GOTOOLCHAIN=user-value", + }, + { + name: "gotoolchain empty, should not add", + baseEnv: []string{}, + gotoolchain: "", + wantAbsent: "GOTOOLCHAIN=", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + env := computeEnv("/tmp/goroot", tt.gotoolchain, tt.baseEnv) + + foundContain := false + foundAbsent := false + for _, e := range env { + if tt.wantContain != "" && e == tt.wantContain { + foundContain = true + } + if tt.wantAbsent != "" && e == tt.wantAbsent { + foundAbsent = true + } + } + + if tt.wantContain != "" && !foundContain { + t.Errorf("expected env to contain %q, but it didn't. Env: %v", tt.wantContain, env) + } + if tt.wantAbsent != "" && foundAbsent { + t.Errorf("expected env to NOT contain %q, but it did. Env: %v", tt.wantAbsent, env) + } + }) + } +}