DAS  3.0
Das Analysis System
Options

Description

Common class to interpret the command line, based on Boost Program Options.

Options may also be partly provided via a configuration file. Additional options to split the input file are also possible. Minimal working example:

namespace DT = Darwin::Tools;
DT::Options options("Global description.", DT::config | DT::split);
options.input ("input" , &input , "input ROOT file" );
options.output("output", &output, "output ROOT file");
options.arg<int>("myArg", "correction.here", "my description");
options.args("allOtherArgs", "correction.there.list", "garbage collector");
auto const& config = options(argc, argv);

where the config is a Boost Property Tree. A one-liner is even possible:

auto const& config = DT::Options("Global description.", DT::config | DT::split).input("input", &input, "input ROOT file").output("output", &output, "output ROOT file").arg<int>("myArg", "correction.here", "my description").args("allOtherArgs", "correction.there.list", "garbage collector")(argc, argv);

The order matters only for the positional options, where input(s) should be given first, then output(s), then additional positional options. The position of explicit options (e.g. -v) does not matter. Options::args may be used as a garbage collector for extra positional options.

#include <Options.h>

+ Collaboration diagram for Options:

Public Member Functions

 Options (const std::string &, int=none, const char *commit=DARWIN_GIT_COMMIT, const char *example=DARWIN_EXAMPLE)
 
 Options ()=delete
 
 ~Options ()
 
Optionsinput (const char *, std::filesystem::path *, const char *, const std::vector< std::string > &={".root", ".xml"})
 
Optionsinputs (const char *, std::vector< std::filesystem::path > *, const char *, const std::vector< std::string > &={".root", ".xml"})
 
Optionsoutput (const char *, std::filesystem::path *, const char *, const std::vector< std::string > &={".root", ".xml"})
 
template<typename T >
Optionsarg (const char *name, const char *configpath, const char *desc)
 
Optionsargs (const char *name, const char *configpath, const char *desc)
 
const boost::property_tree::ptree & operator() (int, const char *const [])
 
auto commit () const
 
int steering () const
 
std::vector< std::filesystem::path > plugins () const
 
std::pair< unsigned, unsigned > slice () const
 
 Options (const std::string &, int=none, const char *commit=DARWIN_GIT_COMMIT, const char *example=DARWIN_EXAMPLE)
 
 Options ()=delete
 
 ~Options ()
 
Optionsinput (const char *, std::filesystem::path *, const char *, const std::vector< std::string > &={".root", ".xml"})
 
Optionsinputs (const char *, std::vector< std::filesystem::path > *, const char *, const std::vector< std::string > &={".root", ".xml"})
 
Optionsoutput (const char *, std::filesystem::path *, const char *, const std::vector< std::string > &={".root", ".xml"})
 
template<typename T >
Optionsarg (const char *name, const char *configpath, const char *desc)
 
Optionsargs (const char *name, const char *configpath, const char *desc)
 
const boost::property_tree::ptree & operator() (int, const char *const [])
 
auto commit () const
 
int steering () const
 
std::vector< std::filesystem::path > plugins () const
 
std::pair< unsigned, unsigned > slice () const
 

Static Public Member Functions

static std::string parse_env_var (std::string)
 
static std::string parse_env_var (const char *p)
 
static std::filesystem::path parse_env_var (const std::filesystem::path &p)
 
static void parse_config (boost::property_tree::ptree &, std::string="")
 
static std::string parse_env_var (std::string)
 
static std::string parse_env_var (const char *p)
 
static std::filesystem::path parse_env_var (const std::filesystem::path &p)
 
static void parse_config (boost::property_tree::ptree &, std::string="")
 

Static Public Attributes

static std::string full_cmd
 

Private Types

enum  Stage {
  Input, Output, Arg, Args,
  Input, Output, Arg, Args
}
 
enum  Stage {
  Input, Output, Arg, Args,
  Input, Output, Arg, Args
}
 

Private Member Functions

void parse_helper (int, const char *const [])
 
void parse_common (int, const char *const [])
 
void parse_custom (int, const char *const [])
 
Optionsset (const char *, const boost::program_options::value_semantic *, const char *)
 
template<typename T >
std::function< void(T)> put (const std::string &configpath)
 
bool allow_unregistered () const
 
std::string exec (const std::string &)
 
void parse_helper (int, const char *const [])
 
void parse_common (int, const char *const [])
 
void parse_custom (int, const char *const [])
 
Optionsset (const char *, const boost::program_options::value_semantic *, const char *)
 
template<typename T >
std::function< void(T)> put (const std::string &configpath)
 
bool allow_unregistered () const
 
std::string exec (const std::string &)
 

Static Private Member Functions

static void check_input (const std::filesystem::path &)
 
static void check_output (const std::filesystem::path &)
 
static void check_input (const std::filesystem::path &)
 
static void check_output (const std::filesystem::path &)
 

Private Attributes

boost::program_options::options_description hidden
 
boost::program_options::options_description helper
 
boost::program_options::options_description common
 
boost::program_options::options_description custom
 
boost::program_options::positional_options_description pos_hide
 
boost::property_tree::ptree pt_conf
 
const std::filesystem::path example
 
std::filesystem::path config_file
 
const std::string tutorial
 
std::string synopsis
 
std::vector< std::string > names
 
std::vector< std::string > configpaths
 
std::optional< unsigned > registered
 
Stage stage
 
int params
 
const std::string m_commit
 
int steer
 
int j
 
int k
 
std::vector< std::filesystem::path > plugin_paths
 
std::vector< std::vector< std::string > > inputExt
 
std::vector< std::vector< std::string > > outputExt
 

Static Private Attributes

static std::filesystem::path prefix
 

Member Enumeration Documentation

◆ Stage [1/2]

enum Stage
private
Enumerator
Input 

first the inputs

Output 

then the outputs (inputs are no longer allowed)

Arg 

then the registered arguments (inputs and outputs no longer allowed)

Args 

finally the remaining arguments / garbage collector (must be very last)

Input 

first the inputs

Output 

then the outputs (inputs are no longer allowed)

