From 97fd93272f0a480907246cf41b109bb81c3e01ee Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Fri, 11 Jul 2014 13:29:56 -0400 Subject: [PATCH 1/3] Starting to hack in some env var configuration goodness --- flag.go | 161 ++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 126 insertions(+), 35 deletions(-) diff --git a/flag.go b/flag.go index e6f8838..50f192f 100644 --- a/flag.go +++ b/flag.go @@ -3,18 +3,19 @@ package cli import ( "flag" "fmt" + "os" "strconv" "strings" ) // This flag enables bash-completion for all commands and subcommands -var BashCompletionFlag = BoolFlag{"generate-bash-completion", ""} +var BashCompletionFlag = BoolFlag{"generate-bash-completion", "", ""} // This flag prints the version for the application -var VersionFlag = BoolFlag{"version, v", "print the version"} +var VersionFlag = BoolFlag{"version, v", "print the version", ""} // This flag prints the help for all commands and subcommands -var HelpFlag = BoolFlag{"help, h", "show help"} +var HelpFlag = BoolFlag{"help, h", "show help", ""} // Flag is a common interface related to parsing flags in cli. // For more advanced flag parsing techniques, it is recomended that @@ -51,16 +52,24 @@ type Generic interface { // GenericFlag is the flag type for types implementing Generic type GenericFlag struct { - Name string - Value Generic - Usage string + Name string + Value Generic + Usage string + EnvVar string } func (f GenericFlag) String() string { - return fmt.Sprintf("%s%s %v\t`%v` %s", prefixFor(f.Name), f.Name, f.Value, "-"+f.Name+" option -"+f.Name+" option", f.Usage) + return withEnvHint(f.EnvVar, fmt.Sprintf("%s%s %v\t`%v` %s", prefixFor(f.Name), f.Name, f.Value, "-"+f.Name+" option -"+f.Name+" option", f.Usage)) } func (f GenericFlag) Apply(set *flag.FlagSet) { + val := f.Value + if f.EnvVar != "" { + if envVal := os.Getenv(f.EnvVar); envVal != "" { + val.Set(envVal) + } + } + eachName(f.Name, func(name string) { set.Var(f.Value, name, f.Usage) }) @@ -86,18 +95,29 @@ func (f *StringSlice) Value() []string { } type StringSliceFlag struct { - Name string - Value *StringSlice - Usage string + Name string + Value *StringSlice + Usage string + EnvVar string } func (f StringSliceFlag) String() string { firstName := strings.Trim(strings.Split(f.Name, ",")[0], " ") pref := prefixFor(firstName) - return fmt.Sprintf("%s '%v'\t%v", prefixedNames(f.Name), pref+firstName+" option "+pref+firstName+" option", f.Usage) + return withEnvHint(f.EnvVar, fmt.Sprintf("%s '%v'\t%v", prefixedNames(f.Name), pref+firstName+" option "+pref+firstName+" option", f.Usage)) } func (f StringSliceFlag) Apply(set *flag.FlagSet) { + if f.EnvVar != "" { + if envVal := os.Getenv(f.EnvVar); envVal != "" { + newVal := &StringSlice{} + for _, s := range strings.Split(envVal, ",") { + newVal.Set(s) + } + f.Value = newVal + } + } + eachName(f.Name, func(name string) { set.Var(f.Value, name, f.Usage) }) @@ -129,18 +149,32 @@ func (f *IntSlice) Value() []int { } type IntSliceFlag struct { - Name string - Value *IntSlice - Usage string + Name string + Value *IntSlice + Usage string + EnvVar string } func (f IntSliceFlag) String() string { firstName := strings.Trim(strings.Split(f.Name, ",")[0], " ") pref := prefixFor(firstName) - return fmt.Sprintf("%s '%v'\t%v", prefixedNames(f.Name), pref+firstName+" option "+pref+firstName+" option", f.Usage) + return withEnvHint(f.EnvVar, fmt.Sprintf("%s '%v'\t%v", prefixedNames(f.Name), pref+firstName+" option "+pref+firstName+" option", f.Usage)) } func (f IntSliceFlag) Apply(set *flag.FlagSet) { + if f.EnvVar != "" { + if envVal := os.Getenv(f.EnvVar); envVal != "" { + newVal := &IntSlice{} + for _, s := range strings.Split(envVal, ",") { + err := newVal.Set(s) + if err != nil { + fmt.Fprintf(os.Stderr, err.Error()) + } + } + f.Value = newVal + } + } + eachName(f.Name, func(name string) { set.Var(f.Value, name, f.Usage) }) @@ -151,17 +185,28 @@ func (f IntSliceFlag) getName() string { } type BoolFlag struct { - Name string - Usage string + Name string + Usage string + EnvVar string } func (f BoolFlag) String() string { - return fmt.Sprintf("%s\t%v", prefixedNames(f.Name), f.Usage) + return withEnvHint(f.EnvVar, fmt.Sprintf("%s\t%v", prefixedNames(f.Name), f.Usage)) } func (f BoolFlag) Apply(set *flag.FlagSet) { + val := false + if f.EnvVar != "" { + if envVal := os.Getenv(f.EnvVar); envVal != "" { + envValBool, err := strconv.ParseBool(envVal) + if err == nil { + val = envValBool + } + } + } + eachName(f.Name, func(name string) { - set.Bool(name, false, f.Usage) + set.Bool(name, val, f.Usage) }) } @@ -170,17 +215,28 @@ func (f BoolFlag) getName() string { } type BoolTFlag struct { - Name string - Usage string + Name string + Usage string + EnvVar string } func (f BoolTFlag) String() string { - return fmt.Sprintf("%s\t%v", prefixedNames(f.Name), f.Usage) + return withEnvHint(f.EnvVar, fmt.Sprintf("%s\t%v", prefixedNames(f.Name), f.Usage)) } func (f BoolTFlag) Apply(set *flag.FlagSet) { + val := true + if f.EnvVar != "" { + if envVal := os.Getenv(f.EnvVar); envVal != "" { + envValBool, err := strconv.ParseBool(envVal) + if err == nil { + val = envValBool + } + } + } + eachName(f.Name, func(name string) { - set.Bool(name, true, f.Usage) + set.Bool(name, val, f.Usage) }) } @@ -189,9 +245,10 @@ func (f BoolTFlag) getName() string { } type StringFlag struct { - Name string - Value string - Usage string + Name string + Value string + Usage string + EnvVar string } func (f StringFlag) String() string { @@ -204,10 +261,16 @@ func (f StringFlag) String() string { fmtString = "%s %v\t%v" } - return fmt.Sprintf(fmtString, prefixedNames(f.Name), f.Value, f.Usage) + return withEnvHint(f.EnvVar, fmt.Sprintf(fmtString, prefixedNames(f.Name), f.Value, f.Usage)) } func (f StringFlag) Apply(set *flag.FlagSet) { + if f.EnvVar != "" { + if envVal := os.Getenv(f.EnvVar); envVal != "" { + f.Value = envVal + } + } + eachName(f.Name, func(name string) { set.String(name, f.Value, f.Usage) }) @@ -218,16 +281,26 @@ func (f StringFlag) getName() string { } type IntFlag struct { - Name string - Value int - Usage string + Name string + Value int + Usage string + EnvVar string } func (f IntFlag) String() string { - return fmt.Sprintf("%s '%v'\t%v", prefixedNames(f.Name), f.Value, f.Usage) + return withEnvHint(f.EnvVar, fmt.Sprintf("%s '%v'\t%v", prefixedNames(f.Name), f.Value, f.Usage)) } func (f IntFlag) Apply(set *flag.FlagSet) { + if f.EnvVar != "" { + if envVal := os.Getenv(f.EnvVar); envVal != "" { + envValInt, err := strconv.ParseUint(envVal, 10, 64) + if err == nil { + f.Value = int(envValInt) + } + } + } + eachName(f.Name, func(name string) { set.Int(name, f.Value, f.Usage) }) @@ -238,16 +311,26 @@ func (f IntFlag) getName() string { } type Float64Flag struct { - Name string - Value float64 - Usage string + Name string + Value float64 + Usage string + EnvVar string } func (f Float64Flag) String() string { - return fmt.Sprintf("%s '%v'\t%v", prefixedNames(f.Name), f.Value, f.Usage) + return withEnvHint(f.EnvVar, fmt.Sprintf("%s '%v'\t%v", prefixedNames(f.Name), f.Value, f.Usage)) } func (f Float64Flag) Apply(set *flag.FlagSet) { + if f.EnvVar != "" { + if envVal := os.Getenv(f.EnvVar); envVal != "" { + envValFloat, err := strconv.ParseFloat(envVal, 10) + if err == nil { + f.Value = float64(envValFloat) + } + } + } + eachName(f.Name, func(name string) { set.Float64(name, f.Value, f.Usage) }) @@ -278,3 +361,11 @@ func prefixedNames(fullName string) (prefixed string) { } return } + +func withEnvHint(envVar, str string) string { + envText := "" + if envVar != "" { + envText = fmt.Sprintf(" [$%s]", envVar) + } + return str + envText +} From fc16c67be3bb3ed54d832f03870e9d2460f6a14a Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Fri, 11 Jul 2014 18:13:10 -0400 Subject: [PATCH 2/3] Updating structs to use labels, adding tests for env stuff --- README.md | 27 +++- app_test.go | 6 +- cli_test.go | 18 ++- flag.go | 14 ++- flag_test.go | 340 +++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 396 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 4621310..2453c1a 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,11 @@ Setting and querying flags is simple. ``` go ... app.Flags = []cli.Flag { - cli.StringFlag{"lang", "english", "language for the greeting"}, + cli.StringFlag{ + Name: "lang", + Value: "english", + Usage: "language for the greeting", + }, } app.Action = func(c *cli.Context) { name := "someone" @@ -159,7 +163,26 @@ You can set alternate (or short) names for flags by providing a comma-delimited ``` go app.Flags = []cli.Flag { - cli.StringFlag{"lang, l", "english", "language for the greeting"}, + cli.StringFlag{ + Name: "lang, l", + Value: "english", + Usage: "language for the greeting", + }, +} +``` + +#### Values from the Environment + +You can also have the default value set from the environment via EnvVar. e.g. + +``` go +app.Flags = []cli.Flag { + cli.StringFlag{ + Name: "lang, l", + Value: "english", + Usage: "language for the greeting", + EnvVar: "APP_LANG", + }, } ``` diff --git a/app_test.go b/app_test.go index cf0e3d0..26c674a 100644 --- a/app_test.go +++ b/app_test.go @@ -43,7 +43,11 @@ func ExampleAppSubcommand() { Usage: "sends a greeting in english", Description: "greets someone in english", Flags: []cli.Flag{ - cli.StringFlag{"name", "Bob", "Name of the person to greet"}, + cli.StringFlag{ + Name: "name", + Value: "Bob", + Usage: "Name of the person to greet", + }, }, Action: func(c *cli.Context) { fmt.Println("Hello,", c.String("name")) diff --git a/cli_test.go b/cli_test.go index 30f3c13..71dd5a4 100644 --- a/cli_test.go +++ b/cli_test.go @@ -47,7 +47,11 @@ func ExampleSubcommand() { Usage: "sends a greeting in english", Description: "greets someone in english", Flags: []cli.Flag{ - cli.StringFlag{"name", "Bob", "Name of the person to greet"}, + cli.StringFlag{ + Name: "name", + Value: "Bob", + Usage: "Name of the person to greet", + }, }, Action: func(c *cli.Context) { println("Hello, ", c.String("name")) @@ -57,7 +61,11 @@ func ExampleSubcommand() { ShortName: "sp", Usage: "sends a greeting in spanish", Flags: []cli.Flag{ - cli.StringFlag{"surname", "Jones", "Surname of the person to greet"}, + cli.StringFlag{ + Name: "surname", + Value: "Jones", + Usage: "Surname of the person to greet", + }, }, Action: func(c *cli.Context) { println("Hola, ", c.String("surname")) @@ -67,7 +75,11 @@ func ExampleSubcommand() { ShortName: "fr", Usage: "sends a greeting in french", Flags: []cli.Flag{ - cli.StringFlag{"nickname", "Stevie", "Nickname of the person to greet"}, + cli.StringFlag{ + Name: "nickname", + Value: "Stevie", + Usage: "Nickname of the person to greet", + }, }, Action: func(c *cli.Context) { println("Bonjour, ", c.String("nickname")) diff --git a/flag.go b/flag.go index 50f192f..60353e2 100644 --- a/flag.go +++ b/flag.go @@ -9,13 +9,21 @@ import ( ) // This flag enables bash-completion for all commands and subcommands -var BashCompletionFlag = BoolFlag{"generate-bash-completion", "", ""} +var BashCompletionFlag = BoolFlag{ + Name: "generate-bash-completion", +} // This flag prints the version for the application -var VersionFlag = BoolFlag{"version, v", "print the version", ""} +var VersionFlag = BoolFlag{ + Name: "version, v", + Usage: "print the version", +} // This flag prints the help for all commands and subcommands -var HelpFlag = BoolFlag{"help, h", "show help", ""} +var HelpFlag = BoolFlag{ + Name: "help, h", + Usage: "show help", +} // Flag is a common interface related to parsing flags in cli. // For more advanced flag parsing techniques, it is recomended that diff --git a/flag_test.go b/flag_test.go index 1c05f01..76dad72 100644 --- a/flag_test.go +++ b/flag_test.go @@ -4,6 +4,7 @@ import ( "github.com/codegangsta/cli" "fmt" + "os" "reflect" "strings" "testing" @@ -52,6 +53,55 @@ func TestStringFlagHelpOutput(t *testing.T) { } } +func TestStringFlagWithEnvVarHelpOutput(t *testing.T) { + + os.Setenv("APP_FOO", "derp") + for _, test := range stringFlagTests { + flag := cli.StringFlag{Name: test.name, Value: test.value, EnvVar: "APP_FOO"} + output := flag.String() + + if !strings.HasSuffix(output, " [$APP_FOO]") { + t.Errorf("%s does not end with [$APP_FOO]", output) + } + } +} + +var stringSliceFlagTests = []struct { + name string + value *cli.StringSlice + expected string +}{ + {"help", &cli.StringSlice{""}, "--help '--help option --help option'\t"}, + {"h", &cli.StringSlice{""}, "-h '-h option -h option'\t"}, + {"h", &cli.StringSlice{""}, "-h '-h option -h option'\t"}, + {"test", &cli.StringSlice{"Something"}, "--test '--test option --test option'\t"}, +} + +func TestStringSliceFlagHelpOutput(t *testing.T) { + + for _, test := range stringSliceFlagTests { + flag := cli.StringSliceFlag{Name: test.name, Value: test.value} + output := flag.String() + + if output != test.expected { + t.Errorf("%q does not match %q", output, test.expected) + } + } +} + +func TestStringSliceFlagWithEnvVarHelpOutput(t *testing.T) { + + os.Setenv("APP_QWWX", "11,4") + for _, test := range stringSliceFlagTests { + flag := cli.StringSliceFlag{Name: test.name, Value: test.value, EnvVar: "APP_QWWX"} + output := flag.String() + + if !strings.HasSuffix(output, " [$APP_QWWX]") { + t.Errorf("%q does not end with [$APP_QWWX]", output) + } + } +} + var intFlagTests = []struct { name string expected string @@ -72,6 +122,55 @@ func TestIntFlagHelpOutput(t *testing.T) { } } +func TestIntFlagWithEnvVarHelpOutput(t *testing.T) { + + os.Setenv("APP_BAR", "2") + for _, test := range intFlagTests { + flag := cli.IntFlag{Name: test.name, EnvVar: "APP_BAR"} + output := flag.String() + + if !strings.HasSuffix(output, " [$APP_BAR]") { + t.Errorf("%s does not end with [$APP_BAR]", output) + } + } +} + +var intSliceFlagTests = []struct { + name string + value *cli.IntSlice + expected string +}{ + {"help", &cli.IntSlice{}, "--help '--help option --help option'\t"}, + {"h", &cli.IntSlice{}, "-h '-h option -h option'\t"}, + {"h", &cli.IntSlice{}, "-h '-h option -h option'\t"}, + {"test", &cli.IntSlice{9}, "--test '--test option --test option'\t"}, +} + +func TestIntSliceFlagHelpOutput(t *testing.T) { + + for _, test := range intSliceFlagTests { + flag := cli.IntSliceFlag{Name: test.name, Value: test.value} + output := flag.String() + + if output != test.expected { + t.Errorf("%q does not match %q", output, test.expected) + } + } +} + +func TestIntSliceFlagWithEnvVarHelpOutput(t *testing.T) { + + os.Setenv("APP_SMURF", "42,3") + for _, test := range intSliceFlagTests { + flag := cli.IntSliceFlag{Name: test.name, Value: test.value, EnvVar: "APP_SMURF"} + output := flag.String() + + if !strings.HasSuffix(output, " [$APP_SMURF]") { + t.Errorf("%q does not end with [$APP_SMURF]", output) + } + } +} + var float64FlagTests = []struct { name string expected string @@ -92,6 +191,54 @@ func TestFloat64FlagHelpOutput(t *testing.T) { } } +func TestFloat64FlagWithEnvVarHelpOutput(t *testing.T) { + + os.Setenv("APP_BAZ", "99.4") + for _, test := range float64FlagTests { + flag := cli.Float64Flag{Name: test.name, EnvVar: "APP_BAZ"} + output := flag.String() + + if !strings.HasSuffix(output, " [$APP_BAZ]") { + t.Errorf("%s does not end with [$APP_BAZ]", output) + } + } +} + +var genericFlagTests = []struct { + name string + value cli.Generic + expected string +}{ + {"help", &Parser{}, "--help \t`-help option -help option` "}, + {"h", &Parser{}, "-h \t`-h option -h option` "}, + {"test", &Parser{}, "--test \t`-test option -test option` "}, +} + +func TestGenericFlagHelpOutput(t *testing.T) { + + for _, test := range genericFlagTests { + flag := cli.GenericFlag{Name: test.name} + output := flag.String() + + if output != test.expected { + t.Errorf("%q does not match %q", output, test.expected) + } + } +} + +func TestGenericFlagWithEnvVarHelpOutput(t *testing.T) { + + os.Setenv("APP_ZAP", "3") + for _, test := range genericFlagTests { + flag := cli.GenericFlag{Name: test.name, EnvVar: "APP_ZAP"} + output := flag.String() + + if !strings.HasSuffix(output, " [$APP_ZAP]") { + t.Errorf("%s does not end with [$APP_ZAP]", output) + } + } +} + func TestParseMultiString(t *testing.T) { (&cli.App{ Flags: []cli.Flag{ @@ -108,6 +255,23 @@ func TestParseMultiString(t *testing.T) { }).Run([]string{"run", "-s", "10"}) } +func TestParseMultiStringFromEnv(t *testing.T) { + os.Setenv("APP_COUNT", "20") + (&cli.App{ + Flags: []cli.Flag{ + cli.StringFlag{Name: "count, c", EnvVar: "APP_COUNT"}, + }, + Action: func(ctx *cli.Context) { + if ctx.String("count") != "20" { + t.Errorf("main name not set") + } + if ctx.String("c") != "20" { + t.Errorf("short name not set") + } + }, + }).Run([]string{"run"}) +} + func TestParseMultiStringSlice(t *testing.T) { (&cli.App{ Flags: []cli.Flag{ @@ -124,6 +288,24 @@ func TestParseMultiStringSlice(t *testing.T) { }).Run([]string{"run", "-s", "10", "-s", "20"}) } +func TestParseMultiStringSliceFromEnv(t *testing.T) { + os.Setenv("APP_INTERVALS", "20,30,40") + + (&cli.App{ + Flags: []cli.Flag{ + cli.StringSliceFlag{Name: "intervals, i", Value: &cli.StringSlice{}, EnvVar: "APP_INTERVALS"}, + }, + Action: func(ctx *cli.Context) { + if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) { + t.Errorf("main name not set from env") + } + if !reflect.DeepEqual(ctx.StringSlice("i"), []string{"20", "30", "40"}) { + t.Errorf("short name not set from env") + } + }, + }).Run([]string{"run"}) +} + func TestParseMultiInt(t *testing.T) { a := cli.App{ Flags: []cli.Flag{ @@ -141,6 +323,93 @@ func TestParseMultiInt(t *testing.T) { a.Run([]string{"run", "-s", "10"}) } +func TestParseMultiIntFromEnv(t *testing.T) { + os.Setenv("APP_TIMEOUT_SECONDS", "10") + a := cli.App{ + Flags: []cli.Flag{ + cli.IntFlag{Name: "timeout, t", EnvVar: "APP_TIMEOUT_SECONDS"}, + }, + Action: func(ctx *cli.Context) { + if ctx.Int("timeout") != 10 { + t.Errorf("main name not set") + } + if ctx.Int("t") != 10 { + t.Errorf("short name not set") + } + }, + } + a.Run([]string{"run"}) +} + +func TestParseMultiIntSlice(t *testing.T) { + (&cli.App{ + Flags: []cli.Flag{ + cli.IntSliceFlag{Name: "serve, s", Value: &cli.IntSlice{}}, + }, + Action: func(ctx *cli.Context) { + if !reflect.DeepEqual(ctx.IntSlice("serve"), []int{10, 20}) { + t.Errorf("main name not set") + } + if !reflect.DeepEqual(ctx.IntSlice("s"), []int{10, 20}) { + t.Errorf("short name not set") + } + }, + }).Run([]string{"run", "-s", "10", "-s", "20"}) +} + +func TestParseMultiIntSliceFromEnv(t *testing.T) { + os.Setenv("APP_INTERVALS", "20,30,40") + + (&cli.App{ + Flags: []cli.Flag{ + cli.IntSliceFlag{Name: "intervals, i", Value: &cli.IntSlice{}, EnvVar: "APP_INTERVALS"}, + }, + Action: func(ctx *cli.Context) { + if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) { + t.Errorf("main name not set from env") + } + if !reflect.DeepEqual(ctx.IntSlice("i"), []int{20, 30, 40}) { + t.Errorf("short name not set from env") + } + }, + }).Run([]string{"run"}) +} + +func TestParseMultiFloat64(t *testing.T) { + a := cli.App{ + Flags: []cli.Flag{ + cli.Float64Flag{Name: "serve, s"}, + }, + Action: func(ctx *cli.Context) { + if ctx.Float64("serve") != 10.2 { + t.Errorf("main name not set") + } + if ctx.Float64("s") != 10.2 { + t.Errorf("short name not set") + } + }, + } + a.Run([]string{"run", "-s", "10.2"}) +} + +func TestParseMultiFloat64FromEnv(t *testing.T) { + os.Setenv("APP_TIMEOUT_SECONDS", "15.5") + a := cli.App{ + Flags: []cli.Flag{ + cli.Float64Flag{Name: "timeout, t", EnvVar: "APP_TIMEOUT_SECONDS"}, + }, + Action: func(ctx *cli.Context) { + if ctx.Float64("timeout") != 15.5 { + t.Errorf("main name not set") + } + if ctx.Float64("t") != 15.5 { + t.Errorf("short name not set") + } + }, + } + a.Run([]string{"run"}) +} + func TestParseMultiBool(t *testing.T) { a := cli.App{ Flags: []cli.Flag{ @@ -158,6 +427,59 @@ func TestParseMultiBool(t *testing.T) { a.Run([]string{"run", "--serve"}) } +func TestParseMultiBoolFromEnv(t *testing.T) { + os.Setenv("APP_DEBUG", "1") + a := cli.App{ + Flags: []cli.Flag{ + cli.BoolFlag{Name: "debug, d", EnvVar: "APP_DEBUG"}, + }, + Action: func(ctx *cli.Context) { + if ctx.Bool("debug") != true { + t.Errorf("main name not set from env") + } + if ctx.Bool("d") != true { + t.Errorf("short name not set from env") + } + }, + } + a.Run([]string{"run"}) +} + +func TestParseMultiBoolT(t *testing.T) { + a := cli.App{ + Flags: []cli.Flag{ + cli.BoolTFlag{Name: "serve, s"}, + }, + Action: func(ctx *cli.Context) { + if ctx.BoolT("serve") != true { + t.Errorf("main name not set") + } + if ctx.BoolT("s") != true { + t.Errorf("short name not set") + } + }, + } + a.Run([]string{"run", "--serve"}) +} + +func TestParseMultiBoolTFromEnv(t *testing.T) { + os.Setenv("APP_DEBUG", "0") + a := cli.App{ + Flags: []cli.Flag{ + cli.BoolTFlag{Name: "debug, d", EnvVar: "APP_DEBUG"}, + }, + Action: func(ctx *cli.Context) { + if ctx.BoolT("debug") != false { + t.Errorf("main name not set from env") + } + if ctx.BoolT("d") != false { + t.Errorf("short name not set from env") + } + }, + } + a.Run([]string{"run"}) +} + type Parser [2]string func (p *Parser) Set(value string) error { @@ -192,3 +514,21 @@ func TestParseGeneric(t *testing.T) { } a.Run([]string{"run", "-s", "10,20"}) } + +func TestParseGenericFromEnv(t *testing.T) { + os.Setenv("APP_SERVE", "20,30") + a := cli.App{ + Flags: []cli.Flag{ + cli.GenericFlag{Name: "serve, s", Value: &Parser{}, EnvVar: "APP_SERVE"}, + }, + Action: func(ctx *cli.Context) { + if !reflect.DeepEqual(ctx.Generic("serve"), &Parser{"20", "30"}) { + t.Errorf("main name not set from env") + } + if !reflect.DeepEqual(ctx.Generic("s"), &Parser{"20", "30"}) { + t.Errorf("short name not set from env") + } + }, + } + a.Run([]string{"run"}) +} From 48869e13a4e5d5695de22e4232d516b1d973aca9 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Fri, 11 Jul 2014 18:30:16 -0400 Subject: [PATCH 3/3] Addressing `go vet` offenses --- flag_test.go | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/flag_test.go b/flag_test.go index 76dad72..4103236 100644 --- a/flag_test.go +++ b/flag_test.go @@ -71,10 +71,26 @@ var stringSliceFlagTests = []struct { value *cli.StringSlice expected string }{ - {"help", &cli.StringSlice{""}, "--help '--help option --help option'\t"}, - {"h", &cli.StringSlice{""}, "-h '-h option -h option'\t"}, - {"h", &cli.StringSlice{""}, "-h '-h option -h option'\t"}, - {"test", &cli.StringSlice{"Something"}, "--test '--test option --test option'\t"}, + {"help", func() *cli.StringSlice { + s := &cli.StringSlice{} + s.Set("") + return s + }(), "--help '--help option --help option'\t"}, + {"h", func() *cli.StringSlice { + s := &cli.StringSlice{} + s.Set("") + return s + }(), "-h '-h option -h option'\t"}, + {"h", func() *cli.StringSlice { + s := &cli.StringSlice{} + s.Set("") + return s + }(), "-h '-h option -h option'\t"}, + {"test", func() *cli.StringSlice { + s := &cli.StringSlice{} + s.Set("Something") + return s + }(), "--test '--test option --test option'\t"}, } func TestStringSliceFlagHelpOutput(t *testing.T) { @@ -143,7 +159,11 @@ var intSliceFlagTests = []struct { {"help", &cli.IntSlice{}, "--help '--help option --help option'\t"}, {"h", &cli.IntSlice{}, "-h '-h option -h option'\t"}, {"h", &cli.IntSlice{}, "-h '-h option -h option'\t"}, - {"test", &cli.IntSlice{9}, "--test '--test option --test option'\t"}, + {"test", func() *cli.IntSlice { + i := &cli.IntSlice{} + i.Set("9") + return i + }(), "--test '--test option --test option'\t"}, } func TestIntSliceFlagHelpOutput(t *testing.T) {