phobos
phobos copied to clipboard
Add std.getopt.config.helpLike to std.getopt module
The new directive std.getopt.config.helpLike allows to use command-line arguments like additional 'help' arguments. The argument following this new directive is treated like '-h' or '--help'.
A common use-case is an option to just output the (git-)version of a programm and then return with no error.
In the current implementation of getOpt() it is needed to check the args array passed to main() to contain your special option '--version'.
With this patch the option can be added to your getOpt() call. This increases readability of code and removed special case-handling of arguments before calling getOpt().
Thanks for your pull request and interest in making D better, @cschlote! We are looking forward to reviewing it, and you should be hearing from a maintainer soon. Please verify that your PR follows this checklist:
- My PR is fully covered with tests (you can see the coverage diff by visiting the details link of the codecov check)
- My PR is as minimal as possible (smaller, focused PRs are easier to review than big ones)
- I have provided a detailed rationale explaining my changes
- New or modified functions have Ddoc comments (with
Params:andReturns:)
Please see CONTRIBUTING.md for more information.
If you have addressed all reviews or aren't sure how to proceed, don't hesitate to ping us with a simple comment.
Bugzilla references
Your PR doesn't reference any Bugzilla issue.
If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog.
Testing this PR locally
If you don't have a local development environment setup, you can use Digger to test this PR:
dub run digger -- build "master + phobos#8566"
Is it really a problem to check for the --version option after parsing instead? E.g.,
void main(string[] args)
{
import std.getopt;
bool showVersion;
// ...
auto result = args.getopt(
"version", &showVersion,
// ...
);
if (showVersion) {
printVersion();
return;
}
if (result.helpWanted) {
printHelp();
return;
}
}
As far as I can tell, most commonly-used command-line programs do not preemptively check for --version in the way proposed by this PR. Some examples:
$ cat --asdf --version
cat: unrecognized option '--asdf'
Try 'cat --help' for more information.
$ git --asdf --version
unknown option: --asdf
usage: git [--version] [--help] [-C <path>] [-c <name>=<value>]
[--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
[-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare]
[--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
<command> [<args>]
Is it really a problem to check for the
--versionoption after parsing instead? E.g.,void main(string[] args) { import std.getopt; bool showVersion; // ... auto result = args.getopt( "version", &showVersion, // ... ); if (showVersion) { printVersion(); return; } if (result.helpWanted) { printHelp(); return; } }As far as I can tell, most commonly-used command-line programs do not preemptively check for
--versionin the way proposed by this PR. Some examples:$ cat --asdf --version cat: unrecognized option '--asdf' Try 'cat --help' for more information. $ git --asdf --version unknown option: --asdf usage: git [--version] [--help] [-C <path>] [-c <name>=<value>] [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path] [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare] [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>] <command> [<args>]
The intended action of '--version' is to output just the version info the tool and exit without any error.
But if you set some other commandline option to be 'required', you can NOT specify a single '--version' anymore. You will get an exception if the required argument is not specified.
This is ttrue for mostly all our D scripts - we want to output the --version in our CI pipelines to trackdown problems with outdated scripts. But in normal operation without --version, we usually have one or two required arguments to enforce proper usage of the script.
The proposed patch removes the need for any special hacks outside of getopt(). Just denote a commandline argument to be 'helplike' circumvents the required checks and return without exception. Then it is possible to check if the 'helplike' argument is set and we can either output the version OR the help text and exit.
This improves readability and removed special extra tests from the main() function. So I see a clear use-case for this option. You can also easily find outer usecases like '--morehelp' to output extra long help texts without out being forced to set '--help' all the time. Or e.g. '--help-backend', '--help-whatever' style options, which output different kind of helptexts. This can be easily implemented as some kind of CL arg with 'helpLike' properity set.
Example:
...
auto helpInformation = getopt(args,
std.getopt.config.required,
"mode|m", "Operation Mode.", &argOpMode,
...
"version", "Print version tag", &argPrintVersion);
...
If you try to pass just --version to the programm, then it will abort with an exception. You can workaround this by also passing --help. But we just want to pass --version on the commandline. And we do not want special extra code to check, if --version is on the commandline before we call getopt().
So this patch adds:
...
auto helpInformation = getopt(args,
std.getopt.config.required,
"mode|m", "Operation Mode.", &argOpMode,
...
std.getopt.config.helpLike,
"version", "Print version tag", &argPrintVersion);
...
Now you can just pass --version. No need to have special checks before we call getopt(). There is also no need to pass --help in addition as a workaround. The commandline argument is now defined together will all other arguments in the call to getopt() and if --version is found, it is handled and the helpWanted flag is set as well. The exception is delayed and only thrown, if no helpWanted flag is set at the end of the commandline processing.
I hope, this will clarify the intention of this pull-request.
By the way, I'm a bit skeptical about the need for this because I'm skeptical about required options in the first place (I can't think of a single command line program with required - arguments), but I'll leave that judgement to @atilaneves .
I use the requiredflag a lot in my D scripts at work. The call to getopt() is wrapped into a try{}section and the exception message is printed without a stack trace. This avoids any additional checks in the main() function, and users of the scripts see a sufficient error messages, when required options are missing.
Sure, these checks could be done in main(). But there IS a requiredoption, so we are going to use it. However, there is the need to circumvent the required flag, when arguments like --version are given on the CL to just output the version or similiar. The --help is still available to print out useful help and examples.
This patch adds this feature. Maybe the option can be split into an circumventRequired and helpOption option, which could be combined, when needed.
Reworked changelog and example.
I don't understand the use case for this, and second the doubts already "voiced" in this PR.