diff --git a/kong.go b/kong.go index 8db9636..42b9c47 100644 --- a/kong.go +++ b/kong.go @@ -52,12 +52,13 @@ type Kong struct { // See the README (https://github.com/alecthomas/kong) for usage instructions. func New(grammar interface{}, options ...Option) (*Kong, error) { k := &Kong{ - Exit: os.Exit, - Stdout: os.Stdout, - Stderr: os.Stderr, - before: map[reflect.Value]HookFunc{}, - registry: NewRegistry().RegisterDefaults(), - help: PrintHelp, + Exit: os.Exit, + Stdout: os.Stdout, + Stderr: os.Stderr, + before: map[reflect.Value]HookFunc{}, + registry: NewRegistry().RegisterDefaults(), + help: PrintHelp, + resolvers: []ResolverFunc{EnvResolver()}, } for _, option := range options { diff --git a/options.go b/options.go index 7af0c54..17e95cc 100755 --- a/options.go +++ b/options.go @@ -97,6 +97,13 @@ func Help(help HelpFunction) Option { } } +// ClearResolvers clears all existing resolvers. +func ClearResolvers() Option { + return func(k *Kong) { + k.resolvers = nil + } +} + // Resolver registers flag resolvers. func Resolver(resolvers ...ResolverFunc) Option { return func(k *Kong) { diff --git a/resolver.go b/resolver.go index 833b94a..1627b91 100755 --- a/resolver.go +++ b/resolver.go @@ -62,8 +62,9 @@ func jsonDecodeValue(sep rune, value interface{}) (string, error) { } // PerFlagEnvResolver automatically determines environment variables based on the name of each flag, transformed to -// uppercase and underscored, e.g. `my-flag` -> `MY_FLAG` The environment variable key can be overridden with the `env` -// tag. +// uppercase and underscored, e.g. `my-flag` -> `MY_FLAG`. +// +// The environment variable key can be overridden with the `env:""` tag. func PerFlagEnvResolver(prefix string) ResolverFunc { return func(context *Context, parent *Path, flag *Flag) (string, error) { v, _ := os.LookupEnv(envString(prefix, flag)) @@ -71,6 +72,19 @@ func PerFlagEnvResolver(prefix string) ResolverFunc { } } +// EnvResolver resolves flag values using the `env:""` tag. It ignores flags without this tag. +// +// This resolver is installed by default. +func EnvResolver() ResolverFunc { + return func(context *Context, parent *Path, flag *Flag) (string, error) { + if flag.Tag.Env == "" { + return "", nil + } + v, _ := os.LookupEnv(flag.Tag.Env) + return v, nil + } +} + func envString(prefix string, flag *Flag) string { if env, ok := flag.Tag.Get("env"); ok { return env diff --git a/resolver_test.go b/resolver_test.go index 721cd4e..9ba6831 100755 --- a/resolver_test.go +++ b/resolver_test.go @@ -235,3 +235,14 @@ func TestResolverSatisfiesRequired(t *testing.T) { require.NoError(t, err) require.Equal(t, 1, cli.Int) } + +func TestEnvResolver(t *testing.T) { + var cli struct { + Int int `env:"SOME_ENVAR"` + } + restoreEnv := tempEnv(envMap{"SOME_ENVAR": "12"}) + defer restoreEnv() + _, err := mustNew(t, &cli, Resolver(EnvResolver())).Parse(nil) + require.NoError(t, err) + require.Equal(t, 12, cli.Int) +}