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