github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/go/not-internal/base/goflags.go (about) 1 // Copyright 2018 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package base 6 7 import ( 8 "flag" 9 "fmt" 10 "runtime" 11 "strings" 12 13 "github.com/gagliardetto/golang-go/cmd/go/not-internal/cfg" 14 ) 15 16 var ( 17 goflags []string // cached $GOFLAGS list; can be -x or --x form 18 knownFlag = make(map[string]bool) // flags allowed to appear in $GOFLAGS; no leading dashes 19 ) 20 21 // AddKnownFlag adds name to the list of known flags for use in $GOFLAGS. 22 func AddKnownFlag(name string) { 23 knownFlag[name] = true 24 } 25 26 // GOFLAGS returns the flags from $GOFLAGS. 27 // The list can be assumed to contain one string per flag, 28 // with each string either beginning with -name or --name. 29 func GOFLAGS() []string { 30 InitGOFLAGS() 31 return goflags 32 } 33 34 // InitGOFLAGS initializes the goflags list from $GOFLAGS. 35 // If goflags is already initialized, it does nothing. 36 func InitGOFLAGS() { 37 if goflags != nil { // already initialized 38 return 39 } 40 41 // Build list of all flags for all commands. 42 // If no command has that flag, then we report the problem. 43 // This catches typos while still letting users record flags in GOFLAGS 44 // that only apply to a subset of go commands. 45 // Commands using CustomFlags can report their flag names 46 // by calling AddKnownFlag instead. 47 var walkFlags func(*Command) 48 walkFlags = func(cmd *Command) { 49 for _, sub := range cmd.Commands { 50 walkFlags(sub) 51 } 52 cmd.Flag.VisitAll(func(f *flag.Flag) { 53 knownFlag[f.Name] = true 54 }) 55 } 56 walkFlags(Go) 57 58 // Ignore bad flag in go env and go bug, because 59 // they are what people reach for when debugging 60 // a problem, and maybe they're debugging GOFLAGS. 61 // (Both will show the GOFLAGS setting if let succeed.) 62 hideErrors := cfg.CmdName == "env" || cfg.CmdName == "bug" 63 64 goflags = strings.Fields(cfg.Getenv("GOFLAGS")) 65 if goflags == nil { 66 goflags = []string{} // avoid work on later InitGOFLAGS call 67 } 68 69 // Each of the words returned by strings.Fields must be its own flag. 70 // To set flag arguments use -x=value instead of -x value. 71 // For boolean flags, -x is fine instead of -x=true. 72 for _, f := range goflags { 73 // Check that every flag looks like -x --x -x=value or --x=value. 74 if !strings.HasPrefix(f, "-") || f == "-" || f == "--" || strings.HasPrefix(f, "---") || strings.HasPrefix(f, "-=") || strings.HasPrefix(f, "--=") { 75 if hideErrors { 76 continue 77 } 78 Fatalf("go: parsing $GOFLAGS: non-flag %q", f) 79 } 80 81 name := f[1:] 82 if name[0] == '-' { 83 name = name[1:] 84 } 85 if i := strings.Index(name, "="); i >= 0 { 86 name = name[:i] 87 } 88 if !knownFlag[name] { 89 if hideErrors { 90 continue 91 } 92 Fatalf("go: parsing $GOFLAGS: unknown flag -%s", name) 93 } 94 } 95 } 96 97 // boolFlag is the optional interface for flag.Value known to the flag package. 98 // (It is not clear why package flag does not export this interface.) 99 type boolFlag interface { 100 flag.Value 101 IsBoolFlag() bool 102 } 103 104 // SetFromGOFLAGS sets the flags in the given flag set using settings in $GOFLAGS. 105 func SetFromGOFLAGS(flags flag.FlagSet) { 106 InitGOFLAGS() 107 108 // This loop is similar to flag.Parse except that it ignores 109 // unknown flags found in goflags, so that setting, say, GOFLAGS=-ldflags=-w 110 // does not break commands that don't have a -ldflags. 111 // It also adjusts the output to be clear that the reported problem is from $GOFLAGS. 112 where := "$GOFLAGS" 113 if runtime.GOOS == "windows" { 114 where = "%GOFLAGS%" 115 } 116 for _, goflag := range goflags { 117 name, value, hasValue := goflag, "", false 118 if i := strings.Index(goflag, "="); i >= 0 { 119 name, value, hasValue = goflag[:i], goflag[i+1:], true 120 } 121 if strings.HasPrefix(name, "--") { 122 name = name[1:] 123 } 124 f := flags.Lookup(name[1:]) 125 if f == nil { 126 continue 127 } 128 if fb, ok := f.Value.(boolFlag); ok && fb.IsBoolFlag() { 129 if hasValue { 130 if err := fb.Set(value); err != nil { 131 fmt.Fprintf(flags.Output(), "go: invalid boolean value %q for flag %s (from %s): %v\n", value, name, where, err) 132 flags.Usage() 133 } 134 } else { 135 if err := fb.Set("true"); err != nil { 136 fmt.Fprintf(flags.Output(), "go: invalid boolean flag %s (from %s): %v\n", name, where, err) 137 flags.Usage() 138 } 139 } 140 } else { 141 if !hasValue { 142 fmt.Fprintf(flags.Output(), "go: flag needs an argument: %s (from %s)\n", name, where) 143 flags.Usage() 144 } 145 if err := f.Value.Set(value); err != nil { 146 fmt.Fprintf(flags.Output(), "go: invalid value %q for flag %s (from %s): %v\n", value, name, where, err) 147 flags.Usage() 148 } 149 } 150 } 151 }