Merge pull request #421 from urfave/minimize-struct-copying
Minimize copying while keeping things safe-ish
This commit is contained in:
commit
459201f506
30
README.md
30
README.md
@ -216,7 +216,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",
|
||||||
@ -243,7 +243,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",
|
||||||
@ -275,7 +275,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`",
|
||||||
@ -296,7 +296,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",
|
||||||
@ -313,7 +313,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",
|
||||||
@ -327,7 +327,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",
|
||||||
@ -344,7 +344,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.
|
||||||
@ -373,8 +373,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)
|
||||||
@ -386,7 +386,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"},
|
||||||
@ -409,7 +409,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",
|
||||||
@ -442,7 +442,7 @@ E.g.
|
|||||||
|
|
||||||
```go
|
```go
|
||||||
...
|
...
|
||||||
app.Commands = []cli.Command{
|
app.Commands = []*cli.Command{
|
||||||
{
|
{
|
||||||
Name: "noop",
|
Name: "noop",
|
||||||
},
|
},
|
||||||
@ -490,7 +490,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?",
|
||||||
@ -498,7 +498,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
app.Action = func(ctx *cli.Context) error {
|
app.Action = func(ctx *cli.Context) error {
|
||||||
if !ctx.Bool("ginger-crouton") {
|
if !ctx.Bool("ginger-crouton") {
|
||||||
return cli.NewExitError("it is not in the soup", 86)
|
return cli.Exit("it is not in the soup", 86)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -519,7 +519,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)
|
||||||
|
71
app.go
71
app.go
@ -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
|
||||||
@ -36,8 +36,8 @@ type App struct {
|
|||||||
HideHelp bool
|
HideHelp bool
|
||||||
// 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()
|
// Categories contains the categorized commands and is populated on app startup
|
||||||
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,16 +113,17 @@ 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.AddCommand(command.Category, command)
|
||||||
}
|
}
|
||||||
sort.Sort(a.categories)
|
sort.Sort(a.Categories.(*commandCategories))
|
||||||
|
|
||||||
// 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -183,7 +184,7 @@ func (a *App) Run(arguments []string) (err error) {
|
|||||||
defer func() {
|
defer func() {
|
||||||
if afterErr := a.After(context); afterErr != nil {
|
if afterErr := a.After(context); afterErr != nil {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = NewMultiError(err, afterErr)
|
err = newMultiError(err, afterErr)
|
||||||
} else {
|
} else {
|
||||||
err = afterErr
|
err = afterErr
|
||||||
}
|
}
|
||||||
@ -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)
|
||||||
@ -294,7 +296,7 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) {
|
|||||||
if afterErr != nil {
|
if afterErr != nil {
|
||||||
HandleExitCoder(err)
|
HandleExitCoder(err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = NewMultiError(err, afterErr)
|
err = newMultiError(err, afterErr)
|
||||||
} else {
|
} else {
|
||||||
err = afterErr
|
err = afterErr
|
||||||
}
|
}
|
||||||
@ -331,28 +333,21 @@ 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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Categories returns a slice containing all the categories with the commands they contain
|
|
||||||
func (a *App) Categories() CommandCategories {
|
|
||||||
return a.categories
|
|
||||||
}
|
|
||||||
|
|
||||||
// VisibleCategories returns a slice of categories and commands that are
|
// VisibleCategories returns a slice of categories and commands that are
|
||||||
// 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 {
|
if len(category.VisibleCommands()) > 0 {
|
||||||
if !command.Hidden {
|
return category
|
||||||
return category
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}(); visible != nil {
|
}(); visible != nil {
|
||||||
@ -363,8 +358,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 +393,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 +412,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 + "> "
|
||||||
|
276
app_test.go
276
app_test.go
@ -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
|
||||||
|
defer func() {
|
||||||
|
expectedCommand.Action = expectedAction
|
||||||
|
actualCommand.Action = actualAction
|
||||||
|
}()
|
||||||
|
expectedCommand.Action = nil
|
||||||
|
actualCommand.Action = nil
|
||||||
|
|
||||||
if !reflect.DeepEqual(expectedCommand, actualCommand) {
|
if !reflect.DeepEqual(expectedCommand, actualCommand) {
|
||||||
t.Errorf("expected\n%#v\n!=\n%#v", 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,23 +1142,24 @@ func TestApp_Run_Categories(t *testing.T) {
|
|||||||
|
|
||||||
app.Run([]string{"categories"})
|
app.Run([]string{"categories"})
|
||||||
|
|
||||||
expect := CommandCategories{
|
expect := commandCategories([]*commandCategory{
|
||||||
&CommandCategory{
|
{
|
||||||
Name: "1",
|
name: "1",
|
||||||
Commands: []Command{
|
commands: []*Command{
|
||||||
app.Commands[0],
|
app.Commands[0],
|
||||||
app.Commands[1],
|
app.Commands[1],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
&CommandCategory{
|
{
|
||||||
Name: "2",
|
name: "2",
|
||||||
Commands: []Command{
|
commands: []*Command{
|
||||||
app.Commands[2],
|
app.Commands[2],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
})
|
||||||
if !reflect.DeepEqual(app.Categories(), expect) {
|
|
||||||
t.Fatalf("expected categories %#v, to equal %#v", app.Categories(), expect)
|
if !reflect.DeepEqual(app.Categories, &expect) {
|
||||||
|
t.Fatalf("expected categories %#v, to equal %#v", app.Categories, &expect)
|
||||||
}
|
}
|
||||||
|
|
||||||
output := buf.String()
|
output := buf.String()
|
||||||
@ -1149,7 +1173,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",
|
||||||
@ -1168,16 +1192,16 @@ func TestApp_VisibleCategories(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := []*CommandCategory{
|
expected := []CommandCategory{
|
||||||
{
|
&commandCategory{
|
||||||
Name: "2",
|
name: "2",
|
||||||
Commands: []Command{
|
commands: []*Command{
|
||||||
app.Commands[1],
|
app.Commands[1],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
&commandCategory{
|
||||||
Name: "3",
|
name: "3",
|
||||||
Commands: []Command{
|
commands: []*Command{
|
||||||
app.Commands[2],
|
app.Commands[2],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -1188,7 +1212,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",
|
||||||
@ -1208,10 +1232,10 @@ func TestApp_VisibleCategories(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
expected = []*CommandCategory{
|
expected = []CommandCategory{
|
||||||
{
|
&commandCategory{
|
||||||
Name: "3",
|
name: "3",
|
||||||
Commands: []Command{
|
commands: []*Command{
|
||||||
app.Commands[2],
|
app.Commands[2],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -1222,7 +1246,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",
|
||||||
@ -1243,10 +1267,8 @@ func TestApp_VisibleCategories(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
expected = []*CommandCategory{}
|
|
||||||
|
|
||||||
app.Setup()
|
app.Setup()
|
||||||
expect(t, expected, app.VisibleCategories())
|
expect(t, []CommandCategory{}, app.VisibleCategories())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestApp_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) {
|
func TestApp_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) {
|
||||||
@ -1270,9 +1292,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 +1321,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 +1332,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 +1351,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 +1362,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",
|
||||||
},
|
},
|
||||||
|
60
args.go
Normal file
60
args.go
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package cli
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
var (
|
||||||
|
argsRangeErr = errors.New("index out of range")
|
||||||
|
)
|
||||||
|
|
||||||
|
type Args interface {
|
||||||
|
// Get returns the nth argument, or else a blank string
|
||||||
|
Get(n int) string
|
||||||
|
// First returns the first argument, or else a blank string
|
||||||
|
First() string
|
||||||
|
// Tail returns the rest of the arguments (not the first one)
|
||||||
|
// or else an empty string slice
|
||||||
|
Tail() []string
|
||||||
|
// Len returns the length of the wrapped slice
|
||||||
|
Len() int
|
||||||
|
// Present checks if there are any arguments present
|
||||||
|
Present() bool
|
||||||
|
// Slice returns a copy of the internal slice
|
||||||
|
Slice() []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type args []string
|
||||||
|
|
||||||
|
func (a *args) Get(n int) string {
|
||||||
|
if len(*a) > n {
|
||||||
|
return (*a)[n]
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *args) First() string {
|
||||||
|
return a.Get(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *args) Tail() []string {
|
||||||
|
if a.Len() >= 2 {
|
||||||
|
tail := []string((*a)[1:])
|
||||||
|
ret := make([]string, len(tail))
|
||||||
|
copy(ret, tail)
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *args) Len() int {
|
||||||
|
return len(*a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *args) Present() bool {
|
||||||
|
return a.Len() != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *args) Slice() []string {
|
||||||
|
ret := make([]string, len(*a))
|
||||||
|
copy(ret, []string(*a))
|
||||||
|
return ret
|
||||||
|
}
|
89
category.go
89
category.go
@ -1,41 +1,82 @@
|
|||||||
package cli
|
package cli
|
||||||
|
|
||||||
// CommandCategories is a slice of *CommandCategory.
|
type CommandCategories interface {
|
||||||
type CommandCategories []*CommandCategory
|
// AddCommand adds a command to a category, creating a new category if necessary.
|
||||||
|
AddCommand(category string, command *Command)
|
||||||
// CommandCategory is a category containing commands.
|
// Categories returns a copy of the category slice
|
||||||
type CommandCategory struct {
|
Categories() []CommandCategory
|
||||||
Name string
|
|
||||||
Commands Commands
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c CommandCategories) Less(i, j int) bool {
|
type commandCategories []*commandCategory
|
||||||
return c[i].Name < c[j].Name
|
|
||||||
|
func newCommandCategories() CommandCategories {
|
||||||
|
ret := commandCategories([]*commandCategory{})
|
||||||
|
return &ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c CommandCategories) Len() int {
|
func (c *commandCategories) Less(i, j int) bool {
|
||||||
return len(c)
|
return (*c)[i].Name() < (*c)[j].Name()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c CommandCategories) Swap(i, j int) {
|
func (c *commandCategories) Len() int {
|
||||||
c[i], c[j] = c[j], c[i]
|
return len(*c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddCommand adds a command to a category.
|
func (c *commandCategories) Swap(i, j int) {
|
||||||
func (c CommandCategories) AddCommand(category string, command Command) CommandCategories {
|
(*c)[i], (*c)[j] = (*c)[j], (*c)[i]
|
||||||
for _, commandCategory := range c {
|
}
|
||||||
if commandCategory.Name == category {
|
|
||||||
commandCategory.Commands = append(commandCategory.Commands, command)
|
func (c *commandCategories) AddCommand(category string, command *Command) {
|
||||||
return c
|
for _, commandCategory := range []*commandCategory(*c) {
|
||||||
|
if commandCategory.name == category {
|
||||||
|
commandCategory.commands = append(commandCategory.commands, command)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return append(c, &CommandCategory{Name: category, Commands: []Command{command}})
|
newVal := commandCategories(append(*c,
|
||||||
|
&commandCategory{name: category, commands: []*Command{command}}))
|
||||||
|
(*c) = newVal
|
||||||
}
|
}
|
||||||
|
|
||||||
// VisibleCommands returns a slice of the Commands with Hidden=false
|
func (c *commandCategories) Categories() []CommandCategory {
|
||||||
func (c *CommandCategory) VisibleCommands() []Command {
|
ret := make([]CommandCategory, len(*c))
|
||||||
ret := []Command{}
|
for i, cat := range *c {
|
||||||
for _, command := range c.Commands {
|
ret[i] = cat
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommandCategory is a category containing commands.
|
||||||
|
type CommandCategory interface {
|
||||||
|
// Name returns the category name string
|
||||||
|
Name() string
|
||||||
|
// VisibleCommands returns a slice of the Commands with Hidden=false
|
||||||
|
VisibleCommands() []*Command
|
||||||
|
}
|
||||||
|
|
||||||
|
type commandCategory struct {
|
||||||
|
name string
|
||||||
|
commands []*Command
|
||||||
|
}
|
||||||
|
|
||||||
|
func newCommandCategory(name string) *commandCategory {
|
||||||
|
return &commandCategory{
|
||||||
|
name: name,
|
||||||
|
commands: []*Command{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *commandCategory) Name() string {
|
||||||
|
return c.name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *commandCategory) VisibleCommands() []*Command {
|
||||||
|
if c.commands == nil {
|
||||||
|
c.commands = []*Command{}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret := []*Command{}
|
||||||
|
for _, command := range c.commands {
|
||||||
if !command.Hidden {
|
if !command.Hidden {
|
||||||
ret = append(ret, command)
|
ret = append(ret, command)
|
||||||
}
|
}
|
||||||
|
54
command.go
54
command.go
@ -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)
|
||||||
@ -127,7 +120,7 @@ func (c Command) Run(ctx *Context) (err error) {
|
|||||||
if afterErr != nil {
|
if afterErr != nil {
|
||||||
HandleExitCoder(err)
|
HandleExitCoder(err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = NewMultiError(err, afterErr)
|
err = newMultiError(err, afterErr)
|
||||||
} else {
|
} else {
|
||||||
err = afterErr
|
err = afterErr
|
||||||
}
|
}
|
||||||
@ -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,12 +193,12 @@ 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.AddCommand(command.Category, command)
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Sort(app.categories)
|
sort.Sort(app.Categories.(*commandCategories))
|
||||||
|
|
||||||
// bash completion
|
// bash completion
|
||||||
app.EnableBashCompletion = ctx.App.EnableBashCompletion
|
app.EnableBashCompletion = ctx.App.EnableBashCompletion
|
||||||
@ -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\"") {
|
||||||
|
49
context.go
49
context.go
@ -10,11 +10,11 @@ import (
|
|||||||
|
|
||||||
// Context is a type that is passed through to
|
// Context is a type that is passed through to
|
||||||
// each Handler action in a cli application. Context
|
// each Handler action in a cli application. Context
|
||||||
// can be used to retrieve context-specific Args and
|
// can be used to retrieve context-specific args and
|
||||||
// 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,54 +147,15 @@ 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())
|
ret := args(c.flagSet.Args())
|
||||||
return args
|
return &ret
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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()
|
||||||
}
|
|
||||||
|
|
||||||
// Get returns the nth argument, or else a blank string
|
|
||||||
func (a Args) Get(n int) string {
|
|
||||||
if len(a) > n {
|
|
||||||
return a[n]
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// First returns the first argument, or else a blank string
|
|
||||||
func (a Args) First() string {
|
|
||||||
return a.Get(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tail returns the rest of the arguments (not the first one)
|
|
||||||
// or else an empty string slice
|
|
||||||
func (a Args) Tail() []string {
|
|
||||||
if len(a) >= 2 {
|
|
||||||
return []string(a)[1:]
|
|
||||||
}
|
|
||||||
return []string{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Present checks if there are any arguments present
|
|
||||||
func (a Args) Present() bool {
|
|
||||||
return len(a) != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Swap swaps arguments at the given indexes
|
|
||||||
func (a Args) Swap(from, to int) error {
|
|
||||||
if from >= len(a) || to >= len(a) {
|
|
||||||
return errors.New("index out of range")
|
|
||||||
}
|
|
||||||
a[from], a[to] = a[to], a[from]
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func lookupFlagSet(name string, ctx *Context) *flag.FlagSet {
|
func lookupFlagSet(name string, ctx *Context) *flag.FlagSet {
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
50
errors.go
50
errors.go
@ -15,25 +15,39 @@ var OsExiter = os.Exit
|
|||||||
var ErrWriter io.Writer = os.Stderr
|
var ErrWriter io.Writer = os.Stderr
|
||||||
|
|
||||||
// MultiError is an error that wraps multiple errors.
|
// MultiError is an error that wraps multiple errors.
|
||||||
type MultiError struct {
|
type MultiError interface {
|
||||||
Errors []error
|
error
|
||||||
|
// Errors returns a copy of the errors slice
|
||||||
|
Errors() []error
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMultiError creates a new MultiError. Pass in one or more errors.
|
// NewMultiError creates a new MultiError. Pass in one or more errors.
|
||||||
func NewMultiError(err ...error) MultiError {
|
func newMultiError(err ...error) MultiError {
|
||||||
return MultiError{Errors: err}
|
ret := multiError(err)
|
||||||
|
return &ret
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error implents the error interface.
|
type multiError []error
|
||||||
func (m MultiError) Error() string {
|
|
||||||
errs := make([]string, len(m.Errors))
|
// Error implements the error interface.
|
||||||
for i, err := range m.Errors {
|
func (m *multiError) Error() string {
|
||||||
|
errs := make([]string, len(*m))
|
||||||
|
for i, err := range *m {
|
||||||
errs[i] = err.Error()
|
errs[i] = err.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.Join(errs, "\n")
|
return strings.Join(errs, "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Errors returns a copy of the errors slice
|
||||||
|
func (m *multiError) Errors() []error {
|
||||||
|
errs := make([]error, len(*m))
|
||||||
|
for _, err := range *m {
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
|
return errs
|
||||||
|
}
|
||||||
|
|
||||||
// ExitCoder is the interface checked by `App` and `Command` for a custom exit
|
// ExitCoder is the interface checked by `App` and `Command` for a custom exit
|
||||||
// code
|
// code
|
||||||
type ExitCoder interface {
|
type ExitCoder interface {
|
||||||
@ -41,29 +55,25 @@ type ExitCoder interface {
|
|||||||
ExitCode() int
|
ExitCode() int
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExitError fulfills both the builtin `error` interface and `ExitCoder`
|
type exitError struct {
|
||||||
type ExitError struct {
|
|
||||||
exitCode int
|
exitCode int
|
||||||
message string
|
message string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewExitError makes a new *ExitError
|
// Exit wraps a message and exit code into an ExitCoder suitable for handling by
|
||||||
func NewExitError(message string, exitCode int) *ExitError {
|
// HandleExitCoder
|
||||||
return &ExitError{
|
func Exit(message string, exitCode int) ExitCoder {
|
||||||
|
return &exitError{
|
||||||
exitCode: exitCode,
|
exitCode: exitCode,
|
||||||
message: message,
|
message: message,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error returns the string message, fulfilling the interface required by
|
func (ee *exitError) Error() string {
|
||||||
// `error`
|
|
||||||
func (ee *ExitError) Error() string {
|
|
||||||
return ee.message
|
return ee.message
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExitCode returns the exit code, fulfilling the interface required by
|
func (ee *exitError) ExitCode() int {
|
||||||
// `ExitCoder`
|
|
||||||
func (ee *ExitError) ExitCode() int {
|
|
||||||
return ee.exitCode
|
return ee.exitCode
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,7 +95,7 @@ func HandleExitCoder(err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if multiErr, ok := err.(MultiError); ok {
|
if multiErr, ok := err.(MultiError); ok {
|
||||||
for _, merr := range multiErr.Errors {
|
for _, merr := range multiErr.Errors() {
|
||||||
HandleExitCoder(merr)
|
HandleExitCoder(merr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ func TestHandleExitCoder_ExitCoder(t *testing.T) {
|
|||||||
|
|
||||||
defer func() { OsExiter = os.Exit }()
|
defer func() { OsExiter = os.Exit }()
|
||||||
|
|
||||||
HandleExitCoder(NewExitError("galactic perimeter breach", 9))
|
HandleExitCoder(Exit("galactic perimeter breach", 9))
|
||||||
|
|
||||||
expect(t, exitCode, 9)
|
expect(t, exitCode, 9)
|
||||||
expect(t, called, true)
|
expect(t, called, true)
|
||||||
@ -51,8 +51,8 @@ func TestHandleExitCoder_MultiErrorWithExitCoder(t *testing.T) {
|
|||||||
|
|
||||||
defer func() { OsExiter = os.Exit }()
|
defer func() { OsExiter = os.Exit }()
|
||||||
|
|
||||||
exitErr := NewExitError("galactic perimeter breach", 9)
|
exitErr := Exit("galactic perimeter breach", 9)
|
||||||
err := NewMultiError(errors.New("wowsa"), errors.New("egad"), exitErr)
|
err := newMultiError(errors.New("wowsa"), errors.New("egad"), exitErr)
|
||||||
HandleExitCoder(err)
|
HandleExitCoder(err)
|
||||||
|
|
||||||
expect(t, exitCode, 9)
|
expect(t, exitCode, 9)
|
||||||
|
80
flag.go
80
flag.go
@ -22,22 +22,22 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// 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",
|
||||||
@ -90,13 +90,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 {
|
||||||
@ -113,7 +113,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 flagNames(f)
|
return flagNames(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,12 +174,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 {
|
||||||
if envVal := os.Getenv(envVar); envVal != "" {
|
if envVal := os.Getenv(envVar); envVal != "" {
|
||||||
@ -204,7 +204,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 flagNames(f)
|
return flagNames(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,12 +280,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 {
|
||||||
if envVal := os.Getenv(envVar); envVal != "" {
|
if envVal := os.Getenv(envVar); envVal != "" {
|
||||||
@ -313,7 +313,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 flagNames(f)
|
return flagNames(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -329,12 +329,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 {
|
||||||
if envVal := os.Getenv(envVar); envVal != "" {
|
if envVal := os.Getenv(envVar); envVal != "" {
|
||||||
@ -357,7 +357,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 flagNames(f)
|
return flagNames(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -373,12 +373,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 {
|
||||||
if envVal := os.Getenv(envVar); envVal != "" {
|
if envVal := os.Getenv(envVar); envVal != "" {
|
||||||
@ -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 flagNames(f)
|
return flagNames(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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 {
|
||||||
if envVal := os.Getenv(envVar); envVal != "" {
|
if envVal := os.Getenv(envVar); envVal != "" {
|
||||||
@ -443,7 +443,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 flagNames(f)
|
return flagNames(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -460,12 +460,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 {
|
||||||
if envVal := os.Getenv(envVar); envVal != "" {
|
if envVal := os.Getenv(envVar); envVal != "" {
|
||||||
@ -488,7 +488,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 flagNames(f)
|
return flagNames(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -505,12 +505,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 {
|
||||||
if envVal := os.Getenv(envVar); envVal != "" {
|
if envVal := os.Getenv(envVar); envVal != "" {
|
||||||
@ -532,14 +532,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 flagNames(f)
|
return flagNames(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -658,10 +658,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())
|
||||||
@ -693,7 +693,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() {
|
||||||
@ -704,7 +704,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() {
|
||||||
@ -731,3 +731,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
|
||||||
|
}
|
||||||
|
102
flag_test.go
102
flag_test.go
@ -21,7 +21,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 {
|
||||||
@ -58,7 +58,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 {
|
||||||
@ -71,7 +71,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]"
|
||||||
@ -110,7 +110,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 {
|
||||||
@ -123,7 +123,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]"
|
||||||
@ -155,7 +155,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 {
|
||||||
@ -168,7 +168,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]"
|
||||||
@ -202,7 +202,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 {
|
||||||
@ -215,7 +215,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]"
|
||||||
@ -252,7 +252,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 {
|
||||||
@ -265,7 +265,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]"
|
||||||
@ -297,7 +297,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 {
|
||||||
@ -310,7 +310,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]"
|
||||||
@ -345,7 +345,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 {
|
||||||
@ -358,7 +358,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]"
|
||||||
@ -383,7 +383,7 @@ func TestGenericFlagApply_SetsAllNames(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" {
|
||||||
@ -401,7 +401,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,
|
||||||
},
|
},
|
||||||
@ -421,7 +421,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" {
|
||||||
@ -440,7 +440,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" {
|
||||||
@ -457,7 +457,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"}
|
||||||
@ -475,7 +475,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"}
|
||||||
@ -493,7 +493,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"}) {
|
||||||
@ -513,7 +513,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"}) {
|
||||||
@ -533,7 +533,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"}) {
|
||||||
@ -553,7 +553,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"}) {
|
||||||
@ -573,7 +573,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"}) {
|
||||||
@ -590,7 +590,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 {
|
||||||
@ -609,7 +609,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,
|
||||||
},
|
},
|
||||||
@ -629,7 +629,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 {
|
||||||
@ -649,7 +649,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 {
|
||||||
@ -667,7 +667,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}) {
|
||||||
@ -684,7 +684,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}) {
|
||||||
@ -701,7 +701,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}) {
|
||||||
@ -721,7 +721,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}) {
|
||||||
@ -741,7 +741,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}) {
|
||||||
@ -761,7 +761,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}) {
|
||||||
@ -778,7 +778,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 {
|
||||||
@ -797,7 +797,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,
|
||||||
},
|
},
|
||||||
@ -817,7 +817,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 {
|
||||||
@ -837,7 +837,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 {
|
||||||
@ -855,7 +855,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 {
|
||||||
@ -874,7 +874,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,
|
||||||
},
|
},
|
||||||
@ -894,7 +894,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 {
|
||||||
@ -914,7 +914,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 {
|
||||||
@ -932,7 +932,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") {
|
||||||
@ -952,7 +952,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,
|
||||||
@ -973,7 +973,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,
|
||||||
@ -998,7 +998,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,
|
||||||
@ -1039,7 +1039,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"}) {
|
||||||
@ -1059,7 +1059,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{},
|
||||||
@ -1084,7 +1084,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"},
|
||||||
|
35
help.go
35
help.go
@ -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",
|
||||||
@ -149,7 +149,7 @@ func ShowCommandHelp(ctx *Context, command string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ctx.App.CommandNotFound == nil {
|
if ctx.App.CommandNotFound == nil {
|
||||||
return NewExitError(fmt.Sprintf("No help topic for '%v'", command), 3)
|
return Exit(fmt.Sprintf("No help topic for '%v'", command), 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.App.CommandNotFound(ctx, command)
|
ctx.App.CommandNotFound(ctx, 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
|
||||||
@ -193,15 +201,28 @@ func printHelp(out io.Writer, templ string, data interface{}) {
|
|||||||
|
|
||||||
w := tabwriter.NewWriter(out, 0, 8, 1, '\t', 0)
|
w := tabwriter.NewWriter(out, 0, 8, 1, '\t', 0)
|
||||||
t := template.Must(template.New("help").Funcs(funcMap).Parse(templ))
|
t := template.Must(template.New("help").Funcs(funcMap).Parse(templ))
|
||||||
|
|
||||||
|
errDebug := os.Getenv("CLI_TEMPLATE_ERROR_DEBUG") != ""
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
if errDebug {
|
||||||
|
fmt.Fprintf(ErrWriter, "CLI TEMPLATE PANIC: %#v\n", r)
|
||||||
|
}
|
||||||
|
if os.Getenv("CLI_TEMPLATE_REPANIC") != "" {
|
||||||
|
panic(r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
err := t.Execute(w, data)
|
err := t.Execute(w, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// If the writer is closed, t.Execute will fail, and there's nothing
|
if errDebug {
|
||||||
// we can do to recover.
|
|
||||||
if os.Getenv("CLI_TEMPLATE_ERROR_DEBUG") != "" {
|
|
||||||
fmt.Fprintf(ErrWriter, "CLI TEMPLATE ERROR: %#v\n", err)
|
fmt.Fprintf(ErrWriter, "CLI TEMPLATE ERROR: %#v\n", err)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Flush()
|
w.Flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
24
help_test.go
24
help_test.go
@ -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 {
|
||||||
@ -129,9 +129,9 @@ func Test_helpCommand_Action_ErrorIfNoTopic(t *testing.T) {
|
|||||||
t.Fatalf("expected error from helpCommand.Action(), but got nil")
|
t.Fatalf("expected error from helpCommand.Action(), but got nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
exitErr, ok := err.(*ExitError)
|
exitErr, ok := err.(*exitError)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Fatalf("expected ExitError from helpCommand.Action(), but instead got: %v", err.Error())
|
t.Fatalf("expected *exitError from helpCommand.Action(), but instead got: %v", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
if !strings.HasPrefix(exitErr.Error(), "No help topic for") {
|
if !strings.HasPrefix(exitErr.Error(), "No help topic for") {
|
||||||
@ -157,9 +157,9 @@ func Test_helpSubcommand_Action_ErrorIfNoTopic(t *testing.T) {
|
|||||||
t.Fatalf("expected error from helpCommand.Action(), but got nil")
|
t.Fatalf("expected error from helpCommand.Action(), but got nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
exitErr, ok := err.(*ExitError)
|
exitErr, ok := err.(*exitError)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Fatalf("expected ExitError from helpCommand.Action(), but instead got: %v", err.Error())
|
t.Fatalf("expected *exitError from helpCommand.Action(), but instead got: %v", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
if !strings.HasPrefix(exitErr.Error(), "No help topic for") {
|
if !strings.HasPrefix(exitErr.Error(), "No help topic for") {
|
||||||
@ -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 {
|
||||||
|
@ -12,6 +12,10 @@ var (
|
|||||||
wd, _ = os.Getwd()
|
wd, _ = os.Getwd()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
os.Setenv("CLI_TEMPLATE_REPANIC", "1")
|
||||||
|
}
|
||||||
|
|
||||||
func expect(t *testing.T, a interface{}, b interface{}) {
|
func expect(t *testing.T, a interface{}, b interface{}) {
|
||||||
_, fn, line, _ := runtime.Caller(1)
|
_, fn, line, _ := runtime.Caller(1)
|
||||||
fn = strings.Replace(fn, wd+"/", "", -1)
|
fn = strings.Replace(fn, wd+"/", "", -1)
|
||||||
|
Loading…
Reference in New Issue
Block a user