summaryrefslogtreecommitdiff
path: root/libgo/go/cmd/go/internal/base/goflags.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/cmd/go/internal/base/goflags.go')
-rw-r--r--libgo/go/cmd/go/internal/base/goflags.go152
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()
+ }
+ }
+ }
+}