Unverified Commit 13095ce9 authored by Joseph Noir's avatar Joseph Noir Committed by GitHub

Merge pull request #817

Fix handling of CLI/INI options and fail early on misconfiguration
parents e9946674 0410a0e7
...@@ -33,13 +33,13 @@ void hello_world(event_based_actor* self, const actor& buddy) { ...@@ -33,13 +33,13 @@ void hello_world(event_based_actor* self, const actor& buddy) {
); );
} }
int main() { void caf_main(actor_system& system) {
// our CAF environment
actor_system_config cfg;
actor_system system{cfg};
// create a new actor that calls 'mirror()' // create a new actor that calls 'mirror()'
auto mirror_actor = system.spawn(mirror); auto mirror_actor = system.spawn(mirror);
// create another actor that calls 'hello_world(mirror_actor)'; // create another actor that calls 'hello_world(mirror_actor)';
system.spawn(hello_world, mirror_actor); system.spawn(hello_world, mirror_actor);
// system will wait until both actors are destroyed before leaving main // system will wait until both actors are destroyed before leaving main
} }
// creates a main function for us that calls our caf_main
CAF_MAIN()
...@@ -316,6 +316,16 @@ public: ...@@ -316,6 +316,16 @@ public:
int (*slave_mode_fun)(actor_system&, const actor_system_config&); int (*slave_mode_fun)(actor_system&, const actor_system_config&);
// -- default error rendering functions --------------------------------------
static std::string render(const error& err);
static std::string render_sec(uint8_t, atom_value, const message&);
static std::string render_exit_reason(uint8_t, atom_value, const message&);
static std::string render_pec(uint8_t, atom_value, const message&);
protected: protected:
virtual std::string make_help_text(const std::vector<message::cli_arg>&); virtual std::string make_help_text(const std::vector<message::cli_arg>&);
...@@ -332,12 +342,6 @@ private: ...@@ -332,12 +342,6 @@ private:
actor_system_config& set_impl(string_view name, config_value value); actor_system_config& set_impl(string_view name, config_value value);
static std::string render_sec(uint8_t, atom_value, const message&);
static std::string render_exit_reason(uint8_t, atom_value, const message&);
static std::string render_pec(uint8_t, atom_value, const message&);
void extract_config_file_path(string_list& args); void extract_config_file_path(string_list& args);
/// Adjusts the content of the configuration, e.g., for ensuring backwards /// Adjusts the content of the configuration, e.g., for ensuring backwards
......
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#include "caf/actor_system.hpp" #include "caf/actor_system.hpp"
#include "caf/actor_system_config.hpp" #include "caf/actor_system_config.hpp"
#include "caf/detail/type_list.hpp" #include "caf/detail/type_list.hpp"
#include "caf/detail/type_traits.hpp" #include "caf/detail/type_traits.hpp"
...@@ -70,27 +69,31 @@ int exec_main(F fun, int argc, char** argv, ...@@ -70,27 +69,31 @@ int exec_main(F fun, int argc, char** argv,
"second parameter of main function must take a subtype of " "second parameter of main function must take a subtype of "
"actor_system_config as const reference"); "actor_system_config as const reference");
using helper = exec_main_helper<typename trait::arg_types>; using helper = exec_main_helper<typename trait::arg_types>;
// pass CLI options to config // Pass CLI options to config.
typename helper::config cfg; typename helper::config cfg;
cfg.parse(argc, argv, config_file_name); if (auto err = cfg.parse(argc, argv, config_file_name)) {
// return immediately if a help text was printed std::cerr << "error while parsing CLI and file options: "
<< actor_system_config::render(err) << std::endl;
return EXIT_FAILURE;
}
// Return immediately if a help text was printed.
if (cfg.cli_helptext_printed) if (cfg.cli_helptext_printed)
return 0; return EXIT_SUCCESS;
// load modules // Load modules.
std::initializer_list<unit_t> unused{unit_t{cfg.template load<Ts>()}...}; std::initializer_list<unit_t> unused{unit_t{cfg.template load<Ts>()}...};
CAF_IGNORE_UNUSED(unused); CAF_IGNORE_UNUSED(unused);
// pass config to the actor system // Initialize the actor system.
actor_system system{cfg}; actor_system system{cfg};
if (cfg.slave_mode) { if (cfg.slave_mode) {
if (!cfg.slave_mode_fun) { if (!cfg.slave_mode_fun) {
std::cerr << "cannot run slave mode, I/O module not loaded" << std::endl; std::cerr << "cannot run slave mode, I/O module not loaded" << std::endl;
return 1; return EXIT_FAILURE;
} }
return cfg.slave_mode_fun(system, cfg); return cfg.slave_mode_fun(system, cfg);
} }
helper f; helper f;
f(fun, system, cfg); f(fun, system, cfg);
return 0; return EXIT_SUCCESS;
} }
} // namespace caf } // namespace caf
...@@ -99,4 +102,3 @@ int exec_main(F fun, int argc, char** argv, ...@@ -99,4 +102,3 @@ int exec_main(F fun, int argc, char** argv,
int main(int argc, char** argv) { \ int main(int argc, char** argv) { \
return ::caf::exec_main<__VA_ARGS__>(caf_main, argc, argv); \ return ::caf::exec_main<__VA_ARGS__>(caf_main, argc, argv); \
} }
...@@ -256,16 +256,16 @@ error actor_system_config::parse(string_list args, std::istream& ini) { ...@@ -256,16 +256,16 @@ error actor_system_config::parse(string_list args, std::istream& ini) {
remainder.insert(remainder.end(), make_move_iterator(first), remainder.insert(remainder.end(), make_move_iterator(first),
make_move_iterator(args.end())); make_move_iterator(args.end()));
} else { } else {
cli_helptext_printed = get_or(content, "global.help", false) cli_helptext_printed = get_or(content, "help", false)
|| get_or(content, "global.long-help", false); || get_or(content, "long-help", false);
} }
// Generate help text if needed. // Generate help text if needed.
if (cli_helptext_printed) { if (cli_helptext_printed) {
bool long_help = get_or(content, "global.long-help", false); bool long_help = get_or(content, "long-help", false);
std::cout << custom_options_.help_text(!long_help) << std::endl; std::cout << custom_options_.help_text(!long_help) << std::endl;
} }
// Generate INI dump if needed. // Generate INI dump if needed.
if (!cli_helptext_printed && get_or(content, "global.dump-config", false)) { if (!cli_helptext_printed && get_or(content, "dump-config", false)) {
for (auto& category : content) { for (auto& category : content) {
if (auto dict = get_if<config_value::dictionary>(&category.second)) { if (auto dict = get_if<config_value::dictionary>(&category.second)) {
std::cout << '[' << category.first << "]\n"; std::cout << '[' << category.first << "]\n";
...@@ -325,6 +325,18 @@ timespan actor_system_config::stream_tick_duration() const noexcept { ...@@ -325,6 +325,18 @@ timespan actor_system_config::stream_tick_duration() const noexcept {
stream_max_batch_delay.count()); stream_max_batch_delay.count());
return timespan{ns_count}; return timespan{ns_count};
} }
std::string actor_system_config::render(const error& err) {
std::string msg;
switch (static_cast<uint64_t>(err.category())) {
case atom_uint("system"):
return render_sec(err.code(), err.category(), err.context());
case atom_uint("exit"):
return render_exit_reason(err.code(), err.category(), err.context());
case atom_uint("parser"):
return render_pec(err.code(), err.category(), err.context());
}
return "unknown-error";
}
std::string actor_system_config::render_sec(uint8_t x, atom_value, std::string actor_system_config::render_sec(uint8_t x, atom_value,
const message& xs) { const message& xs) {
...@@ -342,7 +354,7 @@ std::string actor_system_config::render_exit_reason(uint8_t x, atom_value, ...@@ -342,7 +354,7 @@ std::string actor_system_config::render_exit_reason(uint8_t x, atom_value,
std::string actor_system_config::render_pec(uint8_t x, atom_value, std::string actor_system_config::render_pec(uint8_t x, atom_value,
const message& xs) { const message& xs) {
auto tmp = static_cast<exit_reason>(x); auto tmp = static_cast<pec>(x);
return deep_to_string(meta::type_name("parser_error"), tmp, return deep_to_string(meta::type_name("parser_error"), tmp,
meta::omittable_if_empty(), xs); meta::omittable_if_empty(), xs);
} }
......
...@@ -62,7 +62,6 @@ CAF_TEST(lookup) { ...@@ -62,7 +62,6 @@ CAF_TEST(lookup) {
CAF_CHECK_EQUAL(opts.size(), 3u); CAF_CHECK_EQUAL(opts.size(), 3u);
CAF_MESSAGE("lookup by long name"); CAF_MESSAGE("lookup by long name");
CAF_CHECK_NOT_EQUAL(opts.cli_long_name_lookup("opt1"), nullptr); CAF_CHECK_NOT_EQUAL(opts.cli_long_name_lookup("opt1"), nullptr);
CAF_CHECK_NOT_EQUAL(opts.cli_long_name_lookup("global.opt1"), nullptr);
CAF_CHECK_NOT_EQUAL(opts.cli_long_name_lookup("test.opt2"), nullptr); CAF_CHECK_NOT_EQUAL(opts.cli_long_name_lookup("test.opt2"), nullptr);
CAF_CHECK_NOT_EQUAL(opts.cli_long_name_lookup("test.flag"), nullptr); CAF_CHECK_NOT_EQUAL(opts.cli_long_name_lookup("test.flag"), nullptr);
CAF_MESSAGE("lookup by short name"); CAF_MESSAGE("lookup by short name");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment