kythe.io@v0.0.68-0.20240422202219-7225dbc01741/kythe/go/util/flagutil/flagutil.go (about) 1 /* 2 * Copyright 2015 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 flagutil is a collection of helper functions for Kythe binaries using 18 // the flag package. 19 package flagutil // import "kythe.io/kythe/go/util/flagutil" 20 21 import ( 22 "flag" 23 "fmt" 24 "os" 25 "path/filepath" 26 "sort" 27 "strconv" 28 "strings" 29 30 "kythe.io/kythe/go/util/build" 31 32 "bitbucket.org/creachadair/stringset" 33 ) 34 35 // SimpleUsage returns a basic flag.Usage function that prints the given 36 // description and list of arguments in the following format: 37 // 38 // Usage: binary <arg0> <arg1> ... <argN> 39 // <description> 40 // 41 // <build.VersionLine()> 42 // 43 // Flags: 44 // <flag.PrintDefaults()> 45 func SimpleUsage(description string, args ...string) func() { 46 return func() { 47 prefix := fmt.Sprintf("Usage: %s ", filepath.Base(os.Args[0])) 48 alignArgs(len(prefix), args) 49 fmt.Fprintf(os.Stderr, `%s%s 50 %s 51 52 %s 53 54 Flags: 55 `, prefix, strings.Join(args, " "), description, build.VersionLine()) 56 flag.PrintDefaults() 57 } 58 } 59 60 func alignArgs(col int, args []string) { 61 s := strings.Repeat(" ", col) 62 for i, arg := range args { 63 args[i] = strings.Replace(arg, "\n", "\n"+s, -1) 64 } 65 } 66 67 // UsageError prints msg to stderr, calls flag.Usage, and exits the program 68 // unsuccessfully. 69 func UsageError(msg string) { 70 fmt.Fprintln(os.Stderr, "ERROR: "+msg) 71 flag.Usage() 72 os.Exit(1) 73 } 74 75 // UsageErrorf prints str formatted with the given vals to stderr, calls 76 // flag.Usage, and exits the program unsuccessfully. 77 func UsageErrorf(str string, vals ...any) { 78 UsageError(fmt.Sprintf(str, vals...)) 79 } 80 81 // StringList implements a flag.Value that accepts an sequence of values as a CSV. 82 type StringList []string 83 84 // Set implements part of the flag.Getter interface and will append new values to the flag. 85 func (f *StringList) Set(s string) error { 86 *f = append(*f, strings.Split(s, ",")...) 87 return nil 88 } 89 90 // String implements part of the flag.Getter interface and returns a string-ish value for the flag. 91 func (f *StringList) String() string { 92 if f == nil { 93 return "" 94 } 95 return strings.Join(*f, ",") 96 } 97 98 // Get implements flag.Getter and returns a slice of string values. 99 func (f *StringList) Get() any { 100 if f == nil { 101 return []string(nil) 102 } 103 return *f 104 } 105 106 // StringSet implements a flag.Value that accepts an set of values as a CSV. 107 type StringSet stringset.Set 108 109 // Set implements part of the flag.Getter interface and will append new values to the flag. 110 func (f *StringSet) Set(s string) error { 111 (*stringset.Set)(f).Add(strings.Split(s, ",")...) 112 return nil 113 } 114 115 // Update adds the values from other to the contained stringset. 116 func (f *StringSet) Update(o StringSet) bool { 117 return (*stringset.Set)(f).Update(stringset.Set(o)) 118 } 119 120 // Elements returns the set of elements as a sorted slice. 121 func (f *StringSet) Elements() []string { 122 return (*stringset.Set)(f).Elements() 123 } 124 125 // Len returns the number of elements. 126 func (f *StringSet) Len() int { 127 return (*stringset.Set)(f).Len() 128 } 129 130 // String implements part of the flag.Getter interface and returns a string-ish value for the flag. 131 func (f *StringSet) String() string { 132 if f == nil { 133 return "" 134 } 135 return strings.Join(f.Elements(), ",") 136 } 137 138 // Get implements flag.Getter and returns a slice of string values. 139 func (f *StringSet) Get() any { 140 if f == nil { 141 return stringset.Set(nil) 142 } 143 return *f 144 } 145 146 // StringMultimap implements a flag.Value that accepts an set of key-value entries as a CSV. 147 type StringMultimap map[string]stringset.Set 148 149 // Set implements part of the flag.Getter interface and will append new values to the flag. 150 func (f *StringMultimap) Set(s string) error { 151 if *f == nil { 152 *f = make(map[string]stringset.Set) 153 } 154 m := *f 155 for _, e := range strings.Split(s, ",") { 156 pair := strings.SplitN(e, "=", 2) 157 if len(pair) != 2 { 158 return fmt.Errorf("invalid key-value entry: %q", e) 159 } 160 key, val := pair[0], pair[1] 161 set := m[key] 162 if set == nil { 163 set = stringset.New() 164 m[key] = set 165 } 166 set.Add(val) 167 } 168 return nil 169 } 170 171 // String implements part of the flag.Getter interface and returns a string-ish value for the flag. 172 func (f *StringMultimap) String() string { 173 if f == nil || *f == nil { 174 return "{}" 175 } 176 entries := make([]string, 0, len(*f)) 177 for k, vs := range *f { 178 for _, v := range vs.Elements() { 179 entries = append(entries, fmt.Sprintf("%s=%s", k, v)) 180 } 181 } 182 sort.Strings(entries) 183 return strings.Join(entries, ",") 184 } 185 186 // Get implements flag.Getter and returns a slice of string values. 187 func (f *StringMultimap) Get() any { 188 if f == nil { 189 return map[string]stringset.Set(nil) 190 } 191 return *f 192 } 193 194 // IntList implements a flag.Value that accepts multiple values by repeatedly specifying the flag. 195 type IntList []int 196 197 // String returns a string representation of the flag's value. 198 func (i *IntList) String() string { return fmt.Sprintf("%v", *i) } 199 200 // Set adds a value to the flag's list of integers. 201 func (i *IntList) Set(value string) error { 202 v, err := strconv.Atoi(value) 203 if err != nil { 204 return err 205 } 206 *i = append(*i, v) 207 return nil 208 }