go-cobra

make flag persistent in one subcommand only


Building from What is the difference between go-Cobra PersistentFlags and Flags?:

Assume we have a top-level prog command, and two start and stop subcommands in it.

Assume the prog command has a persistent flag called database.

How can we make this flag required in the start command only? Note that the stop command should have the flag but it should be optional.

progCmd.MarkPersistentFlagRequired("database") does not work as intended, as it would make the flag required in both start and stop.

startCmd.MarkPersistentFlagRequired("database") does not work either:

no such flag -database

Solution

  • Here is minimal example that functions as you describe.

    TLDR:

    You may have attached PersistentFlags to the root command prog with start and stop being sub commands, and thus persists by definition.

    A flag can be ‘persistent’ meaning that this flag will be available to the command it’s assigned to as well as every command under that command. For global flags, assign a flag as a persistent flag on the root.

    In the example below, set PersistenFlags() or Flags() to each start and stop sub command and apply MarkPersistentFlagRequired() or MarkFlagRequired() respectively for each required flag.


    Example File Layout

    ├── cmd
    │   ├── root.go
    │   ├── start.go
    │   └── stop.go
    ├── go.mod
    ├── go.sum
    ├── main.go
    

    main.go

    package main
    
    import (
        "stackoverflow/78807651/prog/cmd"
    )
    
    func main() {
        cmd.Execute()
    }
    
    

    cmd/root.go

    package cmd
    
    import (
        "github.com/spf13/cobra"
    )
    
    var RootCmd = &cobra.Command{
        Use:   "prog",
    }
    
    func Execute() {
        RootCmd.Execute()
    }
    
    

    cmd/start.go

    package cmd
    
    import (
        "fmt"
        "github.com/spf13/cobra"
    )
    
    var startCmd = &cobra.Command{
        Use:   "start",
        Run: func(cmd *cobra.Command, args []string) {
            fmt.Println("starting...")
        },
    }
    
    func init() {
        RootCmd.AddCommand(startCmd)
    
        // startCmd.Flags().StringP("database", "d", "", "testdb")
        // startCmd.MarkFlagRequired("database")
    
        startCmd.PersistentFlags().StringP("database", "d", "", "testdb")
        startCmd.MarkPersistentFlagRequired("database")
    }
    
    

    cmd/stop.go

    package cmd
    
    import (
        "fmt"
        "github.com/spf13/cobra"
    )
    
    var stopCmd = &cobra.Command{
        Use:   "stop",
        Run: func(cmd *cobra.Command, args []string) {
            fmt.Println("stopped...")
        },
    }
    
    func init() {
        RootCmd.AddCommand(stopCmd)
    
        // stopCmd.Flags().StringP("database", "d", "", "testdb")
        // stopCmd.MarkFlagRequired("database")
    
        stopCmd.PersistentFlags().StringP("database", "d", "", "testdb")
        // stopCmd.MarkPersistentFlagRequired("database")
    
    }