Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:12:08

0001 #include "FWCore/Framework/interface/CmsRunParser.h"
0002 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0003 #include "FWCore/Utilities/interface/EDMException.h"
0004 
0005 #include <vector>
0006 #include <string>
0007 #include <iostream>
0008 
0009 namespace {
0010   //additional_parser is documented at https://www.boost.org/doc/libs/1_83_0/doc/html/program_options/howto.html#id-1.3.30.6.3
0011   //extra_style_parser was added in https://www.boost.org/users/history/version_1_33_0.html
0012   //it allows performing a fully custom processing on whatever arguments have not yet been processed
0013   //the function is responsible for removing processed arguments from the input vector
0014   //and assembling the return value, which is a vector of boost's option type
0015   //some usage examples: https://stackoverflow.com/a/5481228, https://stackoverflow.com/a/37993517
0016   //internally, when cmdline::run() is called, the function given to extra_style_parser is added to the beginning of list of parsers
0017   //all parsers are called in order until args is empty (validity of non-empty output is checked after each parser)
0018   std::vector<boost::program_options::option> final_opts_parser(std::vector<std::string>& args) {
0019     std::vector<boost::program_options::option> result;
0020     std::string configName;
0021     if (!args.empty() and !args[0].empty()) {
0022       if (args[0][0] != '-') {  // name is first positional arg -> doesn't start with '-'
0023         configName = args[0];
0024         args.erase(args.begin());
0025       } else if (args[0] == "--" and args.size() > 1) {  // name can start with '-' if separator comes first
0026         configName = args[1];
0027         args.erase(args.begin(), args.begin() + 2);
0028       }
0029     }
0030     if (!configName.empty()) {
0031       result.emplace_back(edm::CmsRunParser::kParameterSetOpt, std::vector<std::string>(1, configName));
0032       result.emplace_back();
0033       auto& pythonOpts = result.back();
0034       pythonOpts.string_key = edm::CmsRunParser::kPythonOpt;
0035       pythonOpts.value.reserve(args.size());
0036       pythonOpts.original_tokens.reserve(args.size());
0037       for (const auto& arg : args) {
0038         pythonOpts.value.push_back(arg);
0039         pythonOpts.original_tokens.push_back(arg);
0040       }
0041       //default value to avoid "is missing" error
0042       if (pythonOpts.value.empty()) {
0043         pythonOpts.value.push_back(edm::CmsRunParser::kPythonOptDefault);
0044         pythonOpts.original_tokens.push_back("");
0045       }
0046       args.clear();
0047     }
0048     return result;
0049   }
0050 }  // namespace
0051 
0052 namespace edm {
0053   CmsRunParser::CmsRunParser(const char* name)
0054       : desc_(std::string(name) + " [options] [--] config_file [python options]\nAllowed options"),
0055         all_options_("All Options") {
0056     // clang-format off
0057       desc_.add_options()(kHelpCommandOpt, "produce help message")(
0058           kJobreportCommandOpt,
0059           boost::program_options::value<std::string>(),
0060           "file name to use for a job report file: default extension is .xml")(
0061           kEnableJobreportCommandOpt, "enable job report files (if any) specified in configuration file")(
0062           kJobModeCommandOpt,
0063           boost::program_options::value<std::string>(),
0064           "Job Mode for MessageLogger defaults - default mode is grid")(
0065           kNumberOfThreadsCommandOpt,
0066           boost::program_options::value<unsigned int>(),
0067           "Number of threads to use in job (0 is use all CPUs)")(
0068           kSizeOfStackForThreadCommandOpt,
0069           boost::program_options::value<unsigned int>(),
0070           "Size of stack in KB to use for extra threads (0 is use system default size)")(kStrictOpt, "strict parsing")(
0071           kCmdCommandOpt, boost::program_options::value<std::string>(), "config passed in as string (cannot be used with config_file)");
0072     // clang-format on
0073 
0074     // anything at the end will be ignored, and sent to python
0075     pos_options_.add(kParameterSetOpt, 1).add(kPythonOpt, -1);
0076 
0077     // This --fwk option is not used anymore, but I'm leaving it around as
0078     // it might be useful again in the future for code development
0079     // purposes.  We originally used it when implementing the boost
0080     // state machine code.
0081     boost::program_options::options_description hidden("hidden options");
0082     hidden.add_options()("fwk", "For use only by Framework Developers")(
0083         kParameterSetOpt, boost::program_options::value<std::string>(), "configuration file")(
0084         kPythonOpt,
0085         boost::program_options::value<std::vector<std::string>>(),
0086         "options at the end to be passed to python");
0087 
0088     all_options_.add(desc_).add(hidden);
0089   }
0090   CmsRunParser::MapOrExit CmsRunParser::parse(int argc, const char* argv[]) const {
0091     boost::program_options::variables_map vm;
0092     try {
0093       store(boost::program_options::command_line_parser(argc, argv)
0094                 .extra_style_parser(final_opts_parser)
0095                 .options(all_options_)
0096                 .positional(pos_options_)
0097                 .run(),
0098             vm);
0099       notify(vm);
0100     } catch (boost::program_options::error const& iException) {
0101       edm::LogAbsolute("CommandLineProcessing")
0102           << "cmsRun: Error while trying to process command line arguments:\n"
0103           << iException.what() << "\nFor usage and an options list, please do 'cmsRun --help'.";
0104       return MapOrExit(edm::errors::CommandLineProcessing);
0105     }
0106 
0107     if (vm.count(kHelpOpt)) {
0108       std::cout << desc_ << std::endl;
0109       edm::HaltMessageLogging();
0110       return MapOrExit(0);
0111     }
0112 
0113     //special handling of python options
0114     if (vm.count(kPythonOpt)) {
0115       const auto& pythonOptValues = vm[kPythonOpt].as<std::vector<std::string>>();
0116       //omit default arg
0117       if (pythonOptValues.size() == 1 and pythonOptValues[0] == kPythonOptDefault)
0118         vm.erase(kPythonOpt);
0119     }
0120 
0121     return MapOrExit(vm);
0122   }
0123 }  // namespace edm