12

I'm developing some CLI utility with Cobra. For my RootCmd I've set up some persistent flags (i.e. flags which also affect all the commands). But some of the commands don't use those flags, so I'd like to make them hidden for these particular commands, so those flags won't be displayed with myutil help mycmd or myutil mycmd --help.

The following snippet does the job, but as for me it's a bit ugly and rather hard to maintain:

func init() {
    RootCmd.PersistentFlags().StringVar(&someVar, "some-flag", "", "Nothing to see here, move along.")

    origHelpFunc := TidalCmd.HelpFunc()
    RootCmd.SetHelpFunc(func(cmd *cobra.Command, args []string) {
        if cmd.Name() == "no-flags-cmd" || (cmd.Parent() != nil && cmd.Parent().Name() == "no-flags-cmd") {
            cmd.Flags().MarkHidden("some-flag")
        }
        origHelpFunc(cmd, args)
    })
}

Is there any better way to hide some global persistent flags for some commands?

Petr Razumov
  • 1,952
  • 2
  • 17
  • 32
  • 3
    This seems like a design flaw - global flags, by definition, are flags that apply to all commands. If they don't apply to all commands, they shouldn't be set up as global flags. – Adrian Oct 06 '17 at 13:40
  • 6
    Let's say you have a program that uses those global flags in 9 of 10 commands. Where do you park that? – Justus Wingert Mar 04 '20 at 08:59

2 Answers2

6

Exceptions should be applied to exception cases.

You should override/set the help function for the command you want the flag to be hidden for instead of your root command. This way you can keep your customized logic packaged with your command and it will help maintaining it.

Example:

mySubCommand := &cobra.Command{
    Use:   "no-flags-cmd [command]",
    Short: "Takes no flags for an argument",
    RunE: func(cmd *cobra.Command, args []string) error {
        return nil
    },
}

mySubCommand.SetHelpFunc(func(command *cobra.Command, strings []string) {
   // Hide flag for this command
   command.Flags().MarkHidden("some-flag")
   // Call parent help func
    command.Parent().HelpFunc()(command, strings)
})

rootCmd.AddCommand(mySubCommand)

NOTE: This is just an example. You may need to check and handle any errors.

Paperclip
  • 615
  • 5
  • 14
1

In my case I had like 30 global flags so I had to create a a helper function that passes the flags that should not be hidden

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


var parentCmd = &cobra.Command{}
var subCommand= &cobra.Command{}

func init(){
    subCommand.SetHelpFunc(func(command *cobra.Command, strings []string) {
        markGlobalFlagsHiddenExcept(parentCmd,"unide-this","unhide-this-too")
        command.Parent().HelpFunc()(command, strings)
    })

    parentCmd.AddCommand(subCommand)
}


func markGlobalFlagsHiddenExcept(command *cobra.Command, unhidden ...string) {
    command.PersistentFlags().VisitAll(func(flag *pflag.Flag) {
        name := flag.Name
        if !contains(unhidden, name) {
            flag.Hidden = true
        }
    })
}

// contains returns true if the string is in the slice
func contains(b []string, i string) bool {
    for _, s := range b {
        if s == i {
            return true
        }
    }
    return false
}