Further simplify and optimize the hooks logic

This commit is contained in:
Bart de Boer 2020-06-30 19:20:26 +02:00
parent 45ac9307d4
commit 014899635a

View file

@ -827,80 +827,83 @@ func (c *Command) execute(a []string) (err error) {
return err return err
} }
var persistentPreRunHooks []func(cmd *Command, args []string) error // Allocate the hooks execution chain for the current command
preRunHooks := c.preRunHooks var hooks []func(cmd *Command, args []string) error
runHooks := c.runHooks
postRunHooks := c.postRunHooks
var persistentPostRunHooks []func(cmd *Command, args []string) error
// Merge the PreRun* functions into the preRunHooks array // First append the PreRun* hooks
hooks = append(hooks, c.preRunHooks...)
if c.PreRunE != nil { if c.PreRunE != nil {
preRunHooks = append(preRunHooks, c.PreRunE) hooks = append(hooks, c.PreRunE)
} else if c.PreRun != nil { } else if c.PreRun != nil {
preRunHooks = append(preRunHooks, wrapVoidHook(c.PreRun)) hooks = append(hooks, wrapVoidHook(c.PreRun))
} }
// Merge the Run* functions into the runHooks array // Include the validateRequiredFlags() logic as a hook
// to be executed before running the main Run hooks.
hooks = append(hooks, func(cmd *Command, args []string) error {
if err := cmd.validateRequiredFlags(); err != nil {
return err
}
return nil
})
// Append the main Run* hooks
hooks = append(hooks, c.runHooks...)
if c.RunE != nil { if c.RunE != nil {
runHooks = append(runHooks, c.RunE) hooks = append(hooks, c.RunE)
} else if c.Run != nil { } else if c.Run != nil {
runHooks = append(runHooks, wrapVoidHook(c.Run)) hooks = append(hooks, wrapVoidHook(c.Run))
} }
// Merge the PostRun* functions into the runHooks array // Append the PostRun* hooks
hooks = append(hooks, c.postRunHooks...)
if c.PostRunE != nil { if c.PostRunE != nil {
postRunHooks = append(postRunHooks, c.PostRunE) hooks = append(hooks, c.PostRunE)
} else if c.PostRun != nil { } else if c.PostRun != nil {
postRunHooks = append(postRunHooks, wrapVoidHook(c.PostRun)) hooks = append(hooks, wrapVoidHook(c.PostRun))
} }
// Find and merge the Persistent*Run functions into the persistent*Run array. // Lastly find and append/prepend the Persistent*Run hooks.
// If EnablePersistentRunOverride is set Persistent*Run from childs will override their parents. // Setting EnablePersistentRunOverride to true (default) preserves
// Any hooks registered through OnPersistent*Run will always be executed and cannot be overriden. // the previous behavior/concern where childs should override their parents.
// Any hooks registered through OnPersistent*Run will always
// be executed and cannot be overriden.
hasPersistentPreRunFromStruct := false hasPersistentPreRunFromStruct := false
hasPersistentPostRunFromStruct := false hasPersistentPostRunFromStruct := false
for p := c; p != nil; p = p.Parent() { for p := c; p != nil; p = p.Parent() {
// Find and prepend the PersistentPreRun* hooks as defined on the commands
if !hasPersistentPreRunFromStruct || !EnablePersistentRunOverride { if !hasPersistentPreRunFromStruct || !EnablePersistentRunOverride {
if p.PersistentPreRunE != nil { if p.PersistentPreRunE != nil {
persistentPreRunHooks = prependHook(&persistentPreRunHooks, p.PersistentPreRunE) hooks = prependHook(&hooks, p.PersistentPreRunE)
hasPersistentPreRunFromStruct = true hasPersistentPreRunFromStruct = true
} else if p.PersistentPreRun != nil { } else if p.PersistentPreRun != nil {
persistentPreRunHooks = prependHook(&persistentPreRunHooks, wrapVoidHook(p.PersistentPreRun)) hooks = prependHook(&hooks, wrapVoidHook(p.PersistentPreRun))
hasPersistentPreRunFromStruct = true hasPersistentPreRunFromStruct = true
} }
} }
// Find and append the PersistentPostRun* hooks as defined on the commands
if !hasPersistentPostRunFromStruct || !EnablePersistentRunOverride { if !hasPersistentPostRunFromStruct || !EnablePersistentRunOverride {
if p.PersistentPostRunE != nil { if p.PersistentPostRunE != nil {
persistentPostRunHooks = append(persistentPostRunHooks, p.PersistentPostRunE) hooks = append(hooks, p.PersistentPostRunE)
hasPersistentPostRunFromStruct = true hasPersistentPostRunFromStruct = true
} else if p.PersistentPostRun != nil { } else if p.PersistentPostRun != nil {
persistentPostRunHooks = append(persistentPostRunHooks, wrapVoidHook(p.PersistentPostRun)) hooks = append(hooks, wrapVoidHook(p.PersistentPostRun))
hasPersistentPostRunFromStruct = true hasPersistentPostRunFromStruct = true
} }
} }
persistentPreRunHooks = append(p.persistentPreRunHooks, persistentPreRunHooks...) // Hooks registered through OnPersistent*Run should always be executed
persistentPostRunHooks = append(persistentPostRunHooks, p.persistentPostRunHooks...) // Prepend the PersistentPreRun* hooks
hooks = append(p.persistentPreRunHooks, hooks...)
// Append the PersistentPostRun* hooks
hooks = append(hooks, p.persistentPostRunHooks...)
} }
// Execute the hooks: // Execute the hooks execution chain:
if err := c.executeHooks(&persistentPreRunHooks, argWoFlags); err != nil { for _, x := range hooks {
return err if err := x(c, argWoFlags); err != nil {
} return err
if err := c.executeHooks(&preRunHooks, argWoFlags); err != nil { }
return err
}
if err := c.validateRequiredFlags(); err != nil {
return err
}
if err := c.executeHooks(&runHooks, argWoFlags); err != nil {
return err
}
if err := c.executeHooks(&postRunHooks, argWoFlags); err != nil {
return err
}
if err := c.executeHooks(&persistentPostRunHooks, argWoFlags); err != nil {
return err
} }
return nil return nil
@ -912,16 +915,6 @@ func (c *Command) preRun() {
} }
} }
// executeHooks executes the hooks
func (c *Command) executeHooks(hooks *[]func(cmd *Command, args []string) error, args []string) error {
for _, x := range *hooks {
if err := x(c, args); err != nil {
return err
}
}
return nil
}
// prependHook prepends a hook onto the array of hooks // prependHook prepends a hook onto the array of hooks
func prependHook(hooks *[]func(cmd *Command, args []string) error, hook ...func(cmd *Command, args []string) error) []func(cmd *Command, args []string) error { func prependHook(hooks *[]func(cmd *Command, args []string) error, hook ...func(cmd *Command, args []string) error) []func(cmd *Command, args []string) error {
return append(hook, *hooks...) return append(hook, *hooks...)