Skip to content

Commit

Permalink
Put functionality related to command-line args in own cpp file
Browse files Browse the repository at this point in the history
  • Loading branch information
alexdewar committed Aug 9, 2023
1 parent 9a1188c commit 3efc2be
Show file tree
Hide file tree
Showing 8 changed files with 196 additions and 189 deletions.
3 changes: 2 additions & 1 deletion src/HealthGPS.Console/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR})

target_sources(HealthGPS.Console
PRIVATE
"command_options.cpp"
"command_options.h"
"configuration.cpp"
"configuration.h"
"csvparser.cpp"
Expand All @@ -27,7 +29,6 @@ target_sources(HealthGPS.Console
"jsonparser.cpp"
"jsonparser.h"
"model_info.h"
"options.h"
"resource.h"
"result_writer.h"
"riskmodel.h"
Expand Down
96 changes: 96 additions & 0 deletions src/HealthGPS.Console/command_options.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#include "command_options.h"
#include "version.h"

#include <fmt/color.h>

#include <iostream>

namespace host {

cxxopts::Options create_options() {
cxxopts::Options options("HealthGPS.Console", "Health-GPS microsimulation for policy options.");
options.add_options()("f,file", "Configuration file full name.", cxxopts::value<std::string>())(
"s,storage", "Path to root folder of the data storage.", cxxopts::value<std::string>())(
"j,jobid", "The batch execution job identifier.",
cxxopts::value<int>())("verbose", "Print more information about progress",
cxxopts::value<bool>()->default_value("false"))(
"help", "Help about this application.")("version", "Print the application version number.");

return options;
}

CommandOptions parse_arguments(cxxopts::Options &options, int &argc, char *argv[]) {
namespace fs = std::filesystem;

CommandOptions cmd;
try {
cmd.success = true;
cmd.exit_code = EXIT_SUCCESS;
cmd.verbose = false;
auto result = options.parse(argc, argv);
if (result.count("help")) {
std::cout << options.help() << std::endl;
cmd.success = false;
return cmd;
}

if (result.count("version")) {
fmt::print("Version {}\n\n", PROJECT_VERSION);
cmd.success = false;
return cmd;
}

cmd.verbose = result["verbose"].as<bool>();
if (cmd.verbose) {
fmt::print(fg(fmt::color::dark_salmon), "Verbose output enabled\n");
}

if (result.count("file")) {
cmd.config_file = result["file"].as<std::string>();
if (cmd.config_file.is_relative()) {
cmd.config_file = std::filesystem::absolute(cmd.config_file);
fmt::print("Configuration file..: {}\n", cmd.config_file.string());
}
}

if (!fs::exists(cmd.config_file)) {
fmt::print(fg(fmt::color::red), "\nConfiguration file: {} not found.\n",
cmd.config_file.string());
cmd.exit_code = EXIT_FAILURE;
}

if (result.count("storage")) {
cmd.storage_folder = result["storage"].as<std::string>();
if (cmd.storage_folder.is_relative()) {
cmd.storage_folder = std::filesystem::absolute(cmd.storage_folder);
fmt::print("File storage folder.: {}\n", cmd.storage_folder.string());
}
}

if (!fs::exists(cmd.storage_folder)) {
fmt::print(fg(fmt::color::red), "\nFile storage folder: {} not found.\n",
cmd.storage_folder.string());
cmd.exit_code = EXIT_FAILURE;
}

if (result.count("jobid")) {
cmd.job_id = result["jobid"].as<int>();
if (cmd.job_id < 1) {
fmt::print(fg(fmt::color::red),
"\nJob identifier value outside range: (0 < x) given: {}.\n",
std::to_string(cmd.job_id));
cmd.exit_code = EXIT_FAILURE;
}
}

cmd.success = cmd.exit_code == EXIT_SUCCESS;
} catch (const cxxopts::exceptions::exception &ex) {
fmt::print(fg(fmt::color::red), "\nInvalid command line argument: {}.\n", ex.what());
fmt::print("\n{}\n", options.help());
cmd.success = false;
cmd.exit_code = EXIT_FAILURE;
}

return cmd;
}
} // namespace host
39 changes: 39 additions & 0 deletions src/HealthGPS.Console/command_options.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#pragma once
#include <cxxopts.hpp>

#include <filesystem>

namespace host {
/// @brief Defines the Command Line Interface (CLI) arguments options
struct CommandOptions {
/// @brief Indicates whether the argument parsing succeed
bool success{};

/// @brief The exit code to return, in case of CLI arguments parsing failure
int exit_code{};

/// @brief The configuration file argument value
std::filesystem::path config_file{};

/// @brief The back-end storage full path argument value
std::filesystem::path storage_folder{};

/// @brief Indicates whether the application logging is verbose
bool verbose{};

/// @brief The batch job identifier value, optional.
int job_id{};
};

/// @brief Creates the command-line interface (CLI) options
/// @return Health-GPS CLI options
cxxopts::Options create_options();

/// @brief Parses the command-line interface (CLI) arguments
/// @param options The valid CLI options
/// @param argc Number of input arguments
/// @param argv List of input arguments
/// @return User command-line options
CommandOptions parse_arguments(cxxopts::Options &options, int &argc, char *argv[]);

} // namespace host
92 changes: 0 additions & 92 deletions src/HealthGPS.Console/configuration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,94 +33,6 @@ namespace host {
using namespace hgps;
using json = nlohmann::json;

cxxopts::Options create_options() {
cxxopts::Options options("HealthGPS.Console", "Health-GPS microsimulation for policy options.");
options.add_options()("f,file", "Configuration file full name.", cxxopts::value<std::string>())(
"s,storage", "Path to root folder of the data storage.", cxxopts::value<std::string>())(
"j,jobid", "The batch execution job identifier.",
cxxopts::value<int>())("verbose", "Print more information about progress",
cxxopts::value<bool>()->default_value("false"))(
"help", "Help about this application.")("version", "Print the application version number.");

return options;
}

CommandOptions parse_arguments(cxxopts::Options &options, int &argc, char *argv[]) {
MEASURE_FUNCTION();
namespace fs = std::filesystem;

CommandOptions cmd;
try {
cmd.success = true;
cmd.exit_code = EXIT_SUCCESS;
cmd.verbose = false;
auto result = options.parse(argc, argv);
if (result.count("help")) {
std::cout << options.help() << std::endl;
cmd.success = false;
return cmd;
}

if (result.count("version")) {
fmt::print("Version {}\n\n", PROJECT_VERSION);
cmd.success = false;
return cmd;
}

cmd.verbose = result["verbose"].as<bool>();
if (cmd.verbose) {
fmt::print(fg(fmt::color::dark_salmon), "Verbose output enabled\n");
}

if (result.count("file")) {
cmd.config_file = result["file"].as<std::string>();
if (cmd.config_file.is_relative()) {
cmd.config_file = std::filesystem::absolute(cmd.config_file);
fmt::print("Configuration file..: {}\n", cmd.config_file.string());
}
}

if (!fs::exists(cmd.config_file)) {
fmt::print(fg(fmt::color::red), "\nConfiguration file: {} not found.\n",
cmd.config_file.string());
cmd.exit_code = EXIT_FAILURE;
}

if (result.count("storage")) {
cmd.storage_folder = result["storage"].as<std::string>();
if (cmd.storage_folder.is_relative()) {
cmd.storage_folder = std::filesystem::absolute(cmd.storage_folder);
fmt::print("File storage folder.: {}\n", cmd.storage_folder.string());
}
}

if (!fs::exists(cmd.storage_folder)) {
fmt::print(fg(fmt::color::red), "\nFile storage folder: {} not found.\n",
cmd.storage_folder.string());
cmd.exit_code = EXIT_FAILURE;
}

if (result.count("jobid")) {
cmd.job_id = result["jobid"].as<int>();
if (cmd.job_id < 1) {
fmt::print(fg(fmt::color::red),
"\nJob identifier value outside range: (0 < x) given: {}.\n",
std::to_string(cmd.job_id));
cmd.exit_code = EXIT_FAILURE;
}
}

cmd.success = cmd.exit_code == EXIT_SUCCESS;
} catch (const cxxopts::exceptions::exception &ex) {
fmt::print(fg(fmt::color::red), "\nInvalid command line argument: {}.\n", ex.what());
fmt::print("\n{}\n", options.help());
cmd.success = false;
cmd.exit_code = EXIT_FAILURE;
}

return cmd;
}

ConfigurationError::ConfigurationError(const std::string &msg) : std::runtime_error{msg} {}

auto get_key(const json &j, const std::string &key) {
Expand Down Expand Up @@ -455,10 +367,6 @@ Configuration get_configuration(CommandOptions &options) {
success = false;
}

// application version
config.app_name = PROJECT_NAME;
config.app_version = PROJECT_VERSION;

// Base dir for relative paths
const auto config_dir = options.config_file.parent_path();

Expand Down
71 changes: 58 additions & 13 deletions src/HealthGPS.Console/configuration.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#pragma once
#include <cxxopts.hpp>

#include "command_options.h"
#include "poco.h"
#include "version.h"

#include "HealthGPS/healthgps.h"
#include "HealthGPS/intervention_scenario.h"
Expand All @@ -8,30 +11,72 @@

#include "HealthGPS.Core/api.h"

#include "options.h"
#include "result_file_writer.h"

#include <stdexcept>

namespace host {

/// @brief Defines the application configuration data structure
struct Configuration {
/// @brief The input data file details
poco::FileInfo file;

/// @brief Experiment population settings
poco::SettingsInfo settings;

/// @brief Socio-economic status (SES) model inputs
poco::SESInfo ses;

/// @brief User defined model and parameters information
poco::ModellingInfo modelling;

/// @brief List of diseases to include in experiment
std::vector<std::string> diseases;

/// @brief Simulation initialisation custom seed value, optional
std::optional<unsigned int> custom_seed;

/// @brief The experiment start time (simulation clock)
unsigned int start_time{};

/// @brief The experiment stop time (simulation clock)
unsigned int stop_time{};

/// @brief The number of simulation runs (replications) to execute
unsigned int trial_runs{};

/// @brief Baseline to intervention data synchronisation time out (milliseconds)
unsigned int sync_timeout_ms{};

/// @brief Indicates whether an alternative intervention policy is active
bool has_active_intervention{false};

/// @brief The active intervention policy definition
poco::PolicyScenarioInfo intervention;

/// @brief Experiment output folder and file information
poco::OutputInfo output;

/// @brief Application logging verbosity mode
hgps::core::VerboseMode verbosity{};

/// @brief Experiment batch job identifier
int job_id{};

/// @brief Experiment model name
const char *app_name = PROJECT_NAME;

/// @brief Experiment model version
const char *app_version = PROJECT_VERSION;
};

/// @brief Represents an error that occurred with the format of a config file
class ConfigurationError : public std::runtime_error {
public:
ConfigurationError(const std::string &msg);
};

/// @brief Creates the command-line interface (CLI) options
/// @return Health-GPS CLI options
cxxopts::Options create_options();

/// @brief Parses the command-line interface (CLI) arguments
/// @param options The valid CLI options
/// @param argc Number of input arguments
/// @param argv List of input arguments
/// @return User command-line options
CommandOptions parse_arguments(cxxopts::Options &options, int &argc, char *argv[]);

/// @brief Loads the input configuration file, *.json, information
/// @param options User command-line options
/// @return The configuration file information
Expand Down
2 changes: 1 addition & 1 deletion src/HealthGPS.Console/jsonparser.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#pragma once
#include "options.h"
#include "poco.h"
#include "riskmodel.h"

#include <nlohmann/json.hpp>
Expand Down
1 change: 0 additions & 1 deletion src/HealthGPS.Console/model_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
#include "HealthGPS/riskfactor_adjustment_types.h"

#include "jsonparser.h"
#include "options.h"

#include <utility>

Expand Down
Loading

0 comments on commit 3efc2be

Please sign in to comment.