From 287b6fd8bd92d7caefb3172f93c888efa0f15b76 Mon Sep 17 00:00:00 2001 From: Calle Wilund Date: Mon, 6 Nov 2017 09:53:05 +0000 Subject: [PATCH 1/4] config_file: Add optional "error_handler" to yaml parse functions Allowing parse errors / unknown options to be ignored. --- utils/config_file.cc | 41 +++++++++++++++++++++++++++-------------- utils/config_file.hh | 23 +++++++++++++++++++---- 2 files changed, 46 insertions(+), 18 deletions(-) diff --git a/utils/config_file.cc b/utils/config_file.cc index 855b1b2fa1..e61533f39d 100644 --- a/utils/config_file.cc +++ b/utils/config_file.cc @@ -241,13 +241,18 @@ utils::config_file::add_options(bpo::options_description_easy_init& init) { return init; } -void utils::config_file::read_from_yaml(const sstring& yaml) { - read_from_yaml(yaml.c_str()); +void utils::config_file::read_from_yaml(const sstring& yaml, error_handler h) { + read_from_yaml(yaml.c_str(), std::move(h)); } -void utils::config_file::read_from_yaml(const char* yaml) { +void utils::config_file::read_from_yaml(const char* yaml, error_handler h) { std::unordered_map values; + if (!h) { + h = [](auto & opt, auto & msg, auto) { + throw std::invalid_argument(msg + " : " + opt); + }; + } /* * Note: this is not very "half-fault" tolerant. I.e. there could be * yaml syntax errors that origin handles and still sets the options @@ -261,7 +266,8 @@ void utils::config_file::read_from_yaml(const char* yaml) { auto i = std::find_if(_cfgs.begin(), _cfgs.end(), [&label](const config_src& cfg) { return cfg.name() == label; }); if (i == _cfgs.end()) { - throw std::invalid_argument("Unknown option " + label); + h(label, "Unknown option", stdx::nullopt); + continue; } config_src& cfg = *i; @@ -272,7 +278,8 @@ void utils::config_file::read_from_yaml(const char* yaml) { } switch (cfg.status()) { case value_status::Invalid: - throw std::invalid_argument("Option " + label + "is not applicable"); + h(label, "Option is not applicable", cfg.status()); + continue; case value_status::Unused: default: break; @@ -281,7 +288,13 @@ void utils::config_file::read_from_yaml(const char* yaml) { continue; } // Still, a syntax error is an error warning, not a fail - cfg.set_value(node.second); + try { + cfg.set_value(node.second); + } catch (std::exception& e) { + h(label, e.what(), cfg.status()); + } catch (...) { + h(label, "Could not convert value", cfg.status()); + } } } @@ -305,19 +318,19 @@ utils::config_file::configs utils::config_file::unset_values() const { return res; } -future<> utils::config_file::read_from_file(file f) { - return f.size().then([this, f](size_t s) { - return do_with(make_file_input_stream(f), [this, s](input_stream& in) { - return in.read_exactly(s).then([this](temporary_buffer buf) { - read_from_yaml(sstring(buf.begin(), buf.end())); +future<> utils::config_file::read_from_file(file f, error_handler h) { + return f.size().then([this, f, h](size_t s) { + return do_with(make_file_input_stream(f), [this, s, h](input_stream& in) { + return in.read_exactly(s).then([this, h](temporary_buffer buf) { + read_from_yaml(sstring(buf.begin(), buf.end()), h); }); }); }); } -future<> utils::config_file::read_from_file(const sstring& filename) { - return open_file_dma(filename, open_flags::ro).then([this](file f) { - return read_from_file(std::move(f)); +future<> utils::config_file::read_from_file(const sstring& filename, error_handler h) { + return open_file_dma(filename, open_flags::ro).then([this, h](file f) { + return read_from_file(std::move(f), h); }); } diff --git a/utils/config_file.hh b/utils/config_file.hh index ec4f82fc7e..15e7ce309a 100644 --- a/utils/config_file.hh +++ b/utils/config_file.hh @@ -143,10 +143,25 @@ public: boost::program_options::options_description_easy_init& add_options(boost::program_options::options_description_easy_init&); - void read_from_yaml(const sstring&); - void read_from_yaml(const char *); - future<> read_from_file(const sstring&); - future<> read_from_file(file); + /** + * Default behaviour for yaml parser is to throw on + * unknown stuff, invalid opts or conversion errors. + * + * Error handling function allows overriding this. + * + * error: