From ccb1528bb0d6a578c4781f785ef3f378eb2d7c14 Mon Sep 17 00:00:00 2001 From: Jared Forsyth Date: Mon, 18 Nov 2013 16:35:23 -0700 Subject: [PATCH] adding multi-named flags --- app.go | 1 + context.go | 53 +++++++++++++++++++++++++++++------------ flag.go | 51 +++++++++++++++++++++++++++++++++++---- flag_test.go | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 152 insertions(+), 20 deletions(-) diff --git a/app.go b/app.go index c5ff05a..8957427 100644 --- a/app.go +++ b/app.go @@ -48,6 +48,7 @@ func (a *App) Run(arguments []string) error { set := flagSet(a.Name, a.Flags) set.SetOutput(ioutil.Discard) err := set.Parse(arguments[1:]) + normalizeFlags(a.Flags, set) context := NewContext(a, set, set) if err != nil { diff --git a/context.go b/context.go index 877aaa1..ce83a14 100644 --- a/context.go +++ b/context.go @@ -2,6 +2,7 @@ package cli import ( "flag" + "strings" "strconv" ) @@ -22,52 +23,52 @@ func NewContext(app *App, set *flag.FlagSet, globalSet *flag.FlagSet) *Context { // Looks up the value of a local int flag, returns 0 if no int flag exists func (c *Context) Int(name string) int { - return c.lookupInt(name, c.flagSet) + return lookupInt(name, c.flagSet) } // Looks up the value of a local bool flag, returns false if no bool flag exists func (c *Context) Bool(name string) bool { - return c.lookupBool(name, c.flagSet) + return lookupBool(name, c.flagSet) } // Looks up the value of a local string flag, returns "" if no string flag exists func (c *Context) String(name string) string { - return c.lookupString(name, c.flagSet) + return lookupString(name, c.flagSet) } // Looks up the value of a local string slice flag, returns nil if no string slice flag exists func (c *Context) StringSlice(name string) []string { - return c.lookupStringSlice(name, c.flagSet) + return lookupStringSlice(name, c.flagSet) } // Looks up the value of a local int slice flag, returns nil if no int slice flag exists func (c *Context) IntSlice(name string) []int { - return c.lookupIntSlice(name, c.flagSet) + return lookupIntSlice(name, c.flagSet) } // Looks up the value of a global int flag, returns 0 if no int flag exists func (c *Context) GlobalInt(name string) int { - return c.lookupInt(name, c.globalSet) + return lookupInt(name, c.globalSet) } // Looks up the value of a global bool flag, returns false if no bool flag exists func (c *Context) GlobalBool(name string) bool { - return c.lookupBool(name, c.globalSet) + return lookupBool(name, c.globalSet) } // Looks up the value of a global string flag, returns "" if no string flag exists func (c *Context) GlobalString(name string) string { - return c.lookupString(name, c.globalSet) + return lookupString(name, c.globalSet) } // Looks up the value of a global string slice flag, returns nil if no string slice flag exists func (c *Context) GlobalStringSlice(name string) []string { - return c.lookupStringSlice(name, c.globalSet) + return lookupStringSlice(name, c.globalSet) } // Looks up the value of a global int slice flag, returns nil if no int slice flag exists func (c *Context) GlobalIntSlice(name string) []int { - return c.lookupIntSlice(name, c.globalSet) + return lookupIntSlice(name, c.globalSet) } // Returns the command line arguments associated with the context. @@ -75,7 +76,7 @@ func (c *Context) Args() []string { return c.flagSet.Args() } -func (c *Context) lookupInt(name string, set *flag.FlagSet) int { +func lookupInt(name string, set *flag.FlagSet) int { f := set.Lookup(name) if f != nil { val, err := strconv.Atoi(f.Value.String()) @@ -88,7 +89,7 @@ func (c *Context) lookupInt(name string, set *flag.FlagSet) int { return 0 } -func (c *Context) lookupString(name string, set *flag.FlagSet) string { +func lookupString(name string, set *flag.FlagSet) string { f := set.Lookup(name) if f != nil { return f.Value.String() @@ -97,7 +98,7 @@ func (c *Context) lookupString(name string, set *flag.FlagSet) string { return "" } -func (c *Context) lookupStringSlice(name string, set *flag.FlagSet) []string { +func lookupStringSlice(name string, set *flag.FlagSet) []string { f := set.Lookup(name) if f != nil { return (f.Value.(*StringSlice)).Value() @@ -107,7 +108,7 @@ func (c *Context) lookupStringSlice(name string, set *flag.FlagSet) []string { return nil } -func (c *Context) lookupIntSlice(name string, set *flag.FlagSet) []int { +func lookupIntSlice(name string, set *flag.FlagSet) []int { f := set.Lookup(name) if f != nil { return (f.Value.(*IntSlice)).Value() @@ -117,7 +118,7 @@ func (c *Context) lookupIntSlice(name string, set *flag.FlagSet) []int { return nil } -func (c *Context) lookupBool(name string, set *flag.FlagSet) bool { +func lookupBool(name string, set *flag.FlagSet) bool { f := set.Lookup(name) if f != nil { val, err := strconv.ParseBool(f.Value.String()) @@ -129,3 +130,25 @@ func (c *Context) lookupBool(name string, set *flag.FlagSet) bool { return false } + +func normalizeFlags(flags []Flag, set *flag.FlagSet) { + for _, f := range flags { + parts := strings.Split(f.GetName(), ", ") + if len(parts) == 1 { + continue + } + var ff *flag.Flag + for _, name := range parts { + ff = set.Lookup(name) + if ff != nil && ff.Value.String() != "" { + break + } + } + if ff == nil { + continue + } + for _, name := range parts { + set.Set(name, ff.Value.String()) + } + } +} diff --git a/flag.go b/flag.go index ae70e94..2e1d611 100644 --- a/flag.go +++ b/flag.go @@ -3,6 +3,7 @@ package cli import "fmt" import "flag" import "strconv" +import "strings" // Flag is a common interface related to parsing flags in cli. // For more advanced flag parsing techniques, it is recomended that @@ -11,6 +12,7 @@ type Flag interface { fmt.Stringer // Apply Flag settings to the given flag set Apply(*flag.FlagSet) + GetName() string } func flagSet(name string, flags []Flag) *flag.FlagSet { @@ -48,7 +50,14 @@ func (f StringSliceFlag) String() string { } func (f StringSliceFlag) Apply(set *flag.FlagSet) { - set.Var(f.Value, f.Name, f.Usage) + parts := strings.Split(f.Name, ", ") + for _, name := range parts { + set.Var(f.Value, name, f.Usage) + } +} + +func (f StringSliceFlag) GetName() string { + return f.Name } type IntSlice []int @@ -83,7 +92,14 @@ func (f IntSliceFlag) String() string { } func (f IntSliceFlag) Apply(set *flag.FlagSet) { - set.Var(f.Value, f.Name, f.Usage) + parts := strings.Split(f.Name, ", ") + for _, name := range parts { + set.Var(f.Value, name, f.Usage) + } +} + +func (f IntSliceFlag) GetName() string { + return f.Name } type BoolFlag struct { @@ -96,7 +112,14 @@ func (f BoolFlag) String() string { } func (f BoolFlag) Apply(set *flag.FlagSet) { - set.Bool(f.Name, false, f.Usage) + parts := strings.Split(f.Name, ", ") + for _, name := range parts { + set.Bool(name, false, f.Usage) + } +} + +func (f BoolFlag) GetName() string { + return f.Name } type StringFlag struct { @@ -110,7 +133,14 @@ func (f StringFlag) String() string { } func (f StringFlag) Apply(set *flag.FlagSet) { - set.String(f.Name, f.Value, f.Usage) + parts := strings.Split(f.Name, ", ") + for _, name := range parts { + set.String(name, f.Value, f.Usage) + } +} + +func (f StringFlag) GetName() string { + return f.Name } type IntFlag struct { @@ -124,7 +154,14 @@ func (f IntFlag) String() string { } func (f IntFlag) Apply(set *flag.FlagSet) { - set.Int(f.Name, f.Value, f.Usage) + parts := strings.Split(f.Name, ", ") + for _, name := range parts { + set.Int(name, f.Value, f.Usage) + } +} + +func (f IntFlag) GetName() string { + return f.Name } type helpFlag struct { @@ -140,6 +177,10 @@ func (f helpFlag) Apply(set *flag.FlagSet) { set.Bool("help", false, f.Usage) } +func (f helpFlag) GetName() string { + return "help" +} + func prefixFor(name string) (prefix string) { if len(name) == 1 { prefix = "-" diff --git a/flag_test.go b/flag_test.go index 0cd7990..04c0952 100644 --- a/flag_test.go +++ b/flag_test.go @@ -64,3 +64,70 @@ func TestIntFlagHelpOutput(t *testing.T) { } } } + + +func TestParseMultiString(t *testing.T) { + (&cli.App{ + Flags: []cli.Flag{ + cli.StringFlag{Name: "serve, s"}, + }, + Action: func(ctx *cli.Context) { + if ctx.String("serve") != "10" { + t.Errorf("main name not set") + } + if ctx.String("s") != "10" { + t.Errorf("short name not set") + } + }, + }).Run([]string{"run", "-s", "10"}) + + (&cli.App{ + Flags: []cli.Flag{ + cli.StringFlag{Name: "serve, s"}, + }, + Action: func(ctx *cli.Context) { + if ctx.String("serve") != "10" { + t.Errorf("main name not set") + } + if ctx.String("s") != "10" { + t.Errorf("short name not set") + } + }, + }).Run([]string{"run", "--serve", "10"}) +} + +func TestParseMultiInt(t *testing.T) { + a := cli.App{ + Flags: []cli.Flag{ + cli.IntFlag{Name: "serve, s"}, + }, + Action: func(ctx *cli.Context) { + if ctx.Int("serve") != 10 { + t.Errorf("main name not set") + } + if ctx.Int("s") != 10 { + t.Errorf("short name not set") + } + }, + } + a.Run([]string{"run", "--serve", "10"}) +} + +func TestParseMultiBool(t *testing.T) { + a := cli.App{ + Flags: []cli.Flag{ + cli.BoolFlag{Name: "serve, s"}, + }, + Action: func(ctx *cli.Context) { + if ctx.Bool("serve") != true { + t.Errorf("main name not set") + } + if ctx.Bool("s") != true { + t.Errorf("short name not set") + } + }, + } + a.Run([]string{"run", "--serve"}) +} + +