kythe.io@v0.0.68-0.20240422202219-7225dbc01741/kythe/go/platform/tools/kzip/createcmd/flag.go (about) 1 /* 2 * Copyright 2019 The Kythe Authors. All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package createcmd 18 19 import ( 20 "encoding/json" 21 "errors" 22 "fmt" 23 "io/ioutil" 24 "sort" 25 "strings" 26 27 "kythe.io/kythe/go/util/kytheuri" 28 "kythe.io/kythe/go/util/vnameutil" 29 30 "google.golang.org/protobuf/encoding/protojson" 31 32 anypb "github.com/golang/protobuf/ptypes/any" 33 apb "kythe.io/kythe/proto/analysis_go_proto" 34 ) 35 36 type repeatedString []string 37 38 // Set implements part of the flag.Getter interface and will append a new value to the flag. 39 func (f *repeatedString) Set(s string) error { 40 *f = append(*f, s) 41 return nil 42 } 43 44 // String implements part of the flag.Getter interface and returns a string-ish value for the flag. 45 func (f *repeatedString) String() string { 46 if f == nil { 47 return "" 48 } 49 return strings.Join(*f, ",") 50 } 51 52 // Get implements flag.Getter and returns a slice of string values. 53 func (f *repeatedString) Get() any { 54 if f == nil { 55 return []string(nil) 56 } 57 return *f 58 } 59 60 type repeatedEnv map[string]string 61 62 // Set implements part of the flag.Getter interface and will append a new value to the flag. 63 func (f *repeatedEnv) Set(s string) error { 64 parts := strings.SplitN(s, "=", 2) 65 if len(parts) != 2 { 66 return fmt.Errorf("invalid environment entry: %v", s) 67 } 68 if *f == nil { 69 *f = make(map[string]string) 70 } 71 (*f)[parts[0]] = parts[1] 72 return nil 73 } 74 75 // String implements part of the flag.Getter interface and returns a string-ish value for the flag. 76 func (f *repeatedEnv) String() string { 77 if f == nil || *f == nil { 78 return "" 79 } 80 var values []string 81 for key, value := range *f { 82 values = append(values, key+"="+value) 83 } 84 return strings.Join(values, "\n") 85 } 86 87 // Get implements flag.Getter and returns a slice of string values. 88 func (f *repeatedEnv) Get() any { 89 if f == nil { 90 return map[string]string(nil) 91 } 92 return *f 93 } 94 95 // ToProto returns a []*apb.CompilationUnit_Env for the mapped environment. 96 func (f *repeatedEnv) ToProto() []*apb.CompilationUnit_Env { 97 if f == nil || *f == nil { 98 return nil 99 } 100 var result []*apb.CompilationUnit_Env 101 for key, value := range *f { 102 result = append(result, &apb.CompilationUnit_Env{ 103 Name: key, 104 Value: value, 105 }) 106 } 107 sort.Slice(result, func(i, j int) bool { return result[i].Name < result[j].Name }) 108 return result 109 } 110 111 type kytheURI kytheuri.URI 112 113 // Set implements part of the flag.Value interface and will append a new value to the flag. 114 func (f *kytheURI) Set(s string) error { 115 uri, err := kytheuri.Parse(s) 116 switch { 117 case err != nil: 118 return err 119 case uri.Corpus == "": 120 return errors.New("missing required URI field: corpus") 121 case uri.Language == "": 122 return errors.New("missing required URI field: language") 123 124 } 125 *f = *(*kytheURI)(uri) 126 return err 127 } 128 129 // String implements part of the flag.Value interface and returns a string-ish value for the flag. 130 func (f *kytheURI) String() string { 131 return (*kytheuri.URI)(f).String() 132 } 133 134 // Get implements part of the flag.Getter interface. 135 func (f *kytheURI) Get() any { 136 return f 137 } 138 139 // repeatedAny is a repeated flag of JSON-encoded Any messages. 140 type repeatedAny []*anypb.Any 141 142 // Set implements part of the flag.Getter interface and will append a new value to the flag. 143 func (f *repeatedAny) Set(s string) error { 144 dec := json.NewDecoder(strings.NewReader(s)) 145 for dec.More() { 146 var raw json.RawMessage 147 if err := dec.Decode(&raw); err != nil { 148 return err 149 } 150 var detail anypb.Any 151 if err := protojson.Unmarshal(raw, &detail); err != nil { 152 return err 153 } 154 *f = append(*f, &detail) 155 } 156 return nil 157 } 158 159 var toJSON = &protojson.MarshalOptions{UseProtoNames: true} 160 161 // String implements part of the flag.Getter interface and returns a string-ish value for the flag. 162 func (f *repeatedAny) String() string { 163 if f == nil { 164 return "" 165 } 166 var result []string 167 for _, val := range *f { 168 rec, err := toJSON.Marshal(val) 169 if err != nil { 170 panic(err) 171 } 172 result = append(result, string(rec)) 173 } 174 return strings.Join(result, " ") 175 } 176 177 // Get implements flag.Getter and returns a slice of string values. 178 func (f *repeatedAny) Get() any { 179 if f == nil { 180 return []*anypb.Any(nil) 181 } 182 return *f 183 } 184 185 // vnameRules is a path-valued flag used for loading VName mapping rules from a vnames.json file. 186 type vnameRules struct { 187 filename string 188 vnameutil.Rules 189 } 190 191 // Set implements part of the flag.Value interface and will append a new value to the flag. 192 func (f *vnameRules) Set(s string) error { 193 f.filename = s 194 data, err := ioutil.ReadFile(f.filename) 195 if err != nil { 196 return fmt.Errorf("reading vname rules: %v", err) 197 } 198 f.Rules, err = vnameutil.ParseRules(data) 199 if err != nil { 200 return fmt.Errorf("reading vname rules: %v", err) 201 } 202 return nil 203 } 204 205 // String implements part of the flag.Value interface and returns a string-ish value for the flag. 206 func (f *vnameRules) String() string { 207 return f.filename 208 } 209 210 // Get implements part of the flag.Getter interface. 211 func (f *vnameRules) Get() any { 212 return f 213 }