mirror of
https://github.com/CLIUtils/CLI11.git
synced 2025-04-29 12:13:52 +00:00
Adding example with json config
This commit is contained in:
parent
70587c3a55
commit
2ae5598d95
@ -1,11 +1,14 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
echo -en "travis_fold:start:script.build\\r"
|
echo -en "travis_fold:start:script.build\\r"
|
||||||
echo "Building..."
|
echo "Building..."
|
||||||
|
STD=$1
|
||||||
|
shift
|
||||||
set -evx
|
set -evx
|
||||||
|
|
||||||
|
|
||||||
mkdir -p build
|
mkdir -p build
|
||||||
cd build
|
cd build
|
||||||
cmake .. -DCLI11_CXX_STD=$1 -DCLI11_SINGLE_FILE_TESTS=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
|
cmake .. -DCLI11_CXX_STD=$STD -DCLI11_SINGLE_FILE_TESTS=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER_LAUNCHER=ccache $@
|
||||||
cmake --build . -- -j2
|
cmake --build . -- -j2
|
||||||
|
|
||||||
set +evx
|
set +evx
|
||||||
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -4,3 +4,6 @@
|
|||||||
[submodule "extern/sanitizers"]
|
[submodule "extern/sanitizers"]
|
||||||
path = extern/sanitizers
|
path = extern/sanitizers
|
||||||
url = ../../arsenm/sanitizers-cmake
|
url = ../../arsenm/sanitizers-cmake
|
||||||
|
[submodule "extern/json"]
|
||||||
|
path = extern/json
|
||||||
|
url = ../../nlohmann/json.git
|
||||||
|
@ -76,9 +76,9 @@ matrix:
|
|||||||
- ". .ci/build_lcov.sh"
|
- ". .ci/build_lcov.sh"
|
||||||
- ".ci/run_codecov.sh"
|
- ".ci/run_codecov.sh"
|
||||||
script:
|
script:
|
||||||
- .ci/make_and_test.sh 11
|
- .ci/make_and_test.sh 11 -DCLI11_EXAMPLE_JSON=ON
|
||||||
- .ci/make_and_test.sh 14
|
- .ci/make_and_test.sh 14 -DCLI11_EXAMPLE_JSON=ON
|
||||||
- .ci/make_and_test.sh 17
|
- .ci/make_and_test.sh 17 -DCLI11_EXAMPLE_JSON=ON
|
||||||
|
|
||||||
# GCC 4.7 and Conan
|
# GCC 4.7 and Conan
|
||||||
- compiler: gcc
|
- compiler: gcc
|
||||||
|
@ -14,6 +14,30 @@ function(add_cli_exe T)
|
|||||||
endif()
|
endif()
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
|
option(CLI11_EXAMPLE_JSON OFF)
|
||||||
|
if(CLI11_EXAMPLE_JSON)
|
||||||
|
if(CMAKE_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9)
|
||||||
|
message(WARNING "The json example requires GCC 4.9+ (requirement on json library)")
|
||||||
|
endif()
|
||||||
|
add_cli_exe(json json.cpp)
|
||||||
|
target_include_directories(json PUBLIC SYSTEM ../extern/json/single_include)
|
||||||
|
|
||||||
|
add_test(NAME json_config_out COMMAND json --item 2)
|
||||||
|
set_property(TEST json_config_out PROPERTY PASS_REGULAR_EXPRESSION
|
||||||
|
"{"
|
||||||
|
"\"item\": \"2\""
|
||||||
|
"\"simple\": false"
|
||||||
|
"}")
|
||||||
|
|
||||||
|
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/input.json" [=[{"item":3,"simple":false}]=])
|
||||||
|
add_test(NAME json_config_in COMMAND json --config "${CMAKE_CURRENT_BINARY_DIR}/input.json")
|
||||||
|
set_property(TEST json_config_in PROPERTY PASS_REGULAR_EXPRESSION
|
||||||
|
"{"
|
||||||
|
"\"item\": \"3\""
|
||||||
|
"\"simple\": false"
|
||||||
|
"}")
|
||||||
|
endif()
|
||||||
|
|
||||||
add_cli_exe(simple simple.cpp)
|
add_cli_exe(simple simple.cpp)
|
||||||
add_test(NAME simple_basic COMMAND simple)
|
add_test(NAME simple_basic COMMAND simple)
|
||||||
add_test(NAME simple_all COMMAND simple -f filename.txt -c 12 --flag --flag -d 1.2)
|
add_test(NAME simple_all COMMAND simple -f filename.txt -c 12 --flag --flag -d 1.2)
|
||||||
|
113
examples/json.cpp
Normal file
113
examples/json.cpp
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
#include <CLI/CLI.hpp>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
// This example is only built on GCC 7 on Travis due to mismatch in stdlib
|
||||||
|
// for clang (CLI11 is forgiving about mismatches, json.hpp is not)
|
||||||
|
|
||||||
|
using nlohmann::json;
|
||||||
|
|
||||||
|
class ConfigJSON : public CLI::Config {
|
||||||
|
public:
|
||||||
|
std::string to_config(const CLI::App *app, bool default_also, bool, std::string) const override {
|
||||||
|
|
||||||
|
json j;
|
||||||
|
|
||||||
|
for(const CLI::Option *opt : app->get_options({})) {
|
||||||
|
|
||||||
|
// Only process option with a long-name and configurable
|
||||||
|
if(!opt->get_lnames().empty() && opt->get_configurable()) {
|
||||||
|
std::string name = opt->get_lnames()[0];
|
||||||
|
|
||||||
|
// Non-flags
|
||||||
|
if(opt->get_type_size() != 0) {
|
||||||
|
|
||||||
|
// If the option was found on command line
|
||||||
|
if(opt->count() == 1)
|
||||||
|
j[name] = opt->results().at(0);
|
||||||
|
else if(opt->count() > 1)
|
||||||
|
j[name] = opt->results();
|
||||||
|
|
||||||
|
// If the option has a default and is requested by optional argument
|
||||||
|
else if(default_also && !opt->get_defaultval().empty())
|
||||||
|
j[name] = opt->get_defaultval();
|
||||||
|
|
||||||
|
// Flag, one passed
|
||||||
|
} else if(opt->count() == 1) {
|
||||||
|
j[name] = true;
|
||||||
|
|
||||||
|
// Flag, multiple passed
|
||||||
|
} else if(opt->count() > 1) {
|
||||||
|
j[name] = opt->count();
|
||||||
|
|
||||||
|
// Flag, not present
|
||||||
|
} else if(opt->count() == 0 && default_also) {
|
||||||
|
j[name] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(const CLI::App *subcom : app->get_subcommands({}))
|
||||||
|
j[subcom->get_name()] = json(to_config(subcom, default_also, false, ""));
|
||||||
|
|
||||||
|
return j.dump(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<CLI::ConfigItem> from_config(std::istream &input) const override {
|
||||||
|
json j;
|
||||||
|
input >> j;
|
||||||
|
return _from_config(j);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<CLI::ConfigItem>
|
||||||
|
_from_config(json j, std::string name = "", std::vector<std::string> prefix = {}) const {
|
||||||
|
std::vector<CLI::ConfigItem> results;
|
||||||
|
|
||||||
|
if(j.is_object()) {
|
||||||
|
for(json::iterator item = j.begin(); item != j.end(); ++item) {
|
||||||
|
auto copy_prefix = prefix;
|
||||||
|
if(!name.empty())
|
||||||
|
copy_prefix.push_back(name);
|
||||||
|
auto sub_results = _from_config(*item, item.key(), copy_prefix);
|
||||||
|
results.insert(results.end(), sub_results.begin(), sub_results.end());
|
||||||
|
}
|
||||||
|
} else if(!name.empty()) {
|
||||||
|
results.emplace_back();
|
||||||
|
CLI::ConfigItem &res = results.back();
|
||||||
|
res.name = name;
|
||||||
|
res.parents = prefix;
|
||||||
|
if(j.is_boolean()) {
|
||||||
|
res.inputs = {j.get<bool>() ? "true" : "false"};
|
||||||
|
} else if(j.is_number()) {
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << j.get<double>();
|
||||||
|
res.inputs = {ss.str()};
|
||||||
|
} else if(j.is_string()) {
|
||||||
|
res.inputs = {j.get<std::string>()};
|
||||||
|
} else if(j.is_array()) {
|
||||||
|
for(std::string ival : j)
|
||||||
|
res.inputs.push_back(ival);
|
||||||
|
} else {
|
||||||
|
throw CLI::ConversionError("Failed to convert " + name);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw CLI::ConversionError("You must make all top level values objects in json!");
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
CLI::App app;
|
||||||
|
app.config_formatter(std::make_shared<ConfigJSON>());
|
||||||
|
|
||||||
|
int item;
|
||||||
|
|
||||||
|
app.add_flag("--simple");
|
||||||
|
app.add_option("--item", item);
|
||||||
|
app.set_config("--config");
|
||||||
|
|
||||||
|
CLI11_PARSE(app, argc, argv);
|
||||||
|
|
||||||
|
std::cout << app.config_to_str(true, true) << std::endl;
|
||||||
|
}
|
1
extern/json
vendored
Submodule
1
extern/json
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit d2dd27dc3b8472dbaa7d66f83619b3ebcd9185fe
|
Loading…
x
Reference in New Issue
Block a user