Arg 

then the registered arguments (inputs and outputs no longer allowed)

Args 

finally the remaining arguments / garbage collector (must be very last)

151  {
152  Input,
153  Output,
154  Arg,
155  Args
156  };

◆ Stage [2/2]

enum Stage
private
Enumerator
Input 

first the inputs

Output 

then the outputs (inputs are no longer allowed)

Arg 

then the registered arguments (inputs and outputs no longer allowed)

Args 

finally the remaining arguments / garbage collector (must be very last)

Input 

first the inputs

Output 

then the outputs (inputs are no longer allowed)

Arg 

then the registered arguments (inputs and outputs no longer allowed)

Args 

finally the remaining arguments / garbage collector (must be very last)

151  {
152  Input,
153  Output,
154  Arg,
155  Args
156  };

Constructor & Destructor Documentation

◆ Options() [1/4]

Options ( const std::string &  tuto,
int  pars = none,
const char *  commit = DARWIN_GIT_COMMIT,
const char *  example = DARWIN_EXAMPLE 
)

Constructor:

  • contains a parser for the help itself
  • contains a parser for the options, like config file and verbosity
  • and contains a parser for the input, output, and any other option as positional arguments
Parameters
tutodescription, to be displayed in the helper
parsflags for explicit, generic command options (see enum)
commitgit commit for --git
examplepath to example
104  : hidden{"Hidden"}, helper{"Helper"}, common{"Options"}, custom{"Positional options"},
105  example(example ? example : DARWIN "/test/example.info"),
106  tutorial(tuto), stage(Stage::Input), params(pars),
108  steer(0), j(1), k(0)
109 {
110  hidden.add_options()
111  ("prefix,%", po::value<fs::path>(&prefix), "Prefix command, `parallel` or `submit` (for history only)");
112 
113  // first the helper
114  helper.add_options()
115  ("help,h", "Help screen (what you are seeing right now)")
116  ("tutorial,t", "Brief description of the command's purpose")
117  ("git,g", "Commit hash of this executable at compilation time")
118  ("input_ext,i", "Expected extension for input(s) (one line for each input)")
119  ("output_ext,o", "Expected extension for output(s) (one line for each output)");
120  if (params & config) helper.add_options()
121  ("example,e", "Print config example");
122 
123  // then the running options
124  common.add_options()
125  ("verbose,v", po::bool_switch()->default_value(false),
126  "Enable debug mode (typically in slow operations such as the event loop)")
127  ("mute,m", po::bool_switch()->default_value(false)->notifier(set_mute),
128  "Disable standard output stream");
129  if (params & config) common.add_options()
130  ("config,c", po::value<fs::path>(&config_file),
131  "Configuration file in INFO, JSON, or XML format");
132  if (params & split) common.add_options()
133  ("nSplit,j", po::value<int>(&j)->default_value(j), "Number of slices")
134  ("nNow,k" , po::value<int>(&k)->default_value(k), "Index of current slice");
135  if (params & (fill | Friend)) common.add_options()
136  ("fill,f", po::bool_switch()->default_value(false), "Enable `TTree::Fill()`");
137  if (params & Friend) common.add_options()
138  ("Friend,F", po::bool_switch()->default_value(false),
139  "Use `TTree` friends instead of cloning the whole input `TTree`");
140  if (params & syst) common.add_options()
141  ("syst,s", po::bool_switch()->default_value(false),
142  "Enable systematic variations");
143  if (params & plugin) common.add_options()
144  ("plugin,p", po::value<vector<fs::path>>(&plugin_paths)->multitoken()->composing(),
145  "Specify a plugin to run before filling the tree (multiple use is allowed)");
146 
147  // positional arguments should be defined by hand by the user
148  // with the various public members
149 }

◆ Options() [2/4]

Options ( )
delete

No default constructor is allowed.

◆ ~Options() [1/2]

~Options ( )
inline

Destructor.

193 { if (steer & verbose) std::cout << "Options: destroying options" << std::endl; }

◆ Options() [3/4]

Options ( const std::string &  ,
int  = none,
const char *  commit = DARWIN_GIT_COMMIT,
const char *  example = DARWIN_EXAMPLE 
)

Constructor:

  • contains a parser for the help itself
  • contains a parser for the options, like config file and verbosity
  • and contains a parser for the input, output, and any other option as positional arguments
Parameters
commitgit commit for --git
examplepath to example

◆ Options() [4/4]

Options ( )
delete

No default constructor is allowed.

◆ ~Options() [2/2]

~Options ( )
inline

Destructor.

193 { if (steer & verbose) std::cout << "Options: destroying options" << std::endl; }

Member Function Documentation

◆ allow_unregistered() [1/2]

bool allow_unregistered ( ) const
inlineprivate
Returns
true if Options::registered has been initialised.
144 { return bool(registered); }

◆ allow_unregistered() [2/2]

bool allow_unregistered ( ) const
inlineprivate
Returns
true if Options::registered has been initialised.
144 { return bool(registered); }

◆ arg() [1/2]

Options& arg ( const char *  name,
const char *  configpath,
const char *  desc 
)
inline

Member to add an argument. It can be called several times in a row. Each argument may be provided via the configuration file too.

Returns
the object itself, so that the arguments can be given in a row.
Parameters
namename of the option, will be shown in helper
configpathpath in config
descdescription, shown in helper too
237  {
238  if (stage > Stage::Arg)
239  BOOST_THROW_EXCEPTION(std::runtime_error(
240  "Not possible to add another argument at this stage"));
241  stage = Stage::Arg;
242 
243  names.push_back(name);
244  configpaths.push_back(configpath);
245  const boost::program_options::value_semantic * s =
246  boost::program_options::value<T>()->notifier(put<T>(configpath));
247  return set(name, s, desc);
248  }

◆ arg() [2/2]

Options& arg ( const char *  name,
const char *  configpath,
const char *  desc 
)
inline

Member to add an argument. It can be called several times in a row. Each argument may be provided via the configuration file too.

