go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/common/flag/stringmapflag/stringmapflag.go (about) 1 // Copyright 2016 The LUCI 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 stringmapflag provides a flag.Value that, when parsed, augments a 16 // map[string]string with the supplied parameter. The parameter is expressed as 17 // a key[=value] option. 18 // 19 // # Example 20 // 21 // Assuming the flag option, "opt", is bound to a stringmapflag.Value, and the 22 // following arguments are parsed: 23 // 24 // -opt foo=bar 25 // -opt baz 26 // 27 // The resulting map would be equivalent to: 28 // map[string]string {"foo": "bar", "baz": ""} 29 package stringmapflag 30 31 import ( 32 "errors" 33 "flag" 34 "fmt" 35 "sort" 36 "strings" 37 ) 38 39 // Value is a flag.Value implementation that stores arbitrary "key[=value]" 40 // command-line flags as a string map. 41 type Value map[string]string 42 43 // Assert that Value conforms to the "flag.Value" interface. 44 var _ = flag.Value(new(Value)) 45 46 func (v *Value) String() string { 47 if len(*v) == 0 { 48 return "" 49 } 50 51 keys := make([]string, 0, len(*v)) 52 for k := range *v { 53 keys = append(keys, k) 54 } 55 sort.Strings(keys) 56 57 for idx, k := range keys { 58 if value := (*v)[k]; value != "" { 59 keys[idx] = fmt.Sprintf("%s=%s", k, value) 60 } 61 } 62 return strings.Join(keys, ",") 63 } 64 65 // Set implements flag.Value. 66 func (v *Value) Set(key string) error { 67 key = strings.TrimSpace(key) 68 if len(key) == 0 { 69 return errors.New("cannot specify an empty k=v pair") 70 } 71 72 value := "" 73 idx := strings.Index(key, "=") 74 switch { 75 case idx == -1: 76 case idx == 0: 77 return errors.New("cannot have a k=v pair with empty key") 78 79 case idx > 0: 80 key, value = key[:idx], key[idx+1:] 81 } 82 83 // Add the entry to our map. 84 if len(*v) > 0 { 85 if _, ok := (*v)[key]; ok { 86 return fmt.Errorf("a value for key '%s' has already been defined", key) 87 } 88 } 89 90 // Record this k=v pair; create a new Value, if necessary. 91 if *v == nil { 92 *v = make(Value) 93 } 94 (*v)[key] = value 95 return nil 96 }