Merge pull request #530 from urfave/consider-empty-env-vars
Consider empty environment variables as set
This commit is contained in:
commit
31b79c9a33
@ -2,9 +2,9 @@ package altsrc
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
"gopkg.in/urfave/cli.v1"
|
"gopkg.in/urfave/cli.v1"
|
||||||
)
|
)
|
||||||
@ -237,13 +237,11 @@ func (f *Float64Flag) ApplyInputSourceValue(context *cli.Context, isc InputSourc
|
|||||||
func isEnvVarSet(envVars string) bool {
|
func isEnvVarSet(envVars string) bool {
|
||||||
for _, envVar := range strings.Split(envVars, ",") {
|
for _, envVar := range strings.Split(envVars, ",") {
|
||||||
envVar = strings.TrimSpace(envVar)
|
envVar = strings.TrimSpace(envVar)
|
||||||
if envVal := os.Getenv(envVar); envVal != "" {
|
if _, ok := syscall.Getenv(envVar); ok {
|
||||||
// TODO: Can't use this for bools as
|
// TODO: Can't use this for bools as
|
||||||
// set means that it was true or false based on
|
// set means that it was true or false based on
|
||||||
// Bool flag type, should work for other types
|
// Bool flag type, should work for other types
|
||||||
if len(envVal) > 0 {
|
return true
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
12
app.go
12
app.go
@ -174,7 +174,11 @@ func (a *App) Run(arguments []string) (err error) {
|
|||||||
a.Setup()
|
a.Setup()
|
||||||
|
|
||||||
// parse flags
|
// parse flags
|
||||||
set := flagSet(a.Name, a.Flags)
|
set, err := flagSet(a.Name, a.Flags)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
set.SetOutput(ioutil.Discard)
|
set.SetOutput(ioutil.Discard)
|
||||||
err = set.Parse(arguments[1:])
|
err = set.Parse(arguments[1:])
|
||||||
nerr := normalizeFlags(a.Flags, set)
|
nerr := normalizeFlags(a.Flags, set)
|
||||||
@ -293,7 +297,11 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// parse flags
|
// parse flags
|
||||||
set := flagSet(a.Name, a.Flags)
|
set, err := flagSet(a.Name, a.Flags)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
set.SetOutput(ioutil.Discard)
|
set.SetOutput(ioutil.Discard)
|
||||||
err = set.Parse(ctx.Args().Tail())
|
err = set.Parse(ctx.Args().Tail())
|
||||||
nerr := normalizeFlags(a.Flags, set)
|
nerr := normalizeFlags(a.Flags, set)
|
||||||
|
24
app_test.go
24
app_test.go
@ -1523,7 +1523,11 @@ func TestApp_OnUsageError_WithWrongFlagValue_ForSubcommand(t *testing.T) {
|
|||||||
func TestHandleAction_WithNonFuncAction(t *testing.T) {
|
func TestHandleAction_WithNonFuncAction(t *testing.T) {
|
||||||
app := NewApp()
|
app := NewApp()
|
||||||
app.Action = 42
|
app.Action = 42
|
||||||
err := HandleAction(app.Action, NewContext(app, flagSet(app.Name, app.Flags), nil))
|
fs, err := flagSet(app.Name, app.Flags)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error creating FlagSet: %s", err)
|
||||||
|
}
|
||||||
|
err = HandleAction(app.Action, NewContext(app, fs, nil))
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("expected to receive error from Run, got none")
|
t.Fatalf("expected to receive error from Run, got none")
|
||||||
@ -1547,7 +1551,11 @@ func TestHandleAction_WithNonFuncAction(t *testing.T) {
|
|||||||
func TestHandleAction_WithInvalidFuncSignature(t *testing.T) {
|
func TestHandleAction_WithInvalidFuncSignature(t *testing.T) {
|
||||||
app := NewApp()
|
app := NewApp()
|
||||||
app.Action = func() string { return "" }
|
app.Action = func() string { return "" }
|
||||||
err := HandleAction(app.Action, NewContext(app, flagSet(app.Name, app.Flags), nil))
|
fs, err := flagSet(app.Name, app.Flags)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error creating FlagSet: %s", err)
|
||||||
|
}
|
||||||
|
err = HandleAction(app.Action, NewContext(app, fs, nil))
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("expected to receive error from Run, got none")
|
t.Fatalf("expected to receive error from Run, got none")
|
||||||
@ -1571,7 +1579,11 @@ func TestHandleAction_WithInvalidFuncSignature(t *testing.T) {
|
|||||||
func TestHandleAction_WithInvalidFuncReturnSignature(t *testing.T) {
|
func TestHandleAction_WithInvalidFuncReturnSignature(t *testing.T) {
|
||||||
app := NewApp()
|
app := NewApp()
|
||||||
app.Action = func(_ *Context) (int, error) { return 0, nil }
|
app.Action = func(_ *Context) (int, error) { return 0, nil }
|
||||||
err := HandleAction(app.Action, NewContext(app, flagSet(app.Name, app.Flags), nil))
|
fs, err := flagSet(app.Name, app.Flags)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error creating FlagSet: %s", err)
|
||||||
|
}
|
||||||
|
err = HandleAction(app.Action, NewContext(app, fs, nil))
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("expected to receive error from Run, got none")
|
t.Fatalf("expected to receive error from Run, got none")
|
||||||
@ -1602,5 +1614,9 @@ func TestHandleAction_WithUnknownPanic(t *testing.T) {
|
|||||||
fn(ctx)
|
fn(ctx)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
HandleAction(app.Action, NewContext(app, flagSet(app.Name, app.Flags), nil))
|
fs, err := flagSet(app.Name, app.Flags)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error creating FlagSet: %s", err)
|
||||||
|
}
|
||||||
|
HandleAction(app.Action, NewContext(app, fs, nil))
|
||||||
}
|
}
|
||||||
|
@ -91,7 +91,10 @@ func (c Command) Run(ctx *Context) (err error) {
|
|||||||
c.Flags = append(c.Flags, BashCompletionFlag)
|
c.Flags = append(c.Flags, BashCompletionFlag)
|
||||||
}
|
}
|
||||||
|
|
||||||
set := flagSet(c.Name, c.Flags)
|
set, err := flagSet(c.Name, c.Flags)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
set.SetOutput(ioutil.Discard)
|
set.SetOutput(ioutil.Discard)
|
||||||
|
|
||||||
if c.SkipFlagParsing {
|
if c.SkipFlagParsing {
|
||||||
|
@ -3,9 +3,9 @@ package cli
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"flag"
|
"flag"
|
||||||
"os"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Context is a type that is passed through to
|
// Context is a type that is passed through to
|
||||||
@ -91,7 +91,7 @@ func (c *Context) IsSet(name string) bool {
|
|||||||
|
|
||||||
eachName(envVarValue.String(), func(envVar string) {
|
eachName(envVarValue.String(), func(envVar string) {
|
||||||
envVar = strings.TrimSpace(envVar)
|
envVar = strings.TrimSpace(envVar)
|
||||||
if envVal := os.Getenv(envVar); envVal != "" {
|
if _, ok := syscall.Getenv(envVar); ok {
|
||||||
c.setFlags[name] = true
|
c.setFlags[name] = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -147,6 +147,11 @@ func (c *Context) Parent() *Context {
|
|||||||
return c.parentContext
|
return c.parentContext
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// value returns the value of the flag coressponding to `name`
|
||||||
|
func (c *Context) value(name string) interface{} {
|
||||||
|
return c.flagSet.Lookup(name).Value.(flag.Getter).Get()
|
||||||
|
}
|
||||||
|
|
||||||
// Args contains apps console arguments
|
// Args contains apps console arguments
|
||||||
type Args []string
|
type Args []string
|
||||||
|
|
||||||
|
@ -184,18 +184,30 @@ func TestContext_IsSet(t *testing.T) {
|
|||||||
// XXX Corresponds to hack in context.IsSet for flags with EnvVar field
|
// XXX Corresponds to hack in context.IsSet for flags with EnvVar field
|
||||||
// Should be moved to `flag_test` in v2
|
// Should be moved to `flag_test` in v2
|
||||||
func TestContext_IsSet_fromEnv(t *testing.T) {
|
func TestContext_IsSet_fromEnv(t *testing.T) {
|
||||||
var timeoutIsSet, tIsSet, noEnvVarIsSet, nIsSet bool
|
var (
|
||||||
|
timeoutIsSet, tIsSet bool
|
||||||
|
noEnvVarIsSet, nIsSet bool
|
||||||
|
passwordIsSet, pIsSet bool
|
||||||
|
unparsableIsSet, uIsSet bool
|
||||||
|
)
|
||||||
|
|
||||||
os.Clearenv()
|
clearenv()
|
||||||
os.Setenv("APP_TIMEOUT_SECONDS", "15.5")
|
os.Setenv("APP_TIMEOUT_SECONDS", "15.5")
|
||||||
|
os.Setenv("APP_PASSWORD", "")
|
||||||
a := App{
|
a := App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
Float64Flag{Name: "timeout, t", EnvVar: "APP_TIMEOUT_SECONDS"},
|
Float64Flag{Name: "timeout, t", EnvVar: "APP_TIMEOUT_SECONDS"},
|
||||||
|
StringFlag{Name: "password, p", EnvVar: "APP_PASSWORD"},
|
||||||
|
Float64Flag{Name: "unparsable, u", EnvVar: "APP_UNPARSABLE"},
|
||||||
Float64Flag{Name: "no-env-var, n"},
|
Float64Flag{Name: "no-env-var, n"},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) error {
|
Action: func(ctx *Context) error {
|
||||||
timeoutIsSet = ctx.IsSet("timeout")
|
timeoutIsSet = ctx.IsSet("timeout")
|
||||||
tIsSet = ctx.IsSet("t")
|
tIsSet = ctx.IsSet("t")
|
||||||
|
passwordIsSet = ctx.IsSet("password")
|
||||||
|
pIsSet = ctx.IsSet("p")
|
||||||
|
unparsableIsSet = ctx.IsSet("unparsable")
|
||||||
|
uIsSet = ctx.IsSet("u")
|
||||||
noEnvVarIsSet = ctx.IsSet("no-env-var")
|
noEnvVarIsSet = ctx.IsSet("no-env-var")
|
||||||
nIsSet = ctx.IsSet("n")
|
nIsSet = ctx.IsSet("n")
|
||||||
return nil
|
return nil
|
||||||
@ -204,8 +216,15 @@ func TestContext_IsSet_fromEnv(t *testing.T) {
|
|||||||
a.Run([]string{"run"})
|
a.Run([]string{"run"})
|
||||||
expect(t, timeoutIsSet, true)
|
expect(t, timeoutIsSet, true)
|
||||||
expect(t, tIsSet, true)
|
expect(t, tIsSet, true)
|
||||||
|
expect(t, passwordIsSet, true)
|
||||||
|
expect(t, pIsSet, true)
|
||||||
expect(t, noEnvVarIsSet, false)
|
expect(t, noEnvVarIsSet, false)
|
||||||
expect(t, nIsSet, false)
|
expect(t, nIsSet, false)
|
||||||
|
|
||||||
|
os.Setenv("APP_UNPARSABLE", "foobar")
|
||||||
|
a.Run([]string{"run"})
|
||||||
|
expect(t, unparsableIsSet, false)
|
||||||
|
expect(t, uIsSet, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContext_GlobalIsSet(t *testing.T) {
|
func TestContext_GlobalIsSet(t *testing.T) {
|
||||||
@ -230,14 +249,22 @@ func TestContext_GlobalIsSet(t *testing.T) {
|
|||||||
// XXX Corresponds to hack in context.IsSet for flags with EnvVar field
|
// XXX Corresponds to hack in context.IsSet for flags with EnvVar field
|
||||||
// Should be moved to `flag_test` in v2
|
// Should be moved to `flag_test` in v2
|
||||||
func TestContext_GlobalIsSet_fromEnv(t *testing.T) {
|
func TestContext_GlobalIsSet_fromEnv(t *testing.T) {
|
||||||
var timeoutIsSet, tIsSet, noEnvVarIsSet, nIsSet bool
|
var (
|
||||||
|
timeoutIsSet, tIsSet bool
|
||||||
|
noEnvVarIsSet, nIsSet bool
|
||||||
|
passwordIsSet, pIsSet bool
|
||||||
|
unparsableIsSet, uIsSet bool
|
||||||
|
)
|
||||||
|
|
||||||
os.Clearenv()
|
clearenv()
|
||||||
os.Setenv("APP_TIMEOUT_SECONDS", "15.5")
|
os.Setenv("APP_TIMEOUT_SECONDS", "15.5")
|
||||||
|
os.Setenv("APP_PASSWORD", "")
|
||||||
a := App{
|
a := App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
Float64Flag{Name: "timeout, t", EnvVar: "APP_TIMEOUT_SECONDS"},
|
Float64Flag{Name: "timeout, t", EnvVar: "APP_TIMEOUT_SECONDS"},
|
||||||
|
StringFlag{Name: "password, p", EnvVar: "APP_PASSWORD"},
|
||||||
Float64Flag{Name: "no-env-var, n"},
|
Float64Flag{Name: "no-env-var, n"},
|
||||||
|
Float64Flag{Name: "unparsable, u", EnvVar: "APP_UNPARSABLE"},
|
||||||
},
|
},
|
||||||
Commands: []Command{
|
Commands: []Command{
|
||||||
{
|
{
|
||||||
@ -245,6 +272,10 @@ func TestContext_GlobalIsSet_fromEnv(t *testing.T) {
|
|||||||
Action: func(ctx *Context) error {
|
Action: func(ctx *Context) error {
|
||||||
timeoutIsSet = ctx.GlobalIsSet("timeout")
|
timeoutIsSet = ctx.GlobalIsSet("timeout")
|
||||||
tIsSet = ctx.GlobalIsSet("t")
|
tIsSet = ctx.GlobalIsSet("t")
|
||||||
|
passwordIsSet = ctx.GlobalIsSet("password")
|
||||||
|
pIsSet = ctx.GlobalIsSet("p")
|
||||||
|
unparsableIsSet = ctx.GlobalIsSet("unparsable")
|
||||||
|
uIsSet = ctx.GlobalIsSet("u")
|
||||||
noEnvVarIsSet = ctx.GlobalIsSet("no-env-var")
|
noEnvVarIsSet = ctx.GlobalIsSet("no-env-var")
|
||||||
nIsSet = ctx.GlobalIsSet("n")
|
nIsSet = ctx.GlobalIsSet("n")
|
||||||
return nil
|
return nil
|
||||||
@ -252,11 +283,22 @@ func TestContext_GlobalIsSet_fromEnv(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
a.Run([]string{"run", "hello"})
|
if err := a.Run([]string{"run", "hello"}); err != nil {
|
||||||
|
t.Logf("error running Run(): %+v", err)
|
||||||
|
}
|
||||||
expect(t, timeoutIsSet, true)
|
expect(t, timeoutIsSet, true)
|
||||||
expect(t, tIsSet, true)
|
expect(t, tIsSet, true)
|
||||||
|
expect(t, passwordIsSet, true)
|
||||||
|
expect(t, pIsSet, true)
|
||||||
expect(t, noEnvVarIsSet, false)
|
expect(t, noEnvVarIsSet, false)
|
||||||
expect(t, nIsSet, false)
|
expect(t, nIsSet, false)
|
||||||
|
|
||||||
|
os.Setenv("APP_UNPARSABLE", "foobar")
|
||||||
|
if err := a.Run([]string{"run"}); err != nil {
|
||||||
|
t.Logf("error running Run(): %+v", err)
|
||||||
|
}
|
||||||
|
expect(t, unparsableIsSet, false)
|
||||||
|
expect(t, uIsSet, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContext_NumFlags(t *testing.T) {
|
func TestContext_NumFlags(t *testing.T) {
|
||||||
|
265
flag.go
265
flag.go
@ -3,11 +3,11 @@ package cli
|
|||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -62,13 +62,29 @@ type Flag interface {
|
|||||||
GetName() string
|
GetName() string
|
||||||
}
|
}
|
||||||
|
|
||||||
func flagSet(name string, flags []Flag) *flag.FlagSet {
|
// errorableFlag is an interface that allows us to return errors during apply
|
||||||
|
// it allows flags defined in this library to return errors in a fashion backwards compatible
|
||||||
|
// TODO remove in v2 and modify the existing Flag interface to return errors
|
||||||
|
type errorableFlag interface {
|
||||||
|
Flag
|
||||||
|
|
||||||
|
applyWithError(*flag.FlagSet) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func flagSet(name string, flags []Flag) (*flag.FlagSet, error) {
|
||||||
set := flag.NewFlagSet(name, flag.ContinueOnError)
|
set := flag.NewFlagSet(name, flag.ContinueOnError)
|
||||||
|
|
||||||
for _, f := range flags {
|
for _, f := range flags {
|
||||||
f.Apply(set)
|
//TODO remove in v2 when errorableFlag is removed
|
||||||
|
if f, ok := f.(errorableFlag); ok {
|
||||||
|
if err := f.applyWithError(set); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
f.Apply(set)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return set
|
return set, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func eachName(longName string, fn func(string)) {
|
func eachName(longName string, fn func(string)) {
|
||||||
@ -87,13 +103,22 @@ type Generic interface {
|
|||||||
|
|
||||||
// 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
|
||||||
|
// Ignores parsing errors
|
||||||
func (f GenericFlag) Apply(set *flag.FlagSet) {
|
func (f GenericFlag) Apply(set *flag.FlagSet) {
|
||||||
|
f.applyWithError(set)
|
||||||
|
}
|
||||||
|
|
||||||
|
// applyWithError takes the flagset and calls Set on the generic flag with the value
|
||||||
|
// provided by the user for parsing by the flag
|
||||||
|
func (f GenericFlag) applyWithError(set *flag.FlagSet) error {
|
||||||
val := f.Value
|
val := f.Value
|
||||||
if f.EnvVar != "" {
|
if f.EnvVar != "" {
|
||||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
||||||
envVar = strings.TrimSpace(envVar)
|
envVar = strings.TrimSpace(envVar)
|
||||||
if envVal := os.Getenv(envVar); envVal != "" {
|
if envVal, ok := syscall.Getenv(envVar); ok {
|
||||||
val.Set(envVal)
|
if err := val.Set(envVal); err != nil {
|
||||||
|
return fmt.Errorf("could not parse %s as value for flag %s: %s", envVal, f.Name, err)
|
||||||
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -102,9 +127,11 @@ func (f GenericFlag) Apply(set *flag.FlagSet) {
|
|||||||
eachName(f.Name, func(name string) {
|
eachName(f.Name, func(name string) {
|
||||||
set.Var(f.Value, name, f.Usage)
|
set.Var(f.Value, name, f.Usage)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// StringSlice is an opaque type for []string to satisfy flag.Value
|
// StringSlice is an opaque type for []string to satisfy flag.Value and flag.Getter
|
||||||
type StringSlice []string
|
type StringSlice []string
|
||||||
|
|
||||||
// Set appends the string value to the list of values
|
// Set appends the string value to the list of values
|
||||||
@ -123,16 +150,29 @@ func (f *StringSlice) Value() []string {
|
|||||||
return *f
|
return *f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get returns the slice of strings set by this flag
|
||||||
|
func (f *StringSlice) Get() interface{} {
|
||||||
|
return *f
|
||||||
|
}
|
||||||
|
|
||||||
// Apply populates the flag given the flag set and environment
|
// Apply populates the flag given the flag set and environment
|
||||||
|
// Ignores errors
|
||||||
func (f StringSliceFlag) Apply(set *flag.FlagSet) {
|
func (f StringSliceFlag) Apply(set *flag.FlagSet) {
|
||||||
|
f.applyWithError(set)
|
||||||
|
}
|
||||||
|
|
||||||
|
// applyWithError populates the flag given the flag set and environment
|
||||||
|
func (f StringSliceFlag) applyWithError(set *flag.FlagSet) error {
|
||||||
if f.EnvVar != "" {
|
if f.EnvVar != "" {
|
||||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
||||||
envVar = strings.TrimSpace(envVar)
|
envVar = strings.TrimSpace(envVar)
|
||||||
if envVal := os.Getenv(envVar); envVal != "" {
|
if envVal, ok := syscall.Getenv(envVar); ok {
|
||||||
newVal := &StringSlice{}
|
newVal := &StringSlice{}
|
||||||
for _, s := range strings.Split(envVal, ",") {
|
for _, s := range strings.Split(envVal, ",") {
|
||||||
s = strings.TrimSpace(s)
|
s = strings.TrimSpace(s)
|
||||||
newVal.Set(s)
|
if err := newVal.Set(s); err != nil {
|
||||||
|
return fmt.Errorf("could not parse %s as string value for flag %s: %s", envVal, f.Name, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
f.Value = newVal
|
f.Value = newVal
|
||||||
break
|
break
|
||||||
@ -146,9 +186,11 @@ func (f StringSliceFlag) Apply(set *flag.FlagSet) {
|
|||||||
}
|
}
|
||||||
set.Var(f.Value, name, f.Usage)
|
set.Var(f.Value, name, f.Usage)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// IntSlice is an opaque type for []int to satisfy flag.Value
|
// IntSlice is an opaque type for []int to satisfy flag.Value and flag.Getter
|
||||||
type IntSlice []int
|
type IntSlice []int
|
||||||
|
|
||||||
// Set parses the value into an integer and appends it to the list of values
|
// Set parses the value into an integer and appends it to the list of values
|
||||||
@ -171,18 +213,28 @@ func (f *IntSlice) Value() []int {
|
|||||||
return *f
|
return *f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get returns the slice of ints set by this flag
|
||||||
|
func (f *IntSlice) Get() interface{} {
|
||||||
|
return *f
|
||||||
|
}
|
||||||
|
|
||||||
// Apply populates the flag given the flag set and environment
|
// Apply populates the flag given the flag set and environment
|
||||||
|
// Ignores errors
|
||||||
func (f IntSliceFlag) Apply(set *flag.FlagSet) {
|
func (f IntSliceFlag) Apply(set *flag.FlagSet) {
|
||||||
|
f.applyWithError(set)
|
||||||
|
}
|
||||||
|
|
||||||
|
// applyWithError populates the flag given the flag set and environment
|
||||||
|
func (f IntSliceFlag) applyWithError(set *flag.FlagSet) error {
|
||||||
if f.EnvVar != "" {
|
if f.EnvVar != "" {
|
||||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
||||||
envVar = strings.TrimSpace(envVar)
|
envVar = strings.TrimSpace(envVar)
|
||||||
if envVal := os.Getenv(envVar); envVal != "" {
|
if envVal, ok := syscall.Getenv(envVar); ok {
|
||||||
newVal := &IntSlice{}
|
newVal := &IntSlice{}
|
||||||
for _, s := range strings.Split(envVal, ",") {
|
for _, s := range strings.Split(envVal, ",") {
|
||||||
s = strings.TrimSpace(s)
|
s = strings.TrimSpace(s)
|
||||||
err := newVal.Set(s)
|
if err := newVal.Set(s); err != nil {
|
||||||
if err != nil {
|
return fmt.Errorf("could not parse %s as int slice value for flag %s: %s", envVal, f.Name, err)
|
||||||
fmt.Fprintf(ErrWriter, err.Error())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f.Value = newVal
|
f.Value = newVal
|
||||||
@ -197,9 +249,11 @@ func (f IntSliceFlag) Apply(set *flag.FlagSet) {
|
|||||||
}
|
}
|
||||||
set.Var(f.Value, name, f.Usage)
|
set.Var(f.Value, name, f.Usage)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Int64Slice is an opaque type for []int to satisfy flag.Value
|
// Int64Slice is an opaque type for []int to satisfy flag.Value and flag.Getter
|
||||||
type Int64Slice []int64
|
type Int64Slice []int64
|
||||||
|
|
||||||
// Set parses the value into an integer and appends it to the list of values
|
// Set parses the value into an integer and appends it to the list of values
|
||||||
@ -222,18 +276,28 @@ func (f *Int64Slice) Value() []int64 {
|
|||||||
return *f
|
return *f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get returns the slice of ints set by this flag
|
||||||
|
func (f *Int64Slice) Get() interface{} {
|
||||||
|
return *f
|
||||||
|
}
|
||||||
|
|
||||||
// Apply populates the flag given the flag set and environment
|
// Apply populates the flag given the flag set and environment
|
||||||
|
// Ignores errors
|
||||||
func (f Int64SliceFlag) Apply(set *flag.FlagSet) {
|
func (f Int64SliceFlag) Apply(set *flag.FlagSet) {
|
||||||
|
f.applyWithError(set)
|
||||||
|
}
|
||||||
|
|
||||||
|
// applyWithError populates the flag given the flag set and environment
|
||||||
|
func (f Int64SliceFlag) applyWithError(set *flag.FlagSet) error {
|
||||||
if f.EnvVar != "" {
|
if f.EnvVar != "" {
|
||||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
||||||
envVar = strings.TrimSpace(envVar)
|
envVar = strings.TrimSpace(envVar)
|
||||||
if envVal := os.Getenv(envVar); envVal != "" {
|
if envVal, ok := syscall.Getenv(envVar); ok {
|
||||||
newVal := &Int64Slice{}
|
newVal := &Int64Slice{}
|
||||||
for _, s := range strings.Split(envVal, ",") {
|
for _, s := range strings.Split(envVal, ",") {
|
||||||
s = strings.TrimSpace(s)
|
s = strings.TrimSpace(s)
|
||||||
err := newVal.Set(s)
|
if err := newVal.Set(s); err != nil {
|
||||||
if err != nil {
|
return fmt.Errorf("could not parse %s as int64 slice value for flag %s: %s", envVal, f.Name, err)
|
||||||
fmt.Fprintf(ErrWriter, err.Error())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f.Value = newVal
|
f.Value = newVal
|
||||||
@ -248,19 +312,33 @@ func (f Int64SliceFlag) Apply(set *flag.FlagSet) {
|
|||||||
}
|
}
|
||||||
set.Var(f.Value, name, f.Usage)
|
set.Var(f.Value, name, f.Usage)
|
||||||
})
|
})
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply populates the flag given the flag set and environment
|
// Apply populates the flag given the flag set and environment
|
||||||
|
// Ignores errors
|
||||||
func (f BoolFlag) Apply(set *flag.FlagSet) {
|
func (f BoolFlag) Apply(set *flag.FlagSet) {
|
||||||
|
f.applyWithError(set)
|
||||||
|
}
|
||||||
|
|
||||||
|
// applyWithError populates the flag given the flag set and environment
|
||||||
|
func (f BoolFlag) applyWithError(set *flag.FlagSet) error {
|
||||||
val := false
|
val := false
|
||||||
if f.EnvVar != "" {
|
if f.EnvVar != "" {
|
||||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
||||||
envVar = strings.TrimSpace(envVar)
|
envVar = strings.TrimSpace(envVar)
|
||||||
if envVal := os.Getenv(envVar); envVal != "" {
|
if envVal, ok := syscall.Getenv(envVar); ok {
|
||||||
envValBool, err := strconv.ParseBool(envVal)
|
if envVal == "" {
|
||||||
if err == nil {
|
val = false
|
||||||
val = envValBool
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
envValBool, err := strconv.ParseBool(envVal)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not parse %s as bool value for flag %s: %s", envVal, f.Name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
val = envValBool
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -273,20 +351,35 @@ func (f BoolFlag) Apply(set *flag.FlagSet) {
|
|||||||
}
|
}
|
||||||
set.Bool(name, val, f.Usage)
|
set.Bool(name, val, f.Usage)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply populates the flag given the flag set and environment
|
// Apply populates the flag given the flag set and environment
|
||||||
|
// Ignores errors
|
||||||
func (f BoolTFlag) Apply(set *flag.FlagSet) {
|
func (f BoolTFlag) Apply(set *flag.FlagSet) {
|
||||||
|
f.applyWithError(set)
|
||||||
|
}
|
||||||
|
|
||||||
|
// applyWithError populates the flag given the flag set and environment
|
||||||
|
func (f BoolTFlag) applyWithError(set *flag.FlagSet) error {
|
||||||
val := true
|
val := true
|
||||||
if f.EnvVar != "" {
|
if f.EnvVar != "" {
|
||||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
||||||
envVar = strings.TrimSpace(envVar)
|
envVar = strings.TrimSpace(envVar)
|
||||||
if envVal := os.Getenv(envVar); envVal != "" {
|
if envVal, ok := syscall.Getenv(envVar); ok {
|
||||||
envValBool, err := strconv.ParseBool(envVal)
|
if envVal == "" {
|
||||||
if err == nil {
|
val = false
|
||||||
val = envValBool
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
envValBool, err := strconv.ParseBool(envVal)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not parse %s as bool value for flag %s: %s", envVal, f.Name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
val = envValBool
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -298,14 +391,22 @@ func (f BoolTFlag) Apply(set *flag.FlagSet) {
|
|||||||
}
|
}
|
||||||
set.Bool(name, val, f.Usage)
|
set.Bool(name, val, f.Usage)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply populates the flag given the flag set and environment
|
// Apply populates the flag given the flag set and environment
|
||||||
|
// Ignores errors
|
||||||
func (f StringFlag) Apply(set *flag.FlagSet) {
|
func (f StringFlag) Apply(set *flag.FlagSet) {
|
||||||
|
f.applyWithError(set)
|
||||||
|
}
|
||||||
|
|
||||||
|
// applyWithError populates the flag given the flag set and environment
|
||||||
|
func (f StringFlag) applyWithError(set *flag.FlagSet) error {
|
||||||
if f.EnvVar != "" {
|
if f.EnvVar != "" {
|
||||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
||||||
envVar = strings.TrimSpace(envVar)
|
envVar = strings.TrimSpace(envVar)
|
||||||
if envVal := os.Getenv(envVar); envVal != "" {
|
if envVal, ok := syscall.Getenv(envVar); ok {
|
||||||
f.Value = envVal
|
f.Value = envVal
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -319,19 +420,28 @@ func (f StringFlag) Apply(set *flag.FlagSet) {
|
|||||||
}
|
}
|
||||||
set.String(name, f.Value, f.Usage)
|
set.String(name, f.Value, f.Usage)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply populates the flag given the flag set and environment
|
// Apply populates the flag given the flag set and environment
|
||||||
|
// Ignores errors
|
||||||
func (f IntFlag) Apply(set *flag.FlagSet) {
|
func (f IntFlag) Apply(set *flag.FlagSet) {
|
||||||
|
f.applyWithError(set)
|
||||||
|
}
|
||||||
|
|
||||||
|
// applyWithError populates the flag given the flag set and environment
|
||||||
|
func (f IntFlag) applyWithError(set *flag.FlagSet) error {
|
||||||
if f.EnvVar != "" {
|
if f.EnvVar != "" {
|
||||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
||||||
envVar = strings.TrimSpace(envVar)
|
envVar = strings.TrimSpace(envVar)
|
||||||
if envVal := os.Getenv(envVar); envVal != "" {
|
if envVal, ok := syscall.Getenv(envVar); ok {
|
||||||
envValInt, err := strconv.ParseInt(envVal, 0, 64)
|
envValInt, err := strconv.ParseInt(envVal, 0, 64)
|
||||||
if err == nil {
|
if err != nil {
|
||||||
f.Value = int(envValInt)
|
return fmt.Errorf("could not parse %s as int value for flag %s: %s", envVal, f.Name, err)
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
f.Value = int(envValInt)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -343,19 +453,29 @@ func (f IntFlag) Apply(set *flag.FlagSet) {
|
|||||||
}
|
}
|
||||||
set.Int(name, f.Value, f.Usage)
|
set.Int(name, f.Value, f.Usage)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply populates the flag given the flag set and environment
|
// Apply populates the flag given the flag set and environment
|
||||||
|
// Ignores errors
|
||||||
func (f Int64Flag) Apply(set *flag.FlagSet) {
|
func (f Int64Flag) Apply(set *flag.FlagSet) {
|
||||||
|
f.applyWithError(set)
|
||||||
|
}
|
||||||
|
|
||||||
|
// applyWithError populates the flag given the flag set and environment
|
||||||
|
func (f Int64Flag) applyWithError(set *flag.FlagSet) error {
|
||||||
if f.EnvVar != "" {
|
if f.EnvVar != "" {
|
||||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
||||||
envVar = strings.TrimSpace(envVar)
|
envVar = strings.TrimSpace(envVar)
|
||||||
if envVal := os.Getenv(envVar); envVal != "" {
|
if envVal, ok := syscall.Getenv(envVar); ok {
|
||||||
envValInt, err := strconv.ParseInt(envVal, 0, 64)
|
envValInt, err := strconv.ParseInt(envVal, 0, 64)
|
||||||
if err == nil {
|
if err != nil {
|
||||||
f.Value = envValInt
|
return fmt.Errorf("could not parse %s as int value for flag %s: %s", envVal, f.Name, err)
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
f.Value = envValInt
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -367,19 +487,29 @@ func (f Int64Flag) Apply(set *flag.FlagSet) {
|
|||||||
}
|
}
|
||||||
set.Int64(name, f.Value, f.Usage)
|
set.Int64(name, f.Value, f.Usage)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply populates the flag given the flag set and environment
|
// Apply populates the flag given the flag set and environment
|
||||||
|
// Ignores errors
|
||||||
func (f UintFlag) Apply(set *flag.FlagSet) {
|
func (f UintFlag) Apply(set *flag.FlagSet) {
|
||||||
|
f.applyWithError(set)
|
||||||
|
}
|
||||||
|
|
||||||
|
// applyWithError populates the flag given the flag set and environment
|
||||||
|
func (f UintFlag) applyWithError(set *flag.FlagSet) error {
|
||||||
if f.EnvVar != "" {
|
if f.EnvVar != "" {
|
||||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
||||||
envVar = strings.TrimSpace(envVar)
|
envVar = strings.TrimSpace(envVar)
|
||||||
if envVal := os.Getenv(envVar); envVal != "" {
|
if envVal, ok := syscall.Getenv(envVar); ok {
|
||||||
envValInt, err := strconv.ParseUint(envVal, 0, 64)
|
envValInt, err := strconv.ParseUint(envVal, 0, 64)
|
||||||
if err == nil {
|
if err != nil {
|
||||||
f.Value = uint(envValInt)
|
return fmt.Errorf("could not parse %s as uint value for flag %s: %s", envVal, f.Name, err)
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
f.Value = uint(envValInt)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -391,19 +521,29 @@ func (f UintFlag) Apply(set *flag.FlagSet) {
|
|||||||
}
|
}
|
||||||
set.Uint(name, f.Value, f.Usage)
|
set.Uint(name, f.Value, f.Usage)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply populates the flag given the flag set and environment
|
// Apply populates the flag given the flag set and environment
|
||||||
|
// Ignores errors
|
||||||
func (f Uint64Flag) Apply(set *flag.FlagSet) {
|
func (f Uint64Flag) Apply(set *flag.FlagSet) {
|
||||||
|
f.applyWithError(set)
|
||||||
|
}
|
||||||
|
|
||||||
|
// applyWithError populates the flag given the flag set and environment
|
||||||
|
func (f Uint64Flag) applyWithError(set *flag.FlagSet) error {
|
||||||
if f.EnvVar != "" {
|
if f.EnvVar != "" {
|
||||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
||||||
envVar = strings.TrimSpace(envVar)
|
envVar = strings.TrimSpace(envVar)
|
||||||
if envVal := os.Getenv(envVar); envVal != "" {
|
if envVal, ok := syscall.Getenv(envVar); ok {
|
||||||
envValInt, err := strconv.ParseUint(envVal, 0, 64)
|
envValInt, err := strconv.ParseUint(envVal, 0, 64)
|
||||||
if err == nil {
|
if err != nil {
|
||||||
f.Value = uint64(envValInt)
|
return fmt.Errorf("could not parse %s as uint64 value for flag %s: %s", envVal, f.Name, err)
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
f.Value = uint64(envValInt)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -415,19 +555,29 @@ func (f Uint64Flag) Apply(set *flag.FlagSet) {
|
|||||||
}
|
}
|
||||||
set.Uint64(name, f.Value, f.Usage)
|
set.Uint64(name, f.Value, f.Usage)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply populates the flag given the flag set and environment
|
// Apply populates the flag given the flag set and environment
|
||||||
|
// Ignores errors
|
||||||
func (f DurationFlag) Apply(set *flag.FlagSet) {
|
func (f DurationFlag) Apply(set *flag.FlagSet) {
|
||||||
|
f.applyWithError(set)
|
||||||
|
}
|
||||||
|
|
||||||
|
// applyWithError populates the flag given the flag set and environment
|
||||||
|
func (f DurationFlag) applyWithError(set *flag.FlagSet) error {
|
||||||
if f.EnvVar != "" {
|
if f.EnvVar != "" {
|
||||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
||||||
envVar = strings.TrimSpace(envVar)
|
envVar = strings.TrimSpace(envVar)
|
||||||
if envVal := os.Getenv(envVar); envVal != "" {
|
if envVal, ok := syscall.Getenv(envVar); ok {
|
||||||
envValDuration, err := time.ParseDuration(envVal)
|
envValDuration, err := time.ParseDuration(envVal)
|
||||||
if err == nil {
|
if err != nil {
|
||||||
f.Value = envValDuration
|
return fmt.Errorf("could not parse %s as duration for flag %s: %s", envVal, f.Name, err)
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
f.Value = envValDuration
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -439,18 +589,29 @@ func (f DurationFlag) Apply(set *flag.FlagSet) {
|
|||||||
}
|
}
|
||||||
set.Duration(name, f.Value, f.Usage)
|
set.Duration(name, f.Value, f.Usage)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply populates the flag given the flag set and environment
|
// Apply populates the flag given the flag set and environment
|
||||||
|
// Ignores errors
|
||||||
func (f Float64Flag) Apply(set *flag.FlagSet) {
|
func (f Float64Flag) Apply(set *flag.FlagSet) {
|
||||||
|
f.applyWithError(set)
|
||||||
|
}
|
||||||
|
|
||||||
|
// applyWithError populates the flag given the flag set and environment
|
||||||
|
func (f Float64Flag) applyWithError(set *flag.FlagSet) error {
|
||||||
if f.EnvVar != "" {
|
if f.EnvVar != "" {
|
||||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
||||||
envVar = strings.TrimSpace(envVar)
|
envVar = strings.TrimSpace(envVar)
|
||||||
if envVal := os.Getenv(envVar); envVal != "" {
|
if envVal, ok := syscall.Getenv(envVar); ok {
|
||||||
envValFloat, err := strconv.ParseFloat(envVal, 10)
|
envValFloat, err := strconv.ParseFloat(envVal, 10)
|
||||||
if err == nil {
|
if err != nil {
|
||||||
f.Value = float64(envValFloat)
|
return fmt.Errorf("could not parse %s as float64 value for flag %s: %s", envVal, f.Name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
f.Value = float64(envValFloat)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -462,6 +623,8 @@ func (f Float64Flag) Apply(set *flag.FlagSet) {
|
|||||||
}
|
}
|
||||||
set.Float64(name, f.Value, f.Usage)
|
set.Float64(name, f.Value, f.Usage)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func visibleFlags(fl []Flag) []Flag {
|
func visibleFlags(fl []Flag) []Flag {
|
||||||
|
111
flag_test.go
111
flag_test.go
@ -29,6 +29,81 @@ func TestBoolFlagHelpOutput(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFlagsFromEnv(t *testing.T) {
|
||||||
|
var flagTests = []struct {
|
||||||
|
input string
|
||||||
|
output interface{}
|
||||||
|
flag Flag
|
||||||
|
err error
|
||||||
|
}{
|
||||||
|
{"", false, BoolFlag{Name: "debug", EnvVar: "DEBUG"}, nil},
|
||||||
|
{"1", true, BoolFlag{Name: "debug", EnvVar: "DEBUG"}, nil},
|
||||||
|
{"false", false, BoolFlag{Name: "debug", EnvVar: "DEBUG"}, nil},
|
||||||
|
{"foobar", true, BoolFlag{Name: "debug", EnvVar: "DEBUG"}, fmt.Errorf(`could not parse foobar as bool value for flag debug: strconv.ParseBool: parsing "foobar": invalid syntax`)},
|
||||||
|
|
||||||
|
{"", false, BoolTFlag{Name: "debug", EnvVar: "DEBUG"}, nil},
|
||||||
|
{"1", true, BoolTFlag{Name: "debug", EnvVar: "DEBUG"}, nil},
|
||||||
|
{"false", false, BoolTFlag{Name: "debug", EnvVar: "DEBUG"}, nil},
|
||||||
|
{"foobar", true, BoolTFlag{Name: "debug", EnvVar: "DEBUG"}, fmt.Errorf(`could not parse foobar as bool value for flag debug: strconv.ParseBool: parsing "foobar": invalid syntax`)},
|
||||||
|
|
||||||
|
{"1s", 1 * time.Second, DurationFlag{Name: "time", EnvVar: "TIME"}, nil},
|
||||||
|
{"foobar", false, DurationFlag{Name: "time", EnvVar: "TIME"}, fmt.Errorf(`could not parse foobar as duration for flag time: time: invalid duration foobar`)},
|
||||||
|
|
||||||
|
{"1.2", 1.2, Float64Flag{Name: "seconds", EnvVar: "SECONDS"}, nil},
|
||||||
|
{"1", 1.0, Float64Flag{Name: "seconds", EnvVar: "SECONDS"}, nil},
|
||||||
|
{"foobar", 0, Float64Flag{Name: "seconds", EnvVar: "SECONDS"}, fmt.Errorf(`could not parse foobar as float64 value for flag seconds: strconv.ParseFloat: parsing "foobar": invalid syntax`)},
|
||||||
|
|
||||||
|
{"1", int64(1), Int64Flag{Name: "seconds", EnvVar: "SECONDS"}, nil},
|
||||||
|
{"1.2", 0, Int64Flag{Name: "seconds", EnvVar: "SECONDS"}, fmt.Errorf(`could not parse 1.2 as int value for flag seconds: strconv.ParseInt: parsing "1.2": invalid syntax`)},
|
||||||
|
{"foobar", 0, Int64Flag{Name: "seconds", EnvVar: "SECONDS"}, fmt.Errorf(`could not parse foobar as int value for flag seconds: strconv.ParseInt: parsing "foobar": invalid syntax`)},
|
||||||
|
|
||||||
|
{"1", 1, IntFlag{Name: "seconds", EnvVar: "SECONDS"}, nil},
|
||||||
|
{"1.2", 0, IntFlag{Name: "seconds", EnvVar: "SECONDS"}, fmt.Errorf(`could not parse 1.2 as int value for flag seconds: strconv.ParseInt: parsing "1.2": invalid syntax`)},
|
||||||
|
{"foobar", 0, IntFlag{Name: "seconds", EnvVar: "SECONDS"}, fmt.Errorf(`could not parse foobar as int value for flag seconds: strconv.ParseInt: parsing "foobar": invalid syntax`)},
|
||||||
|
|
||||||
|
{"1,2", IntSlice{1, 2}, IntSliceFlag{Name: "seconds", EnvVar: "SECONDS"}, nil},
|
||||||
|
{"1.2,2", IntSlice{}, IntSliceFlag{Name: "seconds", EnvVar: "SECONDS"}, fmt.Errorf(`could not parse 1.2,2 as int slice value for flag seconds: strconv.ParseInt: parsing "1.2": invalid syntax`)},
|
||||||
|
{"foobar", IntSlice{}, IntSliceFlag{Name: "seconds", EnvVar: "SECONDS"}, fmt.Errorf(`could not parse foobar as int slice value for flag seconds: strconv.ParseInt: parsing "foobar": invalid syntax`)},
|
||||||
|
|
||||||
|
{"1,2", Int64Slice{1, 2}, Int64SliceFlag{Name: "seconds", EnvVar: "SECONDS"}, nil},
|
||||||
|
{"1.2,2", Int64Slice{}, Int64SliceFlag{Name: "seconds", EnvVar: "SECONDS"}, fmt.Errorf(`could not parse 1.2,2 as int64 slice value for flag seconds: strconv.ParseInt: parsing "1.2": invalid syntax`)},
|
||||||
|
{"foobar", Int64Slice{}, Int64SliceFlag{Name: "seconds", EnvVar: "SECONDS"}, fmt.Errorf(`could not parse foobar as int64 slice value for flag seconds: strconv.ParseInt: parsing "foobar": invalid syntax`)},
|
||||||
|
|
||||||
|
{"foo", "foo", StringFlag{Name: "name", EnvVar: "NAME"}, nil},
|
||||||
|
|
||||||
|
{"foo,bar", StringSlice{"foo", "bar"}, StringSliceFlag{Name: "names", EnvVar: "NAMES"}, nil},
|
||||||
|
|
||||||
|
{"1", uint(1), UintFlag{Name: "seconds", EnvVar: "SECONDS"}, nil},
|
||||||
|
{"1.2", 0, UintFlag{Name: "seconds", EnvVar: "SECONDS"}, fmt.Errorf(`could not parse 1.2 as uint value for flag seconds: strconv.ParseUint: parsing "1.2": invalid syntax`)},
|
||||||
|
{"foobar", 0, UintFlag{Name: "seconds", EnvVar: "SECONDS"}, fmt.Errorf(`could not parse foobar as uint value for flag seconds: strconv.ParseUint: parsing "foobar": invalid syntax`)},
|
||||||
|
|
||||||
|
{"1", uint64(1), Uint64Flag{Name: "seconds", EnvVar: "SECONDS"}, nil},
|
||||||
|
{"1.2", 0, Uint64Flag{Name: "seconds", EnvVar: "SECONDS"}, fmt.Errorf(`could not parse 1.2 as uint64 value for flag seconds: strconv.ParseUint: parsing "1.2": invalid syntax`)},
|
||||||
|
{"foobar", 0, Uint64Flag{Name: "seconds", EnvVar: "SECONDS"}, fmt.Errorf(`could not parse foobar as uint64 value for flag seconds: strconv.ParseUint: parsing "foobar": invalid syntax`)},
|
||||||
|
|
||||||
|
{"foo,bar", &Parser{"foo", "bar"}, GenericFlag{Name: "names", Value: &Parser{}, EnvVar: "NAMES"}, nil},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range flagTests {
|
||||||
|
os.Clearenv()
|
||||||
|
os.Setenv(reflect.ValueOf(test.flag).FieldByName("EnvVar").String(), test.input)
|
||||||
|
a := App{
|
||||||
|
Flags: []Flag{test.flag},
|
||||||
|
Action: func(ctx *Context) error {
|
||||||
|
if !reflect.DeepEqual(ctx.value(test.flag.GetName()), test.output) {
|
||||||
|
t.Errorf("expected %+v to be parsed as %+v, instead was %+v", test.input, test.output, ctx.value(test.flag.GetName()))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := a.Run([]string{"run"})
|
||||||
|
if !reflect.DeepEqual(test.err, err) {
|
||||||
|
t.Errorf("expected error %s, got error %s", test.err, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var stringFlagTests = []struct {
|
var stringFlagTests = []struct {
|
||||||
name string
|
name string
|
||||||
usage string
|
usage string
|
||||||
@ -941,6 +1016,38 @@ func TestParseMultiBoolFromEnvCascade(t *testing.T) {
|
|||||||
a.Run([]string{"run"})
|
a.Run([]string{"run"})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestParseBoolTFromEnv(t *testing.T) {
|
||||||
|
var boolTFlagTests = []struct {
|
||||||
|
input string
|
||||||
|
output bool
|
||||||
|
}{
|
||||||
|
{"", false},
|
||||||
|
{"1", true},
|
||||||
|
{"false", false},
|
||||||
|
{"true", true},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range boolTFlagTests {
|
||||||
|
os.Clearenv()
|
||||||
|
os.Setenv("DEBUG", test.input)
|
||||||
|
a := App{
|
||||||
|
Flags: []Flag{
|
||||||
|
BoolTFlag{Name: "debug, d", EnvVar: "DEBUG"},
|
||||||
|
},
|
||||||
|
Action: func(ctx *Context) error {
|
||||||
|
if ctx.Bool("debug") != test.output {
|
||||||
|
t.Errorf("expected %+v to be parsed as %+v, instead was %+v", test.input, test.output, ctx.Bool("debug"))
|
||||||
|
}
|
||||||
|
if ctx.Bool("d") != test.output {
|
||||||
|
t.Errorf("expected %+v to be parsed as %+v, instead was %+v", test.input, test.output, ctx.Bool("d"))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
a.Run([]string{"run"})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestParseMultiBoolT(t *testing.T) {
|
func TestParseMultiBoolT(t *testing.T) {
|
||||||
a := App{
|
a := App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
@ -1036,6 +1143,10 @@ func (p *Parser) String() string {
|
|||||||
return fmt.Sprintf("%s,%s", p[0], p[1])
|
return fmt.Sprintf("%s,%s", p[0], p[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Parser) Get() interface{} {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
func TestParseGeneric(t *testing.T) {
|
func TestParseGeneric(t *testing.T) {
|
||||||
a := App{
|
a := App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
|
9
helpers_unix_test.go
Normal file
9
helpers_unix_test.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// +build darwin dragonfly freebsd linux netbsd openbsd solaris
|
||||||
|
|
||||||
|
package cli
|
||||||
|
|
||||||
|
import "os"
|
||||||
|
|
||||||
|
func clearenv() {
|
||||||
|
os.Clearenv()
|
||||||
|
}
|
20
helpers_windows_test.go
Normal file
20
helpers_windows_test.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
// os.Clearenv() doesn't actually unset variables on Windows
|
||||||
|
// See: https://github.com/golang/go/issues/17902
|
||||||
|
func clearenv() {
|
||||||
|
for _, s := range os.Environ() {
|
||||||
|
for j := 1; j < len(s); j++ {
|
||||||
|
if s[j] == '=' {
|
||||||
|
keyp, _ := syscall.UTF16PtrFromString(s[0:j])
|
||||||
|
syscall.SetEnvironmentVariable(keyp, nil)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user