Returns
the object itself, so that the arguments can be given in a row.
Parameters
namename of the option, will be shown in helper
configpathpath in config
descdescription, shown in helper too
237  {
238  if (stage > Stage::Arg)
239  BOOST_THROW_EXCEPTION(std::runtime_error(
240  "Not possible to add another argument at this stage"));
241  stage = Stage::Arg;
242 
243  names.push_back(name);
244  configpaths.push_back(configpath);
245  const boost::program_options::value_semantic * s =
246  boost::program_options::value<T>()->notifier(put<T>(configpath));
247  return set(name, s, desc);
248  }

◆ args() [1/2]

Options& args ( const char *  name,
const char *  configpath,
const char *  desc 
)

Member to collect any addition arguments provided in command line. It should be called maximum once. The additional options will be collected as a list of strings.

Parameters
namegeneric name for unregistered options
configpathpath in config.
descdescription, shown in helper too

◆ args() [2/2]

Options & args ( const char *  name,
const char *  configpath,
const char *  desc 
)

Member to collect any addition arguments provided in command line. It should be called maximum once. The additional options will be collected as a list of strings.

Parameters
namegeneric name for unregistered options
configpathpath in config.
descdescription, shown in helper too
554 {
555  if (stage >= Stage::Args)
556  BOOST_THROW_EXCEPTION(runtime_error("Only one garbage collector is possible"));
557  stage = Stage::Args;
558 
559  synopsis += " [" + string(name) + "...]";
560  configpaths.push_back(configpath);
561 
562  registered = pos_hide.max_total_count();
563  const po::value_semantic * s =
564  po::value<vector<string>>()->multitoken()->zero_tokens();
565  custom.add_options()(name, s, desc);
566  pos_hide.add(name, -1);
567 
568  return *this;
569 }

◆ check_input() [1/2]

void check_input ( const std::filesystem::path &  input)
staticprivate

Function used by Boost Program Options to check if the file does exist, and if yes, if it is readable and readable.

Parameters
inputpath to input
40 {
41  if (!fs::exists(input))
42  BOOST_THROW_EXCEPTION(fs::filesystem_error("Bad input", input,
43  make_error_code(errc::no_such_file_or_directory)));
44 
45  full_cmd += ' ' + fs::canonical(input).string();
46 
47  if ((fs::status(input).permissions() & fs::perms::owner_read) == fs::perms::none)
48  BOOST_THROW_EXCEPTION(fs::filesystem_error("Input exists but cannot be read",
49  input, make_error_code(errc::permission_denied)));
50 }

◆ check_input() [2/2]

static void check_input ( const std::filesystem::path &  )
staticprivate

Function used by Boost Program Options to check if the file does exist, and if yes, if it is readable and readable.

◆ check_output() [1/2]

void check_output ( const std::filesystem::path &  output)
staticprivate

Function used by Boost Program Options to check if the file may already exist, and if yes, then if it is writable, and not a directory. (At this stage, the automatic naming of the output according to the name of the input should not happen. Such a thing should rather be done in the executable directly.)

Parameters
outputpath to output
53 {
54  fs::path outputHist = output;
55  if (!prefix.empty() && !fs::is_directory(output)) outputHist.remove_filename();
56  full_cmd += ' ' + outputHist.string();
57 
58  if (!fs::exists(output)) return;
59 
60  if ((fs::status(output).permissions() & fs::perms::owner_write)
61  == fs::perms::none) {
62  full_cmd.clear();
63  BOOST_THROW_EXCEPTION(fs::filesystem_error(
64  "Output already exists and cannot be overwritten",
65  output, make_error_code(errc::permission_denied)));
66  }
67 
68  if (fs::is_directory(output) && fs::equivalent(output,".")) {
69  full_cmd.clear();
70  BOOST_THROW_EXCEPTION(fs::filesystem_error("Not a valid output",
71  output, make_error_code(errc::invalid_argument)));
72  }
73  else if (output != "/dev/null")
74  cerr << orange << "Warning: you are overwriting " << output << def << '\n';
75 }

◆ check_output() [2/2]

static void check_output ( const std::filesystem::path &  )
staticprivate

Function used by Boost Program Options to check if the file may already exist, and if yes, then if it is writable, and not a directory. (At this stage, the automatic naming of the output according to the name of the input should not happen. Such a thing should rather be done in the executable directly.)

◆ commit() [1/2]

auto commit ( ) const
inline

Git commit information.

292 { return m_commit; }

◆ commit() [2/2]

auto commit ( ) const
inline

Git commit information.

292 { return m_commit; }

◆ exec() [1/2]

std::string exec ( const std::string &  )
private
Returns
output from command given to shell

◆ exec() [2/2]

std::string exec ( const std::string &  cmd)
private
Returns
output from command given to shell
Parameters
cmdcmd to run in the shell
479 {
480  string result;
481  char buffer[128];
482  cerr << red;
483  FILE * pipe = popen(cmd.c_str(), "r");
484  while (!feof(pipe))
485  if (fgets(buffer, 128, pipe) != NULL)
486  result += buffer;
487  pclose(pipe);
488  cerr << def;
489  return result;
490 }

◆ input() [1/2]

Options& input ( const char *  ,
std::filesystem::path *  ,
const char *  ,
const std::vector< std::string > &  = {".root", ".xml"} 
)

expected file extension

Member to add an input. It can be called several times in a row. This option should always be provided from the command line, and never via the config file.

Returns
the object itself, so that the arguments can be given in a row.

◆ input() [2/2]

Options & input ( const char *  name,
std::filesystem::path *  file,
const char *  desc,
const std::vector< std::string > &  ext = {".root", ".xml"} 
)

expected file extension

Member to add an input. It can be called several times in a row. This option should always be provided from the command line, and never via the config file.

Returns
the object itself, so that the arguments can be given in a row.
Parameters
namename of the option, will be shown in helper
filepath pointer to file
descdescription, shown in helper too
467 {
468  if (stage > Stage::Input)
469  BOOST_THROW_EXCEPTION(runtime_error(
470  "Not possible to add another input at this stage"));
471 
472  inputExt.push_back(ext);
473  const po::value_semantic * s =
474  po::value<fs::path>(file)->notifier(check_input)->required();
475  return set(name, s, desc);
476 }

