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