35 #include <boost/algorithm/string/predicate.hpp>
36 #include <boost/filesystem/operations.hpp>
37 #include <boost/filesystem/path.hpp>
38 #include <boost/program_options.hpp>
56 using log4cpp::Priority;
59 using boost::program_options::variables_map;
70 const string& parent_project_version,
71 const string& parent_project_name,
72 const string& parent_project_vcs_version,
73 const string& parent_module_version,
74 const string& parent_module_name,
76 const Priority::Value& elements_loglevel):
77 m_program_ptr(move(program_ptr)),
78 m_parent_project_version(move(parent_project_version)),
79 m_parent_project_name(move(parent_project_name)),
80 m_parent_project_vcs_version(move(parent_project_vcs_version)),
81 m_parent_module_version(move(parent_module_version)),
82 m_parent_module_name(move(parent_module_name)),
83 m_search_dirs(move(search_dirs)),
85 m_elements_loglevel(move(elements_loglevel)) {
104 const string& module_name) {
105 path default_config_file{};
108 path conf_name(program_name);
109 conf_name.replace_extension(
"conf");
113 if (default_config_file.empty()) {
114 log.warn() <<
"The " << conf_name <<
" default configuration file cannot be found in:";
116 log.warn() <<
" " << loc;
118 if (not module_name.
empty()) {
119 conf_name =
path {module_name} / conf_name;
120 log.warn() <<
"Trying " << conf_name <<
".";
125 if (default_config_file.empty()) {
126 log.debug() <<
"Couldn't find " << conf_name <<
" default configuration file.";
128 log.debug() <<
"Found " << conf_name <<
" default configuration file at " << default_config_file;
131 return default_config_file;
138 return full_path.filename();
145 return full_path.parent_path();
148 template<
class charT>
150 const boost::program_options::basic_parsed_options<charT>& cmd_parsed_options) {
152 for (
const auto& o : cmd_parsed_options.options) {
153 if (o.string_key ==
"config-file") {
154 if (o.value.size() != 1) {
155 cerr <<
"Wrong usage of the --config-file option" << endl;
158 auto conf_file =
path { o.value[0] };
159 if (not boost::filesystem::exists(conf_file)) {
160 cerr <<
"The " << conf_file
161 <<
" configuration file doesn't exist!" << endl;
173 int argc,
char* argv[]) {
178 using boost::program_options::options_description;
179 using boost::program_options::value;
180 using boost::program_options::store;
181 using boost::program_options::command_line_parser;
182 using boost::program_options::collect_unrecognized;
183 using boost::program_options::include_positional;
184 using boost::program_options::notify;
185 using boost::program_options::parse_config_file;
187 variables_map var_map { };
190 string default_log_level =
"INFO";
197 options_description cmd_only_generic_options {};
198 cmd_only_generic_options.add_options()
199 (
"version",
"Print version string")
200 (
"help",
"Produce help message")
202 value<path>()->default_value(default_config_file),
203 "Name of a configuration file");
206 options_description cmd_and_file_generic_options {};
207 cmd_and_file_generic_options.add_options()
208 (
"log-level", value<string>()->default_value(default_log_level),
209 "Log level: FATAL, ERROR, WARN, INFO (default), DEBUG")
211 value<path>(),
"Name of a log file");
215 options_description all_generic_options {
"Generic options"};
216 for (
auto o : cmd_only_generic_options.options()) {
217 all_generic_options.add(o);
219 for (
auto o : cmd_and_file_generic_options.options()) {
220 all_generic_options.add(o);
225 auto specific_options =
m_program_ptr->defineSpecificProgramOptions();
226 auto program_arguments =
m_program_ptr->defineProgramArguments();
227 options_description all_specific_options {};
228 all_specific_options.add(specific_options)
229 .add(program_arguments.first);
232 options_description all_cmd_and_file_options {};
233 all_cmd_and_file_options.add(cmd_and_file_generic_options)
234 .add(all_specific_options);
237 options_description help_options {};
238 help_options.add(all_generic_options).add(all_specific_options);
241 auto cmd_parsed_options = command_line_parser(argc, argv)
242 .options(cmd_only_generic_options)
243 .allow_unregistered().run();
247 store(cmd_parsed_options, var_map);
250 if (var_map.count(
"help") > 0) {
251 cout << help_options << endl;
256 if (var_map.count(
"version") > 0) {
263 auto config_file = var_map.at(
"config-file").as<
path>();
267 auto leftover_cmd_options = collect_unrecognized(cmd_parsed_options.options,
272 auto parsed_cmdline_options = command_line_parser(leftover_cmd_options)
273 .options(all_cmd_and_file_options)
274 .positional(program_arguments.second)
277 store(parsed_cmdline_options, var_map);
280 if (not config_file.empty() and boost::filesystem::exists(config_file)) {
283 auto parsed_cfgfile_options = parse_config_file(ifs,
284 all_cmd_and_file_options);
285 store(parsed_cfgfile_options, var_map);
290 if (boost::starts_with(e.
what(),
"unrecognised option") or
291 boost::starts_with(e.
what(),
"too many positional options")) {
306 log.log(
m_elements_loglevel,
"##########################################################");
307 log.log(
m_elements_loglevel,
"##########################################################");
316 log.log(
m_elements_loglevel,
"##########################################################");
320 log.log(
m_elements_loglevel,
"##########################################################");
321 log.log(
m_elements_loglevel,
"##########################################################");
331 log.log(
m_elements_loglevel,
"##########################################################");
338 stringstream log_message {};
343 if (v.second.value().type() ==
typeid(
string)) {
344 log_message << v.first <<
" = " << v.second.as<
string>();
346 }
else if (v.second.value().type() ==
typeid(double)) {
347 log_message << v.first <<
" = " << v.second.as<
double>();
349 }
else if (v.second.value().type() ==
typeid(int64_t)) {
350 log_message << v.first <<
" = " << v.second.as<int64_t>();
352 }
else if (v.second.value().type() ==
typeid(int)) {
353 log_message << v.first <<
" = " << v.second.as<
int>();
355 }
else if (v.second.value().type() ==
typeid(bool)) {
356 log_message << v.first <<
" = " << v.second.as<
bool>();
358 }
else if (v.second.value().type() ==
typeid(
path)) {
359 log_message << v.first <<
" = "
360 << v.second.as<
path>();
362 }
else if (v.second.value().type() ==
typeid(
vector<int>)) {
364 stringstream vecContent {};
365 for (
const auto& i : intVec) {
366 vecContent <<
" " << i;
368 log_message << v.first <<
" = {" << vecContent.str() <<
" }";
372 stringstream vecContent {};
373 for (
const auto& i : intVec) {
374 vecContent <<
" " << i;
376 log_message << v.first <<
" = {" << vecContent.str() <<
" }";
380 stringstream vecContent {};
381 for (
const auto& i : intVec) {
382 vecContent <<
" " << i;
384 log_message << v.first <<
" = {" << vecContent.str() <<
" }";
387 log_message <<
"Option " << v.first <<
" of type "
388 << v.second.value().type().name() <<
" not supported in logging !"
402 log.debug() <<
"##########################################################";
404 log.debug() <<
"# Environment of the Run";
405 log.debug() <<
"# ---------------------------";
409 log.debug() << v.second <<
": " <<
m_env[v.second];
423 local_search_paths.
begin(),
425 return boost::filesystem::complete(
s);
430 const path this_parent_path = boost::filesystem::canonical(
m_program_path.parent_path());
431 if (local_search_paths[0] != this_parent_path) {
432 auto b = local_search_paths.begin();
433 local_search_paths.insert(b, this_parent_path);
440 if (
m_env[v.second].exists()) {
461 log.fatal() <<
"# Elements Exception : " << e.
what();
466 string logging_level;
470 throw Exception(
"Required option log-level is not provided!",
492 log.debug() <<
"# Exit Code: " << int(c);
525 log.fatal() <<
"Crash detected";
526 log.fatal() <<
"This is the back trace:";
528 log.fatal() << level;
536 log.fatal() <<
"# Elements Exception : " << exc.
what();
543 log.fatal() <<
"# Standard Exception : " << exc.
what();
547 log.fatal() <<
"# An exception of unknown type occurred, "
548 <<
"i.e., an exception not deriving from std::exception ";
Macro to silence unused variables warnings from the compiler.
ELEMENTS_API const std::map< Type, const std::vector< std::string > > SUFFIXES
map containing the default project installation suffixes for each variable
void tearDown(const ExitCode &)
std::string m_parent_project_vcs_version
boost::program_options::variables_map m_variables_map
ELEMENTS_API std::vector< boost::filesystem::path > getConfigurationLocations(bool exist_only=false)
void logAllOptions() const
Log all program options.
log4cpp::Priority::Value m_elements_loglevel
const boost::filesystem::path & getProgramName() const
Getter.
void bootstrapEnvironment(char *arg0)
Bootstrap the Environment from the executable location and the install path computed at install time...
const boost::filesystem::path & getProgramPath() const
Getter.
static const boost::filesystem::path setProgramPath(char *arg0)
Strip the name from argv[0] to set the program path.
constexpr double e
The base of the natural logarithm .
ProgramManager(std::unique_ptr< Program > program_ptr, const std::string &parent_project_version="", const std::string &parent_project_name="", const std::string &parent_project_vcs_version="", const std::string &parent_module_version="", const std::string &parent_module_name="", const std::vector< std::string > &search_dirs={}, const log4cpp::Priority::Value &elements_loglevel=log4cpp::Priority::DEBUG)
Constructor.
static void onTerminate() noexcept
This is the set_terminate handler that is used in the MAIN_FOR macro.
T current_exception(T...args)
boost::filesystem::path getConfigurationPath(const T &file_name, bool raise_exception)
boost::filesystem::path m_program_name
static const boost::filesystem::path setProgramName(char *arg0)
Strip the path from argv[0] to set the program name.
std::unique_ptr< Program > m_program_ptr
static const boost::filesystem::path getDefaultConfigFile(const boost::filesystem::path &program_name, const std::string &module_name="")
Get a default configuration file name and path, to be used if not provided as a command line option...
boost::filesystem::path m_program_path
void checkCommandLineOptions(const boost::program_options::basic_parsed_options< charT > &cmd_line_options)
check the explicit command line arguments. For the moment, it only checks if the configuration file b...
virtual ~ProgramManager()
Destructor.
std::string m_parent_project_name
This file is intended to iron out all the differences between systems (currently Linux and MacOSX) ...
std::string m_parent_module_name
boost::filesystem::path path
std::vector< std::string > m_search_dirs
const boost::program_options::variables_map getProgramOptions(int argc, char *argv[])
Get the program options from the command line into thevariables_map.
ELEMENTS_API const std::map< Type, const std::string > VARIABLE
map containing the name of the path variable for each type
static void setLogFile(const boost::filesystem::path &fileName)
Sets the file to store the log messages.
void setup(int argc, char *argv[])
Program setup taking care of command line options and logging initialization.
std::vector< boost::filesystem::path > multiPathAppend(const std::vector< T > &initial_locations, const std::vector< U > &suffixes)
ELEMENTS_API boost::filesystem::path getExecutablePath()
Get the full executable path.
ELEMENTS_API int backTrace(ELEMENTS_UNUSED std::shared_ptr< void * > addresses, ELEMENTS_UNUSED const int depth)
ExitCode
Strongly typed exit numbers.
ExitCode exitCode() const noexcept
define a list of standard exit codes for executables
std::string joinPath(const std::vector< T > path_list)
collate a vector of path into a string using PATH_SEP
define an exception for unrecognized commandline options and arguments
provide functions to retrieve resources pointed by environment variables
std::string getVersion() const
This function returns the version of the program computed at compile time. This is the same as the pr...
void logTheEnvironment() const
Log the program environment.
OS specific details to access at run-time the module configuration of the process.
static void setLevel(std::string level)
Sets the global message level.
provide functions to retrieve configuration files
T rethrow_exception(T...args)
const char * what() const noexceptoverride
static Logging getLogger(const std::string &name="")
defines the base Elements exception class
ELEMENTS_API const std::string PATH_SEP
Separator of path entries. Usually ":" on Unix.
void logFooter(std::string program_name) const
Log Footer.
void logHeader(std::string program_name) const
Log Header.
ExitCode run(int argc, char *argv[])
This is the public entry point, i.e., the only method called from the main.