-
Notifications
You must be signed in to change notification settings - Fork 17.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
cmd/go: add $GOFLAGS environment variable
People sometimes want to turn on a particular go command flag by default. In Go 1.11 we have at least two different cases where users may need this. 1. Linking can be noticeably slower on underpowered systems due to DWARF, and users may want to set -ldflags=-w by default. 2. For modules, some users or CI systems will want vendoring always, so they want -getmode=vendor (soon to be -mod=vendor) by default. This CL generalizes the problem to “set default flags for the go command.” $GOFLAGS can be a space-separated list of flag settings, but each space-separated entry in the list must be a standalone flag. That is, you must do 'GOFLAGS=-ldflags=-w' not 'GOFLAGS=-ldflags -w'. The latter would mean to pass -w to go commands that understand it (if any do; if not, it's an error to mention it). For #26074. For #26318. Fixes #26585. Change-Id: I428f79c1fbfb9e41e54d199c68746405aed2319c Reviewed-on: https://go-review.googlesource.com/126656 Run-TryBot: Russ Cox <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Rob Pike <[email protected]>
- Loading branch information
Showing
15 changed files
with
259 additions
and
1 deletion.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
// Copyright 2018 The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
package base | ||
|
||
import ( | ||
"flag" | ||
"fmt" | ||
"os" | ||
"runtime" | ||
"strings" | ||
|
||
"cmd/go/internal/cfg" | ||
) | ||
|
||
var ( | ||
goflags []string // cached $GOFLAGS list; can be -x or --x form | ||
knownFlag = make(map[string]bool) // flags allowed to appear in $GOFLAGS; no leading dashes | ||
) | ||
|
||
// AddKnownFlag adds name to the list of known flags for use in $GOFLAGS. | ||
func AddKnownFlag(name string) { | ||
knownFlag[name] = true | ||
} | ||
|
||
// GOFLAGS returns the flags from $GOFLAGS. | ||
// The list can be assumed to contain one string per flag, | ||
// with each string either beginning with -name or --name. | ||
func GOFLAGS() []string { | ||
InitGOFLAGS() | ||
return goflags | ||
} | ||
|
||
// InitGOFLAGS initializes the goflags list from $GOFLAGS. | ||
// If goflags is already initialized, it does nothing. | ||
func InitGOFLAGS() { | ||
if goflags != nil { // already initialized | ||
return | ||
} | ||
|
||
// Build list of all flags for all commands. | ||
// If no command has that flag, then we report the problem. | ||
// This catches typos while still letting users record flags in GOFLAGS | ||
// that only apply to a subset of go commands. | ||
// Commands using CustomFlags can report their flag names | ||
// by calling AddKnownFlag instead. | ||
var walkFlags func(*Command) | ||
walkFlags = func(cmd *Command) { | ||
for _, sub := range cmd.Commands { | ||
walkFlags(sub) | ||
} | ||
cmd.Flag.VisitAll(func(f *flag.Flag) { | ||
knownFlag[f.Name] = true | ||
}) | ||
} | ||
walkFlags(Go) | ||
|
||
// Ignore bad flag in go env and go bug, because | ||
// they are what people reach for when debugging | ||
// a problem, and maybe they're debugging GOFLAGS. | ||
// (Both will show the GOFLAGS setting if let succeed.) | ||
hideErrors := cfg.CmdName == "env" || cfg.CmdName == "bug" | ||
|
||
goflags = strings.Fields(os.Getenv("GOFLAGS")) | ||
if goflags == nil { | ||
goflags = []string{} // avoid work on later InitGOFLAGS call | ||
} | ||
|
||
// Each of the words returned by strings.Fields must be its own flag. | ||
// To set flag arguments use -x=value instead of -x value. | ||
// For boolean flags, -x is fine instead of -x=true. | ||
for _, f := range goflags { | ||
// Check that every flag looks like -x --x -x=value or --x=value. | ||
if !strings.HasPrefix(f, "-") || f == "-" || f == "--" || strings.HasPrefix(f, "---") || strings.HasPrefix(f, "-=") || strings.HasPrefix(f, "--=") { | ||
if hideErrors { | ||
continue | ||
} | ||
Fatalf("go: parsing $GOFLAGS: non-flag %q", f) | ||
} | ||
|
||
name := f[1:] | ||
if name[0] == '-' { | ||
name = name[1:] | ||
} | ||
if i := strings.Index(name, "="); i >= 0 { | ||
name = name[:i] | ||
} | ||
if !knownFlag[name] { | ||
if hideErrors { | ||
continue | ||
} | ||
Fatalf("go: parsing $GOFLAGS: unknown flag -%s", name) | ||
} | ||
} | ||
} | ||
|
||
// boolFlag is the optional interface for flag.Value known to the flag package. | ||
// (It is not clear why package flag does not export this interface.) | ||
type boolFlag interface { | ||
flag.Value | ||
IsBoolFlag() bool | ||
} | ||
|
||
// SetFromGOFLAGS sets the flags in the given flag set using settings in $GOFLAGS. | ||
func SetFromGOFLAGS(flags flag.FlagSet) { | ||
InitGOFLAGS() | ||
|
||
// This loop is similar to flag.Parse except that it ignores | ||
// unknown flags found in goflags, so that setting, say, GOFLAGS=-ldflags=-w | ||
// does not break commands that don't have a -ldflags. | ||
// It also adjusts the output to be clear that the reported problem is from $GOFLAGS. | ||
where := "$GOFLAGS" | ||
if runtime.GOOS == "windows" { | ||
where = "%GOFLAGS%" | ||
} | ||
for _, goflag := range goflags { | ||
name, value, hasValue := goflag, "", false | ||
if i := strings.Index(goflag, "="); i >= 0 { | ||
name, value, hasValue = goflag[:i], goflag[i+1:], true | ||
} | ||
if strings.HasPrefix(name, "--") { | ||
name = name[1:] | ||
} | ||
f := flags.Lookup(name[1:]) | ||
if f == nil { | ||
continue | ||
} | ||
if fb, ok := f.Value.(boolFlag); ok && fb.IsBoolFlag() { | ||
if hasValue { | ||
if err := fb.Set(value); err != nil { | ||
fmt.Fprintf(flags.Output(), "go: invalid boolean value %q for flag %s (from %s): %v\n", value, name, where, err) | ||
flags.Usage() | ||
} | ||
} else { | ||
if err := fb.Set("true"); err != nil { | ||
fmt.Fprintf(flags.Output(), "go: invalid boolean flag %s (from %s): %v\n", name, where, err) | ||
flags.Usage() | ||
} | ||
} | ||
} else { | ||
if !hasValue { | ||
fmt.Fprintf(flags.Output(), "go: flag needs an argument: %s (from %s)\n", name, where) | ||
flags.Usage() | ||
} | ||
if err := f.Value.Set(value); err != nil { | ||
fmt.Fprintf(flags.Output(), "go: invalid value %q for flag %s (from %s): %v\n", value, name, where, err) | ||
flags.Usage() | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
# GOFLAGS sets flags for commands | ||
|
||
env GOFLAGS='-e -f={{.Dir}} --test.benchtime=1s -count=10' | ||
go list asdfasdfasdf # succeeds because of -e | ||
go list runtime | ||
stdout '[\\/]runtime$' | ||
|
||
env GOFLAGS=-race OLDGOARCH=$GOARCH OLDGOOS=$GOOS GOARCH=386 GOOS=linux | ||
! go list runtime | ||
stderr 'race is only supported on' | ||
|
||
env GOARCH=$OLDGOARCH GOOS=$OLDGOOS | ||
|
||
# go env succeeds even though -f={{.Dir}} is inappropriate | ||
go env | ||
|
||
# bad flags are diagnosed | ||
env GOFLAGS=-typoflag | ||
! go list runtime | ||
stderr 'unknown flag -typoflag' | ||
|
||
env GOFLAGS=- | ||
! go list runtime | ||
stderr '^go: parsing \$GOFLAGS: non-flag "-"' | ||
|
||
env GOFLAGS=-- | ||
! go list runtime | ||
stderr '^go: parsing \$GOFLAGS: non-flag "--"' | ||
|
||
env GOFLAGS=---oops | ||
! go list runtime | ||
stderr '^go: parsing \$GOFLAGS: non-flag "---oops"' | ||
|
||
env GOFLAGS=-=noname | ||
! go list runtime | ||
stderr '^go: parsing \$GOFLAGS: non-flag "-=noname"' | ||
|
||
env GOFLAGS=-f | ||
! go list runtime | ||
stderr '^go: flag needs an argument: -f \(from (\$GOFLAGS|%GOFLAGS%)\)$' | ||
|
||
env GOFLAGS=-e=asdf | ||
! go list runtime | ||
stderr '^go: invalid boolean value \"asdf\" for flag -e \(from (\$GOFLAGS|%GOFLAGS%)\)' | ||
|
||
# except in go bug (untested) and go env | ||
go env | ||
stdout GOFLAGS | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters