jessevdk/go-flags

How to group subcommands

xuezhaokun opened this issue · 3 comments

Hi,

I am trying to group the subcommands using the top-level option "group" in the struct field. But instead of grouping the subcommands, it actually groups the options in the subcommands. Here is my code:

type Cmd1 struct {
	Opt1         string `long:"opt1" description:"first opt" required:"true"`
	Opt2         int    `long:"opt2" description:"second opt" default:"10"`
}

type Cmd2 struct {
	OptA string `long:"optA" description:"opt a" default:":8080"`
	OptB string `long:"optB" description:"opt b" default:"debug"`
}

type MainCmd struct {
	Cmd1      Cmd1      `group:"group1" namespace:"group1" env-namespace:"group1"`
	Cmd2     Cmd2     `group:"group2" namespace:"group2" env-namespace:"group2"`
}

func main() {
	var mainCmd MainCmd
	parser := flags.NewParser(&mainCmd, flags.Default) 
	if _, err := parser.Parse(); err != nil {
		if err, ok := err.(*flags.Error); ok {
			if err.Type == flags.ErrHelp {
				os.Exit(0)
			}
			parser.WriteHelp(os.Stdout)
		}
		os.Exit(1)
	}
}

What I am looking for is when I run the main function, it will print the help message with the grouped subcommands like:

group1:
--Cmd1
group2:
--Cmd2

However it groups the subcommands' options like:

group1:
--group1.opt1=
--group1.opt2=

group2:
--group2.optA=
--group2.optB=

Any ideas or help? Thanks!

I'm not quite sure the reason why you are using groups in this example here. Why do you want to group subcommands?
In my opinion, the commands themselves act like groups, especially in this example. You can achieve what you're looking for if you instead just use the commands and not involve groups:

type Cmd1 struct {
	Opt1 string `long:"opt1" description:"first opt" required:"true"`
	Opt2 int    `long:"opt2" description:"second opt" default:"10"`
}

type Cmd2 struct {
	OptA string `long:"optA" description:"opt a" default:":8080"`
	OptB string `long:"optB" description:"opt b" default:"debug"`
}

type MainCmd struct {
	CmdA Cmd1 `command:"cmd1"`
	CmdB Cmd2 `command:"cmd2"`
}

Even simpler:

type MainCmd struct {
	Cmd1 struct {
		Opt1 string `long:"opt1" description:"first opt" required:"true"`
		Opt2 int    `long:"opt2" description:"second opt" default:"10"`
	} `command:"cmd1"`
	
	Cmd2 struct {
		OptA string `long:"optA" description:"opt a" default:":8080"`
		OptB string `long:"optB" description:"opt b" default:"debug"`
	} `command:"cmd2"`
}

Let me know if this helps.

Thanks for the help. I tried the suggested approach; however, it did not give me the expected output. The help message I have is :

Available commands:
cmd1
cmd2

The example I provided is just a simple piece of workable code to demonstrate my basic need. I think there are many reasons people want to group or categorize subcommands, especially for organizing the help message better. For example, in some system setting related commands, we may want the help message organize the commands as follows:

Troubleshooting and Debugging Commands:
describe Show details
logs Print the logs
exec Execute a command

Settings Commands:
label Update the labels
annotate Update the annotations

Hope this can answer your concerns.

Hello !
I'm allowing myself to redirect you to the last comment I posted in this issue: #380 .
It advertises a project I did work on a lot, and by which you might be interested.
The problem you have here is solved by the advertised project, and much more.