Global StringArg + command: contextual help does not work
3coma3 opened this issue · 4 comments
Hi. First of all, thanks for this excellent package. I hope it will be developed further because it shows an enormous potential.
With the following example code (simplified from docs):
package main
import (
"fmt"
"os"
cli "github.com/jawher/mow.cli"
)
var filename *string
func main() {
app := cli.App("app", "description")
filename = app.StringArg("FILENAME", "", "a string argument")
app.Command("command1", "this should show with -h", command1)
app.Run(os.Args)
}
func command1(cmd *cli.Cmd) {
cmd.Action = func() {
fmt.Printf("Hello from command1")
}
}
I see the following behavior:
./app command1 --help
Error: incorrect usage
Usage: app FILENAME COMMAND [arg...]
description
Arguments:
FILENAME a string argument
Commands:
command1 this should show with -h
Run 'app COMMAND --help' for more information on a command.
I would expect that the contextual help worked here, or is this the intended semantics? I couldn't find anything about this in the documentation, and the sole example combining top level parameters with commands used options instead of string arguments.
In case this is the intended semantics, where can I find the rationale in docs? And if not, and you are kind enough to point me around the code that deals with this part, I hope I can be able to submit a patch (I will at least give it a try).
Thanks!
Take a look at the usage string. FILENAME is being specified before COMMAND. If you invoke the program with ./app file.txt command1 --help
you should get the help message for command1
If you meant for FILENAME to be an argument to command1, it should be specified by calling cmd.StringArg inside command1
Hi @7fffffff , thanks for your reply!
I did look at the usage string, and opened this issue precisely because what the last line is suggesting, is inconsistent with having to pass top level arguments to be able to reach help for subcommands (which also applies for further nested commands):
Run 'app COMMAND --help' for more information on a command.
Actuallly, this is how CLI applications with subcommands work in general: you don't need to pass top level parameters to write CMD subcmd1 --help
or CMD subcmd1 subcmd2 --help
, ie, the contextual help is independent of "normal" invocations.
Examples: git, ip, btrfs, nmcli, virsh, and so on, (most commands with a subcommand structure). The CLIG standard, also neatly sums up this behavior.
As I mentioned in my initial post, the CLI I posted was just a theoretical, simplified example taken from the mow.cli documentation, to the effects of focusing on illustrating my point. My actual application is a REST wrapper, and it's more involved. It is available at this gist, so as to not extend this reply too much, and this is the help text:
Usage: pve-api-go HOSTPORT USERREALM [-i] [-v...] ((-p=<secret> [-r=<seconds>]) | -t=<tokenid=secret>) COMMAND [arg...]
Go client to the Proxmox Virtual Environment API
Arguments:
HOSTPORT Login host:port, port defaults to 8006 if omitted (env $PVE_HOST)
USERREALM Login username@realm, realm defaults to pam if omitted (env $PVE_USER) (default "root")
Options:
-h, --help Show this help
-V, --version Show the version and exit
-i, --insecure Trust unknown TLS certificates
-v Add v's to increase verbosity (max 3)
-p, --pass Login with password or ticket (env $PVE_PASSWORD)
-r, --refresh Minimum ticket lifetime to trigger automatic refresh, 0 to disable (default 0)
-t, --token Login with API token (env $PVE_API_TOKEN)
Commands:
GET, g, get, list issue method GET
POST, p, post, create issue method POST
PUT, u, put, set issue method PUT
DELETE, d, del, delete issue method DELETE
Run 'pve-api-go COMMAND --help' for more information on a command.
It was really this application which lead me to opening the issue originally. So here, I have global arguments that are used for all subcommands. But it doesn't make sense to pass a hostname when you want to follow the recommendation in the last line of the help and attempt to check the contextual help for a subcommand (for example pve-api-go POST --help
).
Ok, I see what you mean. This seems related to #67, in that the bottom line of the help message doesn't reflect the invocation that's expected. The message can be fixed for accuracy and I've made an attempt, but that doesn't address the inconvenience of having to put in an arg just to get help for a subcommand.
I think the parsing process would have to change somewhat to support invoking help the way you want.
Yes, I see how the two issues are related. I understand also that a good start may be adjusting the message, and for a root solution I see two options:
- Somehow implement a "help mode", with a different AST (I am guessing the parser renders an AST that is then evaluated?, please correct me if I'm wrong)
- A generalization of 1. - implement different modes of invocation, each with its own syntax. This would solve not only help modes, but would also add that as a feature. As cool as this one looks, it might be overkill.. OR on the other hand, not a long shot from 1. What's more, if this style of solution leaves to the users the task of writing the syntax spec, it might be even easier than 1. as you would need to write manually the spec for contextual helps, instead of having to generate it automatically.
Anyway, I haven't really looked at the code, and I haven't written parsers yet (but I have written evaluators for DSLs). I hope to be able to help and send a test patch if I succeed. In the meantime, I'll just use it as it is.