Include EnablePersistentHookOverride option to control if PersistentPostRun* functions should override their parents

This commit is contained in:
Bart de Boer 2020-05-25 17:02:42 +02:00
parent 94a87a7b83
commit 233ff01e4c
4 changed files with 48 additions and 21 deletions

View file

@ -601,7 +601,9 @@ It is possible to run functions before or after the main `Run` function of your
- `PostRun`
- `PersistentPostRun`
An example of two commands which use all of these features is below. When the subcommand is executed, it will run the root command's `PersistentPreRun` but not the root command's `PersistentPostRun`:
By default `Persistent*Run` functions declared within children will override their parents. Setting `cobra.EnablePersistentHookOverride` to false changes this behavior to also run the parent `Persistent*Run` functions.
An example of two commands is below. When the subcommand is executed, it will run the root command's `PersistentPreRun` but not the root command's `PersistentPostRun`:
```go
package main

View file

@ -48,6 +48,10 @@ var EnablePrefixMatching = false
// To disable sorting, set it to false.
var EnableCommandSorting = true
// EnablePersistentHookOverride controls if PersistentPreRun* and PersistentPostRun* hooks
// should override their parents. When set to true only the final hooks are executed (default).
var EnablePersistentHookOverride = true
// MousetrapHelpText enables an information splash screen on Windows
// if the CLI is started from explorer.exe.
// To disable the mousetrap, just set this variable to blank string ("").

View file

@ -816,17 +816,28 @@ func (c *Command) execute(a []string) (err error) {
return err
}
// By default PersistentPostRun* functions override their parent functions.
// Disabling EnablePersistentHookOverride runs all PersistentPostRun* functions from root to child
chain := []*Command{}
for p := c; p != nil; p = p.Parent() {
if p.PersistentPreRunE != nil {
if err := p.PersistentPreRunE(c, argWoFlags); err != nil {
return err
if p.PersistentPreRunE != nil || p.PersistentPreRun != nil {
chain = append(chain, p)
if EnablePersistentHookOverride {
break
}
break
} else if p.PersistentPreRun != nil {
p.PersistentPreRun(c, argWoFlags)
break
}
}
for i := len(chain) - 1; i >= 0; i-- {
cc := chain[i]
if cc.PersistentPreRunE != nil {
if err := cc.PersistentPreRunE(c, argWoFlags); err != nil {
return err
}
} else if cc.PersistentPreRun != nil {
cc.PersistentPreRun(c, argWoFlags)
}
}
if c.PreRunE != nil {
if err := c.PreRunE(c, argWoFlags); err != nil {
return err
@ -852,15 +863,22 @@ func (c *Command) execute(a []string) (err error) {
} else if c.PostRun != nil {
c.PostRun(c, argWoFlags)
}
// By default PersistentPostRun* functions override their parent functions.
// Disabling EnablePersistentHookOverride runs all PersistentPostRun* functions from child to root
for p := c; p != nil; p = p.Parent() {
if p.PersistentPostRunE != nil {
if err := p.PersistentPostRunE(c, argWoFlags); err != nil {
return err
}
break
if EnablePersistentHookOverride {
break
}
} else if p.PersistentPostRun != nil {
p.PersistentPostRun(c, argWoFlags)
break
if EnablePersistentHookOverride {
break
}
}
}

View file

@ -1379,11 +1379,10 @@ func TestPersistentHooks(t *testing.T) {
t.Errorf("Unexpected error: %v", err)
}
// TODO: currently PersistenPreRun* defined in parent does not
// run if the matchin child subcommand has PersistenPreRun.
// If the behavior changes (https://github.com/spf13/cobra/issues/252)
// this test must be fixed.
if parentPersPreArgs != "" {
if !EnablePersistentHookOverride && parentPersPreArgs != "one two" {
t.Errorf("Expected parentPersPreArgs %q, got %q", "one two", parentPersPreArgs)
}
if EnablePersistentHookOverride && parentPersPreArgs != "" {
t.Errorf("Expected blank parentPersPreArgs, got %q", parentPersPreArgs)
}
if parentPreArgs != "" {
@ -1395,14 +1394,12 @@ func TestPersistentHooks(t *testing.T) {
if parentPostArgs != "" {
t.Errorf("Expected blank parentPostArgs, got %q", parentPostArgs)
}
// TODO: currently PersistenPostRun* defined in parent does not
// run if the matchin child subcommand has PersistenPostRun.
// If the behavior changes (https://github.com/spf13/cobra/issues/252)
// this test must be fixed.
if parentPersPostArgs != "" {
if !EnablePersistentHookOverride && parentPersPostArgs != "one two" {
t.Errorf("Expected parentPersPostArgs %q, got %q", "one two", parentPersPostArgs)
}
if EnablePersistentHookOverride && parentPersPostArgs != "" {
t.Errorf("Expected blank parentPersPostArgs, got %q", parentPersPostArgs)
}
if childPersPreArgs != "one two" {
t.Errorf("Expected childPersPreArgs %q, got %q", "one two", childPersPreArgs)
}
@ -1420,6 +1417,12 @@ func TestPersistentHooks(t *testing.T) {
}
}
func TestPersistentHooksNotOverriding(t *testing.T) {
EnablePersistentHookOverride = false
TestPersistentHooks(t)
EnablePersistentHookOverride = true
}
// Related to https://github.com/spf13/cobra/issues/521.
func TestGlobalNormFuncPropagation(t *testing.T) {
normFunc := func(f *pflag.FlagSet, name string) pflag.NormalizedName {