Closed halloleo closed 3 years ago
There isn't a way to specify this exactly, but you can get a close approximation like this (side note: if you put Nim after the triple backtick github will highlight the code for you):
import cligen
proc main(file: seq[string]): int =
## What this program does
if file.len != 1:
raise newException(ValueError, "Need exactly one file")
dispatch(main, usage="$command {file}\n${doc}Options:\n$options")
The sense in which it is an approximation is that the generated help message will say [file: string...]
seeming to imply that 0..n files are possible only to be blocked by the run-time unless you ammend it to just {file}
as I show above. Sometimes people say <file>
.
Of course if you add other options you'll want to add some help={ "newParam1": "what newParam1 does" }
after that usage=
.
Thanks a lot. :-) So there's no built-in way. But the workaround is cool.
I guess, I need this workaround for "At least 1 argument" as well. Then I have to write:
if file.len < 1:
raise...
Correct?
One problem though occurs: dispatch
does not seem to wrap the raised newException
. The user gets a stack trace:
/home/halloleo/nim/mytool.nim(32) mytool
/home/halloleo/.nimble/pkgs/cligen-1.2.0/cligen.nim(741) cligenDoNotCollideWithGlobalVar
/home/halloleo/.nimble/pkgs/cligen-1.2.0/cligen.nim(659) dispatchmain
/home/halloleo/nim/mytool.nim(21) main
Error: unhandled exception: Need at least one file [ValueError]
Can I raise another exception, so that cligen
handles it?
No problem. And yes, you are correct about >= 1 argument.
And to suppress the stack trace you can raise ParseError
instead, but you have to write your own error message. Like
stderr.write "Need exactly one file; Run with --help for more info\n"
raise newException(ParseError, "")
Oh, and end CL-users are able to override your usage
template in a $HOME/.config/cligen
file to say whatever they want by default. This is to allow almost any formatting of help that such end users want, but really they could make the help say anything.
The contact of that ability with this use case of yours is that the generated $args
used in such templates will remain [file: string...]
because that is inferred from the seq[string]
type. The config file will just be for all cligen
programs and so should use $args
.
Now, [file: string...]
is not so misleading, of course, but if it is truly hated then the best long-term idea might be to add a new named parameter argsHelp="{file}"
to dispatch
to override the inferred $args
. That's already how $command
and $doc
work. It is also already possible today (by defining you own config file parser) to disable the ability to override that one [templates]/usage
field, but that is pretty awkward.
Also, I would be remiss if I didn't point out that with only string command arguments and no options that you could also just use os.paramCount
and os.paramStr
and not use cligen
at all. It's only barely doing any real work for you in these cases.
Oh, and I should maybe have mentioned that cligen
translates that ParseError
exception into an exit status of 1. Any non-zero is meant to indicate failure. So, on a Unix shell you could check the shell $?
variable or say if myprogram; then echo worked; else echo failed; fi
.
Very detailed! Thanks a lot! Will try it all out tomorrow.
By the way, I assume from the title of the issue that you know that just saying proc main(file: string)
(with no default value) leads to the "option syntax" variation of this.
I mention this in case I was misled by such from-Title-reasoning. foo -fpath
isn't so hard to type, but I get why you might not want to.
Before this commit I had a different mapping more to your particular use case where things like string -> integer/float/enum/etc. conversion would still have been automatic. The 2nd item in the current TODO.md
refers to maybe getting back some of that, but hopefully you are good for now.
Thanks for
cligen
! It looks very promising to me. (In Python I have used argh for quite a while very happily.)But I have some problems: I try to define a program which accepts one required argument and this argument should not be an option-dash parameter. So I want a CLI program (let's call it
tool
) which I can call exactly like this:I tried the Nim code
but this gives me a tool I have to call with
tool --file=myfile.txt
.Then I tried
but this tool I can call without any argument which I don't want. It should error out, beacuse
file
should be required.How can I define the signature of
main
for this?