google / subcommands

Go subcommand library.
Apache License 2.0
744 stars 48 forks source link

No documentation for top level flags #10

Open the-maldridge opened 6 years ago

the-maldridge commented 6 years ago

There seems to be facilities for adding top level flags given that you can define them as normal with the flags library and then mark them important with the given functions, but I can't seem to find out how to get the value in a subcommand. For example, if I have the following command:

$ foo --verbose bar --frobnicate

then I would expect for bar to get the frobnicate flag set true, which I have figured out how to do, but in this case I expect it to also have access to the verbose flag. How can I make sure that bar has access to the top level flags defined outside it's scope? They seem to be available in topFlags but I can't figure out how to access that from a subcommand.

donatj commented 6 years ago

I've been trying to figure out the best way to use the top level flags myself.

the-maldridge commented 6 years ago

After looking into this more and looking into projects that include this, I believe this is referring instead to the flags that are explicitly defined with the flags package. They exist outside the configuration of this package, which is why they must come first. They also need to be plumbed in directly since they reside in the main package.

At least I think that's how it works.

adjackura commented 6 years ago

Yes, from what I recall you at correct. I think the confusion is coming from the comment calling these 'top-level flags', that simply means they are not treated as subcommands but instead parsed using flags.Parse(). Subcommands don't have direct access to these flags other than through normal channels like top level variables.

fgm commented 3 years ago

Suggested example: https://play.golang.org/p/BGV9lVDjIc5

fgm commented 2 years ago

Another way of looking at it, after spending some time creating a tutorial for this package (see https://github.com/fgm/subcommands_demo ): after parsing, add the parsed value to the context, like:

// package scope
type verboseKey string
// function scope
flag.BoolVar(&verbose, "v", false, "make it verbose)
fs.Parse()
ctx = context.WithValue(ctx, verboseKey("v"), verbose)
subcommands.Execute(ctx)

At this point your command can retrieve the flag value from the context without sharing a variable using ctx.Value(verboseKey("v")).(bool). Which makes sense, as a CLI run is pretty much like a request on a server.

You could also pass the value using the extra args, like subcommands.Execute(ctx, verbose) and in the command, retrieve it as args[0].(bool), but that seems a little less robust and less semantically appropriate.