◆ inputs() [1/2]

Options& inputs ( const char *  ,
std::vector< std::filesystem::path > *  ,
const char *  ,
const std::vector< std::string > &  = {".root", ".xml"} 
)

expected file extension

Member to add an undefined amount of input. It can be called only once. This option should always be provided from the command line, and never via the config file. There can be no garbage collector in addition.

Returns
the object itself, so that the arguments can be given in a row.

◆ inputs() [2/2]

Options & inputs ( const char *  name,
std::vector< std::filesystem::path > *  files,
const char *  desc,
const std::vector< std::string > &  ext = {".root", ".xml"} 
)

expected file extension

Member to add an undefined amount of input. It can be called only once. This option should always be provided from the command line, and never via the config file. There can be no garbage collector in addition.

Returns
the object itself, so that the arguments can be given in a row.
Parameters
namename of the options, will be shown in helper
filespaths to files
descdescription, shown in helper too
495 {
496  if (stage > Stage::Input)
497  BOOST_THROW_EXCEPTION(runtime_error(
498  "Not possible to add another input at this stage"));
499 
500  auto store = [files,this](const string& pathRegex) {
501 
502  const string& ls = exec("ls -1d " + pathRegex);
503 
504  vector<fs::path> paths;
505  al::split(paths, ls, al::is_any_of("\n"), al::token_compress_on);
506  for (fs::path const& p: paths) {
507  if (!fs::exists(p)) continue;
508  files->push_back(p);
509  }
510 
511  if (files->empty()) {
512  fs::path p = pathRegex;
513  full_cmd.clear();
514  BOOST_THROW_EXCEPTION(
515  fs::filesystem_error("No input file could be found", p,
516  make_error_code(errc::no_such_file_or_directory)));
517  }
518 
519  auto inputs = accumulate(files->begin(), files->end(), string(),
520  [](string inputs, fs::path input) {
521  return inputs + fs::canonical(input).string() + ' '; });
522  inputs.resize(inputs.size()-1);
523  if (files->size() > 1)
524  inputs = '"' + inputs + '"';
525  full_cmd += ' ' + inputs;
526  };
527 
528  inputExt.push_back(ext);
529  const po::value_semantic * s =
530  po::value<string>()->notifier(store)->required();
531  string full_desc = desc;
532  full_desc += " (use a regular expression, surrounded by quotation marks)";
533  return set(name, s, full_desc.c_str());
534 }

◆ operator()() [1/2]

const boost::property_tree::ptree& operator() ( int  ,
const char * const  [] 
)

Unique parser accessible by the user of the class. It should be directly given argc and argv from the main function.

◆ operator()() [2/2]

const boost::property_tree::ptree & operator() ( int  argc,
const char * const  argv[] 
)

Unique parser accessible by the user of the class. It should be directly given argc and argv from the main function.

419 {
420  pt_conf.clear();
421  full_cmd.clear();
422  prefix.clear();
423  plugin_paths.clear();
424 
425  try {
426  parse_helper(argc, argv);
427  parse_common(argc, argv);
428  parse_custom(argc, argv);
430 
431  if (steer & split && j > 1) full_cmd += " -j " + to_string(j);
432  if (steer & syst ) full_cmd += " -s";
433  if (steer & Friend ) full_cmd += " -F";
434  else if (steer & fill ) full_cmd += " -f";
435 
436  for (fs::path& p: plugin_paths) {
437  if (fs::exists(p))
438  p = fs::canonical(p);
439  // else, at this stage, it is expected to be found via the environment
440  full_cmd += " -p " + p.string();
441  }
442 
443  pt_conf.put<string>("history", full_cmd);
444  }
445  catch (const po::error& e) {
446  BOOST_THROW_EXCEPTION(po::error(e.what()));
447  }
448 
449  return pt_conf;
450 }

◆ output() [1/2]

Options& output ( const char *  ,
std::filesystem::path *  ,
const char *  ,
const std::vector< std::string > &  = {".root", ".xml"} 
)

expected file extension

Member to add an output. It can be called several times in a row. This option should always be provided from the command line, and never via the config file.

Returns
the object itself, so that the arguments can be given in a row.

◆ output() [2/2]

Options & output ( const char *  name,
std::filesystem::path *  file,
const char *  desc,
const std::vector< std::string > &  ext = {".root", ".xml"} 
)

expected file extension

Member to add an output. It can be called several times in a row. This option should always be provided from the command line, and never via the config file.

Returns
the object itself, so that the arguments can be given in a row.
Parameters
namename of the option, will be shown in helper
filepath pointer to file
descdescription, shown in helper too
538 {
539  if (stage > Stage::Output) {
540  full_cmd.clear();
541  BOOST_THROW_EXCEPTION(runtime_error(
542  "Not possible to add another output at this stage"));
543  }
544  stage = Stage::Output;
545 
546  outputExt.push_back(ext);
547  const po::value_semantic * s =
548  po::value<fs::path>(file)->notifier(check_output)->required();
549 
550  return set(name, s, desc);
551 }

◆ parse_common() [1/2]

void parse_common ( int  argc,
const char * const  argv[] 
)
private

Parser for generic options, such as the config (with -c) or slices. It should be directly given argc and argv from the main function.

