Skip to content

Commit

Permalink
cmd/go: add -changed to query for non-defaults in the env
Browse files Browse the repository at this point in the history
Fixes #34208

Change-Id: I8ec2d96262dcd7cbf870f6173690143c54190722
GitHub-Last-Rev: 6543df4
GitHub-Pull-Request: #65655
Reviewed-on: https://go-review.googlesource.com/c/go/+/563137
Reviewed-by: Alan Donovan <[email protected]>
LUCI-TryBot-Result: Go LUCI <[email protected]>
Reviewed-by: Michael Matloob <[email protected]>
  • Loading branch information
qiulaidongfeng authored and matloob committed May 16, 2024
1 parent d367b2a commit 6cd066f
Show file tree
Hide file tree
Showing 16 changed files with 272 additions and 129 deletions.
4 changes: 4 additions & 0 deletions doc/next/3-tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ Distributions that install the `go` command to a location other than
`$GOROOT/bin/go` should install a symlink instead of relocating
or copying the `go` binary.

The new go env `-changed` flag causes the command to print only
those settings whose effective value differs from the default value
that would be obtained in an empty environment with no prior uses of the `-w` flag.

### Vet {#vet}

The `go vet` subcommand now includes the
Expand Down
6 changes: 5 additions & 1 deletion src/cmd/go/alldocs.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/cmd/go/go_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ func TestMain(m *testing.M) {
defer removeAll(testTmpDir)
}

