Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Help.How to use multiple command with multiple flags? #1673

Closed
DG9Jww opened this issue Apr 21, 2022 · 7 comments
Closed

Help.How to use multiple command with multiple flags? #1673

DG9Jww opened this issue Apr 21, 2022 · 7 comments
Labels
kind/support Questions, supporting users, etc.

Comments

@DG9Jww
Copy link

DG9Jww commented Apr 21, 2022

What I want: go run test.go comm1 -d xxx comm2 -a xxx
I want to use comm1 and comm2 with their own flags at the same time
But i got an issue:

Error: unknown shorthand flag: 'a' in -a
Usage:
   comm1 [flags]

Flags:
  -d, --domain string   xxxxxxxxxxxxxxx
  -h, --help            help for comm1

my code:

var (
	cmd1    = &cobra.Command{}
	cmd2    = &cobra.Command{}
	rootCmd = &cobra.Command{}
)

func main() {
	var d string
	var a string


        //
	cmd1 = &cobra.Command{
		Use: "comm1",
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Println("1111")
			fmt.Println(d)
		},
	}
	cmd1.Flags().StringVarP(&d, "domain", "d", "", "xxxxxxxxxxxxxxx")

        //
	cmd2 = &cobra.Command{
		Use: "comm2",
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Println("2222222")
			fmt.Println(a)
		},
	}
	cmd2.Flags().StringVarP(&a, "dirscan", "a", "", "xxxxxxxxxxxxxxx")

        //
	rootCmd = &cobra.Command{
		Run: func(cmd *cobra.Command, args []string) {
			for _, arg := range args {
				switch arg {
				case "comm1":
					cmd1.Execute()
				case "comm2":
					cmd2.Execute()
				}
			}
		},
	}
	rootCmd.AddCommand(cmd1, cmd2)
	rootCmd.Execute()
}

I've ever checked #726 ,but did't solve the problem.😫
Thanks so much if someone can help me🤍

@marckhouzam
Copy link
Collaborator

Hi @DG9Jww. Have you tried the TraverseChildren option?

TraverseChildren bool

You should set it to true on the root command.

Let us know if this is what you were looking for.

@DG9Jww
Copy link
Author

DG9Jww commented Apr 22, 2022

Hi @DG9Jww. Have you tried the TraverseChildren option?

TraverseChildren bool

You should set it to true on the root command.

Let us know if this is what you were looking for.

Unfortunately no,I still got the same issue😥

@johnSchnake
Copy link
Collaborator

Thinking about this out of curiousity for a bit more but the reason you're still getting this is that the root command isn't being selected (and that switch logic never being hit). The reason is that when cobra tries to figure out which command to run, it finds root->comm1. comm2 isnt a child of comm1 so it thinks the cmd invoked is comm1 and the argument is comm2 with two given flags.

@johnSchnake
Copy link
Collaborator

So just tinkering to give you some ideas but this is what I did:

  • remove the commands from the root. This will prevent them from being chosen as "the command that was invoked"
  • add all the flags to the root command so it doesnt error (you can just loop through and add the flagsets as a whole)

This gets everything invoked the way you want but you'll still get the problem each time since cmd1 doesnt know about flags from cmd2:

$ go run main.go comm1 -d dval comm2 -a aval
prerun root
dval
chose root and comm1
Error: unknown shorthand flag: 'a' in -a
Usage:
  comm1 [flags]

Flags:
  -d, --domain string   xxxxxxxxxxxxxxx
  -h, --help            help for comm1

chose root and comm2
Error: unknown shorthand flag: 'd' in -d
Usage:
  comm2 [flags]

Flags:
  -a, --dirscan string   xxxxxxxxxxxxxxx
  -h, --help             help for comm2

I thought about setting the flag error func on the commands to return nil, but that doesn't actually cause the error to be ignored, just exit with no error. I think that actually could be an addition: if cobra had a special class of error you could do something like this:

cmd1.SetFlagErrorFunc(func(command *cobra.Command, err error) error {
     return cobra.ContinueOnError
})

I may create an issue for that and see if it can get picked up.

However, I realized that since we added the flags to the root command, it already did all the parsing necessary so we can skip it entirely on the subcommands by setting DisableFlagParsing=true.

Here is the new output:

go run main.go comm1 -d dval comm2 -a aval
prerun root
chose root and comm1
prerun 1111
1111
dval is dval
chose root and comm2
prerun 2222
2222222
aval is aval

and the updated code is at this playground link: https://go.dev/play/p/KGxUqo9P-wf

but the only important change was at the end after defining the commands (I tweaked their output to better see what was parsed/ran):

for _, c := range []*cobra.Command{cmd1, cmd2} {
     rootCmd.Flags().AddFlagSet(c.Flags())
     c.DisableFlagParsing = true
}
rootCmd.Execute()

So I think those few changes (adding flags to root, disabling children flag parsing, and not adding them as children) solves your problem?

@johnSchnake
Copy link
Collaborator

I also found instead of disabling the flag parsing on the children you can set:

c.FParseErrWhitelist=cobra.FParseErrWhitelist{ UnknownFlags: true}

so that only the unknown flag parsing errors are ignored. Other flag errors, presumably, still get thrown.

@DG9Jww
Copy link
Author

DG9Jww commented Apr 25, 2022

So just tinkering to give you some ideas but this is what I did:

  • remove the commands from the root. This will prevent them from being chosen as "the command that was invoked"
  • add all the flags to the root command so it doesnt error (you can just loop through and add the flagsets as a whole)

This gets everything invoked the way you want but you'll still get the problem each time since cmd1 doesnt know about flags from cmd2:

$ go run main.go comm1 -d dval comm2 -a aval
prerun root
dval
chose root and comm1
Error: unknown shorthand flag: 'a' in -a
Usage:
  comm1 [flags]

Flags:
  -d, --domain string   xxxxxxxxxxxxxxx
  -h, --help            help for comm1

chose root and comm2
Error: unknown shorthand flag: 'd' in -d
Usage:
  comm2 [flags]

Flags:
  -a, --dirscan string   xxxxxxxxxxxxxxx
  -h, --help             help for comm2

I thought about setting the flag error func on the commands to return nil, but that doesn't actually cause the error to be ignored, just exit with no error. I think that actually could be an addition: if cobra had a special class of error you could do something like this:

cmd1.SetFlagErrorFunc(func(command *cobra.Command, err error) error {
     return cobra.ContinueOnError
})

I may create an issue for that and see if it can get picked up.

However, I realized that since we added the flags to the root command, it already did all the parsing necessary so we can skip it entirely on the subcommands by setting DisableFlagParsing=true.

Here is the new output:

go run main.go comm1 -d dval comm2 -a aval
prerun root
chose root and comm1
prerun 1111
1111
dval is dval
chose root and comm2
prerun 2222
2222222
aval is aval

and the updated code is at this playground link: https://go.dev/play/p/KGxUqo9P-wf

but the only important change was at the end after defining the commands (I tweaked their output to better see what was parsed/ran):

for _, c := range []*cobra.Command{cmd1, cmd2} {
     rootCmd.Flags().AddFlagSet(c.Flags())
     c.DisableFlagParsing = true
}
rootCmd.Execute()

So I think those few changes (adding flags to root, disabling children flag parsing, and not adding them as children) solves your problem?

Hi @johnSchnake Thanks for you wonderful answers.Now I know how to deal with it.I appreciate you helping me.🌹

@DG9Jww
Copy link
Author

DG9Jww commented Apr 25, 2022

Hi @johnSchnake
Em.....Well,I got another question.When my different subcommands have same flags,it doesn't work as the rootCmd can not add few same flags.
However,my subcommands do has some same flags such as comm1 -output xxx comm2 -output mmm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/support Questions, supporting users, etc.
Projects
None yet
Development

No branches or pull requests

3 participants