From 3a832f83439002319ba860bfdf2cfe9eff2dc12e Mon Sep 17 00:00:00 2001 From: Alec Thomas Date: Fri, 21 Sep 2018 12:06:24 +1000 Subject: [PATCH] Treat envars as higher priority than resolvers. --- context.go | 3 +++ kong.go | 24 ++++++++++++------------ model.go | 14 +++++++++++++- resolver.go | 14 -------------- resolver_test.go | 25 ------------------------- 5 files changed, 28 insertions(+), 52 deletions(-) diff --git a/context.go b/context.go index 78c4b0e..a502412 100644 --- a/context.go +++ b/context.go @@ -198,6 +198,9 @@ func (c *Context) FlagValue(flag *Flag) interface{} { return v.Interface() } } + if flag.Target.IsValid() { + return flag.Target.Interface() + } return flag.DefaultValue.Interface() } diff --git a/kong.go b/kong.go index 53c345d..b1c45c4 100644 --- a/kong.go +++ b/kong.go @@ -63,13 +63,12 @@ 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, - registry: NewRegistry().RegisterDefaults(), - resolvers: []ResolverFunc{Envars()}, - vars: Vars{}, - bindings: bindings{}, + Exit: os.Exit, + Stdout: os.Stdout, + Stderr: os.Stderr, + registry: NewRegistry().RegisterDefaults(), + vars: Vars{}, + bindings: bindings{}, } options = append(options, Bind(k)) @@ -169,11 +168,12 @@ func (k *Kong) extraFlags() []*Flag { value := reflect.ValueOf(&helpTarget).Elem() helpFlag := &Flag{ Value: &Value{ - Name: "help", - Help: "Show context-sensitive help.", - Target: value, - Tag: &Tag{}, - Mapper: k.registry.ForValue(value), + Name: "help", + Help: "Show context-sensitive help.", + Target: value, + Tag: &Tag{}, + Mapper: k.registry.ForValue(value), + DefaultValue: reflect.ValueOf(false), }, } helpFlag.Flag = helpFlag diff --git a/model.go b/model.go index 50c1df9..5b90741 100644 --- a/model.go +++ b/model.go @@ -2,6 +2,7 @@ package kong import ( "fmt" + "os" "reflect" "strconv" "strings" @@ -282,11 +283,22 @@ func (v *Value) Apply(value reflect.Value) { v.Set = true } -// Reset this value to its default, either the zero value or the parsed result of its "default" tag. +// Reset this value to its default, either the zero value or the parsed result of its envar, +// or its "default" tag. // // Does not include resolvers. func (v *Value) Reset() error { v.Target.Set(reflect.Zero(v.Target.Type())) + if v.Tag.Env != "" { + envar := os.Getenv(v.Tag.Env) + if envar != "" { + err := v.Parse(Scan(envar), v.Target) + if err != nil { + return fmt.Errorf("%s (from envar %s=%q)", err, v.Tag.Env, envar) + } + return nil + } + } if v.Default != "" { return v.Parse(Scan(v.Default), v.Target) } diff --git a/resolver.go b/resolver.go index 5c89a18..9de21a5 100644 --- a/resolver.go +++ b/resolver.go @@ -4,7 +4,6 @@ import ( "encoding/json" "fmt" "io" - "os" "strings" ) @@ -61,16 +60,3 @@ func jsonDecodeValue(sep rune, value interface{}) (string, error) { } return "", fmt.Errorf("unsupported JSON value %v (of type %T)", value, value) } - -// Envars resolves flag values using the `env:""` tag. It ignores flags without this tag. -// -// This resolver is installed by default. -func Envars() 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 - } -} diff --git a/resolver_test.go b/resolver_test.go index 501eae9..ad0cebe 100644 --- a/resolver_test.go +++ b/resolver_test.go @@ -61,31 +61,6 @@ func TestEnvarsFlagOverride(t *testing.T) { require.Equal(t, "hello", cli.Flag) } -func TestEnvarsOnlyPopulateUsedBranches(t *testing.T) { - // nolint - var cli struct { - UnvisitedArg struct { - UnvisitedArg string `arg` - Int int `env:"KONG_INT"` - } `arg` - UnvisitedCmd struct { - Int int `env:"KONG_INT"` - } `cmd` - Visited struct { - Int int `env:"KONG_INT"` - } `cmd` - } - parser, restoreEnv := newEnvParser(t, &cli, envMap{"KONG_INT": "512"}) - defer restoreEnv() - - _, err := parser.Parse([]string{"visited"}) - require.NoError(t, err) - - require.Equal(t, 512, cli.Visited.Int) - require.Equal(t, 0, cli.UnvisitedArg.Int) - require.Equal(t, 0, cli.UnvisitedCmd.Int) -} - func TestEnvarsTag(t *testing.T) { var cli struct { Slice []int `env:"KONG_NUMBERS"`