github.com/loggregator/cli@v6.33.1-0.20180224010324-82334f081791+incompatible/cf/flags/flags.go (about) 1 package flags 2 3 import ( 4 "errors" 5 "fmt" 6 "strconv" 7 "strings" 8 ) 9 10 type FlagSet interface { 11 fmt.Stringer 12 GetName() string 13 GetShortName() string 14 GetValue() interface{} 15 Set(string) 16 Visible() bool 17 } 18 19 type FlagContext interface { 20 Parse(...string) error 21 Args() []string 22 Int(string) int 23 Float64(string) float64 24 Bool(string) bool 25 String(string) string 26 StringSlice(string) []string 27 IsSet(string) bool 28 SkipFlagParsing(bool) 29 NewStringFlag(name string, shortName string, usage string) 30 NewStringFlagWithDefault(name string, shortName string, usage string, value string) 31 NewBoolFlag(name string, shortName string, usage string) 32 NewIntFlag(name string, shortName string, usage string) 33 NewIntFlagWithDefault(name string, shortName string, usage string, value int) 34 NewFloat64Flag(name string, shortName string, usage string) 35 NewFloat64FlagWithDefault(name string, shortName string, usage string, value float64) 36 NewStringSliceFlag(name string, shortName string, usage string) 37 NewStringSliceFlagWithDefault(name string, shortName string, usage string, value []string) 38 ShowUsage(leadingSpace int) string 39 } 40 41 type flagContext struct { 42 flagsets map[string]FlagSet 43 args []string 44 cmdFlags map[string]FlagSet //valid flags for command 45 cursor int 46 skipFlagParsing bool 47 } 48 49 func New() FlagContext { 50 return &flagContext{ 51 flagsets: make(map[string]FlagSet), 52 cmdFlags: make(map[string]FlagSet), 53 cursor: 0, 54 } 55 } 56 57 func NewFlagContext(cmdFlags map[string]FlagSet) FlagContext { 58 return &flagContext{ 59 flagsets: make(map[string]FlagSet), 60 cmdFlags: cmdFlags, 61 cursor: 0, 62 } 63 } 64 65 func (c *flagContext) Parse(args ...string) error { 66 c.setDefaultFlagValueIfAny() 67 68 for c.cursor <= len(args)-1 { 69 arg := args[c.cursor] 70 71 if !c.skipFlagParsing && (strings.HasPrefix(arg, "-") || strings.HasPrefix(arg, "--")) { 72 flg := strings.TrimLeft(strings.TrimLeft(arg, "-"), "-") 73 74 c.extractEqualSignIfAny(&flg, &args) 75 76 flagset, ok := c.cmdFlags[flg] 77 if !ok { 78 flg = c.getFlagNameWithShortName(flg) 79 if flagset, ok = c.cmdFlags[flg]; !ok { 80 return errors.New("Invalid flag: " + arg) 81 } 82 } 83 84 switch flagset.GetValue().(type) { 85 case bool: 86 c.flagsets[flg] = &BoolFlag{Name: flg, Value: c.getBoolFlagValue(args)} 87 case int: 88 v, err := c.getFlagValue(args) 89 if err != nil { 90 return err 91 } 92 i, err := strconv.ParseInt(v, 10, 32) 93 if err != nil { 94 return errors.New("Value for flag '" + flg + "' must be an integer") 95 } 96 c.flagsets[flg] = &IntFlag{Name: flg, Value: int(i)} 97 case float64: 98 v, err := c.getFlagValue(args) 99 if err != nil { 100 return err 101 } 102 i, err := strconv.ParseFloat(v, 64) 103 if err != nil { 104 return errors.New("Value for flag '" + flg + "' must be a float64") 105 } 106 c.flagsets[flg] = &Float64Flag{Name: flg, Value: float64(i)} 107 case string: 108 v, err := c.getFlagValue(args) 109 if err != nil { 110 return err 111 } 112 c.flagsets[flg] = &StringFlag{Name: flg, Value: v} 113 case []string: 114 v, err := c.getFlagValue(args) 115 if err != nil { 116 return err 117 } 118 if _, ok = c.flagsets[flg]; !ok { 119 c.flagsets[flg] = &StringSliceFlag{Name: flg, Value: []string{v}} 120 } else { 121 c.flagsets[flg].Set(v) 122 } 123 case backwardsCompatibilityType: 124 // do nothing 125 } 126 } else { 127 c.args = append(c.args, args[c.cursor]) 128 } 129 c.cursor++ 130 } 131 return nil 132 } 133 134 func (c *flagContext) getFlagValue(args []string) (string, error) { 135 if c.cursor >= len(args)-1 { 136 return "", errors.New("No value provided for flag: " + args[c.cursor]) 137 } 138 139 c.cursor++ 140 return args[c.cursor], nil 141 } 142 143 func (c *flagContext) getBoolFlagValue(args []string) bool { 144 if c.cursor >= len(args)-1 { 145 return true 146 } 147 148 b, err := strconv.ParseBool(args[c.cursor+1]) 149 if err == nil { 150 c.cursor++ 151 return b 152 } 153 return true 154 } 155 156 func (c *flagContext) Args() []string { 157 return c.args 158 } 159 160 func (c *flagContext) IsSet(k string) bool { 161 return c.isFlagProvided(&k) 162 } 163 164 func (c *flagContext) Int(k string) int { 165 if !c.isFlagProvided(&k) { 166 return 0 167 } 168 169 v := c.flagsets[k].GetValue() 170 switch v.(type) { 171 case int: 172 return v.(int) 173 } 174 175 return 0 176 } 177 178 func (c *flagContext) Float64(k string) float64 { 179 if !c.isFlagProvided(&k) { 180 return 0 181 } 182 183 v := c.flagsets[k].GetValue() 184 switch v.(type) { 185 case float64: 186 return v.(float64) 187 } 188 return 0 189 } 190 191 func (c *flagContext) String(k string) string { 192 if !c.isFlagProvided(&k) { 193 return "" 194 } 195 196 v := c.flagsets[k].GetValue() 197 switch v.(type) { 198 case string: 199 return v.(string) 200 } 201 return "" 202 } 203 204 func (c *flagContext) Bool(k string) bool { 205 if !c.isFlagProvided(&k) { 206 return false 207 } 208 209 v := c.flagsets[k].GetValue() 210 switch v.(type) { 211 case bool: 212 return v.(bool) 213 } 214 215 return false 216 } 217 218 func (c *flagContext) StringSlice(k string) []string { 219 if !c.isFlagProvided(&k) { 220 return []string{} 221 } 222 223 v := c.flagsets[k].GetValue() 224 switch v.(type) { 225 case []string: 226 return v.([]string) 227 } 228 return []string{} 229 } 230 231 func (c *flagContext) SkipFlagParsing(skip bool) { 232 c.skipFlagParsing = skip 233 } 234 235 func (c *flagContext) extractEqualSignIfAny(flg *string, args *[]string) { 236 if strings.Contains(*flg, "=") { 237 tmpAry := strings.SplitN(*flg, "=", 2) 238 *flg = tmpAry[0] 239 tmpArg := append((*args)[:c.cursor], tmpAry[1]) 240 *args = append(tmpArg, (*args)[c.cursor:]...) 241 } 242 } 243 244 func (c *flagContext) setDefaultFlagValueIfAny() { 245 var v interface{} 246 247 for flgName, flg := range c.cmdFlags { 248 v = flg.GetValue() 249 switch v.(type) { 250 case bool: 251 if v.(bool) != false { 252 c.flagsets[flgName] = &BoolFlag{Name: flgName, Value: v.(bool)} 253 } 254 case int: 255 if v.(int) != 0 { 256 c.flagsets[flgName] = &IntFlag{Name: flgName, Value: v.(int)} 257 } 258 case float64: 259 if v.(float64) != 0 { 260 c.flagsets[flgName] = &Float64Flag{Name: flgName, Value: v.(float64)} 261 } 262 case string: 263 if len(v.(string)) != 0 { 264 c.flagsets[flgName] = &StringFlag{Name: flgName, Value: v.(string)} 265 } 266 case []string: 267 if len(v.([]string)) != 0 { 268 c.flagsets[flgName] = &StringSliceFlag{Name: flgName, Value: v.([]string)} 269 } 270 } 271 } 272 273 } 274 275 func (c *flagContext) getFlagNameWithShortName(shortName string) string { 276 for n, f := range c.cmdFlags { 277 if f.GetShortName() == shortName { 278 return n 279 } 280 } 281 return "" 282 } 283 284 func (c *flagContext) isFlagProvided(flg *string) bool { 285 if _, ok := c.flagsets[*flg]; !ok { 286 *flg = c.getFlagNameWithShortName(*flg) 287 if _, ok := c.flagsets[*flg]; !ok { 288 return false 289 } 290 } 291 292 return true 293 }