Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix:(issue_2032) Support for post parse config loading #2033

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions command.go
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,12 @@ func (cmd *Command) Run(ctx context.Context, osArgs []string) (deferErr error) {
return nil
}

for _, flag := range cmd.Flags {
if err := flag.PostParse(); err != nil {
return err
}
}

if cmd.After != nil && !cmd.Root().shellCompletion {
defer func() {
if err := cmd.After(ctx, cmd); err != nil {
Expand Down
4 changes: 4 additions & 0 deletions command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2306,6 +2306,10 @@ func (c *customBoolFlag) GetUsage() string {
return "usage"
}

func (c *customBoolFlag) PostParse() error {
return nil
}

func (c *customBoolFlag) Apply(set *flag.FlagSet) error {
set.String(c.Nombre, c.Nombre, "")
return nil
Expand Down
2 changes: 2 additions & 0 deletions flag.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ type ActionableFlag interface {
type Flag interface {
fmt.Stringer

PostParse() error

// Apply Flag settings to the given flag set
Apply(*flag.FlagSet) error

Expand Down
14 changes: 14 additions & 0 deletions flag_bool_with_inverse.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,20 @@ func (parent *BoolWithInverseFlag) inverseAliases() (aliases []string) {
return
}

func (parent *BoolWithInverseFlag) PostParse() error {
if parent.positiveFlag != nil {
if err := parent.positiveFlag.PostParse(); err != nil {
return err
}
}
if parent.negativeFlag != nil {
if err := parent.negativeFlag.PostParse(); err != nil {
return err
}
}
return nil
}

func (parent *BoolWithInverseFlag) Apply(set *flag.FlagSet) error {
if parent.positiveFlag == nil {
parent.initialize()
Expand Down
4 changes: 4 additions & 0 deletions flag_ext.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ type extFlag struct {
f *flag.Flag
}

func (e *extFlag) PostParse() error {
return nil
}

func (e *extFlag) Apply(fs *flag.FlagSet) error {
fs.Var(e.f.Value, e.f.Name, e.f.Usage)
return nil
Expand Down
39 changes: 23 additions & 16 deletions flag_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,35 +98,42 @@ func (f *FlagBase[T, C, V]) GetValue() string {
return fmt.Sprintf("%v", f.Value)
}

// Apply populates the flag given the flag set and environment
func (f *FlagBase[T, C, V]) Apply(set *flag.FlagSet) error {
tracef("apply (flag=%[1]q)", f.Name)

// TODO move this phase into a separate flag initialization function
// if flag has been applied previously then it would have already been set
// from env or file. So no need to apply the env set again. However
// lots of units tests prior to persistent flags assumed that the
// flag can be applied to different flag sets multiple times while still
// keeping the env set.
if !f.applied || f.Local {
newVal := f.Value
// PostParse populates the flag given the flag set and environment
func (f *FlagBase[T, C, V]) PostParse() error {
tracef("postparse (flag=%[1]q)", f.Name)

if !f.hasBeenSet {
if val, source, found := f.Sources.LookupWithSource(); found {
tmpVal := f.creator.Create(f.Value, new(T), f.Config)
if val != "" || reflect.TypeOf(f.Value).Kind() == reflect.String {
if err := tmpVal.Set(val); err != nil {
if err := f.value.Set(val); err != nil {
return fmt.Errorf(
"could not parse %[1]q as %[2]T value from %[3]s for flag %[4]s: %[5]s",
val, f.Value, source, f.Name, err,
)
}
} else if val == "" && reflect.TypeOf(f.Value).Kind() == reflect.Bool {
_ = tmpVal.Set("false")
_ = f.value.Set("false")
}

newVal = tmpVal.Get().(T)
f.hasBeenSet = true
}
}

return nil
}

// Apply populates the flag given the flag set and environment
func (f *FlagBase[T, C, V]) Apply(set *flag.FlagSet) error {
tracef("apply (flag=%[1]q)", f.Name)

// TODO move this phase into a separate flag initialization function
// if flag has been applied previously then it would have already been set
// from env or file. So no need to apply the env set again. However
// lots of units tests prior to persistent flags assumed that the
// flag can be applied to different flag sets multiple times while still
// keeping the env set.
if !f.applied || f.Local {
newVal := f.Value

if f.Destination == nil {
f.value = f.creator.Create(newVal, new(T), f.Config)
Expand Down
19 changes: 19 additions & 0 deletions flag_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -772,6 +772,8 @@ func TestStringSliceFlagApply_UsesEnvValues_noDefault(t *testing.T) {
_ = fl.Apply(set)

err := set.Parse(nil)

_ = fl.PostParse()
assert.NoError(t, err)
assert.Equal(t, []string{"vincent van goat", "scape goat"}, set.Lookup("goat").Value.(flag.Getter).Get())
}
Expand All @@ -785,6 +787,7 @@ func TestStringSliceFlagApply_UsesEnvValues_withDefault(t *testing.T) {
set := flag.NewFlagSet("test", 0)
_ = fl.Apply(set)
err := set.Parse(nil)
_ = fl.PostParse()
assert.NoError(t, err)
assert.Equal(t, []string{"vincent van goat", "scape goat"}, set.Lookup("goat").Value.(flag.Getter).Get())
}
Expand All @@ -798,6 +801,8 @@ func TestStringSliceFlagApply_DefaultValueWithDestination(t *testing.T) {
_ = fl.Apply(set)

err := set.Parse([]string{})

_ = fl.PostParse()
assert.NoError(t, err)
assert.Equal(t, defValue, dest)
}
Expand Down Expand Up @@ -1056,6 +1061,7 @@ func TestIntSliceFlagApply_UsesEnvValues_noDefault(t *testing.T) {
r := require.New(t)
r.NoError(fl.Apply(set))
r.NoError(set.Parse(nil))
r.NoError(fl.PostParse())
r.Equal([]int64{1, 2}, set.Lookup("goat").Value.(flag.Getter).Get())
}

Expand All @@ -1068,6 +1074,7 @@ func TestIntSliceFlagApply_UsesEnvValues_withDefault(t *testing.T) {
r := require.New(t)
r.NoError(fl.Apply(set))
r.NoError(set.Parse(nil))
r.NoError(fl.PostParse())
r.Equal([]int64{3, 4}, val)
r.Equal([]int64{1, 2}, set.Lookup("goat").Value.(flag.Getter).Get())
}
Expand All @@ -1081,6 +1088,7 @@ func TestIntSliceFlagApply_DefaultValueWithDestination(t *testing.T) {
_ = fl.Apply(set)

err := set.Parse([]string{})
assert.NoError(t, fl.PostParse())
assert.NoError(t, err)
assert.Equal(t, defValue, dest)
}
Expand Down Expand Up @@ -1184,6 +1192,7 @@ func TestUintSliceFlagApply_UsesEnvValues_noDefault(t *testing.T) {
r.NoError(fl.Apply(set))

r.NoError(set.Parse(nil))
r.NoError(fl.PostParse())
r.Equal([]uint64{1, 2}, set.Lookup("goat").Value.(flag.Getter).Get().([]uint64))
}

Expand All @@ -1195,6 +1204,7 @@ func TestUintSliceFlagApply_UsesEnvValues_withDefault(t *testing.T) {
r := require.New(t)
r.NoError(fl.Apply(set))
r.NoError(set.Parse(nil))
r.NoError(fl.PostParse())
r.Equal([]uint64{3, 4}, val.Value())
r.Equal([]uint64{1, 2}, set.Lookup("goat").Value.(flag.Getter).Get().([]uint64))
}
Expand All @@ -1209,6 +1219,7 @@ func TestUintSliceFlagApply_DefaultValueWithDestination(t *testing.T) {

err := set.Parse([]string{})
assert.NoError(t, err)
assert.NoError(t, fl.PostParse())
assert.Equal(t, defValue, dest)
}

Expand Down Expand Up @@ -1328,6 +1339,7 @@ func TestUint64SliceFlagApply_UsesEnvValues_noDefault(t *testing.T) {

err := set.Parse(nil)
assert.NoError(t, err)
assert.NoError(t, fl.PostParse())
assert.Equal(t, []uint64{1, 2}, set.Lookup("goat").Value.(flag.Getter).Get().([]uint64))
}

Expand All @@ -1341,6 +1353,7 @@ func TestUint64SliceFlagApply_UsesEnvValues_withDefault(t *testing.T) {
_ = fl.Apply(set)
err := set.Parse(nil)
assert.NoError(t, err)
assert.NoError(t, fl.PostParse())
assert.Equal(t, []uint64{1, 2}, set.Lookup("goat").Value.(flag.Getter).Get().([]uint64))
}

Expand All @@ -1354,6 +1367,7 @@ func TestUint64SliceFlagApply_DefaultValueWithDestination(t *testing.T) {

err := set.Parse([]string{})
assert.NoError(t, err)
assert.NoError(t, fl.PostParse())
assert.Equal(t, defValue, dest)
}

Expand Down Expand Up @@ -1519,6 +1533,7 @@ func TestFloat64SliceFlagApply_UsesEnvValues_noDefault(t *testing.T) {

err := set.Parse(nil)
assert.NoError(t, err)
assert.NoError(t, fl.PostParse())
assert.Equal(t, []float64{1, 2}, set.Lookup("goat").Value.(flag.Getter).Get().([]float64))
}

Expand All @@ -1532,6 +1547,7 @@ func TestFloat64SliceFlagApply_UsesEnvValues_withDefault(t *testing.T) {
_ = fl.Apply(set)
err := set.Parse(nil)
assert.NoError(t, err)
assert.NoError(t, fl.PostParse())
assert.Equal(t, []float64{1, 2}, set.Lookup("goat").Value.(flag.Getter).Get().([]float64))
}

Expand Down Expand Up @@ -3056,7 +3072,9 @@ func TestStringMapFlagApply_UsesEnvValues_noDefault(t *testing.T) {
_ = fl.Apply(set)

err := set.Parse(nil)

assert.NoError(t, err)
assert.NoError(t, fl.PostParse())
assert.Nil(t, val)
assert.Equal(t, map[string]string{"vincent van goat": "scape goat"}, set.Lookup("goat").Value.(flag.Getter).Get())
}
Expand All @@ -3071,6 +3089,7 @@ func TestStringMapFlagApply_UsesEnvValues_withDefault(t *testing.T) {
_ = fl.Apply(set)
err := set.Parse(nil)
assert.NoError(t, err)
assert.NoError(t, fl.PostParse())
assert.Equal(t, map[string]string{`some default`: `values here`}, val)
assert.Equal(t, map[string]string{"vincent van goat": "scape goat"}, set.Lookup("goat").Value.(flag.Getter).Get())
}
Expand Down
7 changes: 7 additions & 0 deletions godoc-current.txt
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,8 @@ func (parent *BoolWithInverseFlag) IsSet() bool

func (parent *BoolWithInverseFlag) Names() []string

func (parent *BoolWithInverseFlag) PostParse() error

func (parent *BoolWithInverseFlag) RunAction(ctx context.Context, cmd *Command) error

func (parent *BoolWithInverseFlag) String() string
Expand Down Expand Up @@ -625,6 +627,8 @@ type ExitErrHandlerFunc func(context.Context, *Command, error)
type Flag interface {
fmt.Stringer

PostParse() error

// Apply Flag settings to the given flag set
Apply(*flag.FlagSet) error

Expand Down Expand Up @@ -734,6 +738,9 @@ func (f *FlagBase[T, C, V]) IsVisible() bool
func (f *FlagBase[T, C, V]) Names() []string
Names returns the names of the flag

func (f *FlagBase[T, C, V]) PostParse() error
PostParse populates the flag given the flag set and environment

func (f *FlagBase[T, C, V]) RunAction(ctx context.Context, cmd *Command) error
RunAction executes flag action if set

Expand Down
7 changes: 7 additions & 0 deletions testdata/godoc-v3.x.txt
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,8 @@ func (parent *BoolWithInverseFlag) IsSet() bool

func (parent *BoolWithInverseFlag) Names() []string

func (parent *BoolWithInverseFlag) PostParse() error

func (parent *BoolWithInverseFlag) RunAction(ctx context.Context, cmd *Command) error

func (parent *BoolWithInverseFlag) String() string
Expand Down Expand Up @@ -625,6 +627,8 @@ type ExitErrHandlerFunc func(context.Context, *Command, error)
type Flag interface {
fmt.Stringer

PostParse() error

// Apply Flag settings to the given flag set
Apply(*flag.FlagSet) error

Expand Down Expand Up @@ -734,6 +738,9 @@ func (f *FlagBase[T, C, V]) IsVisible() bool
func (f *FlagBase[T, C, V]) Names() []string
Names returns the names of the flag

func (f *FlagBase[T, C, V]) PostParse() error
PostParse populates the flag given the flag set and environment

func (f *FlagBase[T, C, V]) RunAction(ctx context.Context, cmd *Command) error
RunAction executes flag action if set

Expand Down
Loading