274 {
275  po::options_description cmd_line;
276  cmd_line.add(common)
277  .add(hidden);
278 
279  po::command_line_parser parser{argc, argv};
280  parser.options(cmd_line)
281  .allow_unregistered();
282 
283  po::variables_map vm;
284  po::store(parser.run(), vm);
285  po::notify(vm);
286 
287  if (vm.count("nSplit")) {
288  auto j = vm["nSplit"].as<int>();
289  if (j <= 0)
290  BOOST_THROW_EXCEPTION(
291  invalid_argument("The number of slices must be larger than 0") );
292 
293  if (vm.count("nNow")) {
294  auto k = vm["nNow"].as<int>();
295  if (k >= j)
296  BOOST_THROW_EXCEPTION(
297  invalid_argument("The slice index must be smaller than the "
298  "number of slices.") );
299  }
300  }
301 
302  if (vm.count("config")) {
303  const string ext = config_file.extension();
304  if (ext == ".json") pt::read_json(config_file.c_str(), pt_conf);
305  else if (ext == ".info") pt::read_info(config_file.c_str(), pt_conf);
306  else if (ext == ".xml" ) {
307  pt::ptree userinfo;
308  pt::read_xml(config_file.c_str(), userinfo);
309  pt_conf = userinfo.get_child("userinfo");
310  }
311  else BOOST_THROW_EXCEPTION(
312  fs::filesystem_error("Extension should be .json, .xml, or .info",
313  config_file, make_error_code(errc::invalid_argument)));
314  }
315 
316  if (params & Friend) params |= fill;
317 
318  if ((params & fill ) && vm["fill" ].as<bool>()) steer |= fill ;
319  if ((params & Friend ) && vm["Friend" ].as<bool>()) steer |= Friend | fill;
320  if ((params & syst ) && vm["syst" ].as<bool>()) steer |= syst ;
321  if ( vm["verbose"].as<bool>()) steer |= verbose;
322 }

◆ parse_common() [2/2]

void parse_common ( int  ,
const char * const  [] 
)
private

Parser for generic options, such as the config (with -c) or slices. It should be directly given argc and argv from the main function.

◆ parse_config() [1/2]

static void parse_config ( boost::property_tree::ptree &  ,
std::string  = "" 
)
static

Parse config if given. This method calls itself to parse the tree structure.

key in config (for recursive call)

◆ parse_config() [2/2]

static void parse_config ( boost::property_tree::ptree &  ,
std::string  = "" 
)
static

Parse config if given. This method calls itself to parse the tree structure.

key in config (for recursive call)

◆ parse_custom() [1/2]

void parse_custom ( int  argc,
const char * const  argv[] 
)
private

Parser for options provided with args(), defined differently in each application. It should be directly given argc and argv from the main function.

325 {
326  po::options_description cmd_line;
327  cmd_line.add(common) // only here to avoid using `allow_unregistered()`
328  .add(hidden) // idem
329  .add(custom);
330 
331  po::command_line_parser parser{argc, argv};
332  parser.options(cmd_line)
333  .positional(pos_hide);
334 
335  po::variables_map vm;
336  po::parsed_options parsed = parser.run();
337  po::store(parsed, vm);
338 
339  // if no config file is given, then options are all required
340  if (!fs::exists(config_file))
341  for (auto& name: names) {
342  if (vm.count(name)) continue;
343  throw po::required_option(name);
344  }
345 
346  if (!prefix.empty())
347  full_cmd = prefix.string() + ' ';
348  full_cmd += argv[0];
349 
350  po::notify(vm); // necessary for config to be given the value from the cmd line
351  // note: `full_cmd` is modified here
352 
353  // first fetch values from config (some may be overwritten later)
354  for (auto& configpath: configpaths) {
355  auto arg = pt_conf.get_optional<string>(configpath);
356  if (!arg) continue;
357  al::erase_all(*arg, "\n");
358  al::erase_all(*arg, " ");
359  al::erase_all(*arg, "\"");
360  if (arg->empty()) continue;
361  full_cmd += ' ' + *arg;
362  }
363 
364  if (allow_unregistered()) { // garbage collector
365 
366  string configpath = configpaths.back();
367  if (!pt_conf.count(configpath))
368  pt_conf.add<string>(configpath, "");
369  auto& subtree = pt_conf.get_child(configpath);
370 
371  for (const auto& [key, value]: subtree) {
372  const auto v = value.get_value<string>();
373  if (key.empty() || key == "item")
374  full_cmd += ' ' + v;
375  else if (v.empty())
376  full_cmd += ' ' + key;
377  }
378 
379  vector<string> items = po::collect_unrecognized(parsed.options,
380  po::include_positional);
381  if (items.size() > *registered) {
382 
383  items.erase(items.begin(), items.begin() + *registered);
384 
385  for (string item: items) {
386  if (subtree.count(item)) continue;
387  // the item may contain special characters, such as a dot
388  // (e.g. in filesystem paths), thus we must make sure that
389  // this stays as it should
390  pt::ptree::path_type p(item, '\0');
391  subtree.put<string>(p, "");
392  full_cmd += ' ' + item;
393  }
394  }
395  } // end of garbage collector
396 
398 }

◆ parse_custom() [2/2]

void parse_custom ( int  ,
const char * const  [] 
)
private

Parser for options provided with args(), defined differently in each application. It should be directly given argc and argv from the main function.

◆ parse_env_var() [1/6]

static std::string parse_env_var ( const char *  p)
inlinestatic

Parse environment variable in C-style string.

274  { return parse_env_var(std::string(p)); }

◆ parse_env_var() [2/6]

static std::string parse_env_var ( const char *  p)
inlinestatic

Parse environment variable in C-style string.

274  { return parse_env_var(std::string(p)); }

◆ parse_env_var() [3/6]

static std::filesystem::path parse_env_var ( const std::filesystem::path &  p)
inlinestatic

Parse environment variable in a path.

279  { return std::filesystem::path(parse_env_var(p.string())); }

◆ parse_env_var() [4/6]

static std::filesystem::path parse_env_var ( const std::filesystem::path &  p)
inlinestatic

Parse environment variable in a path.

279  { return std::filesystem::path(parse_env_var(p.string())); }

◆ parse_env_var() [5/6]

string parse_env_var ( std::string  s)
static

Parse environment variable in string. Adapted from https://codereview.stackexchange.com/questions/172644/c-environment-variable-expansion

Remarks
Curly brackets are needed (e.g. ${VAR}, not just $VAR)
78 {
79  static const regex env_re{R"--(\$\{([^}]+)\})--"};
80  smatch match;
81  while (regex_search(s, match, env_re)) {
82  auto const from = match[0];
83  auto const name = match[1].str();
84  auto const value = getenv(name.c_str());
85  if (!value)
86  BOOST_THROW_EXCEPTION(runtime_error(
87  "Environment variable ${" + name + "} does not exist."));
88  s.replace(from.first, from.second, value);
89  }
90  return s;
91 }

