Cobra: child command is not calling the parents PersistentPreRun function

Created on 5 Jan 2016  路  7Comments  路  Source: spf13/cobra

Hi, I've been reading the documentation on the readme that says that the When the subcommand is executed, it will run the root command's PersistentPreRun but not the root command's PersistentPostRun , but the PersistentPreRun isn't getting executed.

package main

import (
    "fmt"
    "github.com/spf13/cobra"
)

func main() {
    var rootCmd = &cobra.Command{
        Use:   "root [sub]",
        Short: "My root command",
        PersistentPreRun: func(cmd *cobra.Command, args []string) {
            fmt.Printf("Inside rootCmd PersistentPreRun with args: %v\n", args)
        },
        PreRun: func(cmd *cobra.Command, args []string) {
            fmt.Printf("Inside rootCmd PreRun with args: %v\n", args)
        },
        Run: func(cmd *cobra.Command, args []string) {
            fmt.Printf("Inside rootCmd Run with args: %v\n", args)
        },
        PostRun: func(cmd *cobra.Command, args []string) {
            fmt.Printf("Inside rootCmd PostRun with args: %v\n", args)
        },
        PersistentPostRun: func(cmd *cobra.Command, args []string) {
            fmt.Printf("Inside rootCmd PersistentPostRun with args: %v\n", args)
        },
    }

    var subCmd = &cobra.Command{
        Use:   "sub [no options!]",
        Short: "My subcommand",
        PersistentPreRun: func(cmd *cobra.Command, args []string) {
                fmt.Printf("Inside subCmd PersistentPreRun with args: %v\n", args)
        },
        PreRun: func(cmd *cobra.Command, args []string) {
            fmt.Printf("Inside subCmd PreRun with args: %v\n", args)
        },
        Run: func(cmd *cobra.Command, args []string) {
            fmt.Printf("Inside subCmd Run with args: %v\n", args)
        },
        PostRun: func(cmd *cobra.Command, args []string) {
            fmt.Printf("Inside subCmd PostRun with args: %v\n", args)
        },
        PersistentPostRun: func(cmd *cobra.Command, args []string) {
            fmt.Printf("Inside subCmd PersistentPostRun with args: %v\n", args)
        },
    }

    rootCmd.AddCommand(subCmd)
    _ = rootCmd.Execute()
}

root@vagrant-ubuntu-vivid-64:/tmp# go version
go version go1.5.2 linux/amd64

root@vagrant-ubuntu-vivid-64:/tmp# go build test.go

root@vagrant-ubuntu-vivid-64:/tmp# ./test 
Inside rootCmd PersistentPreRun with args: []
Inside rootCmd PreRun with args: []
Inside rootCmd Run with args: []
Inside rootCmd PostRun with args: []
Inside rootCmd PersistentPostRun with args: []

root@vagrant-ubuntu-vivid-64:/tmp# ./test sub arg1 arg2 arg3
Inside subCmd PersistentPreRun with args: [arg1 arg2 arg3]
Inside subCmd PreRun with args: [arg1 arg2 arg3]
Inside subCmd Run with args: [arg1 arg2 arg3]
Inside subCmd PostRun with args: [arg1 arg2 arg3]
Inside subCmd PersistentPostRun with args: [arg1 arg2 arg3]

the second example should have also had the output "Inside rootCmd PersistentPreRun" right ?

Most helpful comment

Just fell into this trap too. As the commands are structured into a tree, it makes unnatural not calling {Pre, Post}*Run() during a tree walk. So at least it should be documented as ""do it yourself ;)

All 7 comments

No, you overwrote the PersistentPreRun in the subcommand. If you didn't define a PersistentPreRun in the subcommand, as in the README, then the root PersistentPreRun would be run...

@eparis Is there any way of chaining PersistentPreRuns ? I'd like it to run the parent and then the child.

Today the only option is to call the parent pre run in your pre run. Patches to cobra to allow persistent chaining would be welcome :)

@eparis thank you. I've already got something working.I would like to know what would gel well with your existing naming convention.
Right now I have PreRunChain and PreRunChainE and PostRunChain and PostRunChainE

Just fell into this trap too. As the commands are structured into a tree, it makes unnatural not calling {Pre, Post}*Run() during a tree walk. So at least it should be documented as ""do it yourself ;)

Came across this issue myself.

This suggestion is the way to go:

Today the only option is to call the parent pre run in your pre run. Patches to cobra to allow persistent chaining would be welcome :)

As an example, I added this to my child command's PersistentPreRun:

// Call parent pre-run
if rootCmd.PersistentPreRun != nil {
    rootCmd.PersistentPreRun(cmd, args)
}

Just got caught out on this as well and found this thread. I didn't want my subcommand to have direct knowledge of an ancestor command so I did something like this:

func callPersistentPreRun(cmd *cobra.Command, args []string) { 
    if parent := cmd.Parent(); parent != nil { 
        if parent.PersistentPreRun != nil { 
            parent.PersistentPreRun(parent, args) 
        } 
    } 
} 

sub := &cobra.Command{ 
    ... 
    PersistentPreRun: func(cmd *cobra.Command, args []string) { 
        callPersistentPreRun(cmd, args) 
        ... 
    }, 
}, 
Was this page helpful?
0 / 5 - 0 ratings

Related issues

jjzcru picture jjzcru  路  3Comments

diwakergupta picture diwakergupta  路  5Comments

lukasmalkmus picture lukasmalkmus  路  4Comments

joernott picture joernott  路  6Comments

alapidas picture alapidas  路  3Comments