From fa78d4e78316ebf4cd5a366763005770203b2f97 Mon Sep 17 00:00:00 2001 From: Alex Kremer Date: Fri, 9 Dec 2022 21:21:19 +0000 Subject: [PATCH] Implement cli parsing using boost::po (#436) Fixes #367 --- src/config/Config.cpp | 1 - src/main/main.cpp | 92 +++++++++++++++++++++++++++++++++---------- 2 files changed, 71 insertions(+), 22 deletions(-) diff --git a/src/config/Config.cpp b/src/config/Config.cpp index 2facbd2d..4dd7a91e 100644 --- a/src/config/Config.cpp +++ b/src/config/Config.cpp @@ -165,7 +165,6 @@ ConfigReader::open(std::filesystem::path path) << path.string() << "': " << e.what(); } - LogService::warn() << "Using empty default configuration"; return Config{}; } diff --git a/src/main/main.cpp b/src/main/main.cpp index 3e368f83..c5d1d3e5 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -16,7 +16,9 @@ #include #include #include +#include #include +#include #include #include @@ -31,9 +33,65 @@ #include using namespace clio; +namespace po = boost::program_options; +/** + * @brief Parse command line and return path to configuration file + * + * @param argc + * @param argv + * @return std::string Path to configuration file + */ +std::string +parseCli(int argc, char* argv[]) +{ + static constexpr char defaultConfigPath[] = "/etc/opt/clio/config.json"; + + // clang-format off + po::options_description description("Options"); + description.add_options() + ("help,h", "print help message and exit") + ("version,v", "print version and exit") + ("conf,c", po::value()->default_value(defaultConfigPath), "configuration file") + ; + // clang-format on + po::positional_options_description positional; + positional.add("conf", 1); + + po::variables_map parsed; + po::store( + po::command_line_parser(argc, argv) + .options(description) + .positional(positional) + .run(), + parsed); + po::notify(parsed); + + if (parsed.count("version")) + { + std::cout << Build::getClioFullVersionString() << '\n'; + std::exit(EXIT_SUCCESS); + } + + if (parsed.count("help")) + { + std::cout << "Clio server " << Build::getClioFullVersionString() + << "\n\n" + << description; + std::exit(EXIT_SUCCESS); + } + + return parsed["conf"].as(); +} + +/** + * @brief Parse certificates from configuration file + * + * @param config The configuration + * @return std::optional SSL context if certificates were parsed + */ std::optional -parse_certs(Config const& config) +parseCerts(Config const& config) { if (!config.contains("ssl_cert_file") || !config.contains("ssl_key_file")) return {}; @@ -73,6 +131,12 @@ parse_certs(Config const& config) return ctx; } +/** + * @brief Start context threads + * + * @param ioc Context + * @param numThreads Number of worker threads to start + */ void start(boost::asio::io_context& ioc, std::uint32_t numThreads) { @@ -88,33 +152,19 @@ int main(int argc, char* argv[]) try { - // Check command line arguments. - if (argc != 2) - { - std::cerr << "Usage: clio_server " - " \n" - << "Example:\n" - << " clio_server config.json \n"; - return EXIT_FAILURE; - } - - if (std::string{argv[1]} == "-v" || std::string{argv[1]} == "--version") - { - std::cout << Build::getClioFullVersionString() << std::endl; - return EXIT_SUCCESS; - } - - auto const config = ConfigReader::open(argv[1]); + auto const configPath = parseCli(argc, argv); + auto const config = ConfigReader::open(configPath); if (!config) { - std::cerr << "Couldnt parse config. Exiting..." << std::endl; + std::cerr << "Couldnt parse config '" << configPath << "'." + << std::endl; return EXIT_FAILURE; } LogService::init(config); LogService::info() << "Clio version: " << Build::getClioFullVersionString(); - auto ctx = parse_certs(config); + auto ctx = parseCerts(config); auto ctxRef = ctx ? std::optional>{ctx.value()} : std::nullopt; @@ -127,7 +177,7 @@ try } LogService::info() << "Number of io threads = " << threads; - // io context to handle all incoming requests, as well as other things + // IO context to handle all incoming requests, as well as other things // This is not the only io context in the application boost::asio::io_context ioc{threads};