◆ parse_env_var() [6/6]

static std::string parse_env_var ( std::string  )
static

Parse environment variable in string. Adapted from https://codereview.stackexchange.com/questions/172644/c-environment-variable-expansion

Remarks
Curly brackets are needed (e.g. ${VAR}, not just $VAR)

◆ parse_helper() [1/2]

void parse_helper ( int  argc,
const char * const  argv[] 
)
private

First parser that is called. As soon as -h is given, or if the command is run without options, then the helper is shown. It should be directly given argc and argv from the main function.

189 {
190  po::command_line_parser parser{argc, argv};
191  parser.options(helper) // parse only the helper, but no other option at this stage
192  .allow_unregistered(); // ignore unregistered options
193 
194  // defines actions
195  po::variables_map vm;
196  po::store(parser.run(), vm);
197  po::notify(vm); // necessary for config to be given the value from the cmd line
198 
199  if (vm.count("help") || argc == 1) {
200  fs::path executable = argv[0];
201  cout << bold << executable.filename().string() << synopsis << def
202  << "\nwhere";
203  for (const auto& option: custom.options())
204  cout << '\t' << option->long_name()
205  << " = " << option->description() << '\n';
206  }
207 
208  if (vm.count("help")) {
209  po::options_description cmd_line;
210  cmd_line.add(helper)
211  .add(common); // only used to display the helper message,
212  // but not to parse
213  cout << cmd_line << endl;
214  }
215 
216  if (vm.count("tutorial"))
217  cout << wrap_paragraph(tutorial) << '\n'
218  << wrap_paragraph("General remarks: "
219  "unless stated otherwise, all options except the input and output files "
220  "may be given either from the command line or from such a config. Unused "
221  "options in the config are simply ignored. The `flags` should be set at "
222  "the creation of the n-tuples; the `corrections` should be added step "
223  "by step (typically a couple of corrections per executable at most). How "
224  "the config is parsed may change from executable to executable. This "
225  "example uses the Boost INFO format, but JSON and XML formats are also "
226  "possible. It is possible to extract such a config from an existing ROOT "
227  "file by using `getMetaInfo`. Arguments from command line overwrite "
228  "arguments from the config.") << endl;
229 
230  if (vm.count("git"))
231  cout << commit() << endl;
232 
233  if (vm.count("example")) {
234  if (!fs::exists(example))
235  BOOST_THROW_EXCEPTION(
236  fs::filesystem_error("The example could not be found",
237  example, make_error_code(errc::no_such_file_or_directory)));
238  pt::read_info(example, pt_conf);
239 
240  pt::ptree reduced_config;
241  for (auto const& key: configpaths) {
242  auto value = pt_conf.get<string>(key);
243  reduced_config.add<string>(key, value);
244  }
245 
246  stringstream ss;
247  write_info(ss, reduced_config);
248  string str = ss.str();
249  al::erase_all(str, "\"\"");
250  cout << str << flush;
251  }
252 
253  auto space_separate = [](const string& a, const string& b) {
254  return a + ' ' + b;
255  };
256 
257  if (vm.count("input_ext"))
258  for (const vector<string>& ext: inputExt)
259  if (ext.size() > 0)
260  cout << accumulate(next(begin(ext)), end(ext),
261  ext.front(), space_separate) << endl;
262 
263  if (vm.count("output_ext"))
264  for (const vector<string>& ext: outputExt)
265  if (ext.size() > 0)
266  cout << accumulate(next(begin(ext)), end(ext),
267  ext.front(), space_separate) << endl;
268 
269  if (!vm.empty() || argc == 1)
270  exit(EXIT_SUCCESS);
271 }

◆ parse_helper() [2/2]

void parse_helper ( int  ,
const char * const  [] 
)
private

First parser that is called. As soon as -h is given, or if the command is run without options, then the helper is shown. It should be directly given argc and argv from the main function.

◆ plugins() [1/2]

std::vector<std::filesystem::path> plugins ( ) const
inline

Plugins to run in the executable

Todo:
Save in config ptree? (also need to think of reproducibility)
303  {
304  using namespace std;
305  if (!(params & plugin))
306  BOOST_THROW_EXCEPTION( runtime_error("Plugins have not been activated") );
307  return plugin_paths;
308  }

◆ plugins() [2/2]

std::vector<std::filesystem::path> plugins ( ) const
inline

Plugins to run in the executable

Todo:
Save in config ptree? (also need to think of reproducibility)
303  {
304  using namespace std;
305  if (!(params & plugin))
306  BOOST_THROW_EXCEPTION( runtime_error("Plugins have not been activated") );
307  return plugin_paths;
308  }

◆ put() [1/2]

std::function<void(T)> put ( const std::string &  configpath)
inlineprivate

Helper to call boost::property_tree::put in Darwin::Toos::Options::args.

Returns
true if Options::registered has been initialised.
Parameters
configpathpath in config file
136  {
137  return [configpath,this](T value) { pt_conf.put<T>(configpath, value); };
138  }

◆ put() [2/2]

std::function<void(T)> put ( const std::string &  configpath)
inlineprivate

Helper to call boost::property_tree::put in Darwin::Toos::Options::args.

Returns
true if Options::registered has been initialised.
Parameters
configpathpath in config file
136  {
137  return [configpath,this](T value) { pt_conf.put<T>(configpath, value); };
138  }

◆ set() [1/2]

Options& set ( const char *  ,
const boost::program_options::value_semantic *  ,
const char *   
)
private

Generic code to add options. It is called internally by Options::input(), Options::output(), and Options::args().

Returns
the object itself, so that the arguments can be given in a row.

◆ set() [2/2]

Options & set ( const char *  name,
const boost::program_options::value_semantic *  s,
const char *  desc 
)
private

Generic code to add options. It is called internally by Options::input(), Options::output(), and Options::args().

