github.com/rakutentech/cli@v6.12.5-0.20151006231303-24468b65536e+incompatible/flags/flags.go (about)

     1  package flags
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"strconv"
     7  	"strings"
     8  
     9  	"github.com/cloudfoundry/cli/flags/flag"
    10  )
    11  
    12  type FlagSet interface {
    13  	fmt.Stringer
    14  	GetName() string
    15  	GetValue() interface{}
    16  	Set(string)
    17  }
    18  
    19  type FlagContext interface {
    20  	Parse(...string) error
    21  	Args() []string
    22  	Int(string) int
    23  	Bool(string) bool
    24  	String(string) string
    25  	StringSlice(string) []string
    26  	IsSet(string) bool
    27  	SkipFlagParsing(bool)
    28  }
    29  
    30  type flagContext struct {
    31  	flagsets        map[string]FlagSet
    32  	args            []string
    33  	cmdFlags        map[string]FlagSet //valid flags for command
    34  	cursor          int
    35  	skipFlagParsing bool
    36  }
    37  
    38  func NewFlagContext(cmdFlags map[string]FlagSet) FlagContext {
    39  	return &flagContext{
    40  		flagsets: make(map[string]FlagSet),
    41  		cmdFlags: cmdFlags,
    42  		cursor:   0,
    43  	}
    44  }
    45  
    46  func (c *flagContext) Parse(args ...string) error {
    47  	var flagset FlagSet
    48  	var ok bool
    49  	var v string
    50  	var err error
    51  
    52  	c.setDefaultFlagValueIfAny()
    53  
    54  	for c.cursor <= len(args)-1 {
    55  		arg := args[c.cursor]
    56  
    57  		if !c.skipFlagParsing && (strings.HasPrefix(arg, "-") || strings.HasPrefix(arg, "--")) {
    58  			flg := strings.TrimLeft(strings.TrimLeft(arg, "-"), "-")
    59  
    60  			c.extractEqualSignIfAny(&flg, &args)
    61  
    62  			if flagset, ok = c.cmdFlags[flg]; !ok {
    63  				return errors.New("Invalid flag: " + arg)
    64  			}
    65  
    66  			switch flagset.GetValue().(type) {
    67  			case bool:
    68  				c.flagsets[flg] = &cliFlags.BoolFlag{Name: flg, Value: c.getBoolFlagValue(args)}
    69  			case int:
    70  				if v, err = c.getFlagValue(args); err != nil {
    71  					return err
    72  				}
    73  				i, err := strconv.ParseInt(v, 10, 32)
    74  				if err != nil {
    75  					return errors.New("Value for flag '" + flg + "' must be integer")
    76  				}
    77  				c.flagsets[flg] = &cliFlags.IntFlag{Name: flg, Value: int(i)}
    78  			case string:
    79  				if v, err = c.getFlagValue(args); err != nil {
    80  					return err
    81  				}
    82  				c.flagsets[flg] = &cliFlags.StringFlag{Name: flg, Value: v}
    83  			case []string:
    84  				if v, err = c.getFlagValue(args); err != nil {
    85  					return err
    86  				}
    87  				if _, ok = c.flagsets[flg]; !ok {
    88  					c.flagsets[flg] = &cliFlags.StringSliceFlag{Name: flg, Value: []string{v}}
    89  				} else {
    90  					c.flagsets[flg].Set(v)
    91  				}
    92  			}
    93  		} else {
    94  			c.args = append(c.args, args[c.cursor])
    95  		}
    96  		c.cursor++
    97  	}
    98  	return nil
    99  }
   100  
   101  func (c *flagContext) getFlagValue(args []string) (string, error) {
   102  	if c.cursor >= len(args)-1 {
   103  		return "", errors.New("No value provided for flag: " + args[c.cursor])
   104  	}
   105  
   106  	c.cursor++
   107  	return args[c.cursor], nil
   108  }
   109  
   110  func (c *flagContext) getBoolFlagValue(args []string) bool {
   111  	if c.cursor >= len(args)-1 {
   112  		return true
   113  	}
   114  
   115  	b, err := strconv.ParseBool(args[c.cursor+1])
   116  	if err == nil {
   117  		c.cursor++
   118  		return b
   119  	}
   120  	return true
   121  }
   122  
   123  func (c *flagContext) Args() []string {
   124  	return c.args
   125  }
   126  
   127  func (c *flagContext) IsSet(k string) bool {
   128  	if _, ok := c.flagsets[k]; ok {
   129  		return true
   130  	}
   131  	return false
   132  }
   133  
   134  func (c *flagContext) Int(k string) int {
   135  	if _, ok := c.flagsets[k]; ok {
   136  		v := c.flagsets[k].GetValue()
   137  		switch v.(type) {
   138  		case int:
   139  			return v.(int)
   140  		}
   141  	}
   142  	return 0
   143  }
   144  
   145  func (c *flagContext) String(k string) string {
   146  	if _, ok := c.flagsets[k]; ok {
   147  		v := c.flagsets[k].GetValue()
   148  		switch v.(type) {
   149  		case string:
   150  			return v.(string)
   151  		}
   152  	}
   153  	return ""
   154  }
   155  
   156  func (c *flagContext) Bool(k string) bool {
   157  	if _, ok := c.flagsets[k]; ok {
   158  		v := c.flagsets[k].GetValue()
   159  		switch v.(type) {
   160  		case bool:
   161  			return v.(bool)
   162  		}
   163  	}
   164  	return false
   165  }
   166  
   167  func (c *flagContext) StringSlice(k string) []string {
   168  	if _, ok := c.flagsets[k]; ok {
   169  		v := c.flagsets[k].GetValue()
   170  		switch v.(type) {
   171  		case []string:
   172  			return v.([]string)
   173  		}
   174  	}
   175  	return []string{}
   176  }
   177  
   178  func (c *flagContext) SkipFlagParsing(skip bool) {
   179  	c.skipFlagParsing = skip
   180  }
   181  
   182  func (c *flagContext) extractEqualSignIfAny(flg *string, args *[]string) {
   183  	if strings.Contains(*flg, "=") {
   184  		tmpAry := strings.SplitN(*flg, "=", 2)
   185  		*flg = tmpAry[0]
   186  		tmpArg := append((*args)[:c.cursor], tmpAry[1])
   187  		*args = append(tmpArg, (*args)[c.cursor:]...)
   188  	}
   189  }
   190  
   191  func (c *flagContext) setDefaultFlagValueIfAny() {
   192  	var v interface{}
   193  
   194  	for flgName, flg := range c.cmdFlags {
   195  		v = flg.GetValue()
   196  		switch v.(type) {
   197  		case bool:
   198  			if v.(bool) != false {
   199  				c.flagsets[flgName] = &cliFlags.BoolFlag{Name: flgName, Value: v.(bool)}
   200  			}
   201  		case int:
   202  			if v.(int) != 0 {
   203  				c.flagsets[flgName] = &cliFlags.IntFlag{Name: flgName, Value: v.(int)}
   204  			}
   205  		case string:
   206  			if len(v.(string)) != 0 {
   207  				c.flagsets[flgName] = &cliFlags.StringFlag{Name: flgName, Value: v.(string)}
   208  			}
   209  		case []string:
   210  			if len(v.([]string)) != 0 {
   211  				c.flagsets[flgName] = &cliFlags.StringSliceFlag{Name: flgName, Value: v.([]string)}
   212  			}
   213  		}
   214  	}
   215  
   216  }