gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/tools/nogo/flags/flags.go (about) 1 // Copyright 2019 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package flags contains globally-visible flags. 16 package flags 17 18 import ( 19 "bytes" 20 "encoding/json" 21 "fmt" 22 "os" 23 "os/exec" 24 "runtime" 25 "strings" 26 "sync" 27 28 "gvisor.dev/gvisor/runsc/flag" 29 ) 30 31 var ( 32 // Go location. 33 Go string 34 35 // GOOS defines the GOOS for analysis. 36 GOOS string 37 38 // GOARCH defines the GOARCH for analysis. 39 GOARCH string 40 41 // BuildTags defines the set of build tags for analysis. Note that 42 // while this may also be a StringList, it is kept as an explicit 43 // comma-separated list in order to build the standard flag. 44 BuildTags string 45 46 // ImportMap defines all binary input files. 47 ImportMap = StringMap{} 48 49 // ArchiveMap defines all binary archive files. 50 ArchiveMap = StringMap{} 51 52 // FactMap defines all fact input files. 53 FactMap = StringMap{} 54 55 // Bundles define fact bundles. This is typically used to contain the 56 // inputs for the standard library. 57 Bundles StringList 58 ) 59 60 func init() { 61 flag.StringVar(&Go, "go", "go", "command used to invoke 'go tool'") 62 flag.StringVar(&GOOS, "GOOS", runtime.GOOS, "GOOS for analysis") 63 flag.StringVar(&GOARCH, "GOARCH", runtime.GOARCH, "GOARCH for analysis") 64 flag.StringVar(&BuildTags, "tags", "", "comma-separated build tags") 65 flag.Var(&ImportMap, "import", "map of import paths to binaries") 66 flag.Var(&ArchiveMap, "archive", "map of import paths to archives") 67 flag.Var(&FactMap, "facts", "map of import paths to facts") 68 flag.Var(&Bundles, "bundle", "list of fact bundles") 69 } 70 71 // StringList is a list of strings. 72 type StringList []string 73 74 // String implements fmt.Stringer.String. 75 func (s *StringList) String() string { 76 return strings.Join((*s), ",") 77 } 78 79 // Set implements flag.Value.Set. 80 func (s *StringList) Set(value string) error { 81 (*s) = append((*s), value) 82 return nil 83 } 84 85 // Get implements flag.Value.Get. 86 func (s *StringList) Get() any { 87 return *s 88 } 89 90 // StringMap is a string to string map. 91 type StringMap map[string]string 92 93 // String implements fmt.Stringer.String. 94 func (s *StringMap) String() string { 95 parts := make([]string, 0, len(*s)) 96 for k, v := range *s { 97 parts = append(parts, fmt.Sprintf("%s=%s", k, v)) 98 } 99 return strings.Join(parts, ",") 100 } 101 102 // Get implements flag.Value.Get. 103 func (s *StringMap) Get() any { 104 return *s 105 } 106 107 // Set implements flag.Value.Set. 108 func (s *StringMap) Set(value string) error { 109 if (*s) == nil { 110 (*s) = make(map[string]string) 111 } 112 parts := strings.SplitN(value, "=", 2) 113 if len(parts) != 2 { 114 // We specify the flag as -x=y=z. This string missed the second '='. 115 return fmt.Errorf("invalid format: expected at least one '=' in flag value, got %q", value) 116 } 117 (*s)[parts[0]] = parts[1] 118 return nil 119 } 120 121 var ( 122 envOnce sync.Once 123 envErr error 124 envMap = map[string]string{} 125 ) 126 127 // Env gets a Go environment value. 128 func Env(value string) (string, error) { 129 if v := os.Getenv(value); v != "" { 130 return v, nil 131 } 132 envOnce.Do(func() { 133 // Pull the go environment. 134 cmd := exec.Command(Go, "env", "-json") 135 output, err := cmd.Output() 136 if err != nil { 137 envErr = fmt.Errorf("error executing 'go env -json': %w", err) 138 return 139 } 140 dec := json.NewDecoder(bytes.NewBuffer(output)) 141 if err := dec.Decode(&envMap); err != nil { 142 envErr = fmt.Errorf("error decoding 'go env -json': %w", err) 143 return 144 } 145 }) 146 return envMap[value], envErr // From above. 147 }