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")) {
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()) {
460 auto exit_code =
e.exitCode();
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 : " << exc1.
what();
543 log.fatal() <<
"# Standard Exception : " << exc2.
what();
547 log.fatal() <<
"# An exception of unknown type occurred, " 548 <<
"i.e., an exception not deriving from std::exception ";
ExitCode
Strongly typed exit numbers.
Macro to silence unused variables warnings from the compiler.
void logTheEnvironment() const
Log the program environment.
void tearDown(const ExitCode &)
std::string m_parent_project_vcs_version
void logHeader(std::string program_name) const
Log Header.
boost::program_options::variables_map m_variables_map
ELEMENTS_API std::vector< boost::filesystem::path > getConfigurationLocations(bool exist_only=false)
log4cpp::Priority::Value m_elements_loglevel
void bootstrapEnvironment(char *arg0)
Bootstrap the Environment from the executable location and the install path computed at install time.
OS specific details to access at run-time the module configuration of the process.
static const boost::filesystem::path setProgramPath(char *arg0)
Strip the name from argv[0] to set the program path.
ELEMENTS_API const std::map< Type, const std::string > VARIABLE
map containing the name of the path variable for each type
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 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
std::string getVersion() const
This function returns the version of the program computed at compile time. This is the same as the pr...
ELEMENTS_API std::vector< boost::filesystem::path > multiPathAppend(const std::vector< T > &initial_locations, const std::vector< U > &suffixes)
path join each suffix to each initial locations
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.
ELEMENTS_API const std::map< Type, const std::vector< std::string > > SUFFIXES
map containing the default project installation suffixes for each variable
boost::filesystem::path m_program_path
ELEMENTS_API const std::string PATH_SEP
Separator of path entries. Usually ":" on Unix.
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.
const boost::filesystem::path & getProgramPath() const
Getter.
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.
const char * what() const noexcept override
void logAllOptions() const
Log all program options.
void logFooter(std::string program_name) const
Log Footer.
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.
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 exitCode() const noexcept
define a list of standard exit codes for executables
Elements base exception class.
define an exception for unrecognized commandline options and arguments
provide functions to retrieve resources pointed by environment variables
ELEMENTS_API std::string joinPath(const std::vector< T > &path_list)
collate a vector of path into a string using PATH_SEP
static void setLevel(std::string level)
Sets the global message level.
provide functions to retrieve configuration files
T rethrow_exception(T... args)
ELEMENTS_API boost::filesystem::path getConfigurationPath(const T &file_name, bool raise_exception=true)
const boost::filesystem::path & getProgramName() const
Getter.
static Logging getLogger(const std::string &name="")
defines the base Elements exception class
ExitCode run(int argc, char *argv[])
This is the public entry point, i.e., the only method called from the main.