35 #include <boost/algorithm/string/predicate.hpp>
36 #include <boost/filesystem/operations.hpp>
37 #include <boost/program_options.hpp>
57 using log4cpp::Priority;
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) {
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::Item {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;
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[]) {
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;
190 string default_log_level =
"INFO";
198 cmd_only_generic_options.add_options()
199 (
"version",
"Print version string")
200 (
"help",
"Produce help message")
202 value<Path::Item>()->default_value(default_config_file),
203 "Name of a configuration file");
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::Item>(),
"Name of a log file");
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();
228 all_specific_options.add(specific_options)
229 .add(program_arguments.first);
233 all_cmd_and_file_options.add(cmd_and_file_generic_options)
234 .add(all_specific_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::Item>();
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::Item)) {
359 log_message << v.first <<
" = "
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);
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 ";
provide functions to retrieve configuration files
defines the base Elements exception class
define a list of standard exit codes for executables
OS specific details to access at run-time the module configuration of the process.
define an exception for unrecognized commandline options and arguments
provide functions to retrieve resources pointed by environment variables
define an abstract class for all Elements program
This file is intended to iron out all the differences between systems (currently Linux and MacOSX)
Macro to silence unused variables warnings from the compiler.
Elements base exception class.
ExitCode exitCode() const noexcept
const char * what() const noexcept override
static Logging getLogger(const std::string &name="")
static void setLogFile(const Path::Item &fileName)
Sets the file to store the log messages.
static void setLevel(std::string level)
Sets the global message level.
void setup(int argc, char *argv[])
Program setup taking care of command line options and logging initialization.
Path::Item m_program_name
virtual ~ProgramManager()
Destructor.
std::unique_ptr< Program > m_program_ptr
std::string m_parent_module_name
static void onTerminate() noexcept
This is the set_terminate handler that is used in the MAIN_FOR macro.
const Path::Item & getProgramName() const
Getter.
ExitCode run(int argc, char *argv[])
This is the public entry point, i.e., the only method called from the main.
void bootstrapEnvironment(char *arg0)
Bootstrap the Environment from the executable location and the install path computed at install time.
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.
void logTheEnvironment() const
Log the program environment.
std::string m_parent_project_name
std::vector< std::string > m_search_dirs
void logHeader(std::string program_name) const
Log Header.
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...
const Program::VariablesMap getProgramOptions(int argc, char *argv[])
Get the program options from the command line into thevariables_map.
static const Path::Item setProgramName(char *arg0)
Strip the path from argv[0] to set the program name.
Path::Item m_program_path
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.
std::string getVersion() const
This function returns the version of the program computed at compile time. This is the same as the pr...
log4cpp::Priority::Value m_elements_loglevel
std::string m_parent_project_vcs_version
const Path::Item & getProgramPath() const
Getter.
void tearDown(const ExitCode &)
void logFooter(std::string program_name) const
Log Footer.
Program::VariablesMap m_variables_map
static const Path::Item setProgramPath(char *arg0)
Strip the name from argv[0] to set the program path.
void logAllOptions() const
Log all program options.
options_description OptionsDescription
variables_map VariablesMap
T current_exception(T... args)
ELEMENTS_API const std::map< Type, const std::string > VARIABLE
map containing the name of the path variable for each type
ExitCode
Strongly typed exit numbers.
ELEMENTS_API std::string joinPath(const std::vector< T > &path_list)
collate a vector of path into a string using PATH_SEP
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.
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 Item
ELEMENTS_API Path::Item getExecutablePath()
Get the full executable path.
ELEMENTS_API int backTrace(ELEMENTS_UNUSED std::shared_ptr< void * > addresses, ELEMENTS_UNUSED const int depth)
constexpr double e
The base of the natural logarithm .
ELEMENTS_API Path::Item getConfigurationPath(const T &file_name, bool raise_exception=true)
Program::OptionsDescription OptionsDescription
ELEMENTS_API std::vector< Path::Item > getConfigurationLocations(bool exist_only=false)
Program::VariablesMap VariablesMap
@ NOT_OK
Generic unknown failure.
@ CONFIG
configuration error
@ USAGE
command line usage error
T rethrow_exception(T... args)