diff options
Diffstat (limited to 'libgo/go/cmd/go/internal/base/goflags.go')
-rw-r--r-- | libgo/go/cmd/go/internal/base/goflags.go | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/libgo/go/cmd/go/internal/base/goflags.go b/libgo/go/cmd/go/internal/base/goflags.go new file mode 100644 index 00000000000..2f50b50bfcf --- /dev/null +++ b/libgo/go/cmd/go/internal/base/goflags.go @@ -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() + } + } + } +} |