Returns
the object itself, so that the arguments can be given in a row.
Parameters
nameoptions name
shttps://www.boost.org/doc/libs/1_80_0/doc/html/boost/program_options/value_semantic.html
descdescription (for helper)
454 {
455  if (allow_unregistered())
456  BOOST_THROW_EXCEPTION(invalid_argument(
457  "Once `Options::args()` has been called, "
458  "it is no longer possible to add any further options."));
459  synopsis += ' '; synopsis += name;
460  pos_hide.add(name, 1);
461  custom.add_options()(name, s, desc);
462  return *this;
463 }

◆ slice() [1/2]

std::pair<unsigned, unsigned> slice ( ) const
inline

Compactify slice information into a pair.

313  {
314  using namespace std;
315  if (!(params & split))
316  BOOST_THROW_EXCEPTION(invalid_argument("No splitting of the input file."));
317  return make_pair(j,k);
318  }

◆ slice() [2/2]

std::pair<unsigned, unsigned> slice ( ) const
inline

Compactify slice information into a pair.

313  {
314  using namespace std;
315  if (!(params & split))
316  BOOST_THROW_EXCEPTION(invalid_argument("No splitting of the input file."));
317  return make_pair(j,k);
318  }

◆ steering() [1/2]

int steering ( ) const
inline

Steering information for running of executable.

296 { return steer; }

◆ steering() [2/2]

int steering ( ) const
inline

Steering information for running of executable.

296 { return steer; }

Member Data Documentation

◆ common

boost::program_options::options_description common
private

generic + explicit options like --verbose

◆ config_file

std::filesystem::path config_file
private

path to INFO, JSON, or XML config file

◆ configpaths

std::vector< std::string > configpaths
private

path to the options in config (except for I/O)

◆ custom

boost::program_options::options_description custom
private

for positional arguments, depending on the actual command

◆ example

const std::filesystem::path example
private

path to example config

◆ full_cmd

static std::string full_cmd
static

extended version of the command for reproducibility

◆ helper

boost::program_options::options_description helper
private

to display the helper

◆ hidden

boost::program_options::options_description hidden
private

hidden interface (not for lambda user)

◆ inputExt

std::vector< std::vector< std::string > > inputExt
private

expected extensions of input files

◆ j

int j
private

slices

slices

◆ k

int k
private

slice index

◆ m_commit

const std::string m_commit
private

Commit SHA for –git.

◆ names

std::vector< std::string > names
private

names of the different options (shown in synopsis)

◆ outputExt

std::vector< std::vector< std::string > > outputExt
private

expected extensions of output files

◆ params

int params
private

input parameters to interpret explicit options

◆ plugin_paths

std::vector< std::filesystem::path > plugin_paths
private

plugin locations

◆ pos_hide

boost::program_options::positional_options_description pos_hide
private

parser for positional arguments

◆ prefix

static std::filesystem::path prefix
staticprivate

prefix command to steer -j and -k

◆ pt_conf

boost::property_tree::ptree pt_conf
private

internal config obtained from arugments and input config

◆ registered

std::optional< unsigned > registered
private

collect the number of registered options (only if Options::args has been called before)

◆ stage

Stage stage
private

internal stage

◆ steer

int steer
private

output parameters for code executation

◆ synopsis

std::string synopsis
private

stores a clean version of the command, displayed w. -h

◆ tutorial

const std::string tutorial
private

define in constructor, shown with option -t


