// -*- C++ -*- // // This file was generated by CLI, a command line interface // compiler for C++. // // Begin prologue. // #include // // End prologue. #include #include #include #include #include #include #include #include #include namespace bbot { namespace cli { template struct parser { static void parse (X& x, bool& xs, scanner& s) { using namespace std; const char* o (s.next ()); if (s.more ()) { string v (s.next ()); istringstream is (v); if (!(is >> x && is.peek () == istringstream::traits_type::eof ())) throw invalid_value (o, v); } else throw missing_value (o); xs = true; } }; template <> struct parser { static void parse (bool& x, bool& xs, scanner& s) { const char* o (s.next ()); if (s.more ()) { const char* v (s.next ()); if (std::strcmp (v, "1") == 0 || std::strcmp (v, "true") == 0 || std::strcmp (v, "TRUE") == 0 || std::strcmp (v, "True") == 0) x = true; else if (std::strcmp (v, "0") == 0 || std::strcmp (v, "false") == 0 || std::strcmp (v, "FALSE") == 0 || std::strcmp (v, "False") == 0) x = false; else throw invalid_value (o, v); } else throw missing_value (o); xs = true; } }; template <> struct parser { static void parse (std::string& x, bool& xs, scanner& s) { const char* o (s.next ()); if (s.more ()) x = s.next (); else throw missing_value (o); xs = true; } }; template struct parser > { static void parse (std::pair& x, bool& xs, scanner& s) { x.second = s.position (); parser::parse (x.first, xs, s); } }; template struct parser > { static void parse (std::vector& c, bool& xs, scanner& s) { X x; bool dummy; parser::parse (x, dummy, s); c.push_back (x); xs = true; } }; template struct parser > { static void parse (std::set& c, bool& xs, scanner& s) { X x; bool dummy; parser::parse (x, dummy, s); c.insert (x); xs = true; } }; template struct parser > { static void parse (std::map& m, bool& xs, scanner& s) { const char* o (s.next ()); if (s.more ()) { std::size_t pos (s.position ()); std::string ov (s.next ()); std::string::size_type p = ov.find ('='); K k = K (); V v = V (); std::string kstr (ov, 0, p); std::string vstr (ov, (p != std::string::npos ? p + 1 : ov.size ())); int ac (2); char* av[] = { const_cast (o), 0 }; bool dummy; if (!kstr.empty ()) { av[1] = const_cast (kstr.c_str ()); argv_scanner s (0, ac, av, false, pos); parser::parse (k, dummy, s); } if (!vstr.empty ()) { av[1] = const_cast (vstr.c_str ()); argv_scanner s (0, ac, av, false, pos); parser::parse (v, dummy, s); } m[k] = v; } else throw missing_value (o); xs = true; } }; template struct parser > { static void parse (std::multimap& m, bool& xs, scanner& s) { const char* o (s.next ()); if (s.more ()) { std::size_t pos (s.position ()); std::string ov (s.next ()); std::string::size_type p = ov.find ('='); K k = K (); V v = V (); std::string kstr (ov, 0, p); std::string vstr (ov, (p != std::string::npos ? p + 1 : ov.size ())); int ac (2); char* av[] = { const_cast (o), 0 }; bool dummy; if (!kstr.empty ()) { av[1] = const_cast (kstr.c_str ()); argv_scanner s (0, ac, av, false, pos); parser::parse (k, dummy, s); } if (!vstr.empty ()) { av[1] = const_cast (vstr.c_str ()); argv_scanner s (0, ac, av, false, pos); parser::parse (v, dummy, s); } m.insert (typename std::multimap::value_type (k, v)); } else throw missing_value (o); xs = true; } }; template void thunk (X& x, scanner& s) { parser::parse (x.*M, s); } template void thunk (X& x, scanner& s) { s.next (); x.*M = true; } template void thunk (X& x, scanner& s) { parser::parse (x.*M, x.*S, s); } } } #include namespace bbot { // agent_options // agent_options:: agent_options () : help_ (), version_ (), verbose_ (1), verbose_specified_ (false), systemd_daemon_ (), toolchain_name_ ("default"), toolchain_name_specified_ (false), toolchain_num_ (1), toolchain_num_specified_ (false), toolchain_lock_ (), toolchain_lock_specified_ (false), toolchain_ver_ (), toolchain_ver_specified_ (false), toolchain_id_ (), toolchain_id_specified_ (false), interactive_ (interactive_mode::false_), interactive_specified_ (false), instance_ (1), instance_specified_ (false), instance_max_ (0), instance_max_specified_ (false), cpu_ (1), cpu_specified_ (false), ram_ (1024 * 1024), ram_specified_ (false), bridge_ ("br1"), bridge_specified_ (false), auth_key_ (), auth_key_specified_ (false), trust_ (), trust_specified_ (false), machines_ ("/build/machines/"), machines_specified_ (false), tftp_ ("/build/tftp/"), tftp_specified_ (false), tftp_port_ (23400), tftp_port_specified_ (false), bootstrap_startup_ (300), bootstrap_startup_specified_ (false), bootstrap_timeout_ (3600), bootstrap_timeout_specified_ (false), bootstrap_retries_ (2), bootstrap_retries_specified_ (false), build_startup_ (240), build_startup_specified_ (false), build_timeout_ (5400), build_timeout_specified_ (false), build_retries_ (2), build_retries_specified_ (false), intactive_timeout_ (10800), intactive_timeout_specified_ (false), connect_timeout_ (60), connect_timeout_specified_ (false), request_timeout_ (300), request_timeout_specified_ (false), request_retries_ (4), request_retries_specified_ (false), openssl_ ("openssl"), openssl_specified_ (false), openssl_option_ (), openssl_option_specified_ (false), dump_machines_ (), dump_task_ (), dump_result_ (), fake_bootstrap_ (), fake_build_ (), fake_machine_ (), fake_machine_specified_ (false), fake_request_ (), fake_request_specified_ (false) { } bool agent_options:: parse (int& argc, char** argv, bool erase, ::bbot::cli::unknown_mode opt, ::bbot::cli::unknown_mode arg) { ::bbot::cli::argv_scanner s (argc, argv, erase); bool r = _parse (s, opt, arg); return r; } bool agent_options:: parse (int start, int& argc, char** argv, bool erase, ::bbot::cli::unknown_mode opt, ::bbot::cli::unknown_mode arg) { ::bbot::cli::argv_scanner s (start, argc, argv, erase); bool r = _parse (s, opt, arg); return r; } bool agent_options:: parse (int& argc, char** argv, int& end, bool erase, ::bbot::cli::unknown_mode opt, ::bbot::cli::unknown_mode arg) { ::bbot::cli::argv_scanner s (argc, argv, erase); bool r = _parse (s, opt, arg); end = s.end (); return r; } bool agent_options:: parse (int start, int& argc, char** argv, int& end, bool erase, ::bbot::cli::unknown_mode opt, ::bbot::cli::unknown_mode arg) { ::bbot::cli::argv_scanner s (start, argc, argv, erase); bool r = _parse (s, opt, arg); end = s.end (); return r; } bool agent_options:: parse (::bbot::cli::scanner& s, ::bbot::cli::unknown_mode opt, ::bbot::cli::unknown_mode arg) { bool r = _parse (s, opt, arg); return r; } ::bbot::cli::usage_para agent_options:: print_usage (::std::ostream& os, ::bbot::cli::usage_para p) { CLI_POTENTIALLY_UNUSED (os); if (p != ::bbot::cli::usage_para::none) os << ::std::endl; os << "\033[1mOPTIONS\033[0m" << ::std::endl; os << std::endl << "\033[1m--help\033[0m Print usage information and exit." << ::std::endl; os << std::endl << "\033[1m--version\033[0m Print version and exit." << ::std::endl; os << std::endl << "\033[1m--verbose\033[0m \033[4mlevel\033[0m Set the diagnostics verbosity to \033[4mlevel\033[0m between 0 and 6" << ::std::endl << " with level 1 being the default." << ::std::endl; os << std::endl << "\033[1m--systemd-daemon\033[0m Run as a simple systemd daemon." << ::std::endl; os << std::endl << "\033[1m--toolchain-name\033[0m \033[4mstr\033[0m Toolchain name, \033[1mdefault\033[0m by default." << ::std::endl; os << std::endl << "\033[1m--toolchain-num\033[0m \033[4mnum\033[0m Toolchain number, 1 by default. If agents are running" << ::std::endl << " for several toolchains, then each of them should have a" << ::std::endl << " unique toolchain number between 1 and 99. This number" << ::std::endl << " is used as an offset for network ports, interfaces," << ::std::endl << " etc." << ::std::endl; os << std::endl << "\033[1m--toolchain-lock\033[0m \033[4mpath\033[0m Absolute path to the global toolchain lock file. If" << ::std::endl << " unspecified, then" << ::std::endl << " \033[1m/var/lock/bbot-agent-\033[0m\033[4mtoolchain-name\033[0m\033[1m.lock\033[0m\033[0m is used by" << ::std::endl << " default. If empty path is specified then no global" << ::std::endl << " locking is performed. If one of the \033[1m--fake-*\033[0m options is" << ::std::endl << " specified, then no locking is performed by default." << ::std::endl; os << std::endl << "\033[1m--toolchain-ver\033[0m \033[4mstdver\033[0m Toolchain version. If unspecified, then the agent's" << ::std::endl << " version will be used (which will be imprecise for" << ::std::endl << " snapshot versions)." << ::std::endl; os << std::endl << "\033[1m--toolchain-id\033[0m \033[4mstr\033[0m Toolchain id. If unspecified or empty, then no" << ::std::endl << " re-bootstrapping on toolchain changes will be performed" << ::std::endl << " (which is primarily useful for testing)." << ::std::endl; os << std::endl << "\033[1m--interactive\033[0m \033[4mmode\033[0m Interactive build support. Valid values for this option" << ::std::endl << " are \033[1mfalse\033[0m (only non-interactive), \033[1mtrue\033[0m (only" << ::std::endl << " interactive), and \033[1mboth\033[0m. If this option is not" << ::std::endl << " specified, then only non-interactive builds are" << ::std::endl << " supported." << ::std::endl; os << std::endl << "\033[1m--instance\033[0m \033[4mnum\033[0m Instance number, 1 by default. If several instances of" << ::std::endl << " an agent are running for the same toolchain, then each" << ::std::endl << " of them should have a unique instance number between 1" << ::std::endl << " and 99. This number is used as an offset for network" << ::std::endl << " ports, interfaces, etc." << ::std::endl; os << std::endl << "\033[1m--instance-max\033[0m \033[4mnum\033[0m Maximum number of instances that can perform tasks" << ::std::endl << " concurrently. If the number of instances that have been" << ::std::endl << " started is greater than this number (normally by just" << ::std::endl << " one), then when the maximum number of tasks is already" << ::std::endl << " being performed, the extra instances operate in the" << ::std::endl << " \033[4mpriority monitor\033[0m mode: they only query controller URLs" << ::std::endl << " with priorities higher than of the existing tasks and" << ::std::endl << " can only perform a task by interrupting one of them. If" << ::std::endl << " the maximum number of instances is \033[1m0\033[0m (default), then it" << ::std::endl << " is assumed the number of instances started is the" << ::std::endl << " maximum number, essentially disabling the priority" << ::std::endl << " monitor functionality." << ::std::endl; os << std::endl << "\033[1m--cpu\033[0m \033[4mnum\033[0m Number of CPUs (threads) to use, 1 by default." << ::std::endl; os << std::endl << "\033[1m--ram\033[0m \033[4mnum\033[0m Amount of RAM (in kB) to use, 1G by default." << ::std::endl; os << std::endl << "\033[1m--bridge\033[0m \033[4miface\033[0m Bridge interface to use for machine networking, \033[1mbr1\033[0m by" << ::std::endl << " default." << ::std::endl; os << std::endl << "\033[1m--auth-key\033[0m \033[4mfile\033[0m Private key for the public key-based agent" << ::std::endl << " authentication. If not specified, then the agent will" << ::std::endl << " not be able to request tasks from controllers that" << ::std::endl << " require authentication." << ::std::endl << ::std::endl << " The file is expected to contain a single PEM-encoded" << ::std::endl << " private key without a password. A suitable key can be" << ::std::endl << " generated using the following command:" << ::std::endl << ::std::endl << " $ openssl genrsa 4096 >key.pem" << ::std::endl; os << std::endl << "\033[1m--trust\033[0m \033[4mfingerprint\033[0m Trust repository certificate with a SHA256 \033[4mfingerprint\033[0m." << ::std::endl; os << std::endl << "\033[1m--machines\033[0m \033[4mdir\033[0m The location of the build machines, \033[1m/build/machines/\033[0m by" << ::std::endl << " default." << ::std::endl; os << std::endl << "\033[1m--tftp\033[0m \033[4mdir\033[0m The location of the TFTP server root, \033[1m/build/tftp/\033[0m by" << ::std::endl << " default." << ::std::endl; os << std::endl << "\033[1m--tftp-port\033[0m \033[4mnum\033[0m TFTP server port base, 23400 by default. The actual" << ::std::endl << " port is calculated by adding an offset calculated based" << ::std::endl << " on the toolchain and instance numbers." << ::std::endl; os << std::endl << "\033[1m--bootstrap-startup\033[0m \033[4msec\033[0m Maximum number of seconds to wait for machine bootstrap" << ::std::endl << " startup, 300 (5 minutes) by default." << ::std::endl; os << std::endl << "\033[1m--bootstrap-timeout\033[0m \033[4msec\033[0m Maximum number of seconds to wait for machine bootstrap" << ::std::endl << " completion, 3600 (60 minutes) by default." << ::std::endl; os << std::endl << "\033[1m--bootstrap-retries\033[0m \033[4mnum\033[0m Number of times to retry a mis-booted bootstrap, 2 (3" << ::std::endl << " attempts total) by default." << ::std::endl; os << std::endl << "\033[1m--build-startup\033[0m \033[4msec\033[0m Maximum number of seconds to wait for build startup," << ::std::endl << " 240 (4 minutes) by default." << ::std::endl; os << std::endl << "\033[1m--build-timeout\033[0m \033[4msec\033[0m Maximum number of seconds to wait for build completion," << ::std::endl << " 5400 (90 minutes) by default." << ::std::endl; os << std::endl << "\033[1m--build-retries\033[0m \033[4mnum\033[0m Number of times to retry a mis-booted build, 2 (3" << ::std::endl << " attempts total) by default." << ::std::endl; os << std::endl << "\033[1m--intactive-timeout\033[0m \033[4msec\033[0m Maximum number of seconds to wait for interactive build" << ::std::endl << " completion, 10800 (3 hours) by default." << ::std::endl; os << std::endl << "\033[1m--connect-timeout\033[0m \033[4msec\033[0m Maximum number of seconds to wait for controller" << ::std::endl << " request connection, 60 (1 minute) by default." << ::std::endl; os << std::endl << "\033[1m--request-timeout\033[0m \033[4msec\033[0m Maximum number of seconds to wait for controller" << ::std::endl << " request completion, 300 (5 minutes) by default." << ::std::endl; os << std::endl << "\033[1m--request-retries\033[0m \033[4mnum\033[0m Number of times to retry a controller request, 4 (5" << ::std::endl << " attempts total) by default. Note that both the total" << ::std::endl << " time for all retries as well as the time of each retry" << ::std::endl << " are limited by the same --request-timeout\033[0m value. This" << ::std::endl << " means that a successful request may take up to twice as" << ::std::endl << " long if a connection was established at the end of the" << ::std::endl << " retry window and took just as long to complete." << ::std::endl; os << std::endl << "\033[1m--openssl\033[0m \033[4mpath\033[0m The openssl program to be used for crypto operations." << ::std::endl << " You can also specify additional options that should be" << ::std::endl << " passed to the openssl program with \033[1m--openssl-option\033[0m. If" << ::std::endl << " the openssl program is not explicitly specified, then" << ::std::endl << " \033[1mbbot-agent\033[0m will use \033[1mopenssl\033[0m by default." << ::std::endl; os << std::endl << "\033[1m--openssl-option\033[0m \033[4mopt\033[0m Additional option to be passed to the openssl program" << ::std::endl << " (see \033[1m--openssl\033[0m for details). Repeat this option to" << ::std::endl << " specify multiple openssl options." << ::std::endl; os << std::endl << "\033[1m--dump-machines\033[0m Dump the available machines to \033[1mstdout\033[0m," << ::std::endl << " (re)-bootstrapping any if necessary, and exit." << ::std::endl; os << std::endl << "\033[1m--dump-task\033[0m Dump the received build task to \033[1mstdout\033[0m and exit." << ::std::endl; os << std::endl << "\033[1m--dump-result\033[0m Dump the obtained build result to \033[1mstdout\033[0m and exit." << ::std::endl; os << std::endl << "\033[1m--fake-bootstrap\033[0m Fake the machine bootstrap process by creating the" << ::std::endl << " expected bootstrapped machine manifest." << ::std::endl; os << std::endl << "\033[1m--fake-build\033[0m Fake the package building process by creating the" << ::std::endl << " aborted build result." << ::std::endl; os << std::endl << "\033[1m--fake-machine\033[0m \033[4mfile\033[0m Fake the machine enumeration process by reading the" << ::std::endl << " machine header manifest from \033[4mfile\033[0m (or \033[1mstdin\033[0m if \033[4mfile\033[0m is" << ::std::endl << " '\033[1m-\033[0m')." << ::std::endl; os << std::endl << "\033[1m--fake-request\033[0m \033[4mfile\033[0m Fake the task request process by reading the task" << ::std::endl << " manifest from \033[4mfile\033[0m (or \033[1mstdin\033[0m if \033[4mfile\033[0m is '\033[1m-\033[0m')." << ::std::endl; p = ::bbot::cli::usage_para::option; return p; } typedef std::map _cli_agent_options_map; static _cli_agent_options_map _cli_agent_options_map_; struct _cli_agent_options_map_init { _cli_agent_options_map_init () { _cli_agent_options_map_["--help"] = &::bbot::cli::thunk< agent_options, &agent_options::help_ >; _cli_agent_options_map_["--version"] = &::bbot::cli::thunk< agent_options, &agent_options::version_ >; _cli_agent_options_map_["--verbose"] = &::bbot::cli::thunk< agent_options, uint16_t, &agent_options::verbose_, &agent_options::verbose_specified_ >; _cli_agent_options_map_["--systemd-daemon"] = &::bbot::cli::thunk< agent_options, &agent_options::systemd_daemon_ >; _cli_agent_options_map_["--toolchain-name"] = &::bbot::cli::thunk< agent_options, string, &agent_options::toolchain_name_, &agent_options::toolchain_name_specified_ >; _cli_agent_options_map_["--toolchain-num"] = &::bbot::cli::thunk< agent_options, uint16_t, &agent_options::toolchain_num_, &agent_options::toolchain_num_specified_ >; _cli_agent_options_map_["--toolchain-lock"] = &::bbot::cli::thunk< agent_options, string, &agent_options::toolchain_lock_, &agent_options::toolchain_lock_specified_ >; _cli_agent_options_map_["--toolchain-ver"] = &::bbot::cli::thunk< agent_options, standard_version, &agent_options::toolchain_ver_, &agent_options::toolchain_ver_specified_ >; _cli_agent_options_map_["--toolchain-id"] = &::bbot::cli::thunk< agent_options, string, &agent_options::toolchain_id_, &agent_options::toolchain_id_specified_ >; _cli_agent_options_map_["--interactive"] = &::bbot::cli::thunk< agent_options, interactive_mode, &agent_options::interactive_, &agent_options::interactive_specified_ >; _cli_agent_options_map_["--instance"] = &::bbot::cli::thunk< agent_options, uint16_t, &agent_options::instance_, &agent_options::instance_specified_ >; _cli_agent_options_map_["--instance-max"] = &::bbot::cli::thunk< agent_options, uint16_t, &agent_options::instance_max_, &agent_options::instance_max_specified_ >; _cli_agent_options_map_["--cpu"] = &::bbot::cli::thunk< agent_options, size_t, &agent_options::cpu_, &agent_options::cpu_specified_ >; _cli_agent_options_map_["--ram"] = &::bbot::cli::thunk< agent_options, size_t, &agent_options::ram_, &agent_options::ram_specified_ >; _cli_agent_options_map_["--bridge"] = &::bbot::cli::thunk< agent_options, string, &agent_options::bridge_, &agent_options::bridge_specified_ >; _cli_agent_options_map_["--auth-key"] = &::bbot::cli::thunk< agent_options, path, &agent_options::auth_key_, &agent_options::auth_key_specified_ >; _cli_agent_options_map_["--trust"] = &::bbot::cli::thunk< agent_options, strings, &agent_options::trust_, &agent_options::trust_specified_ >; _cli_agent_options_map_["--machines"] = &::bbot::cli::thunk< agent_options, dir_path, &agent_options::machines_, &agent_options::machines_specified_ >; _cli_agent_options_map_["--tftp"] = &::bbot::cli::thunk< agent_options, dir_path, &agent_options::tftp_, &agent_options::tftp_specified_ >; _cli_agent_options_map_["--tftp-port"] = &::bbot::cli::thunk< agent_options, uint16_t, &agent_options::tftp_port_, &agent_options::tftp_port_specified_ >; _cli_agent_options_map_["--bootstrap-startup"] = &::bbot::cli::thunk< agent_options, size_t, &agent_options::bootstrap_startup_, &agent_options::bootstrap_startup_specified_ >; _cli_agent_options_map_["--bootstrap-timeout"] = &::bbot::cli::thunk< agent_options, size_t, &agent_options::bootstrap_timeout_, &agent_options::bootstrap_timeout_specified_ >; _cli_agent_options_map_["--bootstrap-retries"] = &::bbot::cli::thunk< agent_options, size_t, &agent_options::bootstrap_retries_, &agent_options::bootstrap_retries_specified_ >; _cli_agent_options_map_["--build-startup"] = &::bbot::cli::thunk< agent_options, size_t, &agent_options::build_startup_, &agent_options::build_startup_specified_ >; _cli_agent_options_map_["--build-timeout"] = &::bbot::cli::thunk< agent_options, size_t, &agent_options::build_timeout_, &agent_options::build_timeout_specified_ >; _cli_agent_options_map_["--build-retries"] = &::bbot::cli::thunk< agent_options, size_t, &agent_options::build_retries_, &agent_options::build_retries_specified_ >; _cli_agent_options_map_["--intactive-timeout"] = &::bbot::cli::thunk< agent_options, size_t, &agent_options::intactive_timeout_, &agent_options::intactive_timeout_specified_ >; _cli_agent_options_map_["--connect-timeout"] = &::bbot::cli::thunk< agent_options, size_t, &agent_options::connect_timeout_, &agent_options::connect_timeout_specified_ >; _cli_agent_options_map_["--request-timeout"] = &::bbot::cli::thunk< agent_options, size_t, &agent_options::request_timeout_, &agent_options::request_timeout_specified_ >; _cli_agent_options_map_["--request-retries"] = &::bbot::cli::thunk< agent_options, size_t, &agent_options::request_retries_, &agent_options::request_retries_specified_ >; _cli_agent_options_map_["--openssl"] = &::bbot::cli::thunk< agent_options, path, &agent_options::openssl_, &agent_options::openssl_specified_ >; _cli_agent_options_map_["--openssl-option"] = &::bbot::cli::thunk< agent_options, strings, &agent_options::openssl_option_, &agent_options::openssl_option_specified_ >; _cli_agent_options_map_["--dump-machines"] = &::bbot::cli::thunk< agent_options, &agent_options::dump_machines_ >; _cli_agent_options_map_["--dump-task"] = &::bbot::cli::thunk< agent_options, &agent_options::dump_task_ >; _cli_agent_options_map_["--dump-result"] = &::bbot::cli::thunk< agent_options, &agent_options::dump_result_ >; _cli_agent_options_map_["--fake-bootstrap"] = &::bbot::cli::thunk< agent_options, &agent_options::fake_bootstrap_ >; _cli_agent_options_map_["--fake-build"] = &::bbot::cli::thunk< agent_options, &agent_options::fake_build_ >; _cli_agent_options_map_["--fake-machine"] = &::bbot::cli::thunk< agent_options, path, &agent_options::fake_machine_, &agent_options::fake_machine_specified_ >; _cli_agent_options_map_["--fake-request"] = &::bbot::cli::thunk< agent_options, path, &agent_options::fake_request_, &agent_options::fake_request_specified_ >; } }; static _cli_agent_options_map_init _cli_agent_options_map_init_; bool agent_options:: _parse (const char* o, ::bbot::cli::scanner& s) { _cli_agent_options_map::const_iterator i (_cli_agent_options_map_.find (o)); if (i != _cli_agent_options_map_.end ()) { (*(i->second)) (*this, s); return true; } return false; } bool agent_options:: _parse (::bbot::cli::scanner& s, ::bbot::cli::unknown_mode opt_mode, ::bbot::cli::unknown_mode arg_mode) { // Can't skip combined flags (--no-combined-flags). // assert (opt_mode != ::bbot::cli::unknown_mode::skip); bool r = false; bool opt = true; while (s.more ()) { const char* o = s.peek (); if (std::strcmp (o, "--") == 0) { opt = false; s.skip (); r = true; continue; } if (opt) { if (_parse (o, s)) { r = true; continue; } if (std::strncmp (o, "-", 1) == 0 && o[1] != '\0') { // Handle combined option values. // std::string co; if (const char* v = std::strchr (o, '=')) { co.assign (o, 0, v - o); ++v; int ac (2); char* av[] = { const_cast (co.c_str ()), const_cast (v) }; ::bbot::cli::argv_scanner ns (0, ac, av); if (_parse (co.c_str (), ns)) { // Parsed the option but not its value? // if (ns.end () != 2) throw ::bbot::cli::invalid_value (co, v); s.next (); r = true; continue; } else { // Set the unknown option and fall through. // o = co.c_str (); } } // Handle combined flags. // char cf[3]; { const char* p = o + 1; for (; *p != '\0'; ++p) { if (!((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || (*p >= '0' && *p <= '9'))) break; } if (*p == '\0') { for (p = o + 1; *p != '\0'; ++p) { std::strcpy (cf, "-"); cf[1] = *p; cf[2] = '\0'; int ac (1); char* av[] = { cf }; ::bbot::cli::argv_scanner ns (0, ac, av); if (!_parse (cf, ns)) break; } if (*p == '\0') { // All handled. // s.next (); r = true; continue; } else { // Set the unknown option and fall through. // o = cf; } } } switch (opt_mode) { case ::bbot::cli::unknown_mode::skip: { s.skip (); r = true; continue; } case ::bbot::cli::unknown_mode::stop: { break; } case ::bbot::cli::unknown_mode::fail: { throw ::bbot::cli::unknown_option (o); } } break; } } switch (arg_mode) { case ::bbot::cli::unknown_mode::skip: { s.skip (); r = true; continue; } case ::bbot::cli::unknown_mode::stop: { break; } case ::bbot::cli::unknown_mode::fail: { throw ::bbot::cli::unknown_argument (o); } } break; } return r; } } namespace bbot { ::bbot::cli::usage_para print_bbot_agent_usage (::std::ostream& os, ::bbot::cli::usage_para p) { CLI_POTENTIALLY_UNUSED (os); if (p != ::bbot::cli::usage_para::none) os << ::std::endl; os << "\033[1mSYNOPSIS\033[0m" << ::std::endl << ::std::endl << "\033[1mbbot-agent --help\033[0m" << ::std::endl << "\033[1mbbot-agent --version\033[0m" << ::std::endl << "\033[1mbbot-agent\033[0m [\033[4moptions\033[0m] [\033[4mpriority\033[0m=]\033[4murl\033[0m...\033[0m" << ::std::endl << ::std::endl << "\033[1mDESCRIPTION\033[0m" << ::std::endl << ::std::endl << "\033[1mbbot-agent\033[0m @@ TODO." << ::std::endl << ::std::endl << "The controller URL \033[4mpriority\033[0m is a four or five-digit decimal value. If it is" << ::std::endl << "absent, then \033[1m0\033[0m (lowest priority) is assumed. URLs with equal priority are" << ::std::endl << "queried at random." << ::std::endl << ::std::endl << "The \033[4mpriority\033[0m value has the [\033[4mF\033[0m]\033[4mDCBA\033[0m\033[0m form which encodes four priority levels" << ::std::endl << "(\033[4mDCBA\033[0m) each occupying one decimal digit (so there are 10 distinct priorities in" << ::std::endl << "each level) plus the optional boost flag (\033[4mF\033[0m). These levels offer different" << ::std::endl << "trade-offs between the speed of completing a higher priority task and" << ::std::endl << "potentially discarding work that has already been done." << ::std::endl << ::std::endl << "The first priority level (\033[4mA\033[0m) is a simple preference: among the URLs with equal" << ::std::endl << "values for other levels (\033[4mDCB\033[0m), those with higher first level priorities are" << ::std::endl << "queried first." << ::std::endl << ::std::endl << "The second priority level (\033[4mB\033[0m) has the semantics of the first level plus it" << ::std::endl << "prevents URLs with lower second priority level from being queried until the" << ::std::endl << "task with a higher second priority level has completed, effectively conserving" << ::std::endl << "the resources for the higher priority task." << ::std::endl << ::std::endl << "The third priority level (\033[4mC\033[0m) has the semantics of the second level plus it may" << ::std::endl << "interrupt one lower third priority level task in order to perform the higher" << ::std::endl << "third priority task (the interrupt is necessary if the desired machine is used" << ::std::endl << "by the lower priority task or the number of tasks already being performed is" << ::std::endl << "the maximum allowed to be performed concurrently; see \033[1m--instance-max\033[0m)." << ::std::endl << ::std::endl << "Finally, the fourth priority level (\033[4mD\033[0m) has the semantics of the third level" << ::std::endl << "except that not one but all the lower fourth priority level tasks are" << ::std::endl << "interrupting, effectively dedicating all the available resources to the higher" << ::std::endl << "priority task. This level can also be combined with the boost flag \033[4mF\033[0m. If this" << ::std::endl << "flag is \033[1m1\033[0m then the higher priority task's CPU number (\033[1m--cpu\033[0m) is boosted to the" << ::std::endl << "full number of available hardware threads (or, to view it another way, the" << ::std::endl << "fourth priority level has 20 possible values, not 10, with the first 0-9 being" << ::std::endl << "without the boost while the last 10-19 being with the boost). Note that this" << ::std::endl << "boosting semantics may not be accurate if the agent is executed with CPU" << ::std::endl << "affinity. Also note that there is no corresponding RAM boosting and it's" << ::std::endl << "possible that in some configurations the amount of RAM will be insufficient for" << ::std::endl << "the boosted CPU count." << ::std::endl << ::std::endl << "Note that the priority levels are hierarchical in a sense that within a given" << ::std::endl << "higher level URLs can be further prioritized using the lower levels. As an" << ::std::endl << "example, consider a deployment with three controller URLs: background package" << ::std::endl << "rebuilds (\033[1mpkg.example.org\033[0m), user-initiated CI (\033[1mci.example.org\033[0m), and" << ::std::endl << "user-initiated interactive CI (\033[1mici.example.org\033[0m). Given the following" << ::std::endl << "priorities:" << ::std::endl << ::std::endl << "0000=https://pkg.example.org" << ::std::endl << "0100=https://ci.example.org" << ::std::endl << "0101=https://ici.example.org" << ::std::endl << ::std::endl << "Both types of CI tasks will interrupt one background rebuild task if necessary" << ::std::endl << "while the interactive CI tasks will be merely preferred over non-interactive." << ::std::endl << ::std::endl << "Note that on termination \033[1mbbot-agent\033[0m may leave behind a machine lock and working" << ::std::endl << "machine snapshot. It is expected that the caller (normally Build OS monitor)" << ::std::endl << "cleans them up before restarting the agent." << ::std::endl; p = ::bbot::agent_options::print_usage (os, ::bbot::cli::usage_para::text); if (p != ::bbot::cli::usage_para::none) os << ::std::endl; os << "\033[1mEXIT STATUS\033[0m" << ::std::endl << ::std::endl << "Non-zero exit status is returned in case of an error." << ::std::endl; p = ::bbot::cli::usage_para::text; return p; } } // Begin epilogue. // // // End epilogue.