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  }