Support parsing value from ENV variable

This commit is contained in:
Tomas Barton 2020-02-17 16:56:04 +01:00
parent b0f67a06de
commit 5c9d507930
No known key found for this signature in database
GPG Key ID: B5F3CC8C2893A125
3 changed files with 84 additions and 0 deletions

View File

@ -153,6 +153,14 @@ completely replaced by calling `options.custom_help`. Note that you might
also want to override the positional help by calling `options.positional_help`.
## Value from ENV variable
When parameter is not set, value will be fetched from an environment variable (if such variable is defined).
```cpp
cxxopts::value<int>()->env("MY_VAR")
```
## Example
Putting all together:

View File

@ -314,6 +314,15 @@ namespace cxxopts
virtual std::shared_ptr<Value>
implicit_value(const std::string& value) = 0;
virtual std::shared_ptr<Value>
env(const std::string& var) = 0;
virtual bool
has_env() const = 0;
virtual std::string
get_env_var() const = 0;
virtual std::shared_ptr<Value>
no_implicit_value() = 0;
@ -888,6 +897,26 @@ namespace cxxopts
return m_implicit_value;
}
std::shared_ptr<Value>
env(const std::string& var)
{
m_env = true;
m_env_var = var;
return shared_from_this();
}
bool
has_env() const
{
return m_env;
}
std::string
get_env_var() const
{
return m_env_var;
}
bool
is_boolean() const
{
@ -913,9 +942,11 @@ namespace cxxopts
bool m_default = false;
bool m_implicit = false;
bool m_env = false;
std::string m_default_value;
std::string m_implicit_value;
std::string m_env_var;
};
template <typename T>
@ -1961,6 +1992,15 @@ ParseResult::parse(int& argc, char**& argv)
if(value.has_default() && !store.count() && !store.has_default()){
parse_default(detail);
}
if(value.has_env() && store.count() < 1){
const char* env = std::getenv(value.get_env_var().c_str());
if(env){
std::string str(env);
store.parse(detail, str);
}
}
}
if (consume_remaining)

View File

@ -774,3 +774,39 @@ TEST_CASE("Option add with add_option(string, Option)", "[options]") {
CHECK(result["aggregate"].as<int>() == 4);
CHECK(result["test"].as<int>() == 5);
}
TEST_CASE("Value from ENV variable", "[options]") {
cxxopts::Options options("Reads value from ENV", " - if no parameter value is passed");
options.add_options("", {
{"b,bar", "bar option", cxxopts::value<int>()->env("CXXOPTS_BAR")},
{"f,foo", "foo option", cxxopts::value<int>()->env("CXXOPTS_FOO")},
{"z,baz", "baz option", cxxopts::value<int>()->env("CXXOPTS_BAZ")->default_value("99")},
{"e,empty", "empty option", cxxopts::value<int>()->env("CXXOPTS_EMPTY")->default_value("1")},
});
putenv((char*)"CXXOPTS_FOO=7");
putenv((char*)"CXXOPTS_BAR=8");
putenv((char*)"CXXOPTS_BAZ=9");
Argv argv_({
"test",
"--foo",
"5"
});
auto argc = argv_.argc();
char** argv = argv_.argv();
auto result = options.parse(argc, argv);
CHECK(result.arguments().size()==1);
CHECK(options.groups().size() == 1);
CHECK(result.count("foo") == 1);
// value passed as an argument should take precedence
CHECK(result["foo"].as<int>() == 5);
// from ENV variable
CHECK(result["bar"].as<int>() == 8);
// from ENV variable
CHECK(result["baz"].as<int>() == 9);
// env not defined, should fallback to default value
CHECK(result["empty"].as<int>() == 1);
}