testGOCACHE = cache.DefaultDir()
testGOCACHE, _ = cache.DefaultDir()
if testenv.HasGoBuild() {
testBin = filepath.Join(testTmpDir, "testbin")
if err := os.Mkdir(testBin, 0777); err != nil {
Expand Down
2 changes: 1 addition & 1 deletion src/cmd/go/internal/bug/bug.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ func printGoEnv(w io.Writer) {
env := envcmd.MkEnv()
env = append(env, envcmd.ExtraEnvVars()...)
env = append(env, envcmd.ExtraEnvVarsCostly()...)
envcmd.PrintEnv(w, env)
envcmd.PrintEnv(w, env, false)
}

func printGoDetails(w io.Writer) {
Expand Down
24 changes: 14 additions & 10 deletions src/cmd/go/internal/cache/default.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ See golang.org to learn more about Go.
// initDefaultCache does the work of finding the default cache
// the first time Default is called.
func initDefaultCache() {
dir := DefaultDir()
dir, _ := DefaultDir()
if dir == "off" {
if defaultDirErr != nil {
base.Fatalf("build cache is required, but could not be located: %v", defaultDirErr)
Expand Down Expand Up @@ -67,25 +67,28 @@ func initDefaultCache() {
}

var (
defaultDirOnce sync.Once
defaultDir string
defaultDirErr error
defaultDirOnce sync.Once
defaultDir string
defaultDirChanged bool // effective value differs from $GOCACHE
defaultDirErr error
)

// DefaultDir returns the effective GOCACHE setting.
// It returns "off" if the cache is disabled.
func DefaultDir() string {
// It returns "off" if the cache is disabled,
// and reports whether the effective value differs from GOCACHE.
func DefaultDir() (string, bool) {
// Save the result of the first call to DefaultDir for later use in
// initDefaultCache. cmd/go/main.go explicitly sets GOCACHE so that
// subprocesses will inherit it, but that means initDefaultCache can't
// otherwise distinguish between an explicit "off" and a UserCacheDir error.

defaultDirOnce.Do(func() {
defaultDir = cfg.Getenv("GOCACHE")
if filepath.IsAbs(defaultDir) || defaultDir == "off" {
return
}
if defaultDir != "" {
defaultDirChanged = true
if filepath.IsAbs(defaultDir) || defaultDir == "off" {
return
}
defaultDir = "off"
defaultDirErr = fmt.Errorf("GOCACHE is not an absolute path")
return
Expand All @@ -95,11 +98,12 @@ func DefaultDir() string {
dir, err := os.UserCacheDir()
if err != nil {
defaultDir = "off"
defaultDirChanged = true
defaultDirErr = fmt.Errorf("GOCACHE is not defined and %v", err)
return
}
defaultDir = filepath.Join(dir, "go-build")
})

return defaultDir
return defaultDir, defaultDirChanged
}
122 changes: 72 additions & 50 deletions src/cmd/go/internal/cfg/cfg.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,9 @@ var (

// GoPathError is set when GOPATH is not set. it contains an
// explanation why GOPATH is unset.
GoPathError string
GoPathError string
GOPATHChanged bool
CGOChanged bool
)

func defaultContext() build.Context {
Expand All @@ -111,7 +113,7 @@ func defaultContext() build.Context {

// Override defaults computed in go/build with defaults
// from go environment configuration file, if known.
ctxt.GOPATH = envOr("GOPATH", gopath(ctxt))
ctxt.GOPATH, GOPATHChanged = EnvOrAndChanged("GOPATH", gopath(ctxt))
ctxt.GOOS = Goos
ctxt.GOARCH = Goarch

Expand All @@ -125,14 +127,16 @@ func defaultContext() build.Context {
ctxt.ToolTags = save

// The go/build rule for whether cgo is enabled is:
// 1. If $CGO_ENABLED is set, respect it.
// 2. Otherwise, if this is a cross-compile, disable cgo.
// 3. Otherwise, use built-in default for GOOS/GOARCH.
// 1. If $CGO_ENABLED is set, respect it.
// 2. Otherwise, if this is a cross-compile, disable cgo.
// 3. Otherwise, use built-in default for GOOS/GOARCH.
//
// Recreate that logic here with the new GOOS/GOARCH setting.
if v := Getenv("CGO_ENABLED"); v == "0" || v == "1" {
ctxt.CgoEnabled = v[0] == '1'
} else if ctxt.GOOS != runtime.GOOS || ctxt.GOARCH != runtime.GOARCH {
ctxt.CgoEnabled = false
// We need to run steps 2 and 3 to determine what the default value
// of CgoEnabled would be for computing CGOChanged.
defaultCgoEnabled := ctxt.CgoEnabled
if ctxt.GOOS != runtime.GOOS || ctxt.GOARCH != runtime.GOARCH {
defaultCgoEnabled = false
} else {
// Use built-in default cgo setting for GOOS/GOARCH.
// Note that ctxt.GOOS/GOARCH are derived from the preference list
Expand All @@ -159,11 +163,16 @@ func defaultContext() build.Context {
if os.Getenv("CC") == "" {
cc := DefaultCC(ctxt.GOOS, ctxt.GOARCH)
if _, err := LookPath(cc); err != nil {
ctxt.CgoEnabled = false
defaultCgoEnabled = false
}
}
}
}
ctxt.CgoEnabled = defaultCgoEnabled
if v := Getenv("CGO_ENABLED"); v == "0" || v == "1" {
ctxt.CgoEnabled = v[0] == '1'
}
CGOChanged = ctxt.CgoEnabled != defaultCgoEnabled

ctxt.OpenFile = func(path string) (io.ReadCloser, error) {
return fsys.Open(path)
Expand Down Expand Up @@ -262,8 +271,9 @@ func init() {

// An EnvVar is an environment variable Name=Value.
type EnvVar struct {
Name string
Value string
Name string
Value string
Changed bool // effective Value differs from default
}

// OrigEnv is the original environment of the program at startup.
Expand All @@ -279,27 +289,28 @@ var envCache struct {
m map[string]string
}

// EnvFile returns the name of the Go environment configuration file.
func EnvFile() (string, error) {
// EnvFile returns the name of the Go environment configuration file,
// and reports whether the effective value differs from the default.
func EnvFile() (string, bool, error) {
if file := os.Getenv("GOENV"); file != "" {
if file == "off" {
return "", fmt.Errorf("GOENV=off")
return "", false, fmt.Errorf("GOENV=off")
}
return file, nil
return file, true, nil
}
dir, err := os.UserConfigDir()
if err != nil {
return "", err
return "", false, err
}
if dir == "" {
return "", fmt.Errorf("missing user-config dir")
return "", false, fmt.Errorf("missing user-config dir")
}
return filepath.Join(dir, "go/env"), nil
return filepath.Join(dir, "go/env"), false, nil
}

func initEnvCache() {
envCache.m = make(map[string]string)
if file, _ := EnvFile(); file != "" {
if file, _, _ := EnvFile(); file != "" {
readEnvFile(file, "user")
}
goroot := findGOROOT(envCache.m["GOROOT"])
Expand Down Expand Up @@ -397,57 +408,67 @@ var (
GOROOTpkg string
GOROOTsrc string

GOBIN = Getenv("GOBIN")
GOMODCACHE = envOr("GOMODCACHE", gopathDir("pkg/mod"))
GOBIN = Getenv("GOBIN")
GOMODCACHE, GOMODCACHEChanged = EnvOrAndChanged("GOMODCACHE", gopathDir("pkg/mod"))

// Used in envcmd.MkEnv and build ID computations.
GOARM = envOr("GOARM", fmt.Sprint(buildcfg.GOARM))
GOARM64 = envOr("GOARM64", fmt.Sprint(buildcfg.GOARM64))
GO386 = envOr("GO386", buildcfg.GO386)
GOAMD64 = envOr("GOAMD64", fmt.Sprintf("%s%d", "v", buildcfg.GOAMD64))
GOMIPS = envOr("GOMIPS", buildcfg.GOMIPS)
GOMIPS64 = envOr("GOMIPS64", buildcfg.GOMIPS64)
GOPPC64 = envOr("GOPPC64", fmt.Sprintf("%s%d", "power", buildcfg.GOPPC64))
GORISCV64 = envOr("GORISCV64", fmt.Sprintf("rva%du64", buildcfg.GORISCV64))
GOWASM = envOr("GOWASM", fmt.Sprint(buildcfg.GOWASM))

GOPROXY = envOr("GOPROXY", "")
GOSUMDB = envOr("GOSUMDB", "")
GOPRIVATE = Getenv("GOPRIVATE")
GONOPROXY = envOr("GONOPROXY", GOPRIVATE)
GONOSUMDB = envOr("GONOSUMDB", GOPRIVATE)
GOINSECURE = Getenv("GOINSECURE")
GOVCS = Getenv("GOVCS")
GOARM64, goARM64Changed = EnvOrAndChanged("GOARM64", fmt.Sprint(buildcfg.GOARM64))
GOARM, goARMChanged = EnvOrAndChanged("GOARM", fmt.Sprint(buildcfg.GOARM))
GO386, go386Changed = EnvOrAndChanged("GO386", buildcfg.GO386)
GOAMD64, goAMD64Changed = EnvOrAndChanged("GOAMD64", fmt.Sprintf("%s%d", "v", buildcfg.GOAMD64))
GOMIPS, goMIPSChanged = EnvOrAndChanged("GOMIPS", buildcfg.GOMIPS)
GOMIPS64, goMIPS64Changed = EnvOrAndChanged("GOMIPS64", buildcfg.GOMIPS64)
GOPPC64, goPPC64Changed = EnvOrAndChanged("GOPPC64", fmt.Sprintf("%s%d", "power", buildcfg.GOPPC64))
GORISCV64, goRISCV64Changed = EnvOrAndChanged("GORISCV64", fmt.Sprintf("rva%du64", buildcfg.GORISCV64))
GOWASM, goWASMChanged = EnvOrAndChanged("GOWASM", fmt.Sprint(buildcfg.GOWASM))

GOPROXY, GOPROXYChanged = EnvOrAndChanged("GOPROXY", "")
GOSUMDB, GOSUMDBChanged = EnvOrAndChanged("GOSUMDB", "")
GOPRIVATE = Getenv("GOPRIVATE")
GONOPROXY, GONOPROXYChanged = EnvOrAndChanged("GONOPROXY", GOPRIVATE)
GONOSUMDB, GONOSUMDBChanged = EnvOrAndChanged("GONOSUMDB", GOPRIVATE)
GOINSECURE = Getenv("GOINSECURE")
GOVCS = Getenv("GOVCS")
)

// EnvOrAndChanged returns the environment variable value
// and reports whether it differs from the default value.
func EnvOrAndChanged(name, def string) (string, bool) {
val := Getenv(name)
if val != "" {
return val, val != def
}
return def, false
}

var SumdbDir = gopathDir("pkg/sumdb")

// GetArchEnv returns the name and setting of the
// GOARCH-specific architecture environment variable.
// If the current architecture has no GOARCH-specific variable,
// GetArchEnv returns empty key and value.
func GetArchEnv() (key, val string) {
func GetArchEnv() (key, val string, changed bool) {
switch Goarch {
case "arm":
return "GOARM", GOARM
return "GOARM", GOARM, goARMChanged
case "arm64":
return "GOARM64", GOARM64
return "GOARM64", GOARM64, goARM64Changed
case "386":
return "GO386", GO386
return "GO386", GO386, go386Changed
case "amd64":
return "GOAMD64", GOAMD64
return "GOAMD64", GOAMD64, goAMD64Changed
case "mips", "mipsle":
return "GOMIPS", GOMIPS
return "GOMIPS", GOMIPS, goMIPSChanged
case "mips64", "mips64le":
return "GOMIPS64", GOMIPS64
return "GOMIPS64", GOMIPS64, goMIPS64Changed
case "ppc64", "ppc64le":
return "GOPPC64", GOPPC64
return "GOPPC64", GOPPC64, goPPC64Changed
case "riscv64":
return "GORISCV64", GORISCV64
return "GORISCV64", GORISCV64, goRISCV64Changed
case "wasm":
return "GOWASM", GOWASM
return "GOWASM", GOWASM, goWASMChanged
}
return "", ""
return "", "", false
}

// envOr returns Getenv(key) if set, or else def.
Expand Down Expand Up @@ -565,6 +586,7 @@ func gopathDir(rel string) string {
return filepath.Join(list[0], rel)
}

// Keep consistent with go/build.defaultGOPATH.
func gopath(ctxt build.Context) string {
if len(ctxt.GOPATH) > 0 {
return ctxt.GOPATH
Expand Down
4 changes: 2 additions & 2 deletions src/cmd/go/internal/clean/clean.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ func runClean(ctx context.Context, cmd *base.Command, args []string) {
sh := work.NewShell("", fmt.Print)

if cleanCache {
dir := cache.DefaultDir()
dir, _ := cache.DefaultDir()
if dir != "off" {
// Remove the cache subdirectories but not the top cache directory.
// The top cache directory may have been created with special permissions
Expand All @@ -180,7 +180,7 @@ func runClean(ctx context.Context, cmd *base.Command, args []string) {
// Instead of walking through the entire cache looking for test results,
// we write a file to the cache indicating that all test results from before
// right now are to be ignored.
dir := cache.DefaultDir()
dir, _ := cache.DefaultDir()
if dir != "off" {
f, err := lockedfile.Edit(filepath.Join(dir, "testexpire.txt"))
if err == nil {
Expand Down
Loading

0 comments on commit 6cd066f

Please sign in to comment.