github.com/ungtb10d/cli/v2@v2.0.0-20221110210412-98537dd9d6a1/pkg/cmdutil/flags.go (about) 1 package cmdutil 2 3 import ( 4 "fmt" 5 "strconv" 6 "strings" 7 8 "github.com/spf13/cobra" 9 "github.com/spf13/pflag" 10 ) 11 12 // NilStringFlag defines a new flag with a string pointer receiver. This is useful for differentiating 13 // between the flag being set to a blank value and the flag not being passed at all. 14 func NilStringFlag(cmd *cobra.Command, p **string, name string, shorthand string, usage string) *pflag.Flag { 15 return cmd.Flags().VarPF(newStringValue(p), name, shorthand, usage) 16 } 17 18 // NilBoolFlag defines a new flag with a bool pointer receiver. This is useful for differentiating 19 // between the flag being explicitly set to a false value and the flag not being passed at all. 20 func NilBoolFlag(cmd *cobra.Command, p **bool, name string, shorthand string, usage string) *pflag.Flag { 21 f := cmd.Flags().VarPF(newBoolValue(p), name, shorthand, usage) 22 f.NoOptDefVal = "true" 23 return f 24 } 25 26 // StringEnumFlag defines a new string flag that only allows values listed in options. 27 func StringEnumFlag(cmd *cobra.Command, p *string, name, shorthand, defaultValue string, options []string, usage string) *pflag.Flag { 28 *p = defaultValue 29 val := &enumValue{string: p, options: options} 30 f := cmd.Flags().VarPF(val, name, shorthand, fmt.Sprintf("%s: %s", usage, formatValuesForUsageDocs(options))) 31 _ = cmd.RegisterFlagCompletionFunc(name, func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { 32 return options, cobra.ShellCompDirectiveNoFileComp 33 }) 34 return f 35 } 36 37 func StringSliceEnumFlag(cmd *cobra.Command, p *[]string, name, shorthand string, defaultValues, options []string, usage string) *pflag.Flag { 38 *p = defaultValues 39 val := &enumMultiValue{value: p, options: options} 40 f := cmd.Flags().VarPF(val, name, shorthand, fmt.Sprintf("%s: %s", usage, formatValuesForUsageDocs(options))) 41 _ = cmd.RegisterFlagCompletionFunc(name, func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { 42 return options, cobra.ShellCompDirectiveNoFileComp 43 }) 44 return f 45 } 46 47 func formatValuesForUsageDocs(values []string) string { 48 return fmt.Sprintf("{%s}", strings.Join(values, "|")) 49 } 50 51 type stringValue struct { 52 string **string 53 } 54 55 func newStringValue(p **string) *stringValue { 56 return &stringValue{p} 57 } 58 59 func (s *stringValue) Set(value string) error { 60 *s.string = &value 61 return nil 62 } 63 64 func (s *stringValue) String() string { 65 if s.string == nil || *s.string == nil { 66 return "" 67 } 68 return **s.string 69 } 70 71 func (s *stringValue) Type() string { 72 return "string" 73 } 74 75 type boolValue struct { 76 bool **bool 77 } 78 79 func newBoolValue(p **bool) *boolValue { 80 return &boolValue{p} 81 } 82 83 func (b *boolValue) Set(value string) error { 84 v, err := strconv.ParseBool(value) 85 *b.bool = &v 86 return err 87 } 88 89 func (b *boolValue) String() string { 90 if b.bool == nil || *b.bool == nil { 91 return "false" 92 } else if **b.bool { 93 return "true" 94 } 95 return "false" 96 } 97 98 func (b *boolValue) Type() string { 99 return "bool" 100 } 101 102 func (b *boolValue) IsBoolFlag() bool { 103 return true 104 } 105 106 type enumValue struct { 107 string *string 108 options []string 109 } 110 111 func (e *enumValue) Set(value string) error { 112 if !isIncluded(value, e.options) { 113 return fmt.Errorf("valid values are %s", formatValuesForUsageDocs(e.options)) 114 } 115 *e.string = value 116 return nil 117 } 118 119 func (e *enumValue) String() string { 120 return *e.string 121 } 122 123 func (e *enumValue) Type() string { 124 return "string" 125 } 126 127 type enumMultiValue struct { 128 value *[]string 129 options []string 130 } 131 132 func (e *enumMultiValue) Set(value string) error { 133 items := strings.Split(value, ",") 134 for _, item := range items { 135 if !isIncluded(item, e.options) { 136 return fmt.Errorf("valid values are %s", formatValuesForUsageDocs(e.options)) 137 } 138 } 139 *e.value = append(*e.value, items...) 140 return nil 141 } 142 143 func (e *enumMultiValue) String() string { 144 if len(*e.value) == 0 { 145 return "" 146 } 147 return fmt.Sprintf("{%s}", strings.Join(*e.value, ", ")) 148 } 149 150 func (e *enumMultiValue) Type() string { 151 return "stringSlice" 152 } 153 154 func isIncluded(value string, opts []string) bool { 155 for _, opt := range opts { 156 if strings.EqualFold(opt, value) { 157 return true 158 } 159 } 160 return false 161 }