mirror of
https://github.com/spf13/cobra
synced 2025-05-05 21:07:24 +00:00
Issue #219: added PreRunChain and PostRunChain hooks
PreRunChain functions run in the order of root to child. PostRunChain functions run in the order of child to root. The overall exection order for a command is PreRunChain PersistentPreRun PreRun Run PostRun PersistentPostRun PostRunChain The following gist describes the usage and functionality https://gist.github.com/algrebe/23cc8bf4739a129a6d0d
This commit is contained in:
parent
2a426b5c59
commit
3dbb5be47c
2 changed files with 84 additions and 2 deletions
25
README.md
25
README.md
|
@ -641,15 +641,22 @@ command.SetUsageTemplate(s string)
|
||||||
|
|
||||||
## PreRun or PostRun Hooks
|
## PreRun or PostRun Hooks
|
||||||
|
|
||||||
It is possible to run functions before or after the main `Run` function of your command. The `PersistentPreRun` and `PreRun` functions will be executed before `Run`. `PersistentPostRun` and `PostRun` will be executed after `Run`. The `Persistent*Run` functions will be inherrited by children if they do not declare their own. These function are run in the following order:
|
It is possible to run functions before or after the main `Run` function of your command. The `PreRunChain`, `PersistentPreRun` and `PreRun` functions will be executed before `Run`. `PersistentPostRun`, `PostRun` and `PostRunChain` will be executed after `Run`. The `Persistent*Run` functions will be inherrited by children if they do not declare their own. These function are run in the following order:
|
||||||
|
|
||||||
|
- `PreRunChain`
|
||||||
- `PersistentPreRun`
|
- `PersistentPreRun`
|
||||||
- `PreRun`
|
- `PreRun`
|
||||||
- `Run`
|
- `Run`
|
||||||
- `PostRun`
|
- `PostRun`
|
||||||
- `PersistentPostRun`
|
- `PersistentPostRun`
|
||||||
|
- `PostRunChain`
|
||||||
|
|
||||||
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`:
|
|
||||||
|
`PreRunChain` executes all PreRunChain functions from the root to the child. `PostRunChain` executes all PostRunChain functions from the child to the root. These
|
||||||
|
are useful in cases such as setting the logger and profiling at the root level in `PreRunChain`, and stopping the profiler once the proram finishes in the `PostRunChain`, while still allowing subcommand `PreRunChain` and `PostRunChain` commands to execute for their children.
|
||||||
|
|
||||||
|
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` - because the subcommand has overridden the root command's `PersistentPostRun`. However, it will still run the root command's `PreRunChain` and `PostRunChain` in addition to the subcommand's `PreRunChain` and `PostRunChain`, because chains are supposed to execute all defined
|
||||||
|
chain functions, and not just the overridden one.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
|
@ -665,6 +672,9 @@ func main() {
|
||||||
var rootCmd = &cobra.Command{
|
var rootCmd = &cobra.Command{
|
||||||
Use: "root [sub]",
|
Use: "root [sub]",
|
||||||
Short: "My root command",
|
Short: "My root command",
|
||||||
|
PreRunChain: func(cmd *cobra.Command, args []string) {
|
||||||
|
fmt.Printf("Inside rootCmd PreRunChain with args: %v\n", args)
|
||||||
|
},
|
||||||
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
||||||
fmt.Printf("Inside rootCmd PersistentPreRun with args: %v\n", args)
|
fmt.Printf("Inside rootCmd PersistentPreRun with args: %v\n", args)
|
||||||
},
|
},
|
||||||
|
@ -680,11 +690,17 @@ func main() {
|
||||||
PersistentPostRun: func(cmd *cobra.Command, args []string) {
|
PersistentPostRun: func(cmd *cobra.Command, args []string) {
|
||||||
fmt.Printf("Inside rootCmd PersistentPostRun with args: %v\n", args)
|
fmt.Printf("Inside rootCmd PersistentPostRun with args: %v\n", args)
|
||||||
},
|
},
|
||||||
|
PostRunChain: func(cmd *cobra.Command, args []string) {
|
||||||
|
fmt.Printf("Inside rootCmd PostRunChain with args: %v\n", args)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var subCmd = &cobra.Command{
|
var subCmd = &cobra.Command{
|
||||||
Use: "sub [no options!]",
|
Use: "sub [no options!]",
|
||||||
Short: "My subcommand",
|
Short: "My subcommand",
|
||||||
|
PreRunChain: func(cmd *cobra.Command, args []string) {
|
||||||
|
fmt.Printf("Inside subCmd PreRunChain with args: %v\n", args)
|
||||||
|
},
|
||||||
PreRun: func(cmd *cobra.Command, args []string) {
|
PreRun: func(cmd *cobra.Command, args []string) {
|
||||||
fmt.Printf("Inside subCmd PreRun with args: %v\n", args)
|
fmt.Printf("Inside subCmd PreRun with args: %v\n", args)
|
||||||
},
|
},
|
||||||
|
@ -697,6 +713,9 @@ func main() {
|
||||||
PersistentPostRun: func(cmd *cobra.Command, args []string) {
|
PersistentPostRun: func(cmd *cobra.Command, args []string) {
|
||||||
fmt.Printf("Inside subCmd PersistentPostRun with args: %v\n", args)
|
fmt.Printf("Inside subCmd PersistentPostRun with args: %v\n", args)
|
||||||
},
|
},
|
||||||
|
PostRunChain: func(cmd *cobra.Command, args []string) {
|
||||||
|
fmt.Printf("Inside subCmd PostRunChain with args: %v\n", args)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
rootCmd.AddCommand(subCmd)
|
rootCmd.AddCommand(subCmd)
|
||||||
|
@ -714,11 +733,13 @@ func main() {
|
||||||
|
|
||||||
Cobra also has functions where the return signature is an error. This allows for errors to bubble up to the top, providing a way to handle the errors in one location. The current list of functions that return an error is:
|
Cobra also has functions where the return signature is an error. This allows for errors to bubble up to the top, providing a way to handle the errors in one location. The current list of functions that return an error is:
|
||||||
|
|
||||||
|
* PreRunChainE
|
||||||
* PersistentPreRunE
|
* PersistentPreRunE
|
||||||
* PreRunE
|
* PreRunE
|
||||||
* RunE
|
* RunE
|
||||||
* PostRunE
|
* PostRunE
|
||||||
* PersistentPostRunE
|
* PersistentPostRunE
|
||||||
|
* PostRunChainE
|
||||||
|
|
||||||
**Example Usage using RunE:**
|
**Example Usage using RunE:**
|
||||||
|
|
||||||
|
|
61
command.go
61
command.go
|
@ -64,12 +64,18 @@ type Command struct {
|
||||||
// Silence Usage is an option to silence usage when an error occurs.
|
// Silence Usage is an option to silence usage when an error occurs.
|
||||||
SilenceUsage bool
|
SilenceUsage bool
|
||||||
// The *Run functions are executed in the following order:
|
// The *Run functions are executed in the following order:
|
||||||
|
// * PreRunChain()
|
||||||
// * PersistentPreRun()
|
// * PersistentPreRun()
|
||||||
// * PreRun()
|
// * PreRun()
|
||||||
// * Run()
|
// * Run()
|
||||||
// * PostRun()
|
// * PostRun()
|
||||||
// * PersistentPostRun()
|
// * PersistentPostRun()
|
||||||
|
// * PostRunChain()
|
||||||
// All functions get the same args, the arguments after the command name
|
// All functions get the same args, the arguments after the command name
|
||||||
|
// PreRunChain: runs all PreRunChain functions from root to child sequentially
|
||||||
|
PreRunChain func(cmd *Command, args []string)
|
||||||
|
// PreRunChainE: PreRunChain but returns an error
|
||||||
|
PreRunChainE func(cmd *Command, args []string) error
|
||||||
// PersistentPreRun: children of this command will inherit and execute
|
// PersistentPreRun: children of this command will inherit and execute
|
||||||
PersistentPreRun func(cmd *Command, args []string)
|
PersistentPreRun func(cmd *Command, args []string)
|
||||||
// PersistentPreRunE: PersistentPreRun but returns an error
|
// PersistentPreRunE: PersistentPreRun but returns an error
|
||||||
|
@ -90,6 +96,10 @@ type Command struct {
|
||||||
PersistentPostRun func(cmd *Command, args []string)
|
PersistentPostRun func(cmd *Command, args []string)
|
||||||
// PersistentPostRunE: PersistentPostRun but returns an error
|
// PersistentPostRunE: PersistentPostRun but returns an error
|
||||||
PersistentPostRunE func(cmd *Command, args []string) error
|
PersistentPostRunE func(cmd *Command, args []string) error
|
||||||
|
// PostRunChain: runs all PostRunChain functions from child to root sequentially
|
||||||
|
PostRunChain func(cmd *Command, args []string)
|
||||||
|
// PostRunChainE: PostRunChain but returns an error
|
||||||
|
PostRunChainE func(cmd *Command, args []string) error
|
||||||
// DisableAutoGenTag remove
|
// DisableAutoGenTag remove
|
||||||
DisableAutoGenTag bool
|
DisableAutoGenTag bool
|
||||||
// Commands is the list of commands supported by this program.
|
// Commands is the list of commands supported by this program.
|
||||||
|
@ -542,6 +552,10 @@ func (c *Command) execute(a []string) (err error) {
|
||||||
c.preRun()
|
c.preRun()
|
||||||
argWoFlags := c.Flags().Args()
|
argWoFlags := c.Flags().Args()
|
||||||
|
|
||||||
|
if err := c.executePreRunChain(c, argWoFlags); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
for p := c; p != nil; p = p.Parent() {
|
for p := c; p != nil; p = p.Parent() {
|
||||||
if p.PersistentPreRunE != nil {
|
if p.PersistentPreRunE != nil {
|
||||||
if err := p.PersistentPreRunE(c, argWoFlags); err != nil {
|
if err := p.PersistentPreRunE(c, argWoFlags); err != nil {
|
||||||
|
@ -587,6 +601,10 @@ func (c *Command) execute(a []string) (err error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := c.executePostRunChain(c, argWoFlags); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -596,6 +614,49 @@ func (c *Command) preRun() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// executePreRunChain executes all the PreRunChain functions from
|
||||||
|
// the root to the child.
|
||||||
|
func (c *Command) executePreRunChain(cmd *Command, args []string) error {
|
||||||
|
parent := c.Parent()
|
||||||
|
if parent != nil {
|
||||||
|
if err := parent.executePreRunChain(cmd, args); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error = nil
|
||||||
|
switch {
|
||||||
|
case c.PreRunChainE != nil:
|
||||||
|
err = c.PreRunChainE(cmd, args)
|
||||||
|
case c.PreRunChain != nil:
|
||||||
|
c.PreRunChain(cmd, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// executePostRunChain executes all the PostRunChain functions from
|
||||||
|
// the child to the root.
|
||||||
|
func (c *Command) executePostRunChain(cmd *Command, args []string) error {
|
||||||
|
var err error = nil
|
||||||
|
switch {
|
||||||
|
case c.PostRunChainE != nil:
|
||||||
|
err = c.PostRunChainE(cmd, args)
|
||||||
|
case c.PostRunChain != nil:
|
||||||
|
c.PostRunChain(cmd, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
parent := c.Parent()
|
||||||
|
if parent != nil {
|
||||||
|
return parent.executePostRunChain(cmd, args)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Command) errorMsgFromParse() string {
|
func (c *Command) errorMsgFromParse() string {
|
||||||
s := c.flagErrorBuf.String()
|
s := c.flagErrorBuf.String()
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue