# HG changeset patch # User František Kučera # Date 1656783918 -7200 # Node ID ca216de56ef0198b6b01a015add585d38cc6b446 # Parent e1339b8e838ea2a8788d74ef1d4f8e39c25973aa allow setting some options through ENV variables (not only CLI arguments) diff -r e1339b8e838e -r ca216de56ef0 src/CLIParser.h --- a/src/CLIParser.h Sat Jul 02 15:21:59 2022 +0200 +++ b/src/CLIParser.h Sat Jul 02 19:45:18 2022 +0200 @@ -32,6 +32,8 @@ class CLIParser { private: + std::wstring_convert> convertor; // TODO: support also other encodings. + relpipe::reader::string_t readNext(const std::vector& arguments, int& i) { if (i < arguments.size()) return arguments[i++]; else throw relpipe::cli::RelpipeCLIException(L"Missing CLI argument" + (i > 0 ? (L" after " + arguments[i - 1]) : L""), relpipe::cli::CLI::EXIT_CODE_BAD_CLI_ARGUMENTS); @@ -57,7 +59,7 @@ else if (value == L"false") return false; else throw relpipe::cli::RelpipeCLIException(L"Unable to parse boolean value: " + value + L" (expecting true or false)", relpipe::cli::CLI::EXIT_CODE_BAD_CLI_ARGUMENTS); } - + Configuration::ColorScheme parseColorScheme(const relpipe::reader::string_t& value) { if (value == L"greenish") return Configuration::ColorScheme::Greenish; else if (value == L"amberish") return Configuration::ColorScheme::Amberish; @@ -65,7 +67,7 @@ else if (value == L"midnight") return Configuration::ColorScheme::Midnight; else throw relpipe::cli::RelpipeCLIException(L"Unable to parse ColorScheme value: " + value + L" (expecting greenish, amberish, midnight or black-and-white)", relpipe::cli::CLI::EXIT_CODE_BAD_CLI_ARGUMENTS); } - + Configuration::TableStyle parseTableStyle(const relpipe::reader::string_t& value) { if (value == L"rounded") return Configuration::TableStyle::Rounded; else if (value == L"sharp") return Configuration::TableStyle::Sharp; @@ -75,6 +77,54 @@ else throw relpipe::cli::RelpipeCLIException(L"Unable to parse TableStyle value: " + value + L" (expecting rounded, sharp, ascii)", relpipe::cli::CLI::EXIT_CODE_BAD_CLI_ARGUMENTS); } + /** + * TODO: move to common parent class in relpipe-lib-cli + * + * @param cliArguments original CLI arguments + * @param moduleName name of this program e.g. "relpipe-out-tabular" + * @param supportedOptions options that could be specified also as environmental variables, not only CLI arguments, including the "--" prefix e.g. "--color-scheme" + * @return defaults found in ENV + given CLI arguments + */ + const std::vector addEnvDefaults(const std::vector& cliArguments, const relpipe::reader::string_t moduleName, const std::vector& supportedOptions) { + std::vector allArguments; + + auto toEnv = [](char ch) { + return ch == '-' ? '_' : ::toupper(ch); + }; + + std::string envPrefix = convertor.to_bytes(moduleName); + transform(envPrefix.begin(), envPrefix.end(), envPrefix.begin(), toEnv); + envPrefix.append("_"); + + for (auto o : supportedOptions) { + if (o.substr(0, 2) == L"--") { + std::string option = convertor.to_bytes(o); + option.erase(0, 2); + transform(option.begin(), option.end(), option.begin(), toEnv); + + // FIXME: check argument counts (should be specified alongside with supportedOptions) to avoid injection of unwanted options through ENV variables + // TODO: allow repeated options? + for (int i = -1; i < 10; i++) { + std::string envName = i == -1 ? envPrefix + option : envPrefix + option + "_" + std::to_string(i); + const char* value = std::getenv(envName.c_str()); + if (value) { + if (i == -1 || i == 0) allArguments.push_back(o); + allArguments.push_back(convertor.from_bytes(value)); + if (i == -1) break; + } else { + if (i > -1) break; + } + } + } else { + throw std::logic_error("supportedOptions must start with '--'"); + } + } + + for (auto a : cliArguments) allArguments.push_back(a); + + return allArguments; + } + public: static const relpipe::reader::string_t OPTION_RELATION; @@ -84,10 +134,12 @@ static const relpipe::reader::string_t OPTION_COLOR_SCHEME; static const relpipe::reader::string_t OPTION_TABLE_STYLE; - Configuration parse(const std::vector& arguments) { + Configuration parse(const std::vector& cliArguments) { Configuration c; RelationConfiguration currentRelation; - + + const std::vector arguments = addEnvDefaults(cliArguments, L"relpipe-out-tabular",{OPTION_COLOR_SCHEME, OPTION_TABLE_STYLE}); + // TODO: global configuration of writeTypes, writeRelationName, writeRecordCount for (int i = 0; i < arguments.size();) {