From b64fae536f4f7043e03b12d2e6df8183c8a0f8ad Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Mon, 26 Feb 2024 11:41:58 +0300 Subject: Make changes required for CI --- bbot/agent/agent-options.cxx | 1014 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1014 insertions(+) create mode 100644 bbot/agent/agent-options.cxx (limited to 'bbot/agent/agent-options.cxx') diff --git a/bbot/agent/agent-options.cxx b/bbot/agent/agent-options.cxx new file mode 100644 index 0000000..aa5a232 --- /dev/null +++ b/bbot/agent/agent-options.cxx @@ -0,0 +1,1014 @@ +// -*- 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. + -- cgit v1.1