github.com/palisadeinc/bor@v0.0.0-20230615125219-ab7196213d15/internal/cli/flagset/flagset.go (about) 1 package flagset 2 3 import ( 4 "flag" 5 "fmt" 6 "math/big" 7 "sort" 8 "strings" 9 "time" 10 ) 11 12 type Flagset struct { 13 flags []*FlagVar 14 set *flag.FlagSet 15 } 16 17 func NewFlagSet(name string) *Flagset { 18 f := &Flagset{ 19 flags: []*FlagVar{}, 20 set: flag.NewFlagSet(name, flag.ContinueOnError), 21 } 22 23 return f 24 } 25 26 type FlagVar struct { 27 Name string 28 Usage string 29 Group string 30 Default any 31 } 32 33 func (f *Flagset) addFlag(fl *FlagVar) { 34 f.flags = append(f.flags, fl) 35 } 36 37 func (f *Flagset) Help() string { 38 str := "Options:\n\n" 39 40 items := []string{} 41 for _, item := range f.flags { 42 if item.Default != nil { 43 items = append(items, fmt.Sprintf(" -%s\n %s (default: %v)", item.Name, item.Usage, item.Default)) 44 } else { 45 items = append(items, fmt.Sprintf(" -%s\n %s", item.Name, item.Usage)) 46 } 47 } 48 49 return str + strings.Join(items, "\n\n") 50 } 51 52 func (f *Flagset) GetAllFlags() []string { 53 flags := []string{} 54 for _, flag := range f.flags { 55 flags = append(flags, flag.Name) 56 } 57 58 return flags 59 } 60 61 // MarkDown implements cli.MarkDown interface 62 func (f *Flagset) MarkDown() string { 63 if len(f.flags) == 0 { 64 return "" 65 } 66 67 groups := make(map[string][]*FlagVar) 68 69 for _, item := range f.flags { 70 groups[item.Group] = append(groups[item.Group], item) 71 } 72 73 i := 0 74 keys := make([]string, len(groups)) 75 76 for k := range groups { 77 keys[i] = k 78 i++ 79 } 80 81 sort.Strings(keys) 82 83 items := []string{} 84 85 for _, k := range keys { 86 if k == "" { 87 items = append(items, "## Options") 88 } else { 89 items = append(items, fmt.Sprintf("### %s Options", k)) 90 } 91 92 for _, item := range groups[k] { 93 if item.Default != nil { 94 items = append(items, fmt.Sprintf("- ```%s```: %s (default: %v)", item.Name, item.Usage, item.Default)) 95 } else { 96 items = append(items, fmt.Sprintf("- ```%s```: %s", item.Name, item.Usage)) 97 } 98 } 99 } 100 101 return strings.Join(items, "\n\n") 102 } 103 104 func (f *Flagset) Parse(args []string) error { 105 return f.set.Parse(args) 106 } 107 108 func (f *Flagset) Args() []string { 109 return f.set.Args() 110 } 111 112 type BoolFlag struct { 113 Name string 114 Usage string 115 Default bool 116 Value *bool 117 Group string 118 } 119 120 func (f *Flagset) BoolFlag(b *BoolFlag) { 121 f.addFlag(&FlagVar{ 122 Name: b.Name, 123 Usage: b.Usage, 124 Group: b.Group, 125 Default: b.Default, 126 }) 127 f.set.BoolVar(b.Value, b.Name, b.Default, b.Usage) 128 } 129 130 type StringFlag struct { 131 Name string 132 Usage string 133 Default string 134 Value *string 135 Group string 136 HideDefaultFromDoc bool 137 } 138 139 func (f *Flagset) StringFlag(b *StringFlag) { 140 if b.Default == "" || b.HideDefaultFromDoc { 141 f.addFlag(&FlagVar{ 142 Name: b.Name, 143 Usage: b.Usage, 144 Group: b.Group, 145 Default: nil, 146 }) 147 } else { 148 f.addFlag(&FlagVar{ 149 Name: b.Name, 150 Usage: b.Usage, 151 Group: b.Group, 152 Default: b.Default, 153 }) 154 } 155 f.set.StringVar(b.Value, b.Name, b.Default, b.Usage) 156 } 157 158 type IntFlag struct { 159 Name string 160 Usage string 161 Value *int 162 Default int 163 Group string 164 } 165 166 func (f *Flagset) IntFlag(i *IntFlag) { 167 f.addFlag(&FlagVar{ 168 Name: i.Name, 169 Usage: i.Usage, 170 Group: i.Group, 171 Default: i.Default, 172 }) 173 f.set.IntVar(i.Value, i.Name, i.Default, i.Usage) 174 } 175 176 type Uint64Flag struct { 177 Name string 178 Usage string 179 Value *uint64 180 Default uint64 181 Group string 182 } 183 184 func (f *Flagset) Uint64Flag(i *Uint64Flag) { 185 f.addFlag(&FlagVar{ 186 Name: i.Name, 187 Usage: i.Usage, 188 Group: i.Group, 189 Default: fmt.Sprintf("%d", i.Default), 190 }) 191 f.set.Uint64Var(i.Value, i.Name, i.Default, i.Usage) 192 } 193 194 type BigIntFlag struct { 195 Name string 196 Usage string 197 Value *big.Int 198 Group string 199 Default *big.Int 200 } 201 202 func (b *BigIntFlag) String() string { 203 if b.Value == nil { 204 return "" 205 } 206 207 return b.Value.String() 208 } 209 210 func (b *BigIntFlag) Set(value string) error { 211 num := new(big.Int) 212 213 var ok bool 214 if strings.HasPrefix(value, "0x") { 215 num, ok = num.SetString(value[2:], 16) 216 *b.Value = *num 217 } else { 218 num, ok = num.SetString(value, 10) 219 *b.Value = *num 220 } 221 222 if !ok { 223 return fmt.Errorf("failed to set big int") 224 } 225 226 return nil 227 } 228 229 func (f *Flagset) BigIntFlag(b *BigIntFlag) { 230 f.addFlag(&FlagVar{ 231 Name: b.Name, 232 Usage: b.Usage, 233 Group: b.Group, 234 Default: b.Default, 235 }) 236 f.set.Var(b, b.Name, b.Usage) 237 } 238 239 type SliceStringFlag struct { 240 Name string 241 Usage string 242 Value *[]string 243 Default []string 244 Group string 245 } 246 247 // SplitAndTrim splits input separated by a comma 248 // and trims excessive white space from the substrings. 249 func SplitAndTrim(input string) (ret []string) { 250 l := strings.Split(input, ",") 251 for _, r := range l { 252 if r = strings.TrimSpace(r); r != "" { 253 ret = append(ret, r) 254 } 255 } 256 257 return ret 258 } 259 260 func (i *SliceStringFlag) String() string { 261 if i.Value == nil { 262 return "" 263 } 264 265 return strings.Join(*i.Value, ",") 266 } 267 268 func (i *SliceStringFlag) Set(value string) error { 269 // overwritting insted of appending 270 *i.Value = SplitAndTrim(value) 271 return nil 272 } 273 274 func (f *Flagset) SliceStringFlag(s *SliceStringFlag) { 275 if s.Default == nil || len(s.Default) == 0 { 276 f.addFlag(&FlagVar{ 277 Name: s.Name, 278 Usage: s.Usage, 279 Group: s.Group, 280 Default: nil, 281 }) 282 } else { 283 f.addFlag(&FlagVar{ 284 Name: s.Name, 285 Usage: s.Usage, 286 Group: s.Group, 287 Default: strings.Join(s.Default, ","), 288 }) 289 } 290 f.set.Var(s, s.Name, s.Usage) 291 } 292 293 type DurationFlag struct { 294 Name string 295 Usage string 296 Value *time.Duration 297 Default time.Duration 298 Group string 299 } 300 301 func (f *Flagset) DurationFlag(d *DurationFlag) { 302 f.addFlag(&FlagVar{ 303 Name: d.Name, 304 Usage: d.Usage, 305 Group: d.Group, 306 Default: d.Default, 307 }) 308 f.set.DurationVar(d.Value, d.Name, d.Default, "") 309 } 310 311 type MapStringFlag struct { 312 Name string 313 Usage string 314 Value *map[string]string 315 Group string 316 Default map[string]string 317 } 318 319 func formatMapString(m map[string]string) string { 320 if len(m) == 0 { 321 return "" 322 } 323 324 ls := []string{} 325 for k, v := range m { 326 ls = append(ls, k+"="+v) 327 } 328 329 return strings.Join(ls, ",") 330 } 331 332 func (m *MapStringFlag) String() string { 333 return formatMapString(*m.Value) 334 } 335 336 func (m *MapStringFlag) Set(value string) error { 337 if m.Value == nil { 338 m.Value = &map[string]string{} 339 } 340 341 for _, t := range strings.Split(value, ",") { 342 if t != "" { 343 kv := strings.Split(t, "=") 344 345 if len(kv) == 2 { 346 (*m.Value)[kv[0]] = kv[1] 347 } 348 } 349 } 350 351 return nil 352 } 353 354 func (f *Flagset) MapStringFlag(m *MapStringFlag) { 355 if m.Default == nil || len(m.Default) == 0 { 356 f.addFlag(&FlagVar{ 357 Name: m.Name, 358 Usage: m.Usage, 359 Group: m.Group, 360 Default: nil, 361 }) 362 } else { 363 f.addFlag(&FlagVar{ 364 Name: m.Name, 365 Usage: m.Usage, 366 Group: m.Group, 367 Default: formatMapString(m.Default), 368 }) 369 } 370 f.set.Var(m, m.Name, m.Usage) 371 } 372 373 type Float64Flag struct { 374 Name string 375 Usage string 376 Value *float64 377 Default float64 378 Group string 379 } 380 381 func (f *Flagset) Float64Flag(i *Float64Flag) { 382 f.addFlag(&FlagVar{ 383 Name: i.Name, 384 Usage: i.Usage, 385 Group: i.Group, 386 Default: i.Default, 387 }) 388 f.set.Float64Var(i.Value, i.Name, i.Default, "") 389 }