Minimize struct copying

by using pointer func receivers and slices of struct pointers where possible.
main
Dan Buch 8 years ago
parent b35c8a92d2
commit cd10b49473
No known key found for this signature in database
GPG Key ID: FAEF12936DD3E3EC

@ -205,7 +205,7 @@ Setting and querying flags is simple.
``` go ``` go
... ...
app.Flags = []cli.Flag { app.Flags = []cli.Flag {
cli.StringFlag{ &cli.StringFlag{
Name: "lang", Name: "lang",
Value: "english", Value: "english",
Usage: "language for the greeting", Usage: "language for the greeting",
@ -232,7 +232,7 @@ You can also set a destination variable for a flag, to which the content will be
... ...
var language string var language string
app.Flags = []cli.Flag { app.Flags = []cli.Flag {
cli.StringFlag{ &cli.StringFlag{
Name: "lang", Name: "lang",
Value: "english", Value: "english",
Usage: "language for the greeting", Usage: "language for the greeting",
@ -264,7 +264,7 @@ indicated with back quotes.
For example this: For example this:
```go ```go
cli.StringFlag{ &cli.StringFlag{
Name: "config", Name: "config",
Aliases: []string{"c"}, Aliases: []string{"c"},
Usage: "Load configuration from `FILE`", Usage: "Load configuration from `FILE`",
@ -285,7 +285,7 @@ You can set alternate (or short) names for flags by providing a comma-delimited
``` go ``` go
app.Flags = []cli.Flag { app.Flags = []cli.Flag {
cli.StringFlag{ &cli.StringFlag{
Name: "lang", Name: "lang",
Aliases: []string{"l"}, Aliases: []string{"l"},
Value: "english", Value: "english",
@ -302,7 +302,7 @@ You can also have the default value set from the environment via `EnvVars`. e.g
``` go ``` go
app.Flags = []cli.Flag { app.Flags = []cli.Flag {
cli.StringFlag{ &cli.StringFlag{
Name: "lang", Name: "lang",
Aliases: []string{"l"}, Aliases: []string{"l"},
Value: "english", Value: "english",
@ -316,7 +316,7 @@ If `EnvVars` contains more than one string, the first environment variable that
``` go ``` go
app.Flags = []cli.Flag { app.Flags = []cli.Flag {
cli.StringFlag{ &cli.StringFlag{
Name: "lang", Name: "lang",
Aliases: []string{"l"}, Aliases: []string{"l"},
Value: "english", Value: "english",
@ -333,7 +333,7 @@ There is a separate package altsrc that adds support for getting flag values fro
In order to get values for a flag from an alternate input source the following code would be added to wrap an existing cli.Flag like below: In order to get values for a flag from an alternate input source the following code would be added to wrap an existing cli.Flag like below:
``` go ``` go
altsrc.NewIntFlag(cli.IntFlag{Name: "test"}) altsrc.NewIntFlag(&cli.IntFlag{Name: "test"})
``` ```
Initialization must also occur for these flags. Below is an example initializing getting data from a yaml file below. Initialization must also occur for these flags. Below is an example initializing getting data from a yaml file below.
@ -362,8 +362,8 @@ Here is a more complete sample of a command using YAML support:
return nil return nil
}, },
Flags: []cli.Flag{ Flags: []cli.Flag{
NewIntFlag(cli.IntFlag{Name: "test"}), NewIntFlag(&cli.IntFlag{Name: "test"}),
cli.StringFlag{Name: "load"}}, &cli.StringFlag{Name: "load"}},
} }
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load")) command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
err := command.Run(c) err := command.Run(c)
@ -375,7 +375,7 @@ Subcommands can be defined for a more git-like command line app.
```go ```go
... ...
app.Commands = []cli.Command{ app.Commands = []*cli.Command{
{ {
Name: "add", Name: "add",
Aliases: []string{"a"}, Aliases: []string{"a"},
@ -398,7 +398,7 @@ app.Commands = []cli.Command{
Name: "template", Name: "template",
Aliases: []string{"r"}, Aliases: []string{"r"},
Usage: "options for task templates", Usage: "options for task templates",
Subcommands: []cli.Command{ Subcommands: []*cli.Command{
{ {
Name: "add", Name: "add",
Usage: "add a new template", Usage: "add a new template",
@ -431,7 +431,7 @@ E.g.
```go ```go
... ...
app.Commands = []cli.Command{ app.Commands = []*cli.Command{
{ {
Name: "noop", Name: "noop",
}, },
@ -479,7 +479,7 @@ import (
func main() { func main() {
app := cli.NewApp() app := cli.NewApp()
app.Flags = []cli.Flag{ app.Flags = []cli.Flag{
cli.BoolFlag{ &cli.BoolFlag{
Name: "ginger-crouton", Name: "ginger-crouton",
Value: true, Value: true,
Usage: "is it in the soup?", Usage: "is it in the soup?",
@ -508,7 +508,7 @@ the App or its subcommands.
var tasks = []string{"cook", "clean", "laundry", "eat", "sleep", "code"} var tasks = []string{"cook", "clean", "laundry", "eat", "sleep", "code"}
app := cli.NewApp() app := cli.NewApp()
app.EnableBashCompletion = true app.EnableBashCompletion = true
app.Commands = []cli.Command{ app.Commands = []*cli.Command{
{ {
Name: "complete", Name: "complete",
Aliases: []string{"c"}, Aliases: []string{"c"},

@ -62,15 +62,15 @@ func InitInputSourceWithContext(flags []cli.Flag, createInputSource func(context
} }
} }
// GenericFlag is the flag type that wraps cli.GenericFlag to allow // GenericFlag is the flag type that wraps *cli.GenericFlag to allow
// for other values to be specified // for other values to be specified
type GenericFlag struct { type GenericFlag struct {
cli.GenericFlag *cli.GenericFlag
set *flag.FlagSet set *flag.FlagSet
} }
// NewGenericFlag creates a new GenericFlag // NewGenericFlag creates a new GenericFlag
func NewGenericFlag(flag cli.GenericFlag) *GenericFlag { func NewGenericFlag(flag *cli.GenericFlag) *GenericFlag {
return &GenericFlag{GenericFlag: flag, set: nil} return &GenericFlag{GenericFlag: flag, set: nil}
} }
@ -100,15 +100,15 @@ func (f *GenericFlag) Apply(set *flag.FlagSet) {
f.GenericFlag.Apply(set) f.GenericFlag.Apply(set)
} }
// StringSliceFlag is the flag type that wraps cli.StringSliceFlag to allow // StringSliceFlag is the flag type that wraps *cli.StringSliceFlag to allow
// for other values to be specified // for other values to be specified
type StringSliceFlag struct { type StringSliceFlag struct {
cli.StringSliceFlag *cli.StringSliceFlag
set *flag.FlagSet set *flag.FlagSet
} }
// NewStringSliceFlag creates a new StringSliceFlag // NewStringSliceFlag creates a new StringSliceFlag
func NewStringSliceFlag(flag cli.StringSliceFlag) *StringSliceFlag { func NewStringSliceFlag(flag *cli.StringSliceFlag) *StringSliceFlag {
return &StringSliceFlag{StringSliceFlag: flag, set: nil} return &StringSliceFlag{StringSliceFlag: flag, set: nil}
} }
@ -141,15 +141,15 @@ func (f *StringSliceFlag) Apply(set *flag.FlagSet) {
f.StringSliceFlag.Apply(set) f.StringSliceFlag.Apply(set)
} }
// IntSliceFlag is the flag type that wraps cli.IntSliceFlag to allow // IntSliceFlag is the flag type that wraps *cli.IntSliceFlag to allow
// for other values to be specified // for other values to be specified
type IntSliceFlag struct { type IntSliceFlag struct {
cli.IntSliceFlag *cli.IntSliceFlag
set *flag.FlagSet set *flag.FlagSet
} }
// NewIntSliceFlag creates a new IntSliceFlag // NewIntSliceFlag creates a new IntSliceFlag
func NewIntSliceFlag(flag cli.IntSliceFlag) *IntSliceFlag { func NewIntSliceFlag(flag *cli.IntSliceFlag) *IntSliceFlag {
return &IntSliceFlag{IntSliceFlag: flag, set: nil} return &IntSliceFlag{IntSliceFlag: flag, set: nil}
} }
@ -182,15 +182,15 @@ func (f *IntSliceFlag) Apply(set *flag.FlagSet) {
f.IntSliceFlag.Apply(set) f.IntSliceFlag.Apply(set)
} }
// BoolFlag is the flag type that wraps cli.BoolFlag to allow // BoolFlag is the flag type that wraps *cli.BoolFlag to allow
// for other values to be specified // for other values to be specified
type BoolFlag struct { type BoolFlag struct {
cli.BoolFlag *cli.BoolFlag
set *flag.FlagSet set *flag.FlagSet
} }
// NewBoolFlag creates a new BoolFlag // NewBoolFlag creates a new BoolFlag
func NewBoolFlag(flag cli.BoolFlag) *BoolFlag { func NewBoolFlag(flag *cli.BoolFlag) *BoolFlag {
return &BoolFlag{BoolFlag: flag, set: nil} return &BoolFlag{BoolFlag: flag, set: nil}
} }
@ -219,15 +219,15 @@ func (f *BoolFlag) Apply(set *flag.FlagSet) {
f.BoolFlag.Apply(set) f.BoolFlag.Apply(set)
} }
// StringFlag is the flag type that wraps cli.StringFlag to allow // StringFlag is the flag type that wraps *cli.StringFlag to allow
// for other values to be specified // for other values to be specified
type StringFlag struct { type StringFlag struct {
cli.StringFlag *cli.StringFlag
set *flag.FlagSet set *flag.FlagSet
} }
// NewStringFlag creates a new StringFlag // NewStringFlag creates a new StringFlag
func NewStringFlag(flag cli.StringFlag) *StringFlag { func NewStringFlag(flag *cli.StringFlag) *StringFlag {
return &StringFlag{StringFlag: flag, set: nil} return &StringFlag{StringFlag: flag, set: nil}
} }
@ -257,15 +257,15 @@ func (f *StringFlag) Apply(set *flag.FlagSet) {
f.StringFlag.Apply(set) f.StringFlag.Apply(set)
} }
// IntFlag is the flag type that wraps cli.IntFlag to allow // IntFlag is the flag type that wraps *cli.IntFlag to allow
// for other values to be specified // for other values to be specified
type IntFlag struct { type IntFlag struct {
cli.IntFlag *cli.IntFlag
set *flag.FlagSet set *flag.FlagSet
} }
// NewIntFlag creates a new IntFlag // NewIntFlag creates a new IntFlag
func NewIntFlag(flag cli.IntFlag) *IntFlag { func NewIntFlag(flag *cli.IntFlag) *IntFlag {
return &IntFlag{IntFlag: flag, set: nil} return &IntFlag{IntFlag: flag, set: nil}
} }
@ -294,15 +294,15 @@ func (f *IntFlag) Apply(set *flag.FlagSet) {
f.IntFlag.Apply(set) f.IntFlag.Apply(set)
} }
// DurationFlag is the flag type that wraps cli.DurationFlag to allow // DurationFlag is the flag type that wraps *cli.DurationFlag to allow
// for other values to be specified // for other values to be specified
type DurationFlag struct { type DurationFlag struct {
cli.DurationFlag *cli.DurationFlag
set *flag.FlagSet set *flag.FlagSet
} }
// NewDurationFlag creates a new DurationFlag // NewDurationFlag creates a new DurationFlag
func NewDurationFlag(flag cli.DurationFlag) *DurationFlag { func NewDurationFlag(flag *cli.DurationFlag) *DurationFlag {
return &DurationFlag{DurationFlag: flag, set: nil} return &DurationFlag{DurationFlag: flag, set: nil}
} }
@ -332,15 +332,15 @@ func (f *DurationFlag) Apply(set *flag.FlagSet) {
f.DurationFlag.Apply(set) f.DurationFlag.Apply(set)
} }
// Float64Flag is the flag type that wraps cli.Float64Flag to allow // Float64Flag is the flag type that wraps *cli.Float64Flag to allow
// for other values to be specified // for other values to be specified
type Float64Flag struct { type Float64Flag struct {
cli.Float64Flag *cli.Float64Flag
set *flag.FlagSet set *flag.FlagSet
} }
// NewFloat64Flag creates a new Float64Flag // NewFloat64Flag creates a new Float64Flag
func NewFloat64Flag(flag cli.Float64Flag) *Float64Flag { func NewFloat64Flag(flag *cli.Float64Flag) *Float64Flag {
return &Float64Flag{Float64Flag: flag, set: nil} return &Float64Flag{Float64Flag: flag, set: nil}
} }

@ -26,7 +26,7 @@ type testApplyInputSource struct {
func TestGenericApplyInputSourceValue(t *testing.T) { func TestGenericApplyInputSourceValue(t *testing.T) {
v := &Parser{"abc", "def"} v := &Parser{"abc", "def"}
c := runTest(t, testApplyInputSource{ c := runTest(t, testApplyInputSource{
Flag: NewGenericFlag(cli.GenericFlag{Name: "test", Value: &Parser{}}), Flag: NewGenericFlag(&cli.GenericFlag{Name: "test", Value: &Parser{}}),
FlagName: "test", FlagName: "test",
MapValue: v, MapValue: v,
}) })
@ -36,7 +36,7 @@ func TestGenericApplyInputSourceValue(t *testing.T) {
func TestGenericApplyInputSourceMethodContextSet(t *testing.T) { func TestGenericApplyInputSourceMethodContextSet(t *testing.T) {
p := &Parser{"abc", "def"} p := &Parser{"abc", "def"}
c := runTest(t, testApplyInputSource{ c := runTest(t, testApplyInputSource{
Flag: NewGenericFlag(cli.GenericFlag{Name: "test", Value: &Parser{}}), Flag: NewGenericFlag(&cli.GenericFlag{Name: "test", Value: &Parser{}}),
FlagName: "test", FlagName: "test",
MapValue: &Parser{"efg", "hig"}, MapValue: &Parser{"efg", "hig"},
ContextValueString: p.String(), ContextValueString: p.String(),
@ -46,7 +46,7 @@ func TestGenericApplyInputSourceMethodContextSet(t *testing.T) {
func TestGenericApplyInputSourceMethodEnvVarSet(t *testing.T) { func TestGenericApplyInputSourceMethodEnvVarSet(t *testing.T) {
c := runTest(t, testApplyInputSource{ c := runTest(t, testApplyInputSource{
Flag: NewGenericFlag(cli.GenericFlag{ Flag: NewGenericFlag(&cli.GenericFlag{
Name: "test", Name: "test",
Value: &Parser{}, Value: &Parser{},
EnvVars: []string{"TEST"}, EnvVars: []string{"TEST"},
@ -61,7 +61,7 @@ func TestGenericApplyInputSourceMethodEnvVarSet(t *testing.T) {
func TestStringSliceApplyInputSourceValue(t *testing.T) { func TestStringSliceApplyInputSourceValue(t *testing.T) {
c := runTest(t, testApplyInputSource{ c := runTest(t, testApplyInputSource{
Flag: NewStringSliceFlag(cli.StringSliceFlag{Name: "test"}), Flag: NewStringSliceFlag(&cli.StringSliceFlag{Name: "test"}),
FlagName: "test", FlagName: "test",
MapValue: []string{"hello", "world"}, MapValue: []string{"hello", "world"},
}) })
@ -70,7 +70,7 @@ func TestStringSliceApplyInputSourceValue(t *testing.T) {
func TestStringSliceApplyInputSourceMethodContextSet(t *testing.T) { func TestStringSliceApplyInputSourceMethodContextSet(t *testing.T) {
c := runTest(t, testApplyInputSource{ c := runTest(t, testApplyInputSource{
Flag: NewStringSliceFlag(cli.StringSliceFlag{Name: "test"}), Flag: NewStringSliceFlag(&cli.StringSliceFlag{Name: "test"}),
FlagName: "test", FlagName: "test",
MapValue: []string{"hello", "world"}, MapValue: []string{"hello", "world"},
ContextValueString: "ohno", ContextValueString: "ohno",
@ -80,7 +80,7 @@ func TestStringSliceApplyInputSourceMethodContextSet(t *testing.T) {
func TestStringSliceApplyInputSourceMethodEnvVarSet(t *testing.T) { func TestStringSliceApplyInputSourceMethodEnvVarSet(t *testing.T) {
c := runTest(t, testApplyInputSource{ c := runTest(t, testApplyInputSource{
Flag: NewStringSliceFlag(cli.StringSliceFlag{Name: "test", EnvVars: []string{"TEST"}}), Flag: NewStringSliceFlag(&cli.StringSliceFlag{Name: "test", EnvVars: []string{"TEST"}}),
FlagName: "test", FlagName: "test",
MapValue: []string{"hello", "world"}, MapValue: []string{"hello", "world"},
EnvVarName: "TEST", EnvVarName: "TEST",
@ -91,7 +91,7 @@ func TestStringSliceApplyInputSourceMethodEnvVarSet(t *testing.T) {
func TestIntSliceApplyInputSourceValue(t *testing.T) { func TestIntSliceApplyInputSourceValue(t *testing.T) {
c := runTest(t, testApplyInputSource{ c := runTest(t, testApplyInputSource{
Flag: NewIntSliceFlag(cli.IntSliceFlag{Name: "test"}), Flag: NewIntSliceFlag(&cli.IntSliceFlag{Name: "test"}),
FlagName: "test", FlagName: "test",
MapValue: []int{1, 2}, MapValue: []int{1, 2},
}) })
@ -100,7 +100,7 @@ func TestIntSliceApplyInputSourceValue(t *testing.T) {
func TestIntSliceApplyInputSourceMethodContextSet(t *testing.T) { func TestIntSliceApplyInputSourceMethodContextSet(t *testing.T) {
c := runTest(t, testApplyInputSource{ c := runTest(t, testApplyInputSource{
Flag: NewIntSliceFlag(cli.IntSliceFlag{Name: "test"}), Flag: NewIntSliceFlag(&cli.IntSliceFlag{Name: "test"}),
FlagName: "test", FlagName: "test",
MapValue: []int{1, 2}, MapValue: []int{1, 2},
ContextValueString: "3", ContextValueString: "3",
@ -110,7 +110,7 @@ func TestIntSliceApplyInputSourceMethodContextSet(t *testing.T) {
func TestIntSliceApplyInputSourceMethodEnvVarSet(t *testing.T) { func TestIntSliceApplyInputSourceMethodEnvVarSet(t *testing.T) {
c := runTest(t, testApplyInputSource{ c := runTest(t, testApplyInputSource{
Flag: NewIntSliceFlag(cli.IntSliceFlag{Name: "test", EnvVars: []string{"TEST"}}), Flag: NewIntSliceFlag(&cli.IntSliceFlag{Name: "test", EnvVars: []string{"TEST"}}),
FlagName: "test", FlagName: "test",
MapValue: []int{1, 2}, MapValue: []int{1, 2},
EnvVarName: "TEST", EnvVarName: "TEST",
@ -121,7 +121,7 @@ func TestIntSliceApplyInputSourceMethodEnvVarSet(t *testing.T) {
func TestBoolApplyInputSourceMethodSet(t *testing.T) { func TestBoolApplyInputSourceMethodSet(t *testing.T) {
c := runTest(t, testApplyInputSource{ c := runTest(t, testApplyInputSource{
Flag: NewBoolFlag(cli.BoolFlag{Name: "test"}), Flag: NewBoolFlag(&cli.BoolFlag{Name: "test"}),
FlagName: "test", FlagName: "test",
MapValue: true, MapValue: true,
}) })
@ -130,7 +130,7 @@ func TestBoolApplyInputSourceMethodSet(t *testing.T) {
func TestBoolApplyInputSourceMethodContextSet(t *testing.T) { func TestBoolApplyInputSourceMethodContextSet(t *testing.T) {
c := runTest(t, testApplyInputSource{ c := runTest(t, testApplyInputSource{
Flag: NewBoolFlag(cli.BoolFlag{Name: "test"}), Flag: NewBoolFlag(&cli.BoolFlag{Name: "test"}),
FlagName: "test", FlagName: "test",
MapValue: false, MapValue: false,
ContextValueString: "true", ContextValueString: "true",
@ -140,7 +140,7 @@ func TestBoolApplyInputSourceMethodContextSet(t *testing.T) {
func TestBoolApplyInputSourceMethodEnvVarSet(t *testing.T) { func TestBoolApplyInputSourceMethodEnvVarSet(t *testing.T) {
c := runTest(t, testApplyInputSource{ c := runTest(t, testApplyInputSource{
Flag: NewBoolFlag(cli.BoolFlag{Name: "test", EnvVars: []string{"TEST"}}), Flag: NewBoolFlag(&cli.BoolFlag{Name: "test", EnvVars: []string{"TEST"}}),
FlagName: "test", FlagName: "test",
MapValue: false, MapValue: false,
EnvVarName: "TEST", EnvVarName: "TEST",
@ -151,7 +151,7 @@ func TestBoolApplyInputSourceMethodEnvVarSet(t *testing.T) {
func TestStringApplyInputSourceMethodSet(t *testing.T) { func TestStringApplyInputSourceMethodSet(t *testing.T) {
c := runTest(t, testApplyInputSource{ c := runTest(t, testApplyInputSource{
Flag: NewStringFlag(cli.StringFlag{Name: "test"}), Flag: NewStringFlag(&cli.StringFlag{Name: "test"}),
FlagName: "test", FlagName: "test",
MapValue: "hello", MapValue: "hello",
}) })
@ -160,7 +160,7 @@ func TestStringApplyInputSourceMethodSet(t *testing.T) {
func TestStringApplyInputSourceMethodContextSet(t *testing.T) { func TestStringApplyInputSourceMethodContextSet(t *testing.T) {
c := runTest(t, testApplyInputSource{ c := runTest(t, testApplyInputSource{
Flag: NewStringFlag(cli.StringFlag{Name: "test"}), Flag: NewStringFlag(&cli.StringFlag{Name: "test"}),
FlagName: "test", FlagName: "test",
MapValue: "hello", MapValue: "hello",
ContextValueString: "goodbye", ContextValueString: "goodbye",
@ -170,7 +170,7 @@ func TestStringApplyInputSourceMethodContextSet(t *testing.T) {
func TestStringApplyInputSourceMethodEnvVarSet(t *testing.T) { func TestStringApplyInputSourceMethodEnvVarSet(t *testing.T) {
c := runTest(t, testApplyInputSource{ c := runTest(t, testApplyInputSource{
Flag: NewStringFlag(cli.StringFlag{Name: "test", EnvVars: []string{"TEST"}}), Flag: NewStringFlag(&cli.StringFlag{Name: "test", EnvVars: []string{"TEST"}}),
FlagName: "test", FlagName: "test",
MapValue: "hello", MapValue: "hello",
EnvVarName: "TEST", EnvVarName: "TEST",
@ -181,7 +181,7 @@ func TestStringApplyInputSourceMethodEnvVarSet(t *testing.T) {
func TestIntApplyInputSourceMethodSet(t *testing.T) { func TestIntApplyInputSourceMethodSet(t *testing.T) {
c := runTest(t, testApplyInputSource{ c := runTest(t, testApplyInputSource{
Flag: NewIntFlag(cli.IntFlag{Name: "test"}), Flag: NewIntFlag(&cli.IntFlag{Name: "test"}),
FlagName: "test", FlagName: "test",
MapValue: 15, MapValue: 15,
}) })
@ -190,7 +190,7 @@ func TestIntApplyInputSourceMethodSet(t *testing.T) {
func TestIntApplyInputSourceMethodContextSet(t *testing.T) { func TestIntApplyInputSourceMethodContextSet(t *testing.T) {
c := runTest(t, testApplyInputSource{ c := runTest(t, testApplyInputSource{
Flag: NewIntFlag(cli.IntFlag{Name: "test"}), Flag: NewIntFlag(&cli.IntFlag{Name: "test"}),
FlagName: "test", FlagName: "test",
MapValue: 15, MapValue: 15,
ContextValueString: "7", ContextValueString: "7",
@ -200,7 +200,7 @@ func TestIntApplyInputSourceMethodContextSet(t *testing.T) {
func TestIntApplyInputSourceMethodEnvVarSet(t *testing.T) { func TestIntApplyInputSourceMethodEnvVarSet(t *testing.T) {
c := runTest(t, testApplyInputSource{ c := runTest(t, testApplyInputSource{
Flag: NewIntFlag(cli.IntFlag{Name: "test", EnvVars: []string{"TEST"}}), Flag: NewIntFlag(&cli.IntFlag{Name: "test", EnvVars: []string{"TEST"}}),
FlagName: "test", FlagName: "test",
MapValue: 15, MapValue: 15,
EnvVarName: "TEST", EnvVarName: "TEST",
@ -211,7 +211,7 @@ func TestIntApplyInputSourceMethodEnvVarSet(t *testing.T) {
func TestDurationApplyInputSourceMethodSet(t *testing.T) { func TestDurationApplyInputSourceMethodSet(t *testing.T) {
c := runTest(t, testApplyInputSource{ c := runTest(t, testApplyInputSource{
Flag: NewDurationFlag(cli.DurationFlag{Name: "test"}), Flag: NewDurationFlag(&cli.DurationFlag{Name: "test"}),
FlagName: "test", FlagName: "test",
MapValue: time.Duration(30 * time.Second), MapValue: time.Duration(30 * time.Second),
}) })
@ -220,7 +220,7 @@ func TestDurationApplyInputSourceMethodSet(t *testing.T) {
func TestDurationApplyInputSourceMethodContextSet(t *testing.T) { func TestDurationApplyInputSourceMethodContextSet(t *testing.T) {
c := runTest(t, testApplyInputSource{ c := runTest(t, testApplyInputSource{
Flag: NewDurationFlag(cli.DurationFlag{Name: "test"}), Flag: NewDurationFlag(&cli.DurationFlag{Name: "test"}),
FlagName: "test", FlagName: "test",
MapValue: time.Duration(30 * time.Second), MapValue: time.Duration(30 * time.Second),
ContextValueString: time.Duration(15 * time.Second).String(), ContextValueString: time.Duration(15 * time.Second).String(),
@ -230,7 +230,7 @@ func TestDurationApplyInputSourceMethodContextSet(t *testing.T) {
func TestDurationApplyInputSourceMethodEnvVarSet(t *testing.T) { func TestDurationApplyInputSourceMethodEnvVarSet(t *testing.T) {
c := runTest(t, testApplyInputSource{ c := runTest(t, testApplyInputSource{
Flag: NewDurationFlag(cli.DurationFlag{Name: "test", EnvVars: []string{"TEST"}}), Flag: NewDurationFlag(&cli.DurationFlag{Name: "test", EnvVars: []string{"TEST"}}),
FlagName: "test", FlagName: "test",
MapValue: time.Duration(30 * time.Second), MapValue: time.Duration(30 * time.Second),
EnvVarName: "TEST", EnvVarName: "TEST",
@ -241,7 +241,7 @@ func TestDurationApplyInputSourceMethodEnvVarSet(t *testing.T) {
func TestFloat64ApplyInputSourceMethodSet(t *testing.T) { func TestFloat64ApplyInputSourceMethodSet(t *testing.T) {
c := runTest(t, testApplyInputSource{ c := runTest(t, testApplyInputSource{
Flag: NewFloat64Flag(cli.Float64Flag{Name: "test"}), Flag: NewFloat64Flag(&cli.Float64Flag{Name: "test"}),
FlagName: "test", FlagName: "test",
MapValue: 1.3, MapValue: 1.3,
}) })
@ -250,7 +250,7 @@ func TestFloat64ApplyInputSourceMethodSet(t *testing.T) {
func TestFloat64ApplyInputSourceMethodContextSet(t *testing.T) { func TestFloat64ApplyInputSourceMethodContextSet(t *testing.T) {
c := runTest(t, testApplyInputSource{ c := runTest(t, testApplyInputSource{
Flag: NewFloat64Flag(cli.Float64Flag{Name: "test"}), Flag: NewFloat64Flag(&cli.Float64Flag{Name: "test"}),
FlagName: "test", FlagName: "test",
MapValue: 1.3, MapValue: 1.3,
ContextValueString: fmt.Sprintf("%v", 1.4), ContextValueString: fmt.Sprintf("%v", 1.4),
@ -260,7 +260,7 @@ func TestFloat64ApplyInputSourceMethodContextSet(t *testing.T) {
func TestFloat64ApplyInputSourceMethodEnvVarSet(t *testing.T) { func TestFloat64ApplyInputSourceMethodEnvVarSet(t *testing.T) {
c := runTest(t, testApplyInputSource{ c := runTest(t, testApplyInputSource{
Flag: NewFloat64Flag(cli.Float64Flag{Name: "test", EnvVars: []string{"TEST"}}), Flag: NewFloat64Flag(&cli.Float64Flag{Name: "test", EnvVars: []string{"TEST"}}),
FlagName: "test", FlagName: "test",
MapValue: 1.3, MapValue: 1.3,
EnvVarName: "TEST", EnvVarName: "TEST",

@ -35,8 +35,8 @@ func TestCommandYamlFileTest(t *testing.T) {
return nil return nil
}, },
Flags: []cli.Flag{ Flags: []cli.Flag{
NewIntFlag(cli.IntFlag{Name: "test"}), NewIntFlag(&cli.IntFlag{Name: "test"}),
cli.StringFlag{Name: "load"}}, &cli.StringFlag{Name: "load"}},
} }
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load")) command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
err := command.Run(c) err := command.Run(c)
@ -68,8 +68,8 @@ func TestCommandYamlFileTestGlobalEnvVarWins(t *testing.T) {
return nil return nil
}, },
Flags: []cli.Flag{ Flags: []cli.Flag{
NewIntFlag(cli.IntFlag{Name: "test", EnvVars: []string{"THE_TEST"}}), NewIntFlag(&cli.IntFlag{Name: "test", EnvVars: []string{"THE_TEST"}}),
cli.StringFlag{Name: "load"}}, &cli.StringFlag{Name: "load"}},
} }
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load")) command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
@ -103,8 +103,8 @@ func TestCommandYamlFileTestGlobalEnvVarWinsNested(t *testing.T) {
return nil return nil
}, },
Flags: []cli.Flag{ Flags: []cli.Flag{
NewIntFlag(cli.IntFlag{Name: "top.test", EnvVars: []string{"THE_TEST"}}), NewIntFlag(&cli.IntFlag{Name: "top.test", EnvVars: []string{"THE_TEST"}}),
cli.StringFlag{Name: "load"}}, &cli.StringFlag{Name: "load"}},
} }
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load")) command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
@ -135,8 +135,8 @@ func TestCommandYamlFileTestSpecifiedFlagWins(t *testing.T) {
return nil return nil
}, },
Flags: []cli.Flag{ Flags: []cli.Flag{
NewIntFlag(cli.IntFlag{Name: "test"}), NewIntFlag(&cli.IntFlag{Name: "test"}),
cli.StringFlag{Name: "load"}}, &cli.StringFlag{Name: "load"}},
} }
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load")) command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
@ -168,8 +168,8 @@ func TestCommandYamlFileTestSpecifiedFlagWinsNested(t *testing.T) {
return nil return nil
}, },
Flags: []cli.Flag{ Flags: []cli.Flag{
NewIntFlag(cli.IntFlag{Name: "top.test"}), NewIntFlag(&cli.IntFlag{Name: "top.test"}),
cli.StringFlag{Name: "load"}}, &cli.StringFlag{Name: "load"}},
} }
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load")) command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
@ -200,8 +200,8 @@ func TestCommandYamlFileTestDefaultValueFileWins(t *testing.T) {
return nil return nil
}, },
Flags: []cli.Flag{ Flags: []cli.Flag{
NewIntFlag(cli.IntFlag{Name: "test", Value: 7}), NewIntFlag(&cli.IntFlag{Name: "test", Value: 7}),
cli.StringFlag{Name: "load"}}, &cli.StringFlag{Name: "load"}},
} }
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load")) command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
@ -233,8 +233,8 @@ func TestCommandYamlFileTestDefaultValueFileWinsNested(t *testing.T) {
return nil return nil
}, },
Flags: []cli.Flag{ Flags: []cli.Flag{
NewIntFlag(cli.IntFlag{Name: "top.test", Value: 7}), NewIntFlag(&cli.IntFlag{Name: "top.test", Value: 7}),
cli.StringFlag{Name: "load"}}, &cli.StringFlag{Name: "load"}},
} }
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load")) command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
@ -268,8 +268,8 @@ func TestCommandYamlFileFlagHasDefaultGlobalEnvYamlSetGlobalEnvWins(t *testing.T
return nil return nil
}, },
Flags: []cli.Flag{ Flags: []cli.Flag{
NewIntFlag(cli.IntFlag{Name: "test", Value: 7, EnvVars: []string{"THE_TEST"}}), NewIntFlag(&cli.IntFlag{Name: "test", Value: 7, EnvVars: []string{"THE_TEST"}}),
cli.StringFlag{Name: "load"}}, &cli.StringFlag{Name: "load"}},
} }
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load")) command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
err := command.Run(c) err := command.Run(c)
@ -303,8 +303,8 @@ func TestCommandYamlFileFlagHasDefaultGlobalEnvYamlSetGlobalEnvWinsNested(t *tes
return nil return nil
}, },
Flags: []cli.Flag{ Flags: []cli.Flag{
NewIntFlag(cli.IntFlag{Name: "top.test", Value: 7, EnvVars: []string{"THE_TEST"}}), NewIntFlag(&cli.IntFlag{Name: "top.test", Value: 7, EnvVars: []string{"THE_TEST"}}),
cli.StringFlag{Name: "load"}}, &cli.StringFlag{Name: "load"}},
} }
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load")) command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
err := command.Run(c) err := command.Run(c)

@ -27,7 +27,7 @@ type App struct {
// Version of the program // Version of the program
Version string Version string
// List of commands to execute // List of commands to execute
Commands []Command Commands []*Command
// List of flags to parse // List of flags to parse
Flags []Flag Flags []Flag
// Boolean to enable bash completion commands // Boolean to enable bash completion commands
@ -37,7 +37,7 @@ type App struct {
// Boolean to hide built-in version flag and the VERSION section of help // Boolean to hide built-in version flag and the VERSION section of help
HideVersion bool HideVersion bool
// Populate on app startup, only gettable through method Categories() // Populate on app startup, only gettable through method Categories()
categories CommandCategories categories *CommandCategories
// An action to execute when the bash-completion flag is set // An action to execute when the bash-completion flag is set
BashComplete BashCompleteFunc BashComplete BashCompleteFunc
// An action to execute before any subcommands are run, but after the context is ready // An action to execute before any subcommands are run, but after the context is ready
@ -55,7 +55,7 @@ type App struct {
// Compilation date // Compilation date
Compiled time.Time Compiled time.Time
// List of all authors who contributed // List of all authors who contributed
Authors []Author Authors []*Author
// Copyright of the binary if any // Copyright of the binary if any
Copyright string Copyright string
// Writer writer to write output to // Writer writer to write output to
@ -104,7 +104,7 @@ func (a *App) Setup() {
a.didSetup = true a.didSetup = true
newCmds := []Command{} newCmds := []*Command{}
for _, c := range a.Commands { for _, c := range a.Commands {
if c.HelpName == "" { if c.HelpName == "" {
c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name) c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name)
@ -113,7 +113,7 @@ func (a *App) Setup() {
} }
a.Commands = newCmds a.Commands = newCmds
a.categories = CommandCategories{} a.categories = NewCommandCategories()
for _, command := range a.Commands { for _, command := range a.Commands {
a.categories = a.categories.AddCommand(command.Category, command) a.categories = a.categories.AddCommand(command.Category, command)
} }
@ -121,8 +121,9 @@ func (a *App) Setup() {
// append help to commands // append help to commands
if a.Command(helpCommand.Name) == nil && !a.HideHelp { if a.Command(helpCommand.Name) == nil && !a.HideHelp {
a.Commands = append(a.Commands, helpCommand) a.appendCommand(helpCommand)
if !reflect.DeepEqual(HelpFlag, BoolFlag{}) {
if HelpFlag != nil {
a.appendFlag(HelpFlag) a.appendFlag(HelpFlag)
} }
} }
@ -224,14 +225,15 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) {
// append help to commands // append help to commands
if len(a.Commands) > 0 { if len(a.Commands) > 0 {
if a.Command(helpCommand.Name) == nil && !a.HideHelp { if a.Command(helpCommand.Name) == nil && !a.HideHelp {
a.Commands = append(a.Commands, helpCommand) a.appendCommand(helpCommand)
if !reflect.DeepEqual(HelpFlag, BoolFlag{}) {
if HelpFlag != nil {
a.appendFlag(HelpFlag) a.appendFlag(HelpFlag)
} }
} }
} }
newCmds := []Command{} newCmds := []*Command{}
for _, c := range a.Commands { for _, c := range a.Commands {
if c.HelpName == "" { if c.HelpName == "" {
c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name) c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name)
@ -331,7 +333,7 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) {
func (a *App) Command(name string) *Command { func (a *App) Command(name string) *Command {
for _, c := range a.Commands { for _, c := range a.Commands {
if c.HasName(name) { if c.HasName(name) {
return &c return c
} }
} }
@ -339,7 +341,7 @@ func (a *App) Command(name string) *Command {
} }
// Categories returns a slice containing all the categories with the commands they contain // Categories returns a slice containing all the categories with the commands they contain
func (a *App) Categories() CommandCategories { func (a *App) Categories() *CommandCategories {
return a.categories return a.categories
} }
@ -347,7 +349,7 @@ func (a *App) Categories() CommandCategories {
// Hidden=false // Hidden=false
func (a *App) VisibleCategories() []*CommandCategory { func (a *App) VisibleCategories() []*CommandCategory {
ret := []*CommandCategory{} ret := []*CommandCategory{}
for _, category := range a.categories { for _, category := range a.categories.Categories {
if visible := func() *CommandCategory { if visible := func() *CommandCategory {
for _, command := range category.Commands { for _, command := range category.Commands {
if !command.Hidden { if !command.Hidden {
@ -363,8 +365,8 @@ func (a *App) VisibleCategories() []*CommandCategory {
} }
// VisibleCommands returns a slice of the Commands with Hidden=false // VisibleCommands returns a slice of the Commands with Hidden=false
func (a *App) VisibleCommands() []Command { func (a *App) VisibleCommands() []*Command {
ret := []Command{} ret := []*Command{}
for _, command := range a.Commands { for _, command := range a.Commands {
if !command.Hidden { if !command.Hidden {
ret = append(ret, command) ret = append(ret, command)
@ -398,9 +400,15 @@ func (a *App) errWriter() io.Writer {
return a.ErrWriter return a.ErrWriter
} }
func (a *App) appendFlag(flag Flag) { func (a *App) appendFlag(fl Flag) {
if !a.hasFlag(flag) { if !hasFlag(a.Flags, fl) {
a.Flags = append(a.Flags, flag) a.Flags = append(a.Flags, fl)
}
}
func (a *App) appendCommand(c *Command) {
if !hasCommand(a.Commands, c) {
a.Commands = append(a.Commands, c)
} }
} }
@ -411,7 +419,7 @@ type Author struct {
} }
// String makes Author comply to the Stringer interface, to allow an easy print in the templating process // String makes Author comply to the Stringer interface, to allow an easy print in the templating process
func (a Author) String() string { func (a *Author) String() string {
e := "" e := ""
if a.Email != "" { if a.Email != "" {
e = "<" + a.Email + "> " e = "<" + a.Email + "> "

@ -24,14 +24,14 @@ func ExampleApp_Run() {
app := NewApp() app := NewApp()
app.Name = "greet" app.Name = "greet"
app.Flags = []Flag{ app.Flags = []Flag{
StringFlag{Name: "name", Value: "bob", Usage: "a name to say"}, &StringFlag{Name: "name", Value: "bob", Usage: "a name to say"},
} }
app.Action = func(c *Context) error { app.Action = func(c *Context) error {
fmt.Printf("Hello %v\n", c.String("name")) fmt.Printf("Hello %v\n", c.String("name"))
return nil return nil
} }
app.UsageText = "app [first_arg] [second_arg]" app.UsageText = "app [first_arg] [second_arg]"
app.Authors = []Author{{Name: "Oliver Allen", Email: "oliver@toyshop.example.com"}} app.Authors = []*Author{{Name: "Oliver Allen", Email: "oliver@toyshop.example.com"}}
app.Run(os.Args) app.Run(os.Args)
// Output: // Output:
// Hello Jeremy // Hello Jeremy
@ -42,20 +42,20 @@ func ExampleApp_Run_subcommand() {
os.Args = []string{"say", "hi", "english", "--name", "Jeremy"} os.Args = []string{"say", "hi", "english", "--name", "Jeremy"}
app := NewApp() app := NewApp()
app.Name = "say" app.Name = "say"
app.Commands = []Command{ app.Commands = []*Command{
{ {
Name: "hello", Name: "hello",
Aliases: []string{"hi"}, Aliases: []string{"hi"},
Usage: "use it to see a description", Usage: "use it to see a description",
Description: "This is how we describe hello the function", Description: "This is how we describe hello the function",
Subcommands: []Command{ Subcommands: []*Command{
{ {
Name: "english", Name: "english",
Aliases: []string{"en"}, Aliases: []string{"en"},
Usage: "sends a greeting in english", Usage: "sends a greeting in english",
Description: "greets someone in english", Description: "greets someone in english",
Flags: []Flag{ Flags: []Flag{
StringFlag{ &StringFlag{
Name: "name", Name: "name",
Value: "Bob", Value: "Bob",
Usage: "Name of the person to greet", Usage: "Name of the person to greet",
@ -82,9 +82,9 @@ func ExampleApp_Run_help() {
app := NewApp() app := NewApp()
app.Name = "greet" app.Name = "greet"
app.Flags = []Flag{ app.Flags = []Flag{
StringFlag{Name: "name", Value: "bob", Usage: "a name to say"}, &StringFlag{Name: "name", Value: "bob", Usage: "a name to say"},
} }
app.Commands = []Command{ app.Commands = []*Command{
{ {
Name: "describeit", Name: "describeit",
Aliases: []string{"d"}, Aliases: []string{"d"},
@ -115,7 +115,7 @@ func ExampleApp_Run_bashComplete() {
app := NewApp() app := NewApp()
app.Name = "greet" app.Name = "greet"
app.EnableBashCompletion = true app.EnableBashCompletion = true
app.Commands = []Command{ app.Commands = []*Command{
{ {
Name: "describeit", Name: "describeit",
Aliases: []string{"d"}, Aliases: []string{"d"},
@ -175,9 +175,9 @@ var commandAppTests = []struct {
func TestApp_Command(t *testing.T) { func TestApp_Command(t *testing.T) {
app := NewApp() app := NewApp()
fooCommand := Command{Name: "foobar", Aliases: []string{"f"}} fooCommand := &Command{Name: "foobar", Aliases: []string{"f"}}
batCommand := Command{Name: "batbaz", Aliases: []string{"b"}} batCommand := &Command{Name: "batbaz", Aliases: []string{"b"}}
app.Commands = []Command{ app.Commands = []*Command{
fooCommand, fooCommand,
batCommand, batCommand,
} }
@ -191,7 +191,7 @@ func TestApp_RunAsSubcommandParseFlags(t *testing.T) {
var context *Context var context *Context
a := NewApp() a := NewApp()
a.Commands = []Command{ a.Commands = []*Command{
{ {
Name: "foo", Name: "foo",
Action: func(c *Context) error { Action: func(c *Context) error {
@ -199,7 +199,7 @@ func TestApp_RunAsSubcommandParseFlags(t *testing.T) {
return nil return nil
}, },
Flags: []Flag{ Flags: []Flag{
StringFlag{ &StringFlag{
Name: "lang", Name: "lang",
Value: "english", Value: "english",
Usage: "language for the greeting", Usage: "language for the greeting",
@ -216,13 +216,13 @@ func TestApp_RunAsSubcommandParseFlags(t *testing.T) {
func TestApp_CommandWithFlagBeforeTerminator(t *testing.T) { func TestApp_CommandWithFlagBeforeTerminator(t *testing.T) {
var parsedOption string var parsedOption string
var args []string var args *Args
app := NewApp() app := NewApp()
command := Command{ command := &Command{
Name: "cmd", Name: "cmd",
Flags: []Flag{ Flags: []Flag{
StringFlag{Name: "option", Value: "", Usage: "some option"}, &StringFlag{Name: "option", Value: "", Usage: "some option"},
}, },
Action: func(c *Context) error { Action: func(c *Context) error {
parsedOption = c.String("option") parsedOption = c.String("option")
@ -230,58 +230,58 @@ func TestApp_CommandWithFlagBeforeTerminator(t *testing.T) {
return nil return nil
}, },
} }
app.Commands = []Command{command} app.Commands = []*Command{command}
app.Run([]string{"", "cmd", "--option", "my-option", "my-arg", "--", "--notARealFlag"}) app.Run([]string{"", "cmd", "--option", "my-option", "my-arg", "--", "--notARealFlag"})
expect(t, parsedOption, "my-option") expect(t, parsedOption, "my-option")
expect(t, args[0], "my-arg") expect(t, args.Get(0), "my-arg")
expect(t, args[1], "--") expect(t, args.Get(1), "--")
expect(t, args[2], "--notARealFlag") expect(t, args.Get(2), "--notARealFlag")
} }
func TestApp_CommandWithDash(t *testing.T) { func TestApp_CommandWithDash(t *testing.T) {
var args []string var args *Args
app := NewApp() app := NewApp()
command := Command{ command := &Command{
Name: "cmd", Name: "cmd",
Action: func(c *Context) error { Action: func(c *Context) error {
args = c.Args() args = c.Args()
return nil return nil
}, },
} }
app.Commands = []Command{command} app.Commands = []*Command{command}
app.Run([]string{"", "cmd", "my-arg", "-"}) app.Run([]string{"", "cmd", "my-arg", "-"})
expect(t, args[0], "my-arg") expect(t, args.Get(0), "my-arg")
expect(t, args[1], "-") expect(t, args.Get(1), "-")
} }
func TestApp_CommandWithNoFlagBeforeTerminator(t *testing.T) { func TestApp_CommandWithNoFlagBeforeTerminator(t *testing.T) {
var args []string var args *Args
app := NewApp() app := NewApp()
command := Command{ command := &Command{
Name: "cmd", Name: "cmd",
Action: func(c *Context) error { Action: func(c *Context) error {
args = c.Args() args = c.Args()
return nil return nil
}, },
} }
app.Commands = []Command{command} app.Commands = []*Command{command}
app.Run([]string{"", "cmd", "my-arg", "--", "notAFlagAtAll"}) app.Run([]string{"", "cmd", "my-arg", "--", "notAFlagAtAll"})
expect(t, args[0], "my-arg") expect(t, args.Get(0), "my-arg")
expect(t, args[1], "--") expect(t, args.Get(1), "--")
expect(t, args[2], "notAFlagAtAll") expect(t, args.Get(2), "notAFlagAtAll")
} }
func TestApp_VisibleCommands(t *testing.T) { func TestApp_VisibleCommands(t *testing.T) {
app := NewApp() app := NewApp()
app.Commands = []Command{ app.Commands = []*Command{
{ {
Name: "frob", Name: "frob",
HelpName: "foo frob", HelpName: "foo frob",
@ -296,7 +296,7 @@ func TestApp_VisibleCommands(t *testing.T) {
} }
app.Setup() app.Setup()
expected := []Command{ expected := []*Command{
app.Commands[0], app.Commands[0],
app.Commands[2], // help app.Commands[2], // help
} }
@ -310,14 +310,22 @@ func TestApp_VisibleCommands(t *testing.T) {
expect(t, fmt.Sprintf("%p", expectedCommand.Action), fmt.Sprintf("%p", actualCommand.Action)) expect(t, fmt.Sprintf("%p", expectedCommand.Action), fmt.Sprintf("%p", actualCommand.Action))
} }
// nil out funcs, as they cannot be compared func() {
// (https://github.com/golang/go/issues/8554) // nil out funcs, as they cannot be compared
expectedCommand.Action = nil // (https://github.com/golang/go/issues/8554)
actualCommand.Action = nil expectedAction := expectedCommand.Action
actualAction := actualCommand.Action
if !reflect.DeepEqual(expectedCommand, actualCommand) { defer func() {
t.Errorf("expected\n%#v\n!=\n%#v", expectedCommand, actualCommand) expectedCommand.Action = expectedAction
} actualCommand.Action = actualAction
}()
expectedCommand.Action = nil
actualCommand.Action = nil
if !reflect.DeepEqual(expectedCommand, actualCommand) {
t.Errorf("expected\n%#v\n!=\n%#v", expectedCommand, actualCommand)
}
}()
} }
} }
@ -326,7 +334,7 @@ func TestApp_Float64Flag(t *testing.T) {
app := NewApp() app := NewApp()
app.Flags = []Flag{ app.Flags = []Flag{
Float64Flag{Name: "height", Value: 1.5, Usage: "Set the height, in meters"}, &Float64Flag{Name: "height", Value: 1.5, Usage: "Set the height, in meters"},
} }
app.Action = func(c *Context) error { app.Action = func(c *Context) error {
meters = c.Float64("height") meters = c.Float64("height")
@ -343,11 +351,11 @@ func TestApp_ParseSliceFlags(t *testing.T) {
var parsedStringSlice []string var parsedStringSlice []string
app := NewApp() app := NewApp()
command := Command{ command := &Command{
Name: "cmd", Name: "cmd",
Flags: []Flag{ Flags: []Flag{
IntSliceFlag{Name: "p", Value: NewIntSlice(), Usage: "set one or more ip addr"}, &IntSliceFlag{Name: "p", Value: NewIntSlice(), Usage: "set one or more ip addr"},
StringSliceFlag{Name: "ip", Value: NewStringSlice(), Usage: "set one or more ports to open"}, &StringSliceFlag{Name: "ip", Value: NewStringSlice(), Usage: "set one or more ports to open"},
}, },
Action: func(c *Context) error { Action: func(c *Context) error {
parsedIntSlice = c.IntSlice("p") parsedIntSlice = c.IntSlice("p")
@ -357,7 +365,7 @@ func TestApp_ParseSliceFlags(t *testing.T) {
return nil return nil
}, },
} }
app.Commands = []Command{command} app.Commands = []*Command{command}
app.Run([]string{"", "cmd", "-p", "22", "-p", "80", "-ip", "8.8.8.8", "-ip", "8.8.4.4", "my-arg"}) app.Run([]string{"", "cmd", "-p", "22", "-p", "80", "-ip", "8.8.8.8", "-ip", "8.8.4.4", "my-arg"})
@ -401,11 +409,11 @@ func TestApp_ParseSliceFlagsWithMissingValue(t *testing.T) {
var parsedStringSlice []string var parsedStringSlice []string
app := NewApp() app := NewApp()
command := Command{ command := &Command{
Name: "cmd", Name: "cmd",
Flags: []Flag{ Flags: []Flag{
IntSliceFlag{Name: "a", Usage: "set numbers"}, &IntSliceFlag{Name: "a", Usage: "set numbers"},
StringSliceFlag{Name: "str", Usage: "set strings"}, &StringSliceFlag{Name: "str", Usage: "set strings"},
}, },
Action: func(c *Context) error { Action: func(c *Context) error {
parsedIntSlice = c.IntSlice("a") parsedIntSlice = c.IntSlice("a")
@ -413,7 +421,7 @@ func TestApp_ParseSliceFlagsWithMissingValue(t *testing.T) {
return nil return nil
}, },
} }
app.Commands = []Command{command} app.Commands = []*Command{command}
app.Run([]string{"", "cmd", "-a", "2", "-str", "A", "my-arg"}) app.Run([]string{"", "cmd", "-a", "2", "-str", "A", "my-arg"})
@ -491,7 +499,7 @@ func TestApp_BeforeFunc(t *testing.T) {
return nil return nil
} }
app.Commands = []Command{ app.Commands = []*Command{
{ {
Name: "sub", Name: "sub",
Action: func(c *Context) error { Action: func(c *Context) error {
@ -503,7 +511,7 @@ func TestApp_BeforeFunc(t *testing.T) {
} }
app.Flags = []Flag{ app.Flags = []Flag{
StringFlag{Name: "opt"}, &StringFlag{Name: "opt"},
} }
// run with the Before() func succeeding // run with the Before() func succeeding
@ -583,7 +591,7 @@ func TestApp_AfterFunc(t *testing.T) {
return nil return nil
} }
app.Commands = []Command{ app.Commands = []*Command{
{ {
Name: "sub", Name: "sub",
Action: func(c *Context) error { Action: func(c *Context) error {
@ -595,7 +603,7 @@ func TestApp_AfterFunc(t *testing.T) {
} }
app.Flags = []Flag{ app.Flags = []Flag{
StringFlag{Name: "opt"}, &StringFlag{Name: "opt"},
} }
// run with the After() func succeeding // run with the After() func succeeding
@ -639,7 +647,7 @@ func TestAppNoHelpFlag(t *testing.T) {
HelpFlag = oldFlag HelpFlag = oldFlag
}() }()
HelpFlag = BoolFlag{} HelpFlag = nil
app := NewApp() app := NewApp()
app.Writer = ioutil.Discard app.Writer = ioutil.Discard
@ -698,7 +706,7 @@ func TestApp_CommandNotFound(t *testing.T) {
counts.CommandNotFound = counts.Total counts.CommandNotFound = counts.Total
} }
app.Commands = []Command{ app.Commands = []*Command{
{ {
Name: "bar", Name: "bar",
Action: func(c *Context) error { Action: func(c *Context) error {
@ -765,7 +773,7 @@ func TestApp_OrderOfOperations(t *testing.T) {
} }
app.After = afterNoError app.After = afterNoError
app.Commands = []Command{ app.Commands = []*Command{
{ {
Name: "bar", Name: "bar",
Action: func(c *Context) error { Action: func(c *Context) error {
@ -871,21 +879,21 @@ func TestApp_Run_CommandWithSubcommandHasHelpTopic(t *testing.T) {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
app.Writer = buf app.Writer = buf
subCmdBar := Command{ subCmdBar := &Command{
Name: "bar", Name: "bar",
Usage: "does bar things", Usage: "does bar things",
} }
subCmdBaz := Command{ subCmdBaz := &Command{
Name: "baz", Name: "baz",
Usage: "does baz things", Usage: "does baz things",
} }
cmd := Command{ cmd := &Command{
Name: "foo", Name: "foo",
Description: "descriptive wall of text about how it does foo things", Description: "descriptive wall of text about how it does foo things",
Subcommands: []Command{subCmdBar, subCmdBaz}, Subcommands: []*Command{subCmdBar, subCmdBaz},
} }
app.Commands = []Command{cmd} app.Commands = []*Command{cmd}
err := app.Run(flagSet) err := app.Run(flagSet)
if err != nil { if err != nil {
@ -916,16 +924,16 @@ func TestApp_Run_SubcommandFullPath(t *testing.T) {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
app.Writer = buf app.Writer = buf
app.Name = "command" app.Name = "command"
subCmd := Command{ subCmd := &Command{
Name: "bar", Name: "bar",
Usage: "does bar things", Usage: "does bar things",
} }
cmd := Command{ cmd := &Command{
Name: "foo", Name: "foo",
Description: "foo commands", Description: "foo commands",
Subcommands: []Command{subCmd}, Subcommands: []*Command{subCmd},
} }
app.Commands = []Command{cmd} app.Commands = []*Command{cmd}
err := app.Run([]string{"command", "foo", "bar", "--help"}) err := app.Run([]string{"command", "foo", "bar", "--help"})
if err != nil { if err != nil {
@ -933,11 +941,14 @@ func TestApp_Run_SubcommandFullPath(t *testing.T) {
} }
output := buf.String() output := buf.String()
if !strings.Contains(output, "command foo bar - does bar things") { expected := "command foo bar - does bar things"
t.Errorf("expected full path to subcommand: %s", output) if !strings.Contains(output, expected) {
t.Errorf("expected %q in output: %s", expected, output)
} }
if !strings.Contains(output, "command foo bar [arguments...]") {
t.Errorf("expected full path to subcommand: %s", output) expected = "command foo bar [command options] [arguments...]"
if !strings.Contains(output, expected) {
t.Errorf("expected %q in output: %s", expected, output)
} }
} }
@ -946,17 +957,17 @@ func TestApp_Run_SubcommandHelpName(t *testing.T) {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
app.Writer = buf app.Writer = buf
app.Name = "command" app.Name = "command"
subCmd := Command{ subCmd := &Command{
Name: "bar", Name: "bar",
HelpName: "custom", HelpName: "custom",
Usage: "does bar things", Usage: "does bar things",
} }
cmd := Command{ cmd := &Command{
Name: "foo", Name: "foo",
Description: "foo commands", Description: "foo commands",
Subcommands: []Command{subCmd}, Subcommands: []*Command{subCmd},
} }
app.Commands = []Command{cmd} app.Commands = []*Command{cmd}
err := app.Run([]string{"command", "foo", "bar", "--help"}) err := app.Run([]string{"command", "foo", "bar", "--help"})
if err != nil { if err != nil {
@ -964,11 +975,15 @@ func TestApp_Run_SubcommandHelpName(t *testing.T) {
} }
output := buf.String() output := buf.String()
if !strings.Contains(output, "custom - does bar things") {
t.Errorf("expected HelpName for subcommand: %s", output) expected := "custom - does bar things"
if !strings.Contains(output, expected) {
t.Errorf("expected %q in output: %s", expected, output)
} }
if !strings.Contains(output, "custom [arguments...]") {
t.Errorf("expected HelpName to subcommand: %s", output) expected = "custom [command options] [arguments...]"
if !strings.Contains(output, expected) {
t.Errorf("expected %q in output: %s", expected, output)
} }
} }
@ -977,17 +992,17 @@ func TestApp_Run_CommandHelpName(t *testing.T) {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
app.Writer = buf app.Writer = buf
app.Name = "command" app.Name = "command"
subCmd := Command{ subCmd := &Command{
Name: "bar", Name: "bar",
Usage: "does bar things", Usage: "does bar things",
} }
cmd := Command{ cmd := &Command{
Name: "foo", Name: "foo",
HelpName: "custom", HelpName: "custom",
Description: "foo commands", Description: "foo commands",
Subcommands: []Command{subCmd}, Subcommands: []*Command{subCmd},
} }
app.Commands = []Command{cmd} app.Commands = []*Command{cmd}
err := app.Run([]string{"command", "foo", "bar", "--help"}) err := app.Run([]string{"command", "foo", "bar", "--help"})
if err != nil { if err != nil {
@ -995,11 +1010,15 @@ func TestApp_Run_CommandHelpName(t *testing.T) {
} }
output := buf.String() output := buf.String()
if !strings.Contains(output, "command foo bar - does bar things") {
t.Errorf("expected full path to subcommand: %s", output) expected := "command foo bar - does bar things"
if !strings.Contains(output, expected) {
t.Errorf("expected %q in output: %s", expected, output)
} }
if !strings.Contains(output, "command foo bar [arguments...]") {
t.Errorf("expected full path to subcommand: %s", output) expected = "command foo bar [command options] [arguments...]"
if !strings.Contains(output, expected) {
t.Errorf("expected %q in output: %s", expected, output)
} }
} }
@ -1008,17 +1027,17 @@ func TestApp_Run_CommandSubcommandHelpName(t *testing.T) {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
app.Writer = buf app.Writer = buf
app.Name = "base" app.Name = "base"
subCmd := Command{ subCmd := &Command{
Name: "bar", Name: "bar",
HelpName: "custom", HelpName: "custom",
Usage: "does bar things", Usage: "does bar things",
} }
cmd := Command{ cmd := &Command{
Name: "foo", Name: "foo",
Description: "foo commands", Description: "foo commands",
Subcommands: []Command{subCmd}, Subcommands: []*Command{subCmd},
} }
app.Commands = []Command{cmd} app.Commands = []*Command{cmd}
err := app.Run([]string{"command", "foo", "--help"}) err := app.Run([]string{"command", "foo", "--help"})
if err != nil { if err != nil {
@ -1026,11 +1045,15 @@ func TestApp_Run_CommandSubcommandHelpName(t *testing.T) {
} }
output := buf.String() output := buf.String()
if !strings.Contains(output, "base foo - foo commands") {
t.Errorf("expected full path to subcommand: %s", output) expected := "base foo - foo commands"
if !strings.Contains(output, expected) {
t.Errorf("expected %q in output: %q", expected, output)
} }
if !strings.Contains(output, "base foo command [command options] [arguments...]") {
t.Errorf("expected full path to subcommand: %s", output) expected = "base foo command [command options] [arguments...]"
if !strings.Contains(output, expected) {
t.Errorf("expected %q in output: %q", expected, output)
} }
} }
@ -1100,7 +1123,7 @@ func TestApp_Run_Version(t *testing.T) {
func TestApp_Run_Categories(t *testing.T) { func TestApp_Run_Categories(t *testing.T) {
app := NewApp() app := NewApp()
app.Name = "categories" app.Name = "categories"
app.Commands = []Command{ app.Commands = []*Command{
{ {
Name: "command1", Name: "command1",
Category: "1", Category: "1",
@ -1119,18 +1142,20 @@ func TestApp_Run_Categories(t *testing.T) {
app.Run([]string{"categories"}) app.Run([]string{"categories"})
expect := CommandCategories{ expect := &CommandCategories{
&CommandCategory{ Categories: []*CommandCategory{
Name: "1", {
Commands: []Command{ Name: "1",
app.Commands[0], Commands: []*Command{
app.Commands[1], app.Commands[0],
app.Commands[1],
},
}, },
}, {
&CommandCategory{ Name: "2",
Name: "2", Commands: []*Command{
Commands: []Command{ app.Commands[2],
app.Commands[2], },
}, },
}, },
} }
@ -1149,7 +1174,7 @@ func TestApp_Run_Categories(t *testing.T) {
func TestApp_VisibleCategories(t *testing.T) { func TestApp_VisibleCategories(t *testing.T) {
app := NewApp() app := NewApp()
app.Name = "visible-categories" app.Name = "visible-categories"
app.Commands = []Command{ app.Commands = []*Command{
{ {
Name: "command1", Name: "command1",
Category: "1", Category: "1",
@ -1171,13 +1196,13 @@ func TestApp_VisibleCategories(t *testing.T) {
expected := []*CommandCategory{ expected := []*CommandCategory{
{ {
Name: "2", Name: "2",
Commands: []Command{ Commands: []*Command{
app.Commands[1], app.Commands[1],
}, },
}, },
{ {
Name: "3", Name: "3",
Commands: []Command{ Commands: []*Command{
app.Commands[2], app.Commands[2],
}, },
}, },
@ -1188,7 +1213,7 @@ func TestApp_VisibleCategories(t *testing.T) {
app = NewApp() app = NewApp()
app.Name = "visible-categories" app.Name = "visible-categories"
app.Commands = []Command{ app.Commands = []*Command{
{ {
Name: "command1", Name: "command1",
Category: "1", Category: "1",
@ -1211,7 +1236,7 @@ func TestApp_VisibleCategories(t *testing.T) {
expected = []*CommandCategory{ expected = []*CommandCategory{
{ {
Name: "3", Name: "3",
Commands: []Command{ Commands: []*Command{
app.Commands[2], app.Commands[2],
}, },
}, },
@ -1222,7 +1247,7 @@ func TestApp_VisibleCategories(t *testing.T) {
app = NewApp() app = NewApp()
app.Name = "visible-categories" app.Name = "visible-categories"
app.Commands = []Command{ app.Commands = []*Command{
{ {
Name: "command1", Name: "command1",
Category: "1", Category: "1",
@ -1270,9 +1295,9 @@ func TestApp_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) {
func TestApp_Run_SubcommandDoesNotOverwriteErrorFromBefore(t *testing.T) { func TestApp_Run_SubcommandDoesNotOverwriteErrorFromBefore(t *testing.T) {
app := NewApp() app := NewApp()
app.Commands = []Command{ app.Commands = []*Command{
{ {
Subcommands: []Command{ Subcommands: []*Command{
{ {
Name: "sub", Name: "sub",
}, },
@ -1299,7 +1324,7 @@ func TestApp_Run_SubcommandDoesNotOverwriteErrorFromBefore(t *testing.T) {
func TestApp_OnUsageError_WithWrongFlagValue(t *testing.T) { func TestApp_OnUsageError_WithWrongFlagValue(t *testing.T) {
app := NewApp() app := NewApp()
app.Flags = []Flag{ app.Flags = []Flag{
IntFlag{Name: "flag"}, &IntFlag{Name: "flag"},
} }
app.OnUsageError = func(c *Context, err error, isSubcommand bool) error { app.OnUsageError = func(c *Context, err error, isSubcommand bool) error {
if isSubcommand { if isSubcommand {
@ -1310,7 +1335,7 @@ func TestApp_OnUsageError_WithWrongFlagValue(t *testing.T) {
} }
return errors.New("intercepted: " + err.Error()) return errors.New("intercepted: " + err.Error())
} }
app.Commands = []Command{ app.Commands = []*Command{
{ {
Name: "bar", Name: "bar",
}, },
@ -1329,7 +1354,7 @@ func TestApp_OnUsageError_WithWrongFlagValue(t *testing.T) {
func TestApp_OnUsageError_WithWrongFlagValue_ForSubcommand(t *testing.T) { func TestApp_OnUsageError_WithWrongFlagValue_ForSubcommand(t *testing.T) {
app := NewApp() app := NewApp()
app.Flags = []Flag{ app.Flags = []Flag{
IntFlag{Name: "flag"}, &IntFlag{Name: "flag"},
} }
app.OnUsageError = func(c *Context, err error, isSubcommand bool) error { app.OnUsageError = func(c *Context, err error, isSubcommand bool) error {
if isSubcommand { if isSubcommand {
@ -1340,7 +1365,7 @@ func TestApp_OnUsageError_WithWrongFlagValue_ForSubcommand(t *testing.T) {
} }
return errors.New("intercepted: " + err.Error()) return errors.New("intercepted: " + err.Error())
} }
app.Commands = []Command{ app.Commands = []*Command{
{ {
Name: "bar", Name: "bar",
}, },

@ -1,40 +1,48 @@
package cli package cli
// CommandCategories is a slice of *CommandCategory. // CommandCategories is a slice of *CommandCategory.
type CommandCategories []*CommandCategory type CommandCategories struct {
Categories []*CommandCategory
}
func NewCommandCategories() *CommandCategories {
return &CommandCategories{Categories: []*CommandCategory{}}
}
// CommandCategory is a category containing commands. // CommandCategory is a category containing commands.
type CommandCategory struct { type CommandCategory struct {
Name string Name string
Commands Commands Commands []*Command
} }
func (c CommandCategories) Less(i, j int) bool { func (c *CommandCategories) Less(i, j int) bool {
return c[i].Name < c[j].Name return c.Categories[i].Name < c.Categories[j].Name
} }
func (c CommandCategories) Len() int { func (c *CommandCategories) Len() int {
return len(c) return len(c.Categories)
} }
func (c CommandCategories) Swap(i, j int) { func (c *CommandCategories) Swap(i, j int) {
c[i], c[j] = c[j], c[i] c.Categories[i], c.Categories[j] = c.Categories[j], c.Categories[i]
} }
// AddCommand adds a command to a category. // AddCommand adds a command to a category.
func (c CommandCategories) AddCommand(category string, command Command) CommandCategories { func (c *CommandCategories) AddCommand(category string, command *Command) *CommandCategories {
for _, commandCategory := range c { for _, commandCategory := range c.Categories {
if commandCategory.Name == category { if commandCategory.Name == category {
commandCategory.Commands = append(commandCategory.Commands, command) commandCategory.Commands = append(commandCategory.Commands, command)
return c return c
} }
} }
return append(c, &CommandCategory{Name: category, Commands: []Command{command}}) c.Categories = append(c.Categories,
&CommandCategory{Name: category, Commands: []*Command{command}})
return c
} }
// VisibleCommands returns a slice of the Commands with Hidden=false // VisibleCommands returns a slice of the Commands with Hidden=false
func (c *CommandCategory) VisibleCommands() []Command { func (c *CommandCategory) VisibleCommands() []*Command {
ret := []Command{} ret := []*Command{}
for _, command := range c.Commands { for _, command := range c.Commands {
if !command.Hidden { if !command.Hidden {
ret = append(ret, command) ret = append(ret, command)

@ -3,7 +3,6 @@ package cli
import ( import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"reflect"
"sort" "sort"
"strings" "strings"
) )
@ -37,7 +36,7 @@ type Command struct {
// Execute this function if a usage error occurs. // Execute this function if a usage error occurs.
OnUsageError OnUsageErrorFunc OnUsageError OnUsageErrorFunc
// List of child commands // List of child commands
Subcommands Commands Subcommands []*Command
// List of flags to parse // List of flags to parse
Flags []Flag Flags []Flag
// Treat all flags as normal arguments if true // Treat all flags as normal arguments if true
@ -54,32 +53,26 @@ type Command struct {
// FullName returns the full name of the command. // FullName returns the full name of the command.
// For subcommands this ensures that parent commands are part of the command path // For subcommands this ensures that parent commands are part of the command path
func (c Command) FullName() string { func (c *Command) FullName() string {
if c.commandNamePath == nil { if c.commandNamePath == nil {
return c.Name return c.Name
} }
return strings.Join(c.commandNamePath, " ") return strings.Join(c.commandNamePath, " ")
} }
// Commands is a slice of Command
type Commands []Command
// Run invokes the command given the context, parses ctx.Args() to generate command-specific flags // Run invokes the command given the context, parses ctx.Args() to generate command-specific flags
func (c Command) Run(ctx *Context) (err error) { func (c *Command) Run(ctx *Context) (err error) {
if len(c.Subcommands) > 0 { if len(c.Subcommands) > 0 {
return c.startApp(ctx) return c.startApp(ctx)
} }
if !c.HideHelp && !reflect.DeepEqual(HelpFlag, BoolFlag{}) { if !c.HideHelp && HelpFlag != nil {
// append help to flags // append help to flags
c.Flags = append( c.appendFlag(HelpFlag)
c.Flags,
HelpFlag,
)
} }
if ctx.App.EnableBashCompletion { if ctx.App.EnableBashCompletion {
c.Flags = append(c.Flags, BashCompletionFlag) c.appendFlag(BashCompletionFlag)
} }
set := flagSet(c.Name, c.Flags) set := flagSet(c.Name, c.Flags)
@ -156,13 +149,12 @@ func (c Command) Run(ctx *Context) (err error) {
} }
// Names returns the names including short names and aliases. // Names returns the names including short names and aliases.
func (c Command) Names() []string { func (c *Command) Names() []string {
names := []string{c.Name} return append([]string{c.Name}, c.Aliases...)
return append(names, c.Aliases...)
} }
// HasName returns true if Command.Name matches given name // HasName returns true if Command.Name matches given name
func (c Command) HasName(name string) bool { func (c *Command) HasName(name string) bool {
for _, n := range c.Names() { for _, n := range c.Names() {
if n == name { if n == name {
return true return true
@ -171,7 +163,7 @@ func (c Command) HasName(name string) bool {
return false return false
} }
func (c Command) startApp(ctx *Context) error { func (c *Command) startApp(ctx *Context) error {
app := NewApp() app := NewApp()
app.Metadata = ctx.App.Metadata app.Metadata = ctx.App.Metadata
// set the name and usage // set the name and usage
@ -201,7 +193,7 @@ func (c Command) startApp(ctx *Context) error {
app.Compiled = ctx.App.Compiled app.Compiled = ctx.App.Compiled
app.Writer = ctx.App.Writer app.Writer = ctx.App.Writer
app.categories = CommandCategories{} app.categories = NewCommandCategories()
for _, command := range c.Subcommands { for _, command := range c.Subcommands {
app.categories = app.categories.AddCommand(command.Category, command) app.categories = app.categories.AddCommand(command.Category, command)
} }
@ -231,6 +223,22 @@ func (c Command) startApp(ctx *Context) error {
} }
// VisibleFlags returns a slice of the Flags with Hidden=false // VisibleFlags returns a slice of the Flags with Hidden=false
func (c Command) VisibleFlags() []Flag { func (c *Command) VisibleFlags() []Flag {
return visibleFlags(c.Flags) return visibleFlags(c.Flags)
} }
func (c *Command) appendFlag(fl Flag) {
if !hasFlag(c.Flags, fl) {
c.Flags = append(c.Flags, fl)
}
}
func hasCommand(commands []*Command, command *Command) bool {
for _, existing := range commands {
if command == existing {
return true
}
}
return false
}

@ -42,13 +42,13 @@ func TestCommandFlagParsing(t *testing.T) {
err := command.Run(context) err := command.Run(context)
expect(t, err, c.expectedErr) expect(t, err, c.expectedErr)
expect(t, []string(context.Args()), c.testArgs) expect(t, context.Args().Slice(), c.testArgs)
} }
} }
func TestCommand_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) { func TestCommand_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) {
app := NewApp() app := NewApp()
app.Commands = []Command{ app.Commands = []*Command{
{ {
Name: "bar", Name: "bar",
Before: func(c *Context) error { Before: func(c *Context) error {
@ -75,11 +75,11 @@ func TestCommand_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) {
func TestCommand_OnUsageError_WithWrongFlagValue(t *testing.T) { func TestCommand_OnUsageError_WithWrongFlagValue(t *testing.T) {
app := NewApp() app := NewApp()
app.Commands = []Command{ app.Commands = []*Command{
{ {
Name: "bar", Name: "bar",
Flags: []Flag{ Flags: []Flag{
IntFlag{Name: "flag"}, &IntFlag{Name: "flag"},
}, },
OnUsageError: func(c *Context, err error, _ bool) error { OnUsageError: func(c *Context, err error, _ bool) error {
if !strings.HasPrefix(err.Error(), "invalid value \"wrong\"") { if !strings.HasPrefix(err.Error(), "invalid value \"wrong\"") {

@ -14,7 +14,7 @@ import (
// parsed command-line options. // parsed command-line options.
type Context struct { type Context struct {
App *App App *App
Command Command Command *Command
flagSet *flag.FlagSet flagSet *flag.FlagSet
parentContext *Context parentContext *Context
@ -147,56 +147,69 @@ func (c *Context) Lineage() []*Context {
return lineage return lineage
} }
// Args contains apps console arguments
type Args []string
// Args returns the command line arguments associated with the context. // Args returns the command line arguments associated with the context.
func (c *Context) Args() Args { func (c *Context) Args() *Args {
args := Args(c.flagSet.Args()) return &Args{slice: c.flagSet.Args()}
return args
} }
// NArg returns the number of the command line arguments. // NArg returns the number of the command line arguments.
func (c *Context) NArg() int { func (c *Context) NArg() int {
return len(c.Args()) return c.Args().Len()
}
// Args wraps a string slice with some convenience methods
type Args struct {
slice []string
} }
// Get returns the nth argument, or else a blank string // Get returns the nth argument, or else a blank string
func (a Args) Get(n int) string { func (a *Args) Get(n int) string {
if len(a) > n { if len(a.slice) > n {
return a[n] return a.slice[n]
} }
return "" return ""
} }
// First returns the first argument, or else a blank string // First returns the first argument, or else a blank string
func (a Args) First() string { func (a *Args) First() string {
return a.Get(0) return a.Get(0)
} }
// Tail returns the rest of the arguments (not the first one) // Tail returns the rest of the arguments (not the first one)
// or else an empty string slice // or else an empty string slice
func (a Args) Tail() []string { func (a *Args) Tail() []string {
if len(a) >= 2 { if a.Len() >= 2 {
return []string(a)[1:] return a.slice[1:]
} }
return []string{} return []string{}
} }
// Len returns the length of the wrapped slice
func (a *Args) Len() int {
return len(a.slice)
}
// Present checks if there are any arguments present // Present checks if there are any arguments present
func (a Args) Present() bool { func (a *Args) Present() bool {
return len(a) != 0 return a.Len() != 0
} }
// Swap swaps arguments at the given indexes // Swap swaps arguments at the given indexes
func (a Args) Swap(from, to int) error { func (a *Args) Swap(from, to int) error {
if from >= len(a) || to >= len(a) { if from >= a.Len() || to >= a.Len() {
return errors.New("index out of range") return errors.New("index out of range")
} }
a[from], a[to] = a[to], a[from] a.slice[from], a.slice[to] = a.slice[to], a.slice[from]
return nil return nil
} }
// Slice returns a copy of the internal slice
func (a *Args) Slice() []string {
ret := make([]string, len(a.slice))
copy(ret, a.slice)
return ret
}
func lookupFlagSet(name string, ctx *Context) *flag.FlagSet { func lookupFlagSet(name string, ctx *Context) *flag.FlagSet {
for _, c := range ctx.Lineage() { for _, c := range ctx.Lineage() {
if f := c.flagSet.Lookup(name); f != nil { if f := c.flagSet.Lookup(name); f != nil {

@ -15,7 +15,7 @@ func TestNewContext(t *testing.T) {
globalSet.Int("myflag", 42, "doc") globalSet.Int("myflag", 42, "doc")
globalSet.Float64("myflag64", float64(47), "doc") globalSet.Float64("myflag64", float64(47), "doc")
globalCtx := NewContext(nil, globalSet, nil) globalCtx := NewContext(nil, globalSet, nil)
command := Command{Name: "mycommand"} command := &Command{Name: "mycommand"}
c := NewContext(nil, set, globalCtx) c := NewContext(nil, set, globalCtx)
c.Command = command c.Command = command
expect(t, c.Int("myflag"), 12) expect(t, c.Int("myflag"), 12)
@ -63,7 +63,7 @@ func TestContext_Args(t *testing.T) {
set.Bool("myflag", false, "doc") set.Bool("myflag", false, "doc")
c := NewContext(nil, set, nil) c := NewContext(nil, set, nil)
set.Parse([]string{"--myflag", "bat", "baz"}) set.Parse([]string{"--myflag", "bat", "baz"})
expect(t, len(c.Args()), 2) expect(t, c.Args().Len(), 2)
expect(t, c.Bool("myflag"), true) expect(t, c.Bool("myflag"), true)
} }

@ -17,22 +17,22 @@ const defaultPlaceholder = "value"
var slPfx = fmt.Sprintf("sl:::%d:::", time.Now().UTC().UnixNano()) var slPfx = fmt.Sprintf("sl:::%d:::", time.Now().UTC().UnixNano())
// BashCompletionFlag enables bash-completion for all commands and subcommands // BashCompletionFlag enables bash-completion for all commands and subcommands
var BashCompletionFlag = BoolFlag{ var BashCompletionFlag = &BoolFlag{
Name: "generate-bash-completion", Name: "generate-bash-completion",
Hidden: true, Hidden: true,
} }
// VersionFlag prints the version for the application // VersionFlag prints the version for the application
var VersionFlag = BoolFlag{ var VersionFlag = &BoolFlag{
Name: "version", Name: "version",
Aliases: []string{"v"}, Aliases: []string{"v"},
Usage: "print the version", Usage: "print the version",
} }
// HelpFlag prints the help for all commands and subcommands. // HelpFlag prints the help for all commands and subcommands.
// Set to the zero value (BoolFlag{}) to disable the flag. The subcommand // Set to nil to disable the flag. The subcommand
// will still be added unless HideHelp is set to true. // will still be added unless HideHelp is set to true.
var HelpFlag = BoolFlag{ var HelpFlag = &BoolFlag{
Name: "help", Name: "help",
Aliases: []string{"h"}, Aliases: []string{"h"},
Usage: "show help", Usage: "show help",
@ -85,13 +85,13 @@ type GenericFlag struct {
// String returns the string representation of the generic flag to display the // String returns the string representation of the generic flag to display the
// help text to the user (uses the String() method of the generic flag to show // help text to the user (uses the String() method of the generic flag to show
// the value) // the value)
func (f GenericFlag) String() string { func (f *GenericFlag) String() string {
return FlagStringer(f) return FlagStringer(f)
} }
// Apply takes the flagset and calls Set on the generic flag with the value // Apply takes the flagset and calls Set on the generic flag with the value
// provided by the user for parsing by the flag // provided by the user for parsing by the flag
func (f GenericFlag) Apply(set *flag.FlagSet) { func (f *GenericFlag) Apply(set *flag.FlagSet) {
val := f.Value val := f.Value
if f.EnvVars != nil { if f.EnvVars != nil {
for _, envVar := range f.EnvVars { for _, envVar := range f.EnvVars {
@ -109,7 +109,7 @@ func (f GenericFlag) Apply(set *flag.FlagSet) {
} }
// Names returns the names of a flag. // Names returns the names of a flag.
func (f GenericFlag) Names() []string { func (f *GenericFlag) Names() []string {
return append([]string{f.Name}, f.Aliases...) return append([]string{f.Name}, f.Aliases...)
} }
@ -170,12 +170,12 @@ type StringSliceFlag struct {
} }
// String returns the usage // String returns the usage
func (f StringSliceFlag) String() string { func (f *StringSliceFlag) String() string {
return FlagStringer(f) return FlagStringer(f)
} }
// Apply populates the flag given the flag set and environment // Apply populates the flag given the flag set and environment
func (f StringSliceFlag) Apply(set *flag.FlagSet) { func (f *StringSliceFlag) Apply(set *flag.FlagSet) {
if f.EnvVars != nil { if f.EnvVars != nil {
for _, envVar := range f.EnvVars { for _, envVar := range f.EnvVars {
envVar = strings.TrimSpace(envVar) envVar = strings.TrimSpace(envVar)
@ -201,7 +201,7 @@ func (f StringSliceFlag) Apply(set *flag.FlagSet) {
} }
// Names returns the name of a flag. // Names returns the name of a flag.
func (f StringSliceFlag) Names() []string { func (f *StringSliceFlag) Names() []string {
return append([]string{f.Name}, f.Aliases...) return append([]string{f.Name}, f.Aliases...)
} }
@ -277,12 +277,12 @@ type IntSliceFlag struct {
} }
// String returns the usage // String returns the usage
func (f IntSliceFlag) String() string { func (f *IntSliceFlag) String() string {
return FlagStringer(f) return FlagStringer(f)
} }
// Apply populates the flag given the flag set and environment // Apply populates the flag given the flag set and environment
func (f IntSliceFlag) Apply(set *flag.FlagSet) { func (f *IntSliceFlag) Apply(set *flag.FlagSet) {
if f.EnvVars != nil { if f.EnvVars != nil {
for _, envVar := range f.EnvVars { for _, envVar := range f.EnvVars {
envVar = strings.TrimSpace(envVar) envVar = strings.TrimSpace(envVar)
@ -311,7 +311,7 @@ func (f IntSliceFlag) Apply(set *flag.FlagSet) {
} }
// Names returns the name of the flag. // Names returns the name of the flag.
func (f IntSliceFlag) Names() []string { func (f *IntSliceFlag) Names() []string {
return append([]string{f.Name}, f.Aliases...) return append([]string{f.Name}, f.Aliases...)
} }
@ -327,12 +327,12 @@ type BoolFlag struct {
} }
// String returns a readable representation of this value (for usage defaults) // String returns a readable representation of this value (for usage defaults)
func (f BoolFlag) String() string { func (f *BoolFlag) String() string {
return FlagStringer(f) return FlagStringer(f)
} }
// Apply populates the flag given the flag set and environment // Apply populates the flag given the flag set and environment
func (f BoolFlag) Apply(set *flag.FlagSet) { func (f *BoolFlag) Apply(set *flag.FlagSet) {
if f.EnvVars != nil { if f.EnvVars != nil {
for _, envVar := range f.EnvVars { for _, envVar := range f.EnvVars {
envVar = strings.TrimSpace(envVar) envVar = strings.TrimSpace(envVar)
@ -356,7 +356,7 @@ func (f BoolFlag) Apply(set *flag.FlagSet) {
} }
// Names returns the name of the flag. // Names returns the name of the flag.
func (f BoolFlag) Names() []string { func (f *BoolFlag) Names() []string {
return append([]string{f.Name}, f.Aliases...) return append([]string{f.Name}, f.Aliases...)
} }
@ -372,12 +372,12 @@ type StringFlag struct {
} }
// String returns the usage // String returns the usage
func (f StringFlag) String() string { func (f *StringFlag) String() string {
return FlagStringer(f) return FlagStringer(f)
} }
// Apply populates the flag given the flag set and environment // Apply populates the flag given the flag set and environment
func (f StringFlag) Apply(set *flag.FlagSet) { func (f *StringFlag) Apply(set *flag.FlagSet) {
if f.EnvVars != nil { if f.EnvVars != nil {
for _, envVar := range f.EnvVars { for _, envVar := range f.EnvVars {
envVar = strings.TrimSpace(envVar) envVar = strings.TrimSpace(envVar)
@ -398,7 +398,7 @@ func (f StringFlag) Apply(set *flag.FlagSet) {
} }
// Names returns the name of the flag. // Names returns the name of the flag.
func (f StringFlag) Names() []string { func (f *StringFlag) Names() []string {
return append([]string{f.Name}, f.Aliases...) return append([]string{f.Name}, f.Aliases...)
} }
@ -415,12 +415,12 @@ type IntFlag struct {
} }
// String returns the usage // String returns the usage
func (f IntFlag) String() string { func (f *IntFlag) String() string {
return FlagStringer(f) return FlagStringer(f)
} }
// Apply populates the flag given the flag set and environment // Apply populates the flag given the flag set and environment
func (f IntFlag) Apply(set *flag.FlagSet) { func (f *IntFlag) Apply(set *flag.FlagSet) {
if f.EnvVars != nil { if f.EnvVars != nil {
for _, envVar := range f.EnvVars { for _, envVar := range f.EnvVars {
envVar = strings.TrimSpace(envVar) envVar = strings.TrimSpace(envVar)
@ -444,7 +444,7 @@ func (f IntFlag) Apply(set *flag.FlagSet) {
} }
// Names returns the name of the flag. // Names returns the name of the flag.
func (f IntFlag) Names() []string { func (f *IntFlag) Names() []string {
return append([]string{f.Name}, f.Aliases...) return append([]string{f.Name}, f.Aliases...)
} }
@ -461,12 +461,12 @@ type DurationFlag struct {
} }
// String returns a readable representation of this value (for usage defaults) // String returns a readable representation of this value (for usage defaults)
func (f DurationFlag) String() string { func (f *DurationFlag) String() string {
return FlagStringer(f) return FlagStringer(f)
} }
// Apply populates the flag given the flag set and environment // Apply populates the flag given the flag set and environment
func (f DurationFlag) Apply(set *flag.FlagSet) { func (f *DurationFlag) Apply(set *flag.FlagSet) {
if f.EnvVars != nil { if f.EnvVars != nil {
for _, envVar := range f.EnvVars { for _, envVar := range f.EnvVars {
envVar = strings.TrimSpace(envVar) envVar = strings.TrimSpace(envVar)
@ -490,7 +490,7 @@ func (f DurationFlag) Apply(set *flag.FlagSet) {
} }
// Names returns the name of the flag. // Names returns the name of the flag.
func (f DurationFlag) Names() []string { func (f *DurationFlag) Names() []string {
return append([]string{f.Name}, f.Aliases...) return append([]string{f.Name}, f.Aliases...)
} }
@ -507,12 +507,12 @@ type Float64Flag struct {
} }
// String returns the usage // String returns the usage
func (f Float64Flag) String() string { func (f *Float64Flag) String() string {
return FlagStringer(f) return FlagStringer(f)
} }
// Apply populates the flag given the flag set and environment // Apply populates the flag given the flag set and environment
func (f Float64Flag) Apply(set *flag.FlagSet) { func (f *Float64Flag) Apply(set *flag.FlagSet) {
if f.EnvVars != nil { if f.EnvVars != nil {
for _, envVar := range f.EnvVars { for _, envVar := range f.EnvVars {
envVar = strings.TrimSpace(envVar) envVar = strings.TrimSpace(envVar)
@ -535,14 +535,14 @@ func (f Float64Flag) Apply(set *flag.FlagSet) {
} }
// Names returns the name of the flag. // Names returns the name of the flag.
func (f Float64Flag) Names() []string { func (f *Float64Flag) Names() []string {
return append([]string{f.Name}, f.Aliases...) return append([]string{f.Name}, f.Aliases...)
} }
func visibleFlags(fl []Flag) []Flag { func visibleFlags(fl []Flag) []Flag {
visible := []Flag{} visible := []Flag{}
for _, flag := range fl { for _, flag := range fl {
if !reflect.ValueOf(flag).FieldByName("Hidden").Bool() { if !flagValue(flag).FieldByName("Hidden").Bool() {
visible = append(visible, flag) visible = append(visible, flag)
} }
} }
@ -644,10 +644,10 @@ func stringifyFlag(f Flag) string {
fv := flagValue(f) fv := flagValue(f)
switch f.(type) { switch f.(type) {
case IntSliceFlag: case *IntSliceFlag:
return withEnvHint(flagStringSliceField(f, "EnvVars"), stringifyIntSliceFlag(f.(IntSliceFlag))) return withEnvHint(flagStringSliceField(f, "EnvVars"), stringifyIntSliceFlag(f.(*IntSliceFlag)))
case StringSliceFlag: case *StringSliceFlag:
return withEnvHint(flagStringSliceField(f, "EnvVars"), stringifyStringSliceFlag(f.(StringSliceFlag))) return withEnvHint(flagStringSliceField(f, "EnvVars"), stringifyStringSliceFlag(f.(*StringSliceFlag)))
} }
placeholder, usage := unquoteUsage(fv.FieldByName("Usage").String()) placeholder, usage := unquoteUsage(fv.FieldByName("Usage").String())
@ -679,7 +679,7 @@ func stringifyFlag(f Flag) string {
fmt.Sprintf("%s\t%s", prefixedNames(f.Names(), placeholder), usageWithDefault)) fmt.Sprintf("%s\t%s", prefixedNames(f.Names(), placeholder), usageWithDefault))
} }
func stringifyIntSliceFlag(f IntSliceFlag) string { func stringifyIntSliceFlag(f *IntSliceFlag) string {
defaultVals := []string{} defaultVals := []string{}
if f.Value != nil && len(f.Value.Value()) > 0 { if f.Value != nil && len(f.Value.Value()) > 0 {
for _, i := range f.Value.Value() { for _, i := range f.Value.Value() {
@ -690,7 +690,7 @@ func stringifyIntSliceFlag(f IntSliceFlag) string {
return stringifySliceFlag(f.Usage, append([]string{f.Name}, f.Aliases...), defaultVals) return stringifySliceFlag(f.Usage, append([]string{f.Name}, f.Aliases...), defaultVals)
} }
func stringifyStringSliceFlag(f StringSliceFlag) string { func stringifyStringSliceFlag(f *StringSliceFlag) string {
defaultVals := []string{} defaultVals := []string{}
if f.Value != nil && len(f.Value.Value()) > 0 { if f.Value != nil && len(f.Value.Value()) > 0 {
for _, s := range f.Value.Value() { for _, s := range f.Value.Value() {
@ -717,3 +717,13 @@ func stringifySliceFlag(usage string, names, defaultVals []string) string {
usageWithDefault := strings.TrimSpace(fmt.Sprintf("%s%s", usage, defaultVal)) usageWithDefault := strings.TrimSpace(fmt.Sprintf("%s%s", usage, defaultVal))
return fmt.Sprintf("%s\t%s", prefixedNames(names, placeholder), usageWithDefault) return fmt.Sprintf("%s\t%s", prefixedNames(names, placeholder), usageWithDefault)
} }
func hasFlag(flags []Flag, fl Flag) bool {
for _, existing := range flags {
if fl == existing {
return true
}
}
return false
}

@ -20,7 +20,7 @@ var boolFlagTests = []struct {
func TestBoolFlagHelpOutput(t *testing.T) { func TestBoolFlagHelpOutput(t *testing.T) {
for _, test := range boolFlagTests { for _, test := range boolFlagTests {
flag := BoolFlag{Name: test.name} flag := &BoolFlag{Name: test.name}
output := flag.String() output := flag.String()
if output != test.expected { if output != test.expected {
@ -46,7 +46,7 @@ var stringFlagTests = []struct {
func TestStringFlagHelpOutput(t *testing.T) { func TestStringFlagHelpOutput(t *testing.T) {
for _, test := range stringFlagTests { for _, test := range stringFlagTests {
flag := StringFlag{Name: test.name, Aliases: test.aliases, Usage: test.usage, Value: test.value} flag := &StringFlag{Name: test.name, Aliases: test.aliases, Usage: test.usage, Value: test.value}
output := flag.String() output := flag.String()
if output != test.expected { if output != test.expected {
@ -59,7 +59,7 @@ func TestStringFlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv() os.Clearenv()
os.Setenv("APP_FOO", "derp") os.Setenv("APP_FOO", "derp")
for _, test := range stringFlagTests { for _, test := range stringFlagTests {
flag := StringFlag{Name: test.name, Aliases: test.aliases, Value: test.value, EnvVars: []string{"APP_FOO"}} flag := &StringFlag{Name: test.name, Aliases: test.aliases, Value: test.value, EnvVars: []string{"APP_FOO"}}
output := flag.String() output := flag.String()
expectedSuffix := " [$APP_FOO]" expectedSuffix := " [$APP_FOO]"
@ -87,7 +87,7 @@ var stringSliceFlagTests = []struct {
func TestStringSliceFlagHelpOutput(t *testing.T) { func TestStringSliceFlagHelpOutput(t *testing.T) {
for _, test := range stringSliceFlagTests { for _, test := range stringSliceFlagTests {
flag := StringSliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value} flag := &StringSliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value}
output := flag.String() output := flag.String()
if output != test.expected { if output != test.expected {
@ -100,7 +100,7 @@ func TestStringSliceFlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv() os.Clearenv()
os.Setenv("APP_QWWX", "11,4") os.Setenv("APP_QWWX", "11,4")
for _, test := range stringSliceFlagTests { for _, test := range stringSliceFlagTests {
flag := StringSliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value, EnvVars: []string{"APP_QWWX"}} flag := &StringSliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value, EnvVars: []string{"APP_QWWX"}}
output := flag.String() output := flag.String()
expectedSuffix := " [$APP_QWWX]" expectedSuffix := " [$APP_QWWX]"
@ -123,7 +123,7 @@ var intFlagTests = []struct {
func TestIntFlagHelpOutput(t *testing.T) { func TestIntFlagHelpOutput(t *testing.T) {
for _, test := range intFlagTests { for _, test := range intFlagTests {
flag := IntFlag{Name: test.name, Value: 9} flag := &IntFlag{Name: test.name, Value: 9}
output := flag.String() output := flag.String()
if output != test.expected { if output != test.expected {
@ -136,7 +136,7 @@ func TestIntFlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv() os.Clearenv()
os.Setenv("APP_BAR", "2") os.Setenv("APP_BAR", "2")
for _, test := range intFlagTests { for _, test := range intFlagTests {
flag := IntFlag{Name: test.name, EnvVars: []string{"APP_BAR"}} flag := &IntFlag{Name: test.name, EnvVars: []string{"APP_BAR"}}
output := flag.String() output := flag.String()
expectedSuffix := " [$APP_BAR]" expectedSuffix := " [$APP_BAR]"
@ -159,7 +159,7 @@ var durationFlagTests = []struct {
func TestDurationFlagHelpOutput(t *testing.T) { func TestDurationFlagHelpOutput(t *testing.T) {
for _, test := range durationFlagTests { for _, test := range durationFlagTests {
flag := DurationFlag{Name: test.name, Value: 1 * time.Second} flag := &DurationFlag{Name: test.name, Value: 1 * time.Second}
output := flag.String() output := flag.String()
if output != test.expected { if output != test.expected {
@ -172,7 +172,7 @@ func TestDurationFlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv() os.Clearenv()
os.Setenv("APP_BAR", "2h3m6s") os.Setenv("APP_BAR", "2h3m6s")
for _, test := range durationFlagTests { for _, test := range durationFlagTests {
flag := DurationFlag{Name: test.name, EnvVars: []string{"APP_BAR"}} flag := &DurationFlag{Name: test.name, EnvVars: []string{"APP_BAR"}}
output := flag.String() output := flag.String()
expectedSuffix := " [$APP_BAR]" expectedSuffix := " [$APP_BAR]"
@ -198,7 +198,7 @@ var intSliceFlagTests = []struct {
func TestIntSliceFlagHelpOutput(t *testing.T) { func TestIntSliceFlagHelpOutput(t *testing.T) {
for _, test := range intSliceFlagTests { for _, test := range intSliceFlagTests {
flag := IntSliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value} flag := &IntSliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value}
output := flag.String() output := flag.String()
if output != test.expected { if output != test.expected {
@ -211,7 +211,7 @@ func TestIntSliceFlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv() os.Clearenv()
os.Setenv("APP_SMURF", "42,3") os.Setenv("APP_SMURF", "42,3")
for _, test := range intSliceFlagTests { for _, test := range intSliceFlagTests {
flag := IntSliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value, EnvVars: []string{"APP_SMURF"}} flag := &IntSliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value, EnvVars: []string{"APP_SMURF"}}
output := flag.String() output := flag.String()
expectedSuffix := " [$APP_SMURF]" expectedSuffix := " [$APP_SMURF]"
@ -234,7 +234,7 @@ var float64FlagTests = []struct {
func TestFloat64FlagHelpOutput(t *testing.T) { func TestFloat64FlagHelpOutput(t *testing.T) {
for _, test := range float64FlagTests { for _, test := range float64FlagTests {
flag := Float64Flag{Name: test.name, Value: float64(0.1)} flag := &Float64Flag{Name: test.name, Value: float64(0.1)}
output := flag.String() output := flag.String()
if output != test.expected { if output != test.expected {
@ -247,7 +247,7 @@ func TestFloat64FlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv() os.Clearenv()
os.Setenv("APP_BAZ", "99.4") os.Setenv("APP_BAZ", "99.4")
for _, test := range float64FlagTests { for _, test := range float64FlagTests {
flag := Float64Flag{Name: test.name, EnvVars: []string{"APP_BAZ"}} flag := &Float64Flag{Name: test.name, EnvVars: []string{"APP_BAZ"}}
output := flag.String() output := flag.String()
expectedSuffix := " [$APP_BAZ]" expectedSuffix := " [$APP_BAZ]"
@ -271,7 +271,7 @@ var genericFlagTests = []struct {
func TestGenericFlagHelpOutput(t *testing.T) { func TestGenericFlagHelpOutput(t *testing.T) {
for _, test := range genericFlagTests { for _, test := range genericFlagTests {
flag := GenericFlag{Name: test.name, Value: test.value, Usage: "test flag"} flag := &GenericFlag{Name: test.name, Value: test.value, Usage: "test flag"}
output := flag.String() output := flag.String()
if output != test.expected { if output != test.expected {
@ -284,7 +284,7 @@ func TestGenericFlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv() os.Clearenv()
os.Setenv("APP_ZAP", "3") os.Setenv("APP_ZAP", "3")
for _, test := range genericFlagTests { for _, test := range genericFlagTests {
flag := GenericFlag{Name: test.name, EnvVars: []string{"APP_ZAP"}} flag := &GenericFlag{Name: test.name, EnvVars: []string{"APP_ZAP"}}
output := flag.String() output := flag.String()
expectedSuffix := " [$APP_ZAP]" expectedSuffix := " [$APP_ZAP]"
@ -300,7 +300,7 @@ func TestGenericFlagWithEnvVarHelpOutput(t *testing.T) {
func TestParseMultiString(t *testing.T) { func TestParseMultiString(t *testing.T) {
(&App{ (&App{
Flags: []Flag{ Flags: []Flag{
StringFlag{Name: "serve", Aliases: []string{"s"}}, &StringFlag{Name: "serve", Aliases: []string{"s"}},
}, },
Action: func(ctx *Context) error { Action: func(ctx *Context) error {
if ctx.String("serve") != "10" { if ctx.String("serve") != "10" {
@ -318,7 +318,7 @@ func TestParseDestinationString(t *testing.T) {
var dest string var dest string
a := App{ a := App{
Flags: []Flag{ Flags: []Flag{
StringFlag{ &StringFlag{
Name: "dest", Name: "dest",
Destination: &dest, Destination: &dest,
}, },
@ -338,7 +338,7 @@ func TestParseMultiStringFromEnv(t *testing.T) {
os.Setenv("APP_COUNT", "20") os.Setenv("APP_COUNT", "20")
(&App{ (&App{
Flags: []Flag{ Flags: []Flag{
StringFlag{Name: "count", Aliases: []string{"c"}, EnvVars: []string{"APP_COUNT"}}, &StringFlag{Name: "count", Aliases: []string{"c"}, EnvVars: []string{"APP_COUNT"}},
}, },
Action: func(ctx *Context) error { Action: func(ctx *Context) error {
if ctx.String("count") != "20" { if ctx.String("count") != "20" {
@ -357,7 +357,7 @@ func TestParseMultiStringFromEnvCascade(t *testing.T) {
os.Setenv("APP_COUNT", "20") os.Setenv("APP_COUNT", "20")
(&App{ (&App{
Flags: []Flag{ Flags: []Flag{
StringFlag{Name: "count", Aliases: []string{"c"}, EnvVars: []string{"COMPAT_COUNT", "APP_COUNT"}}, &StringFlag{Name: "count", Aliases: []string{"c"}, EnvVars: []string{"COMPAT_COUNT", "APP_COUNT"}},
}, },
Action: func(ctx *Context) error { Action: func(ctx *Context) error {
if ctx.String("count") != "20" { if ctx.String("count") != "20" {
@ -374,7 +374,7 @@ func TestParseMultiStringFromEnvCascade(t *testing.T) {
func TestParseMultiStringSlice(t *testing.T) { func TestParseMultiStringSlice(t *testing.T) {
(&App{ (&App{
Flags: []Flag{ Flags: []Flag{
StringSliceFlag{Name: "serve", Aliases: []string{"s"}, Value: NewStringSlice()}, &StringSliceFlag{Name: "serve", Aliases: []string{"s"}, Value: NewStringSlice()},
}, },
Action: func(ctx *Context) error { Action: func(ctx *Context) error {
expected := []string{"10", "20"} expected := []string{"10", "20"}
@ -392,7 +392,7 @@ func TestParseMultiStringSlice(t *testing.T) {
func TestParseMultiStringSliceWithDefaults(t *testing.T) { func TestParseMultiStringSliceWithDefaults(t *testing.T) {
(&App{ (&App{
Flags: []Flag{ Flags: []Flag{
StringSliceFlag{Name: "serve", Aliases: []string{"s"}, Value: NewStringSlice("9", "2")}, &StringSliceFlag{Name: "serve", Aliases: []string{"s"}, Value: NewStringSlice("9", "2")},
}, },
Action: func(ctx *Context) error { Action: func(ctx *Context) error {
expected := []string{"10", "20"} expected := []string{"10", "20"}
@ -410,7 +410,7 @@ func TestParseMultiStringSliceWithDefaults(t *testing.T) {
func TestParseMultiStringSliceWithDefaultsUnset(t *testing.T) { func TestParseMultiStringSliceWithDefaultsUnset(t *testing.T) {
(&App{ (&App{
Flags: []Flag{ Flags: []Flag{
StringSliceFlag{Name: "serve", Aliases: []string{"s"}, Value: NewStringSlice("9", "2")}, &StringSliceFlag{Name: "serve", Aliases: []string{"s"}, Value: NewStringSlice("9", "2")},
}, },
Action: func(ctx *Context) error { Action: func(ctx *Context) error {
if !reflect.DeepEqual(ctx.StringSlice("serve"), []string{"9", "2"}) { if !reflect.DeepEqual(ctx.StringSlice("serve"), []string{"9", "2"}) {
@ -430,7 +430,7 @@ func TestParseMultiStringSliceFromEnv(t *testing.T) {
(&App{ (&App{
Flags: []Flag{ Flags: []Flag{
StringSliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewStringSlice(), EnvVars: []string{"APP_INTERVALS"}}, &StringSliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewStringSlice(), EnvVars: []string{"APP_INTERVALS"}},
}, },
Action: func(ctx *Context) error { Action: func(ctx *Context) error {
if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) { if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
@ -450,7 +450,7 @@ func TestParseMultiStringSliceFromEnvWithDefaults(t *testing.T) {
(&App{ (&App{
Flags: []Flag{ Flags: []Flag{
StringSliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewStringSlice("1", "2", "5"), EnvVars: []string{"APP_INTERVALS"}}, &StringSliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewStringSlice("1", "2", "5"), EnvVars: []string{"APP_INTERVALS"}},
}, },
Action: func(ctx *Context) error { Action: func(ctx *Context) error {
if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) { if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
@ -470,7 +470,7 @@ func TestParseMultiStringSliceFromEnvCascade(t *testing.T) {
(&App{ (&App{
Flags: []Flag{ Flags: []Flag{
StringSliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewStringSlice(), EnvVars: []string{"COMPAT_INTERVALS", "APP_INTERVALS"}}, &StringSliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewStringSlice(), EnvVars: []string{"COMPAT_INTERVALS", "APP_INTERVALS"}},
}, },
Action: func(ctx *Context) error { Action: func(ctx *Context) error {
if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) { if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
@ -490,7 +490,7 @@ func TestParseMultiStringSliceFromEnvCascadeWithDefaults(t *testing.T) {
(&App{ (&App{
Flags: []Flag{ Flags: []Flag{
StringSliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewStringSlice("1", "2", "5"), EnvVars: []string{"COMPAT_INTERVALS", "APP_INTERVALS"}}, &StringSliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewStringSlice("1", "2", "5"), EnvVars: []string{"COMPAT_INTERVALS", "APP_INTERVALS"}},
}, },
Action: func(ctx *Context) error { Action: func(ctx *Context) error {
if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) { if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
@ -507,7 +507,7 @@ func TestParseMultiStringSliceFromEnvCascadeWithDefaults(t *testing.T) {
func TestParseMultiInt(t *testing.T) { func TestParseMultiInt(t *testing.T) {
a := App{ a := App{
Flags: []Flag{ Flags: []Flag{
IntFlag{Name: "serve", Aliases: []string{"s"}}, &IntFlag{Name: "serve", Aliases: []string{"s"}},
}, },
Action: func(ctx *Context) error { Action: func(ctx *Context) error {
if ctx.Int("serve") != 10 { if ctx.Int("serve") != 10 {
@ -526,7 +526,7 @@ func TestParseDestinationInt(t *testing.T) {
var dest int var dest int
a := App{ a := App{
Flags: []Flag{ Flags: []Flag{
IntFlag{ &IntFlag{
Name: "dest", Name: "dest",
Destination: &dest, Destination: &dest,
}, },
@ -546,7 +546,7 @@ func TestParseMultiIntFromEnv(t *testing.T) {
os.Setenv("APP_TIMEOUT_SECONDS", "10") os.Setenv("APP_TIMEOUT_SECONDS", "10")
a := App{ a := App{
Flags: []Flag{ Flags: []Flag{
IntFlag{Name: "timeout", Aliases: []string{"t"}, EnvVars: []string{"APP_TIMEOUT_SECONDS"}}, &IntFlag{Name: "timeout", Aliases: []string{"t"}, EnvVars: []string{"APP_TIMEOUT_SECONDS"}},
}, },
Action: func(ctx *Context) error { Action: func(ctx *Context) error {
if ctx.Int("timeout") != 10 { if ctx.Int("timeout") != 10 {
@ -566,7 +566,7 @@ func TestParseMultiIntFromEnvCascade(t *testing.T) {
os.Setenv("APP_TIMEOUT_SECONDS", "10") os.Setenv("APP_TIMEOUT_SECONDS", "10")
a := App{ a := App{
Flags: []Flag{ Flags: []Flag{
IntFlag{Name: "timeout", Aliases: []string{"t"}, EnvVars: []string{"COMPAT_TIMEOUT_SECONDS", "APP_TIMEOUT_SECONDS"}}, &IntFlag{Name: "timeout", Aliases: []string{"t"}, EnvVars: []string{"COMPAT_TIMEOUT_SECONDS", "APP_TIMEOUT_SECONDS"}},
}, },
Action: func(ctx *Context) error { Action: func(ctx *Context) error {
if ctx.Int("timeout") != 10 { if ctx.Int("timeout") != 10 {
@ -584,7 +584,7 @@ func TestParseMultiIntFromEnvCascade(t *testing.T) {
func TestParseMultiIntSlice(t *testing.T) { func TestParseMultiIntSlice(t *testing.T) {
(&App{ (&App{
Flags: []Flag{ Flags: []Flag{
IntSliceFlag{Name: "serve", Aliases: []string{"s"}, Value: NewIntSlice()}, &IntSliceFlag{Name: "serve", Aliases: []string{"s"}, Value: NewIntSlice()},
}, },
Action: func(ctx *Context) error { Action: func(ctx *Context) error {
if !reflect.DeepEqual(ctx.IntSlice("serve"), []int{10, 20}) { if !reflect.DeepEqual(ctx.IntSlice("serve"), []int{10, 20}) {
@ -601,7 +601,7 @@ func TestParseMultiIntSlice(t *testing.T) {
func TestParseMultiIntSliceWithDefaults(t *testing.T) { func TestParseMultiIntSliceWithDefaults(t *testing.T) {
(&App{ (&App{
Flags: []Flag{ Flags: []Flag{
IntSliceFlag{Name: "serve", Aliases: []string{"s"}, Value: NewIntSlice(9, 2)}, &IntSliceFlag{Name: "serve", Aliases: []string{"s"}, Value: NewIntSlice(9, 2)},
}, },
Action: func(ctx *Context) error { Action: func(ctx *Context) error {
if !reflect.DeepEqual(ctx.IntSlice("serve"), []int{10, 20}) { if !reflect.DeepEqual(ctx.IntSlice("serve"), []int{10, 20}) {
@ -618,7 +618,7 @@ func TestParseMultiIntSliceWithDefaults(t *testing.T) {
func TestParseMultiIntSliceWithDefaultsUnset(t *testing.T) { func TestParseMultiIntSliceWithDefaultsUnset(t *testing.T) {
(&App{ (&App{
Flags: []Flag{ Flags: []Flag{
IntSliceFlag{Name: "serve", Aliases: []string{"s"}, Value: NewIntSlice(9, 2)}, &IntSliceFlag{Name: "serve", Aliases: []string{"s"}, Value: NewIntSlice(9, 2)},
}, },
Action: func(ctx *Context) error { Action: func(ctx *Context) error {
if !reflect.DeepEqual(ctx.IntSlice("serve"), []int{9, 2}) { if !reflect.DeepEqual(ctx.IntSlice("serve"), []int{9, 2}) {
@ -638,7 +638,7 @@ func TestParseMultiIntSliceFromEnv(t *testing.T) {
(&App{ (&App{
Flags: []Flag{ Flags: []Flag{
IntSliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewIntSlice(), EnvVars: []string{"APP_INTERVALS"}}, &IntSliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewIntSlice(), EnvVars: []string{"APP_INTERVALS"}},
}, },
Action: func(ctx *Context) error { Action: func(ctx *Context) error {
if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) { if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) {
@ -658,7 +658,7 @@ func TestParseMultiIntSliceFromEnvWithDefaults(t *testing.T) {
(&App{ (&App{
Flags: []Flag{ Flags: []Flag{
IntSliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewIntSlice(1, 2, 5), EnvVars: []string{"APP_INTERVALS"}}, &IntSliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewIntSlice(1, 2, 5), EnvVars: []string{"APP_INTERVALS"}},
}, },
Action: func(ctx *Context) error { Action: func(ctx *Context) error {
if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) { if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) {
@ -678,7 +678,7 @@ func TestParseMultiIntSliceFromEnvCascade(t *testing.T) {
(&App{ (&App{
Flags: []Flag{ Flags: []Flag{
IntSliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewIntSlice(), EnvVars: []string{"COMPAT_INTERVALS", "APP_INTERVALS"}}, &IntSliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewIntSlice(), EnvVars: []string{"COMPAT_INTERVALS", "APP_INTERVALS"}},
}, },
Action: func(ctx *Context) error { Action: func(ctx *Context) error {
if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) { if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) {
@ -695,7 +695,7 @@ func TestParseMultiIntSliceFromEnvCascade(t *testing.T) {
func TestParseMultiFloat64(t *testing.T) { func TestParseMultiFloat64(t *testing.T) {
a := App{ a := App{
Flags: []Flag{ Flags: []Flag{
Float64Flag{Name: "serve", Aliases: []string{"s"}}, &Float64Flag{Name: "serve", Aliases: []string{"s"}},
}, },
Action: func(ctx *Context) error { Action: func(ctx *Context) error {
if ctx.Float64("serve") != 10.2 { if ctx.Float64("serve") != 10.2 {
@ -714,7 +714,7 @@ func TestParseDestinationFloat64(t *testing.T) {
var dest float64 var dest float64
a := App{ a := App{
Flags: []Flag{ Flags: []Flag{
Float64Flag{ &Float64Flag{
Name: "dest", Name: "dest",
Destination: &dest, Destination: &dest,
}, },
@ -734,7 +734,7 @@ func TestParseMultiFloat64FromEnv(t *testing.T) {
os.Setenv("APP_TIMEOUT_SECONDS", "15.5") os.Setenv("APP_TIMEOUT_SECONDS", "15.5")
a := App{ a := App{
Flags: []Flag{ Flags: []Flag{
Float64Flag{Name: "timeout", Aliases: []string{"t"}, EnvVars: []string{"APP_TIMEOUT_SECONDS"}}, &Float64Flag{Name: "timeout", Aliases: []string{"t"}, EnvVars: []string{"APP_TIMEOUT_SECONDS"}},
}, },
Action: func(ctx *Context) error { Action: func(ctx *Context) error {
if ctx.Float64("timeout") != 15.5 { if ctx.Float64("timeout") != 15.5 {
@ -754,7 +754,7 @@ func TestParseMultiFloat64FromEnvCascade(t *testing.T) {
os.Setenv("APP_TIMEOUT_SECONDS", "15.5") os.Setenv("APP_TIMEOUT_SECONDS", "15.5")
a := App{ a := App{
Flags: []Flag{ Flags: []Flag{
Float64Flag{Name: "timeout", Aliases: []string{"t"}, EnvVars: []string{"COMPAT_TIMEOUT_SECONDS", "APP_TIMEOUT_SECONDS"}}, &Float64Flag{Name: "timeout", Aliases: []string{"t"}, EnvVars: []string{"COMPAT_TIMEOUT_SECONDS", "APP_TIMEOUT_SECONDS"}},
}, },
Action: func(ctx *Context) error { Action: func(ctx *Context) error {
if ctx.Float64("timeout") != 15.5 { if ctx.Float64("timeout") != 15.5 {
@ -772,7 +772,7 @@ func TestParseMultiFloat64FromEnvCascade(t *testing.T) {
func TestParseMultiBool(t *testing.T) { func TestParseMultiBool(t *testing.T) {
a := App{ a := App{
Flags: []Flag{ Flags: []Flag{
BoolFlag{Name: "serve", Aliases: []string{"s"}}, &BoolFlag{Name: "serve", Aliases: []string{"s"}},
}, },
Action: func(ctx *Context) error { Action: func(ctx *Context) error {
if ctx.Bool("serve") != true { if ctx.Bool("serve") != true {
@ -791,7 +791,7 @@ func TestParseDestinationBool(t *testing.T) {
var dest bool var dest bool
a := App{ a := App{
Flags: []Flag{ Flags: []Flag{
BoolFlag{ &BoolFlag{
Name: "dest", Name: "dest",
Destination: &dest, Destination: &dest,
}, },
@ -811,7 +811,7 @@ func TestParseMultiBoolFromEnv(t *testing.T) {
os.Setenv("APP_DEBUG", "1") os.Setenv("APP_DEBUG", "1")
a := App{ a := App{
Flags: []Flag{ Flags: []Flag{
BoolFlag{Name: "debug", Aliases: []string{"d"}, EnvVars: []string{"APP_DEBUG"}}, &BoolFlag{Name: "debug", Aliases: []string{"d"}, EnvVars: []string{"APP_DEBUG"}},
}, },
Action: func(ctx *Context) error { Action: func(ctx *Context) error {
if ctx.Bool("debug") != true { if ctx.Bool("debug") != true {
@ -831,7 +831,7 @@ func TestParseMultiBoolFromEnvCascade(t *testing.T) {
os.Setenv("APP_DEBUG", "1") os.Setenv("APP_DEBUG", "1")
a := App{ a := App{
Flags: []Flag{ Flags: []Flag{
BoolFlag{Name: "debug", Aliases: []string{"d"}, EnvVars: []string{"COMPAT_DEBUG", "APP_DEBUG"}}, &BoolFlag{Name: "debug", Aliases: []string{"d"}, EnvVars: []string{"COMPAT_DEBUG", "APP_DEBUG"}},
}, },
Action: func(ctx *Context) error { Action: func(ctx *Context) error {
if ctx.Bool("debug") != true { if ctx.Bool("debug") != true {
@ -849,7 +849,7 @@ func TestParseMultiBoolFromEnvCascade(t *testing.T) {
func TestParseMultiBoolTrue(t *testing.T) { func TestParseMultiBoolTrue(t *testing.T) {
a := App{ a := App{
Flags: []Flag{ Flags: []Flag{
BoolFlag{Name: "implode", Aliases: []string{"i"}, Value: true}, &BoolFlag{Name: "implode", Aliases: []string{"i"}, Value: true},
}, },
Action: func(ctx *Context) error { Action: func(ctx *Context) error {
if ctx.Bool("implode") { if ctx.Bool("implode") {
@ -869,7 +869,7 @@ func TestParseDestinationBoolTrue(t *testing.T) {
a := App{ a := App{
Flags: []Flag{ Flags: []Flag{
BoolFlag{ &BoolFlag{
Name: "dest", Name: "dest",
Value: true, Value: true,
Destination: &dest, Destination: &dest,
@ -890,7 +890,7 @@ func TestParseMultiBoolTrueFromEnv(t *testing.T) {
os.Setenv("APP_DEBUG", "0") os.Setenv("APP_DEBUG", "0")
a := App{ a := App{
Flags: []Flag{ Flags: []Flag{
BoolFlag{ &BoolFlag{
Name: "debug", Name: "debug",
Aliases: []string{"d"}, Aliases: []string{"d"},
Value: true, Value: true,
@ -915,7 +915,7 @@ func TestParseMultiBoolTrueFromEnvCascade(t *testing.T) {
os.Setenv("APP_DEBUG", "0") os.Setenv("APP_DEBUG", "0")
a := App{ a := App{
Flags: []Flag{ Flags: []Flag{
BoolFlag{ &BoolFlag{
Name: "debug", Name: "debug",
Aliases: []string{"d"}, Aliases: []string{"d"},
Value: true, Value: true,
@ -956,7 +956,7 @@ func (p *Parser) String() string {
func TestParseGeneric(t *testing.T) { func TestParseGeneric(t *testing.T) {
a := App{ a := App{
Flags: []Flag{ Flags: []Flag{
GenericFlag{Name: "serve", Aliases: []string{"s"}, Value: &Parser{}}, &GenericFlag{Name: "serve", Aliases: []string{"s"}, Value: &Parser{}},
}, },
Action: func(ctx *Context) error { Action: func(ctx *Context) error {
if !reflect.DeepEqual(ctx.Generic("serve"), &Parser{"10", "20"}) { if !reflect.DeepEqual(ctx.Generic("serve"), &Parser{"10", "20"}) {
@ -976,7 +976,7 @@ func TestParseGenericFromEnv(t *testing.T) {
os.Setenv("APP_SERVE", "20,30") os.Setenv("APP_SERVE", "20,30")
a := App{ a := App{
Flags: []Flag{ Flags: []Flag{
GenericFlag{ &GenericFlag{
Name: "serve", Name: "serve",
Aliases: []string{"s"}, Aliases: []string{"s"},
Value: &Parser{}, Value: &Parser{},
@ -1001,7 +1001,7 @@ func TestParseGenericFromEnvCascade(t *testing.T) {
os.Setenv("APP_FOO", "99,2000") os.Setenv("APP_FOO", "99,2000")
a := App{ a := App{
Flags: []Flag{ Flags: []Flag{
GenericFlag{ &GenericFlag{
Name: "foos", Name: "foos",
Value: &Parser{}, Value: &Parser{},
EnvVars: []string{"COMPAT_FOO", "APP_FOO"}, EnvVars: []string{"COMPAT_FOO", "APP_FOO"},

@ -74,7 +74,7 @@ OPTIONS:
{{end}}{{end}} {{end}}{{end}}
` `
var helpCommand = Command{ var helpCommand = &Command{
Name: "help", Name: "help",
Aliases: []string{"h"}, Aliases: []string{"h"},
Usage: "Shows a list of commands or help for one command", Usage: "Shows a list of commands or help for one command",
@ -90,7 +90,7 @@ var helpCommand = Command{
}, },
} }
var helpSubcommand = Command{ var helpSubcommand = &Command{
Name: "help", Name: "help",
Aliases: []string{"h"}, Aliases: []string{"h"},
Usage: "Shows a list of commands or help for one command", Usage: "Shows a list of commands or help for one command",
@ -158,7 +158,15 @@ func ShowCommandHelp(ctx *Context, command string) error {
// ShowSubcommandHelp prints help for the given subcommand // ShowSubcommandHelp prints help for the given subcommand
func ShowSubcommandHelp(c *Context) error { func ShowSubcommandHelp(c *Context) error {
return ShowCommandHelp(c, c.Command.Name) if c == nil {
return nil
}
if c.Command != nil {
return ShowCommandHelp(c, c.Command.Name)
}
return ShowCommandHelp(c, "")
} }
// ShowVersion prints the version number of the App // ShowVersion prints the version number of the App

@ -59,7 +59,7 @@ func Test_Help_Custom_Flags(t *testing.T) {
HelpFlag = oldFlag HelpFlag = oldFlag
}() }()
HelpFlag = BoolFlag{ HelpFlag = &BoolFlag{
Name: "help", Name: "help",
Aliases: []string{"x"}, Aliases: []string{"x"},
Usage: "show help", Usage: "show help",
@ -67,7 +67,7 @@ func Test_Help_Custom_Flags(t *testing.T) {
app := App{ app := App{
Flags: []Flag{ Flags: []Flag{
BoolFlag{Name: "foo", Aliases: []string{"h"}}, &BoolFlag{Name: "foo", Aliases: []string{"h"}},
}, },
Action: func(ctx *Context) error { Action: func(ctx *Context) error {
if ctx.Bool("h") != true { if ctx.Bool("h") != true {
@ -90,7 +90,7 @@ func Test_Version_Custom_Flags(t *testing.T) {
VersionFlag = oldFlag VersionFlag = oldFlag
}() }()
VersionFlag = BoolFlag{ VersionFlag = &BoolFlag{
Name: "version", Name: "version",
Aliases: []string{"V"}, Aliases: []string{"V"},
Usage: "show version", Usage: "show version",
@ -98,7 +98,7 @@ func Test_Version_Custom_Flags(t *testing.T) {
app := App{ app := App{
Flags: []Flag{ Flags: []Flag{
BoolFlag{Name: "foo", Aliases: []string{"v"}}, &BoolFlag{Name: "foo", Aliases: []string{"v"}},
}, },
Action: func(ctx *Context) error { Action: func(ctx *Context) error {
if ctx.Bool("v") != true { if ctx.Bool("v") != true {
@ -173,7 +173,7 @@ func Test_helpSubcommand_Action_ErrorIfNoTopic(t *testing.T) {
func TestShowAppHelp_CommandAliases(t *testing.T) { func TestShowAppHelp_CommandAliases(t *testing.T) {
app := &App{ app := &App{
Commands: []Command{ Commands: []*Command{
{ {
Name: "frobbly", Name: "frobbly",
Aliases: []string{"fr", "frob"}, Aliases: []string{"fr", "frob"},
@ -195,7 +195,7 @@ func TestShowAppHelp_CommandAliases(t *testing.T) {
func TestShowCommandHelp_CommandAliases(t *testing.T) { func TestShowCommandHelp_CommandAliases(t *testing.T) {
app := &App{ app := &App{
Commands: []Command{ Commands: []*Command{
{ {
Name: "frobbly", Name: "frobbly",
Aliases: []string{"fr", "frob", "bork"}, Aliases: []string{"fr", "frob", "bork"},
@ -221,7 +221,7 @@ func TestShowCommandHelp_CommandAliases(t *testing.T) {
func TestShowSubcommandHelp_CommandAliases(t *testing.T) { func TestShowSubcommandHelp_CommandAliases(t *testing.T) {
app := &App{ app := &App{
Commands: []Command{ Commands: []*Command{
{ {
Name: "frobbly", Name: "frobbly",
Aliases: []string{"fr", "frob", "bork"}, Aliases: []string{"fr", "frob", "bork"},
@ -243,7 +243,7 @@ func TestShowSubcommandHelp_CommandAliases(t *testing.T) {
func TestShowAppHelp_HiddenCommand(t *testing.T) { func TestShowAppHelp_HiddenCommand(t *testing.T) {
app := &App{ app := &App{
Commands: []Command{ Commands: []*Command{
{ {
Name: "frobbly", Name: "frobbly",
Action: func(ctx *Context) error { Action: func(ctx *Context) error {

Loading…
Cancel
Save