35 #include <boost/algorithm/string/predicate.hpp>
36 #include <boost/filesystem/operations.hpp>
37 #include <boost/program_options.hpp>
52 using log4cpp::Priority;
69 const string& parent_project_name,
const string& parent_project_vcs_version,
70 const string& parent_module_version,
const string& parent_module_name,
71 const vector<string>& search_dirs,
const Priority::Value& elements_loglevel)
72 : m_program_ptr(move(program_ptr))
73 , m_parent_project_version(move(parent_project_version))
74 , m_parent_project_name(move(parent_project_name))
75 , m_parent_project_vcs_version(move(parent_project_vcs_version))
76 , m_parent_module_version(move(parent_module_version))
77 , m_parent_module_name(move(parent_module_name))
78 , m_search_dirs(move(search_dirs))
80 , m_elements_loglevel(move(elements_loglevel)) {}
100 conf_name.replace_extension(
"conf");
104 if (default_config_file.empty()) {
105 log.warn() <<
"The " << conf_name <<
" default configuration file cannot be found in:";
107 log.warn() <<
" " << loc;
109 if (not module_name.
empty()) {
110 conf_name =
Path::Item{module_name} / conf_name;
111 log.warn() <<
"Trying " << conf_name <<
".";
116 if (default_config_file.empty()) {
117 log.debug() <<
"Couldn't find " << conf_name <<
" default configuration file.";
119 log.debug() <<
"Found " << conf_name <<
" default configuration file at " << default_config_file;
122 return default_config_file;
129 return full_path.filename();
136 return full_path.parent_path();
139 template <
class charT>
141 const boost::program_options::basic_parsed_options<charT>& cmd_parsed_options) {
143 for (
const auto& o : cmd_parsed_options.options) {
144 if (o.string_key ==
"config-file") {
145 if (o.value.size() != 1) {
146 cerr <<
"Wrong usage of the --config-file option" << endl;
150 if (not boost::filesystem::exists(conf_file)) {
151 cerr <<
"The " << conf_file <<
" configuration file doesn't exist!" << endl;
167 using boost::program_options::collect_unrecognized;
168 using boost::program_options::command_line_parser;
169 using boost::program_options::include_positional;
170 using boost::program_options::notify;
171 using boost::program_options::parse_config_file;
172 using boost::program_options::store;
173 using boost::program_options::value;
178 string default_log_level =
"INFO";
185 cmd_only_generic_options.add_options()(
"version",
"Print version string")(
"help",
"Produce help message")(
186 "config-file", value<Path::Item>()->default_value(default_config_file),
"Name of a configuration file");
190 cmd_and_file_generic_options.add_options()(
"log-level", value<string>()->default_value(default_log_level),
191 "Log level: FATAL, ERROR, WARN, INFO (default), DEBUG")(
192 "log-file", value<Path::Item>(),
"Name of a log file");
197 for (
auto o : cmd_only_generic_options.options()) {
198 all_generic_options.add(o);
200 for (
auto o : cmd_and_file_generic_options.options()) {
201 all_generic_options.add(o);
206 auto specific_options =
m_program_ptr->defineSpecificProgramOptions();
207 auto program_arguments =
m_program_ptr->defineProgramArguments();
209 all_specific_options.add(specific_options).add(program_arguments.first);
213 all_cmd_and_file_options.add(cmd_and_file_generic_options).add(all_specific_options);
217 help_options.add(all_generic_options).add(all_specific_options);
220 auto cmd_parsed_options =
221 command_line_parser(argc, argv).options(cmd_only_generic_options).allow_unregistered().run();
225 store(cmd_parsed_options, var_map);
228 if (var_map.count(
"help") > 0) {
229 cout << help_options << endl;
234 if (var_map.count(
"version") > 0) {
241 auto config_file = var_map.at(
"config-file").as<
Path::Item>();
245 auto leftover_cmd_options = collect_unrecognized(cmd_parsed_options.options, include_positional);
249 auto parsed_cmdline_options = command_line_parser(leftover_cmd_options)
250 .options(all_cmd_and_file_options)
251 .positional(program_arguments.second)
254 store(parsed_cmdline_options, var_map);
257 if (not config_file.empty() and boost::filesystem::exists(config_file)) {
260 auto parsed_cfgfile_options = parse_config_file(ifs, all_cmd_and_file_options);
261 store(parsed_cfgfile_options, var_map);
266 if (boost::starts_with(e.
what(),
"unrecognised option") or
267 boost::starts_with(e.
what(),
"too many positional options")) {
313 stringstream log_message{};
318 if (v.second.value().type() ==
typeid(
string)) {
319 log_message << v.first <<
" = " << v.second.as<
string>();
321 }
else if (v.second.value().type() ==
typeid(double)) {
322 log_message << v.first <<
" = " << v.second.as<
double>();
324 }
else if (v.second.value().type() ==
typeid(int64_t)) {
325 log_message << v.first <<
" = " << v.second.as<int64_t>();
327 }
else if (v.second.value().type() ==
typeid(int)) {
328 log_message << v.first <<
" = " << v.second.as<
int>();
330 }
else if (v.second.value().type() ==
typeid(bool)) {
331 log_message << v.first <<
" = " << v.second.as<
bool>();
333 }
else if (v.second.value().type() ==
typeid(
Path::Item)) {
334 log_message << v.first <<
" = " << v.second.as<
Path::Item>();
336 }
else if (v.second.value().type() ==
typeid(
vector<int>)) {
338 stringstream vecContent{};
339 for (
const auto& i : intVec) {
340 vecContent <<
" " << i;
342 log_message << v.first <<
" = {" << vecContent.str() <<
" }";
346 stringstream vecContent{};
347 for (
const auto& i : intVec) {
348 vecContent <<
" " << i;
350 log_message << v.first <<
" = {" << vecContent.str() <<
" }";
354 stringstream vecContent{};
355 for (
const auto& i : intVec) {
356 vecContent <<
" " << i;
358 log_message << v.first <<
" = {" << vecContent.str() <<
" }";
361 log_message <<
"Option " << v.first <<
" of type " << v.second.value().type().name()
362 <<
" not supported in logging !" << endl;
374 log.debug() <<
"##########################################################";
376 log.debug() <<
"# Environment of the Run";
377 log.debug() <<
"# ---------------------------";
381 log.debug() << v.second <<
": " <<
m_env[v.second];
395 return boost::filesystem::complete(
s);
401 if (local_search_paths[0] != this_parent_path) {
402 auto b = local_search_paths.begin();
403 local_search_paths.insert(b, this_parent_path);
410 if (
m_env[v.second].exists()) {
430 log.fatal() <<
"# Elements Exception : " << e.
what();
435 string logging_level;
459 log.debug() <<
"# Exit Code: " << int(c);
491 log.fatal() <<
"Crash detected";
492 log.fatal() <<
"This is the back trace:";
494 log.fatal() << level;
502 log.fatal() <<
"# Elements Exception : " << exc1.
what();
509 log.fatal() <<
"# Standard Exception : " << exc2.
what();
513 log.fatal() <<
"# An exception of unknown type occurred, "
514 <<
"i.e., an exception not deriving from std::exception ";
ExitCode
Strongly typed exit numbers.
Macro to silence unused variables warnings from the compiler.
void tearDown(const ExitCode &)
ELEMENTS_API const std::map< Type, const std::string > VARIABLE
map containing the name of the path variable for each type
std::string m_parent_project_vcs_version
void logAllOptions() const
Log all program options.
log4cpp::Priority::Value m_elements_loglevel
const Program::VariablesMap getProgramOptions(int argc, char *argv[])
Get the program options from the command line into thevariables_map.
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.
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.
Program::OptionsDescription OptionsDescription
Path::Item m_program_path
static void setLogFile(const Path::Item &fileName)
Sets the file to store the log messages.
Program::VariablesMap m_variables_map
T current_exception(T...args)
ELEMENTS_API std::vector< Item > multiPathAppend(const std::vector< T > &initial_locations, const std::vector< U > &suffixes)
path join each suffix to each initial locations
ELEMENTS_API const std::string PATH_SEP
Separator of path entries. Usually ":" on Unix.
std::unique_ptr< Program > m_program_ptr
constexpr double e
The base of the natural logarithm .
ELEMENTS_API int backTrace(ELEMENTS_UNUSED std::shared_ptr< void * > addresses, ELEMENTS_UNUSED const int depth)
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.
boost::filesystem::path Item
std::string m_parent_project_name
This file is intended to iron out all the differences between systems (currently Linux and MacOSX) ...
const Path::Item & getProgramPath() const
Getter.
std::string m_parent_module_name
Path::Item m_program_name
std::vector< std::string > m_search_dirs
define an abstract class for all Elements program
static const Path::Item getDefaultConfigFile(const Path::Item &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 Path::Item getConfigurationPath(const T &file_name, bool raise_exception=true)
ELEMENTS_API std::string joinPath(const std::vector< T > &path_list)
collate a vector of path into a string using PATH_SEP
void setup(int argc, char *argv[])
Program setup taking care of command line options and logging initialization.
variables_map VariablesMap
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
Program::VariablesMap VariablesMap
std::string getVersion() const
This function returns the version of the program computed at compile time. This is the same as the pr...
options_description OptionsDescription
void logTheEnvironment() const
Log the program environment.
static void setLevel(std::string level)
Sets the global message level.
provide functions to retrieve configuration files
static const Path::Item setProgramName(char *arg0)
Strip the path from argv[0] to set the program name.
static const Path::Item setProgramPath(char *arg0)
Strip the name from argv[0] to set the program path.
T rethrow_exception(T...args)
const char * what() const noexceptoverride
ELEMENTS_API Path::Item getExecutablePath()
Get the full executable path.
static Logging getLogger(const std::string &name="")
defines the base Elements exception class
void logFooter(std::string program_name) const
Log Footer.
ELEMENTS_API const std::map< Type, const std::vector< std::string > > SUFFIXES
map containing the default project installation suffixes for each variable
ELEMENTS_API std::vector< Path::Item > getConfigurationLocations(bool exist_only=false)
const Path::Item & getProgramName() const
Getter.
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.