Search code examples
gocommand-line-interfacego-cobra

Retrieve persistent flags only once in cobra


I have the following cobra setup

var rootCmd = &cobra.Command{
    Use:   "basic",
    Short: "This is the basic command",
    PreRunE: func(cmd *cobra.Command, args []string) error {
        if err := viper.BindPFlags(cmd.Flags()); err != nil {
            return err
        }
        return nil
    },
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Println("Hello")
        author := viper.GetString("author")
        fmt.Println(author)
    },
}

var subCmd1 = &cobra.Command{
    Use:   "subcommand1",
    Short: "This is test subcommand 1",
    PreRunE: func(cmd *cobra.Command, args []string) error {
        if err := viper.BindPFlags(cmd.Flags()); err != nil {
            return err
        }
        return nil
    },
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Println("Executing subcommand 1")
        author := viper.GetString("author")
        location := viper.GetString("location")
        fmt.Println(author)
        fmt.Println(location)
    },
}

var subCmd2 = &cobra.Command{
    Use:   "subcommand2",
    Short: "This is test subcommand 2",
    PreRunE: func(cmd *cobra.Command, args []string) error {
        if err := viper.BindPFlags(cmd.Flags()); err != nil {
            return err
        }
        return nil
    },
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Println("Executing subcommand 2")
        author := viper.GetString("author")
        duration := viper.GetInt("duration")
        fmt.Println(author)
        fmt.Printf("%d\n", duration)
    },
}

func Execute() {
    if err := rootCmd.Execute(); err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }
}

func init() {
    rootCmd.PersistentFlags().StringP("author", "a", "Pantelis Karamolegkos", "author name for copyright attribution")
    subCmd1.Flags().StringP("location", "l", "Athens", "location of the command execution")
    subCmd2.Flags().IntP("duration", "d", 10, "duration of the event in minutes")
    rootCmd.AddCommand(subCmd1)
    rootCmd.AddCommand(subCmd2)
}

I use author as a PersistentFlag so that it is available in all subcommands.

I am trying to find a way to skip the repetition of

author := viper.GetString("author")

in each subcommand (I of course want it to be available in all subcommands)

Although this snippet is not that convoluted, in my real code I have a few PerstitentFlags and and several subcommands requiring them, therefore the codebase can become very repetitive very quickly.

Is there any way around this? Can the persistent flags be retrieved only once in the parent command and get passed on to the subcommands? Could not find a suggestion here.

Thanks.


Solution

  • One way to deal with this is to use "flag structs":

    type Cmd1Flags struct {
      Author string
      ... // Other persistent flags for cmd1
    }
    
    func GetCmd1Flags() Cmd1Flags {
       ret:=Cmd1Flags{}
       ret.Author=viper.GetString("author")
       ... // Initialize other flags
       return ret
    }
    

    Then, use GetCmd1Flags() in all the subcommands.