The documentation for this class was generated from the following files:
DYToLL_M-50_13TeV_pythia8_cff_GEN_SIM_RECOBEFMIX_DIGI_L1_DIGI2RAW_L1Reco_RECO.name
name
Definition: DYToLL_M-50_13TeV_pythia8_cff_GEN_SIM_RECOBEFMIX_DIGI_L1_DIGI2RAW_L1Reco_RECO.py:48
Darwin::Tools::Options::parse_env_var
static std::string parse_env_var(std::string)
Definition: Options.cc:77
Ntupliser_cfg.cerr
cerr
Definition: Ntupliser_cfg.py:105
Darwin::Tools::Options::check_input
static void check_input(const std::filesystem::path &)
Definition: Options.cc:39
Darwin::Tools::Options::k
int k
slice index
Definition: Options.h:165
Darwin::Tools::Options::tutorial
const std::string tutorial
define in constructor, shown with option -t
Definition: Options.h:98
Darwin::Tools::fill
@ fill
activate -f to fill the tree
Definition: Options.h:32
DYToLL_M-50_13TeV_pythia8_cff_GEN_SIM_RECOBEFMIX_DIGI_L1_DIGI2RAW_L1Reco_RECO.options
options
Definition: DYToLL_M-50_13TeV_pythia8_cff_GEN_SIM_RECOBEFMIX_DIGI_L1_DIGI2RAW_L1Reco_RECO.py:41
Darwin::Tools::Options::custom
boost::program_options::options_description custom
for positional arguments, depending on the actual command
Definition: Options.h:70
Darwin::Tools::Options::j
int j
Definition: Options.h:164
Step::def
static const char * def
Definition: Step.h:36
Darwin::Tools::Friend
@ Friend
activate -F to only fill the new branches
Definition: Options.h:33
Ntupliser_cfg.paths
paths
Definition: Ntupliser_cfg.py:369
Darwin::Tools::Options::allow_unregistered
bool allow_unregistered() const
Definition: Options.h:144
Darwin::Tools::Options::inputs
Options & inputs(const char *, std::vector< std::filesystem::path > *, const char *, const std::vector< std::string > &={".root", ".xml"})
expected file extension
Definition: Options.cc:492
Darwin::Tools::split
@ split
activate -k and -j to define slice
Definition: Options.h:31
Darwin::Tools::Options::args
Options & args(const char *name, const char *configpath, const char *desc)
Definition: Options.cc:553
Ntupliser_cfg.p
p
Definition: Ntupliser_cfg.py:178
Darwin::Tools::Options::check_output
static void check_output(const std::filesystem::path &)
Definition: Options.cc:52
Darwin::Tools::Options::Input
@ Input
first the inputs
Definition: Options.h:152
Darwin::Tools::Options::hidden
boost::program_options::options_description hidden
hidden interface (not for lambda user)
Definition: Options.h:67
Darwin::Tools::syst
@ syst
activate -s to systematic uncertainties
Definition: Options.h:34
jercExample.key
string key
Definition: jercExample.py:109
Darwin::Tools::none
@ none
default (for simple executables)
Definition: Options.h:28
compareFiles.files
files
Definition: compareFiles.py:125
Darwin::Tools::Options::synopsis
std::string synopsis
stores a clean version of the command, displayed w. -h
Definition: Options.h:99
Darwin::Tools::Options::pos_hide
boost::program_options::positional_options_description pos_hide
parser for positional arguments
Definition: Options.h:72
Darwin::Tools::Options::parse_config
static void parse_config(boost::property_tree::ptree &, std::string="")
Parse config if given. This method calls itself to parse the tree structure.
Darwin::Tools::plugin
@ plugin
activate -p to run a plugin
Definition: Options.h:35
Darwin::Tools::Options::steer
int steer
output parameters for code executation
Definition: Options.h:162
Darwin::Tools::Options::commit
auto commit() const
Git commit information.
Definition: Options.h:292
Darwin::Tools::Options::Output
@ Output
then the outputs (inputs are no longer allowed)
Definition: Options.h:153
Darwin::Tools::Options::parse_common
void parse_common(int, const char *const [])
Definition: Options.cc:273
prefix
Definition: prefix.py:1
Darwin::Tools::Options::parse_helper
void parse_helper(int, const char *const [])
Definition: Options.cc:188
Step::red
static const char * red
Definition: Step.h:34
cmd
cmd
Definition: Core-cfgcmd.txt:1
Darwin::Tools::Options::names
std::vector< std::string > names
names of the different options (shown in synopsis)
Definition: Options.h:101
Darwin::Tools::Options::inputExt
std::vector< std::vector< std::string > > inputExt
expected extensions of input files
Definition: Options.h:170
Darwin::Tools::verbose
@ verbose
bit for debug mode (-v is always available)
Definition: Options.h:29
Ntupliser_cfg.config
config
Definition: Ntupliser_cfg.py:330
orange
static const char * orange
Definition: colours.h:6
Darwin::Tools::Options::set
Options & set(const char *, const boost::program_options::value_semantic *, const char *)
Definition: Options.cc:452
Darwin::Tools::Options
Common class to interpret the command line, based on Boost Program Options.
Definition: Options.h:63
wrap_paragraph
string wrap_paragraph(const string &text)
Definition: Options.cc:154
Darwin::Tools::Options::Args
@ Args
finally the remaining arguments / garbage collector (must be very last)
Definition: Options.h:155
Darwin::Tools::Options::arg
Options & arg(const char *name, const char *configpath, const char *desc)
Definition: Options.h:233
Darwin::Tools::Options::stage
Stage stage
internal stage
Definition: Options.h:158
DARWIN_VERSION
#define DARWIN_VERSION
Definition: version.h:1
Darwin::Tools
Classes and functions related to the framework.
Definition: Darwin_dict.cxx:1144
Darwin::Tools::Options::registered
std::optional< unsigned > registered
collect the number of registered options (only if Options::args has been called before)
Definition: Options.h:140
Darwin::Tools::Options::m_commit
const std::string m_commit
Commit SHA for –git.
Definition: Options.h:161
Darwin::Tools::Options::helper
boost::program_options::options_description helper
to display the helper
Definition: Options.h:68
Darwin::Tools::Options::parse_custom
void parse_custom(int, const char *const [])
Definition: Options.cc:324
Darwin::Tools::Options::config_file
std::filesystem::path config_file
path to INFO, JSON, or XML config file
Definition: Options.h:95
Darwin::Tools::Options::outputExt
std::vector< std::vector< std::string > > outputExt
expected extensions of output files
Definition: Options.h:171
Darwin::Tools::Options::output
Options & output(const char *, std::filesystem::path *, const char *, const std::vector< std::string > &={".root", ".xml"})
expected file extension
Definition: Options.cc:536
compareFiles.parser
parser
Definition: compareFiles.py:118
Darwin::Tools::Options::input
Options & input(const char *, std::filesystem::path *, const char *, const std::vector< std::string > &={".root", ".xml"})
expected file extension
Definition: Options.cc:465
DAS::Options
Darwin::Tools::Options Options(const char *, int=Darwin::Tools::none)
Constructs Darwin options with the correct commit information.
Definition: DASOptions.cc:14
DAS::Normalisation::match
DAS::FourVector match(const DAS::FourVector &jet, const std::vector< DAS::FourVector > *hltJets)
Definition: match.h:7
set_mute
void set_mute(bool flag)
Function used by Boost::PO to disable standard error.
Definition: Options.cc:95
Darwin::Tools::Options::exec
std::string exec(const std::string &)
Definition: Options.cc:478
Darwin::Tools::Options::Arg
@ Arg
then the registered arguments (inputs and outputs no longer allowed)
Definition: Options.h:154
Darwin::Tools::Options::plugin_paths
std::vector< std::filesystem::path > plugin_paths
plugin locations
Definition: Options.h:167
Darwin::Tools::Options::params
int params
input parameters to interpret explicit options
Definition: Options.h:160
Darwin::Tools::Options::configpaths
std::vector< std::string > configpaths
path to the options in config (except for I/O)
Definition: Options.h:102
Darwin::Tools::Options::full_cmd
static std::string full_cmd
extended version of the command for reproducibility
Definition: Options.h:288
Darwin::Tools::config
@ config
activate -c option to provide config file
Definition: Options.h:30
Darwin::Tools::Options::pt_conf
boost::property_tree::ptree pt_conf
internal config obtained from arugments and input config
Definition: Options.h:74
Darwin::Tools::Options::common
boost::program_options::options_description common
generic + explicit options like --verbose
Definition: Options.h:69
Darwin::Tools::Options::example
const std::filesystem::path example
path to example config
Definition: Options.h:76
Step::bold
static const char * bold
Definition: Step.h:35