Skip to content

Commit 706f78e

Browse files
authored
Merge pull request #2033 from dearchap/issue_2032
Fix:(issue_2032) Support for post parse config loading
2 parents f6534a6 + 7d65562 commit 706f78e

File tree

9 files changed

+86
-16
lines changed

9 files changed

+86
-16
lines changed

command.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,12 @@ func (cmd *Command) Run(ctx context.Context, osArgs []string) (deferErr error) {
541541
return nil
542542
}
543543

544+
for _, flag := range cmd.Flags {
545+
if err := flag.PostParse(); err != nil {
546+
return err
547+
}
548+
}
549+
544550
if cmd.After != nil && !cmd.Root().shellCompletion {
545551
defer func() {
546552
if err := cmd.After(ctx, cmd); err != nil {

command_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2343,6 +2343,10 @@ func (c *customBoolFlag) GetUsage() string {
23432343
return "usage"
23442344
}
23452345

2346+
func (c *customBoolFlag) PostParse() error {
2347+
return nil
2348+
}
2349+
23462350
func (c *customBoolFlag) Apply(set *flag.FlagSet) error {
23472351
set.String(c.Nombre, c.Nombre, "")
23482352
return nil

flag.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ type ActionableFlag interface {
104104
type Flag interface {
105105
fmt.Stringer
106106

107+
PostParse() error
108+
107109
// Apply Flag settings to the given flag set
108110
Apply(*flag.FlagSet) error
109111

flag_bool_with_inverse.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,20 @@ func (parent *BoolWithInverseFlag) inverseAliases() (aliases []string) {
135135
return
136136
}
137137

138+
func (parent *BoolWithInverseFlag) PostParse() error {
139+
if parent.positiveFlag != nil {
140+
if err := parent.positiveFlag.PostParse(); err != nil {
141+
return err
142+
}
143+
}
144+
if parent.negativeFlag != nil {
145+
if err := parent.negativeFlag.PostParse(); err != nil {
146+
return err
147+
}
148+
}
149+
return nil
150+
}
151+
138152
func (parent *BoolWithInverseFlag) Apply(set *flag.FlagSet) error {
139153
if parent.positiveFlag == nil {
140154
parent.initialize()

flag_ext.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ type extFlag struct {
66
f *flag.Flag
77
}
88

9+
func (e *extFlag) PostParse() error {
10+
return nil
11+
}
12+
913
func (e *extFlag) Apply(fs *flag.FlagSet) error {
1014
fs.Var(e.f.Value, e.f.Name, e.f.Usage)
1115
return nil

flag_impl.go

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -135,35 +135,42 @@ func (f *FlagBase[T, C, V]) TypeName() string {
135135
}
136136
}
137137

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

142+
if !f.hasBeenSet {
151143
if val, source, found := f.Sources.LookupWithSource(); found {
152-
tmpVal := f.creator.Create(f.Value, new(T), f.Config)
153144
if val != "" || reflect.TypeOf(f.Value).Kind() == reflect.String {
154-
if err := tmpVal.Set(val); err != nil {
145+
if err := f.value.Set(val); err != nil {
155146
return fmt.Errorf(
156147
"could not parse %[1]q as %[2]T value from %[3]s for flag %[4]s: %[5]s",
157148
val, f.Value, source, f.Name, err,
158149
)
159150
}
160151
} else if val == "" && reflect.TypeOf(f.Value).Kind() == reflect.Bool {
161-
_ = tmpVal.Set("false")
152+
_ = f.value.Set("false")
162153
}
163154

164-
newVal = tmpVal.Get().(T)
165155
f.hasBeenSet = true
166156
}
157+
}
158+
159+
return nil
160+
}
161+
162+
// Apply populates the flag given the flag set and environment
163+
func (f *FlagBase[T, C, V]) Apply(set *flag.FlagSet) error {
164+
tracef("apply (flag=%[1]q)", f.Name)
165+
166+
// TODO move this phase into a separate flag initialization function
167+
// if flag has been applied previously then it would have already been set
168+
// from env or file. So no need to apply the env set again. However
169+
// lots of units tests prior to persistent flags assumed that the
170+
// flag can be applied to different flag sets multiple times while still
171+
// keeping the env set.
172+
if !f.applied || f.Local {
173+
newVal := f.Value
167174

168175
if f.Destination == nil {
169176
f.value = f.creator.Create(newVal, new(T), f.Config)

flag_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -772,6 +772,8 @@ func TestStringSliceFlagApply_UsesEnvValues_noDefault(t *testing.T) {
772772
_ = fl.Apply(set)
773773

774774
err := set.Parse(nil)
775+
776+
_ = fl.PostParse()
775777
assert.NoError(t, err)
776778
assert.Equal(t, []string{"vincent van goat", "scape goat"}, set.Lookup("goat").Value.(flag.Getter).Get())
777779
}
@@ -785,6 +787,7 @@ func TestStringSliceFlagApply_UsesEnvValues_withDefault(t *testing.T) {
785787
set := flag.NewFlagSet("test", 0)
786788
_ = fl.Apply(set)
787789
err := set.Parse(nil)
790+
_ = fl.PostParse()
788791
assert.NoError(t, err)
789792
assert.Equal(t, []string{"vincent van goat", "scape goat"}, set.Lookup("goat").Value.(flag.Getter).Get())
790793
}
@@ -798,6 +801,8 @@ func TestStringSliceFlagApply_DefaultValueWithDestination(t *testing.T) {
798801
_ = fl.Apply(set)
799802

800803
err := set.Parse([]string{})
804+
805+
_ = fl.PostParse()
801806
assert.NoError(t, err)
802807
assert.Equal(t, defValue, dest)
803808
}
@@ -1056,6 +1061,7 @@ func TestIntSliceFlagApply_UsesEnvValues_noDefault(t *testing.T) {
10561061
r := require.New(t)
10571062
r.NoError(fl.Apply(set))
10581063
r.NoError(set.Parse(nil))
1064+
r.NoError(fl.PostParse())
10591065
r.Equal([]int64{1, 2}, set.Lookup("goat").Value.(flag.Getter).Get())
10601066
}
10611067

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

10831090
err := set.Parse([]string{})
1091+
assert.NoError(t, fl.PostParse())
10841092
assert.NoError(t, err)
10851093
assert.Equal(t, defValue, dest)
10861094
}
@@ -1184,6 +1192,7 @@ func TestUintSliceFlagApply_UsesEnvValues_noDefault(t *testing.T) {
11841192
r.NoError(fl.Apply(set))
11851193

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

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

12101220
err := set.Parse([]string{})
12111221
assert.NoError(t, err)
1222+
assert.NoError(t, fl.PostParse())
12121223
assert.Equal(t, defValue, dest)
12131224
}
12141225

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

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

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

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

13551368
err := set.Parse([]string{})
13561369
assert.NoError(t, err)
1370+
assert.NoError(t, fl.PostParse())
13571371
assert.Equal(t, defValue, dest)
13581372
}
13591373

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

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

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

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

30583074
err := set.Parse(nil)
3075+
30593076
assert.NoError(t, err)
3077+
assert.NoError(t, fl.PostParse())
30603078
assert.Nil(t, val)
30613079
assert.Equal(t, map[string]string{"vincent van goat": "scape goat"}, set.Lookup("goat").Value.(flag.Getter).Get())
30623080
}
@@ -3071,6 +3089,7 @@ func TestStringMapFlagApply_UsesEnvValues_withDefault(t *testing.T) {
30713089
_ = fl.Apply(set)
30723090
err := set.Parse(nil)
30733091
assert.NoError(t, err)
3092+
assert.NoError(t, fl.PostParse())
30743093
assert.Equal(t, map[string]string{`some default`: `values here`}, val)
30753094
assert.Equal(t, map[string]string{"vincent van goat": "scape goat"}, set.Lookup("goat").Value.(flag.Getter).Get())
30763095
}

godoc-current.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,8 @@ func (parent *BoolWithInverseFlag) IsSet() bool
285285

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

288+
func (parent *BoolWithInverseFlag) PostParse() error
289+
288290
func (parent *BoolWithInverseFlag) RunAction(ctx context.Context, cmd *Command) error
289291

290292
func (parent *BoolWithInverseFlag) String() string
@@ -627,6 +629,8 @@ type ExitErrHandlerFunc func(context.Context, *Command, error)
627629
type Flag interface {
628630
fmt.Stringer
629631

632+
PostParse() error
633+
630634
// Apply Flag settings to the given flag set
631635
Apply(*flag.FlagSet) error
632636

@@ -736,6 +740,9 @@ func (f *FlagBase[T, C, V]) IsVisible() bool
736740
func (f *FlagBase[T, C, V]) Names() []string
737741
Names returns the names of the flag
738742

743+
func (f *FlagBase[T, C, V]) PostParse() error
744+
PostParse populates the flag given the flag set and environment
745+
739746
func (f *FlagBase[T, C, V]) RunAction(ctx context.Context, cmd *Command) error
740747
RunAction executes flag action if set
741748

testdata/godoc-v3.x.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,8 @@ func (parent *BoolWithInverseFlag) IsSet() bool
285285

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

288+
func (parent *BoolWithInverseFlag) PostParse() error
289+
288290
func (parent *BoolWithInverseFlag) RunAction(ctx context.Context, cmd *Command) error
289291

290292
func (parent *BoolWithInverseFlag) String() string
@@ -627,6 +629,8 @@ type ExitErrHandlerFunc func(context.Context, *Command, error)
627629
type Flag interface {
628630
fmt.Stringer
629631

632+
PostParse() error
633+
630634
// Apply Flag settings to the given flag set
631635
Apply(*flag.FlagSet) error
632636

@@ -736,6 +740,9 @@ func (f *FlagBase[T, C, V]) IsVisible() bool
736740
func (f *FlagBase[T, C, V]) Names() []string
737741
Names returns the names of the flag
738742

743+
func (f *FlagBase[T, C, V]) PostParse() error
744+
PostParse populates the flag given the flag set and environment
745+
739746
func (f *FlagBase[T, C, V]) RunAction(ctx context.Context, cmd *Command) error
740747
RunAction executes flag action if set
741748

0 commit comments

Comments
 (0)