mirror of
https://github.com/CLIUtils/CLI11.git
synced 2025-04-29 20:23:55 +00:00
Adding requires, excludes, and getenv (untested)
This commit is contained in:
parent
00acc84b52
commit
f4bf6d7226
@ -103,8 +103,11 @@ Adding a configuration option is special. If it is present, it will be read alon
|
|||||||
|
|
||||||
The add commands return a pointer to an internally stored `Option`. If you set the final argument to true, the default value is captured and printed on the command line with the help flag. This option can be used direcly to check for the count (`->count()`) after parsing to avoid a string based lookup. Before parsing, you can set the following options:
|
The add commands return a pointer to an internally stored `Option`. If you set the final argument to true, the default value is captured and printed on the command line with the help flag. This option can be used direcly to check for the count (`->count()`) after parsing to avoid a string based lookup. Before parsing, you can set the following options:
|
||||||
|
|
||||||
* `->required()`: The program will quit if this option is not present
|
* `->required()`: The program will quit if this option is not present. This is `manditory` in Plumbum, but required options seems to be a more standard term.
|
||||||
* `->expected(N)`: Take `N` values instead of as many as possible, only for vector args
|
* `->expected(N)`: Take `N` values instead of as many as possible, only for vector args
|
||||||
|
* `->requires(opt)`: This option requires another option to also be present, opt is an `Option` pointer
|
||||||
|
* `->excludes(opt)`: This option cannot be given with `opt` present, opt is an `Option` pointer
|
||||||
|
* `->envname(name)`: Gets the value from the environment if present and not passed on the command line
|
||||||
* `->group(name)`: The help group to put the option in. No effect for positional options. Defaults to `"Options"`.
|
* `->group(name)`: The help group to put the option in. No effect for positional options. Defaults to `"Options"`.
|
||||||
* `->check(CLI::ExistingFile)`: Requires that the file exists if given
|
* `->check(CLI::ExistingFile)`: Requires that the file exists if given
|
||||||
* `->check(CLI::ExistingDirectory)`: Requires that the directory exists
|
* `->check(CLI::ExistingDirectory)`: Requires that the directory exists
|
||||||
|
@ -55,6 +55,7 @@ protected:
|
|||||||
std::string ini_file;
|
std::string ini_file;
|
||||||
bool ini_required {false};
|
bool ini_required {false};
|
||||||
Option* ini_setting {nullptr};
|
Option* ini_setting {nullptr};
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -379,12 +380,23 @@ public:
|
|||||||
opt->add_result(0, positionals.front());
|
opt->add_result(0, positionals.front());
|
||||||
positionals.pop_front();
|
positionals.pop_front();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (first_parse && opt->count() == 0 && opt->_envname != "") {
|
||||||
|
// Will not interact very well with ini files
|
||||||
|
char *ename = std::getenv(opt->_envname.c_str());
|
||||||
|
if(ename != nullptr) {
|
||||||
|
opt->get_new();
|
||||||
|
opt->add_result(0, std::string(ename));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (opt->count() > 0) {
|
if (opt->count() > 0) {
|
||||||
if(!opt->run_callback())
|
if(!opt->run_callback())
|
||||||
throw ConversionError(opt->get_name() + "=" + detail::join(opt->flatten_results()));
|
throw ConversionError(opt->get_name() + "=" + detail::join(opt->flatten_results()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process an INI file
|
||||||
if (first_parse && ini_setting != nullptr && ini_file != "") {
|
if (first_parse && ini_setting != nullptr && ini_file != "") {
|
||||||
try {
|
try {
|
||||||
std::vector<std::string> values = detail::parse_ini(ini_file);
|
std::vector<std::string> values = detail::parse_ini(ini_file);
|
||||||
@ -398,9 +410,19 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verify required options
|
||||||
for(const Option_p& opt : options) {
|
for(const Option_p& opt : options) {
|
||||||
|
// Required
|
||||||
if (opt->get_required() && opt->count() < opt->get_expected())
|
if (opt->get_required() && opt->count() < opt->get_expected())
|
||||||
throw RequiredError(opt->get_name());
|
throw RequiredError(opt->get_name());
|
||||||
|
// Requires
|
||||||
|
for (const Option* opt_req : opt->_requires)
|
||||||
|
if (opt_req->count() == 0)
|
||||||
|
throw RequiresError(opt->get_name(), opt_req->get_name());
|
||||||
|
// Excludes
|
||||||
|
for (const Option* opt_ex : opt->_excludes)
|
||||||
|
if (opt_ex->count() != 0)
|
||||||
|
throw ExcludesError(opt->get_name(), opt_ex->get_name());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(positionals.size()>0)
|
if(positionals.size()>0)
|
||||||
|
@ -75,6 +75,16 @@ struct RequiredError : public ParseError {
|
|||||||
RequiredError(std::string name) : ParseError("RequiredError", name, 5) {}
|
RequiredError(std::string name) : ParseError("RequiredError", name, 5) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Thrown when a requires option is missing
|
||||||
|
struct RequiresError : public ParseError {
|
||||||
|
RequiresError(std::string name, std::string subname) : ParseError("RequiresError", name + " requires " + subname, 13) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Thrown when a exludes option is present
|
||||||
|
struct ExcludesError : public ParseError {
|
||||||
|
ExcludesError(std::string name, std::string subname) : ParseError("ExcludesError", name + " excludes " + subname, 14) {}
|
||||||
|
};
|
||||||
|
|
||||||
/// Thrown when too many positionals are found
|
/// Thrown when too many positionals are found
|
||||||
struct PositionalError : public ParseError {
|
struct PositionalError : public ParseError {
|
||||||
PositionalError(std::string name) : ParseError("PositionalError", name, 6) {}
|
PositionalError(std::string name) : ParseError("PositionalError", name, 6) {}
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
#include "CLI/Error.hpp"
|
#include "CLI/Error.hpp"
|
||||||
#include "CLI/StringTools.hpp"
|
#include "CLI/StringTools.hpp"
|
||||||
@ -42,6 +43,10 @@ protected:
|
|||||||
bool allow_vector {false};
|
bool allow_vector {false};
|
||||||
std::vector<std::function<bool(std::string)>> _validators;
|
std::vector<std::function<bool(std::string)>> _validators;
|
||||||
|
|
||||||
|
std::set<Option*> _requires;
|
||||||
|
std::set<Option*> _excludes;
|
||||||
|
std::string _envname;
|
||||||
|
|
||||||
// Results
|
// Results
|
||||||
results_t results;
|
results_t results;
|
||||||
|
|
||||||
@ -69,6 +74,7 @@ public:
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// True if this is a required option
|
||||||
bool get_required() const {
|
bool get_required() const {
|
||||||
return _required;
|
return _required;
|
||||||
}
|
}
|
||||||
@ -115,11 +121,13 @@ public:
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Changes the group membership
|
||||||
Option* group(std::string name) {
|
Option* group(std::string name) {
|
||||||
_group = name;
|
_group = name;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the group of this option
|
||||||
const std::string& get_group() const {
|
const std::string& get_group() const {
|
||||||
return _group;
|
return _group;
|
||||||
}
|
}
|
||||||
@ -129,6 +137,42 @@ public:
|
|||||||
return description;
|
return description;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets required options
|
||||||
|
Option* requires(Option* opt) {
|
||||||
|
auto tup = _requires.insert(opt);
|
||||||
|
if(!tup.second)
|
||||||
|
throw OptionAlreadyAdded(get_name() + " requires " + opt->get_name());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Any number supported
|
||||||
|
template<typename... ARG>
|
||||||
|
Option* requires(Option* opt, Option* opt1, ARG... args) {
|
||||||
|
requires(opt);
|
||||||
|
return requires(opt1, args...);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets excluded options
|
||||||
|
Option* excludes(Option* opt) {
|
||||||
|
auto tup = _excludes.insert(opt);
|
||||||
|
if(!tup.second)
|
||||||
|
throw OptionAlreadyAdded(get_name() + " excludes " + opt->get_name());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Any number supported
|
||||||
|
template<typename... ARG>
|
||||||
|
Option* excludes(Option* opt, Option* opt1, ARG... args) {
|
||||||
|
excludes(opt);
|
||||||
|
return excludes(opt1, args...);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets environment variable to read if no option given
|
||||||
|
Option* envname(std::string name) {
|
||||||
|
_envname = name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/// The name and any extras needed for positionals
|
/// The name and any extras needed for positionals
|
||||||
std::string help_positional() const {
|
std::string help_positional() const {
|
||||||
std::string out = pname;
|
std::string out = pname;
|
||||||
@ -144,6 +188,8 @@ public:
|
|||||||
std::string get_pname() const {
|
std::string get_pname() const {
|
||||||
return pname;
|
return pname;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Process the callback
|
/// Process the callback
|
||||||
bool run_callback() const {
|
bool run_callback() const {
|
||||||
if(_validators.size()>0) {
|
if(_validators.size()>0) {
|
||||||
|
@ -537,4 +537,4 @@ TEST_F(SubcommandProgram, SpareSub) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO: Check help output and formatting
|
// TODO: add tests for requires, excludes, envname
|
||||||
|
Loading…
x
Reference in New Issue
Block a user