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 ++++++++++++++++++++++++++++++++++++++++ bbot/agent/agent-options.hxx | 385 +++++++++++++++ bbot/agent/agent-options.ixx | 441 +++++++++++++++++ bbot/common-options.cxx | 740 +++++++++++++++++++++++++++++ bbot/common-options.hxx | 450 ++++++++++++++++++ bbot/common-options.ixx | 281 +++++++++++ bbot/worker/worker-options.cxx | 690 +++++++++++++++++++++++++++ bbot/worker/worker-options.hxx | 171 +++++++ bbot/worker/worker-options.ixx | 123 +++++ buildfile | 2 +- repositories.manifest | 5 +- 11 files changed, 4299 insertions(+), 3 deletions(-) create mode 100644 bbot/agent/agent-options.cxx create mode 100644 bbot/agent/agent-options.hxx create mode 100644 bbot/agent/agent-options.ixx create mode 100644 bbot/common-options.cxx create mode 100644 bbot/common-options.hxx create mode 100644 bbot/common-options.ixx create mode 100644 bbot/worker/worker-options.cxx create mode 100644 bbot/worker/worker-options.hxx create mode 100644 bbot/worker/worker-options.ixx 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. + diff --git a/bbot/agent/agent-options.hxx b/bbot/agent/agent-options.hxx new file mode 100644 index 0000000..03ae045 --- /dev/null +++ b/bbot/agent/agent-options.hxx @@ -0,0 +1,385 @@ +// -*- C++ -*- +// +// This file was generated by CLI, a command line interface +// compiler for C++. +// + +#ifndef BBOT_AGENT_AGENT_OPTIONS_HXX +#define BBOT_AGENT_AGENT_OPTIONS_HXX + +// Begin prologue. +// +// +// End prologue. + +#include + +#include + +namespace bbot +{ + class agent_options + { + public: + agent_options (); + + // Return true if anything has been parsed. + // + bool + parse (int& argc, + char** argv, + bool erase = false, + ::bbot::cli::unknown_mode option = ::bbot::cli::unknown_mode::fail, + ::bbot::cli::unknown_mode argument = ::bbot::cli::unknown_mode::stop); + + bool + parse (int start, + int& argc, + char** argv, + bool erase = false, + ::bbot::cli::unknown_mode option = ::bbot::cli::unknown_mode::fail, + ::bbot::cli::unknown_mode argument = ::bbot::cli::unknown_mode::stop); + + bool + parse (int& argc, + char** argv, + int& end, + bool erase = false, + ::bbot::cli::unknown_mode option = ::bbot::cli::unknown_mode::fail, + ::bbot::cli::unknown_mode argument = ::bbot::cli::unknown_mode::stop); + + bool + parse (int start, + int& argc, + char** argv, + int& end, + bool erase = false, + ::bbot::cli::unknown_mode option = ::bbot::cli::unknown_mode::fail, + ::bbot::cli::unknown_mode argument = ::bbot::cli::unknown_mode::stop); + + bool + parse (::bbot::cli::scanner&, + ::bbot::cli::unknown_mode option = ::bbot::cli::unknown_mode::fail, + ::bbot::cli::unknown_mode argument = ::bbot::cli::unknown_mode::stop); + + // Option accessors. + // + const bool& + help () const; + + const bool& + version () const; + + const uint16_t& + verbose () const; + + bool + verbose_specified () const; + + const bool& + systemd_daemon () const; + + const string& + toolchain_name () const; + + bool + toolchain_name_specified () const; + + const uint16_t& + toolchain_num () const; + + bool + toolchain_num_specified () const; + + const string& + toolchain_lock () const; + + bool + toolchain_lock_specified () const; + + const standard_version& + toolchain_ver () const; + + bool + toolchain_ver_specified () const; + + const string& + toolchain_id () const; + + bool + toolchain_id_specified () const; + + const interactive_mode& + interactive () const; + + bool + interactive_specified () const; + + const uint16_t& + instance () const; + + bool + instance_specified () const; + + const uint16_t& + instance_max () const; + + bool + instance_max_specified () const; + + const size_t& + cpu () const; + + bool + cpu_specified () const; + + const size_t& + ram () const; + + bool + ram_specified () const; + + const string& + bridge () const; + + bool + bridge_specified () const; + + const path& + auth_key () const; + + bool + auth_key_specified () const; + + const strings& + trust () const; + + bool + trust_specified () const; + + const dir_path& + machines () const; + + bool + machines_specified () const; + + const dir_path& + tftp () const; + + bool + tftp_specified () const; + + const uint16_t& + tftp_port () const; + + bool + tftp_port_specified () const; + + const size_t& + bootstrap_startup () const; + + bool + bootstrap_startup_specified () const; + + const size_t& + bootstrap_timeout () const; + + bool + bootstrap_timeout_specified () const; + + const size_t& + bootstrap_retries () const; + + bool + bootstrap_retries_specified () const; + + const size_t& + build_startup () const; + + bool + build_startup_specified () const; + + const size_t& + build_timeout () const; + + bool + build_timeout_specified () const; + + const size_t& + build_retries () const; + + bool + build_retries_specified () const; + + const size_t& + intactive_timeout () const; + + bool + intactive_timeout_specified () const; + + const size_t& + connect_timeout () const; + + bool + connect_timeout_specified () const; + + const size_t& + request_timeout () const; + + bool + request_timeout_specified () const; + + const size_t& + request_retries () const; + + bool + request_retries_specified () const; + + const path& + openssl () const; + + bool + openssl_specified () const; + + const strings& + openssl_option () const; + + bool + openssl_option_specified () const; + + const bool& + dump_machines () const; + + const bool& + dump_task () const; + + const bool& + dump_result () const; + + const bool& + fake_bootstrap () const; + + const bool& + fake_build () const; + + const path& + fake_machine () const; + + bool + fake_machine_specified () const; + + const path& + fake_request () const; + + bool + fake_request_specified () const; + + // Print usage information. + // + static ::bbot::cli::usage_para + print_usage (::std::ostream&, + ::bbot::cli::usage_para = ::bbot::cli::usage_para::none); + + // Implementation details. + // + protected: + bool + _parse (const char*, ::bbot::cli::scanner&); + + private: + bool + _parse (::bbot::cli::scanner&, + ::bbot::cli::unknown_mode option, + ::bbot::cli::unknown_mode argument); + + public: + bool help_; + bool version_; + uint16_t verbose_; + bool verbose_specified_; + bool systemd_daemon_; + string toolchain_name_; + bool toolchain_name_specified_; + uint16_t toolchain_num_; + bool toolchain_num_specified_; + string toolchain_lock_; + bool toolchain_lock_specified_; + standard_version toolchain_ver_; + bool toolchain_ver_specified_; + string toolchain_id_; + bool toolchain_id_specified_; + interactive_mode interactive_; + bool interactive_specified_; + uint16_t instance_; + bool instance_specified_; + uint16_t instance_max_; + bool instance_max_specified_; + size_t cpu_; + bool cpu_specified_; + size_t ram_; + bool ram_specified_; + string bridge_; + bool bridge_specified_; + path auth_key_; + bool auth_key_specified_; + strings trust_; + bool trust_specified_; + dir_path machines_; + bool machines_specified_; + dir_path tftp_; + bool tftp_specified_; + uint16_t tftp_port_; + bool tftp_port_specified_; + size_t bootstrap_startup_; + bool bootstrap_startup_specified_; + size_t bootstrap_timeout_; + bool bootstrap_timeout_specified_; + size_t bootstrap_retries_; + bool bootstrap_retries_specified_; + size_t build_startup_; + bool build_startup_specified_; + size_t build_timeout_; + bool build_timeout_specified_; + size_t build_retries_; + bool build_retries_specified_; + size_t intactive_timeout_; + bool intactive_timeout_specified_; + size_t connect_timeout_; + bool connect_timeout_specified_; + size_t request_timeout_; + bool request_timeout_specified_; + size_t request_retries_; + bool request_retries_specified_; + path openssl_; + bool openssl_specified_; + strings openssl_option_; + bool openssl_option_specified_; + bool dump_machines_; + bool dump_task_; + bool dump_result_; + bool fake_bootstrap_; + bool fake_build_; + path fake_machine_; + bool fake_machine_specified_; + path fake_request_; + bool fake_request_specified_; + }; +} + +// Print page usage information. +// +namespace bbot +{ + ::bbot::cli::usage_para + print_bbot_agent_usage (::std::ostream&, + ::bbot::cli::usage_para = ::bbot::cli::usage_para::none); +} + +#include + +// Begin epilogue. +// +// +// End epilogue. + +#endif // BBOT_AGENT_AGENT_OPTIONS_HXX diff --git a/bbot/agent/agent-options.ixx b/bbot/agent/agent-options.ixx new file mode 100644 index 0000000..6ec0289 --- /dev/null +++ b/bbot/agent/agent-options.ixx @@ -0,0 +1,441 @@ +// -*- C++ -*- +// +// This file was generated by CLI, a command line interface +// compiler for C++. +// + +// Begin prologue. +// +// +// End prologue. + +namespace bbot +{ + // agent_options + // + + inline const bool& agent_options:: + help () const + { + return this->help_; + } + + inline const bool& agent_options:: + version () const + { + return this->version_; + } + + inline const uint16_t& agent_options:: + verbose () const + { + return this->verbose_; + } + + inline bool agent_options:: + verbose_specified () const + { + return this->verbose_specified_; + } + + inline const bool& agent_options:: + systemd_daemon () const + { + return this->systemd_daemon_; + } + + inline const string& agent_options:: + toolchain_name () const + { + return this->toolchain_name_; + } + + inline bool agent_options:: + toolchain_name_specified () const + { + return this->toolchain_name_specified_; + } + + inline const uint16_t& agent_options:: + toolchain_num () const + { + return this->toolchain_num_; + } + + inline bool agent_options:: + toolchain_num_specified () const + { + return this->toolchain_num_specified_; + } + + inline const string& agent_options:: + toolchain_lock () const + { + return this->toolchain_lock_; + } + + inline bool agent_options:: + toolchain_lock_specified () const + { + return this->toolchain_lock_specified_; + } + + inline const standard_version& agent_options:: + toolchain_ver () const + { + return this->toolchain_ver_; + } + + inline bool agent_options:: + toolchain_ver_specified () const + { + return this->toolchain_ver_specified_; + } + + inline const string& agent_options:: + toolchain_id () const + { + return this->toolchain_id_; + } + + inline bool agent_options:: + toolchain_id_specified () const + { + return this->toolchain_id_specified_; + } + + inline const interactive_mode& agent_options:: + interactive () const + { + return this->interactive_; + } + + inline bool agent_options:: + interactive_specified () const + { + return this->interactive_specified_; + } + + inline const uint16_t& agent_options:: + instance () const + { + return this->instance_; + } + + inline bool agent_options:: + instance_specified () const + { + return this->instance_specified_; + } + + inline const uint16_t& agent_options:: + instance_max () const + { + return this->instance_max_; + } + + inline bool agent_options:: + instance_max_specified () const + { + return this->instance_max_specified_; + } + + inline const size_t& agent_options:: + cpu () const + { + return this->cpu_; + } + + inline bool agent_options:: + cpu_specified () const + { + return this->cpu_specified_; + } + + inline const size_t& agent_options:: + ram () const + { + return this->ram_; + } + + inline bool agent_options:: + ram_specified () const + { + return this->ram_specified_; + } + + inline const string& agent_options:: + bridge () const + { + return this->bridge_; + } + + inline bool agent_options:: + bridge_specified () const + { + return this->bridge_specified_; + } + + inline const path& agent_options:: + auth_key () const + { + return this->auth_key_; + } + + inline bool agent_options:: + auth_key_specified () const + { + return this->auth_key_specified_; + } + + inline const strings& agent_options:: + trust () const + { + return this->trust_; + } + + inline bool agent_options:: + trust_specified () const + { + return this->trust_specified_; + } + + inline const dir_path& agent_options:: + machines () const + { + return this->machines_; + } + + inline bool agent_options:: + machines_specified () const + { + return this->machines_specified_; + } + + inline const dir_path& agent_options:: + tftp () const + { + return this->tftp_; + } + + inline bool agent_options:: + tftp_specified () const + { + return this->tftp_specified_; + } + + inline const uint16_t& agent_options:: + tftp_port () const + { + return this->tftp_port_; + } + + inline bool agent_options:: + tftp_port_specified () const + { + return this->tftp_port_specified_; + } + + inline const size_t& agent_options:: + bootstrap_startup () const + { + return this->bootstrap_startup_; + } + + inline bool agent_options:: + bootstrap_startup_specified () const + { + return this->bootstrap_startup_specified_; + } + + inline const size_t& agent_options:: + bootstrap_timeout () const + { + return this->bootstrap_timeout_; + } + + inline bool agent_options:: + bootstrap_timeout_specified () const + { + return this->bootstrap_timeout_specified_; + } + + inline const size_t& agent_options:: + bootstrap_retries () const + { + return this->bootstrap_retries_; + } + + inline bool agent_options:: + bootstrap_retries_specified () const + { + return this->bootstrap_retries_specified_; + } + + inline const size_t& agent_options:: + build_startup () const + { + return this->build_startup_; + } + + inline bool agent_options:: + build_startup_specified () const + { + return this->build_startup_specified_; + } + + inline const size_t& agent_options:: + build_timeout () const + { + return this->build_timeout_; + } + + inline bool agent_options:: + build_timeout_specified () const + { + return this->build_timeout_specified_; + } + + inline const size_t& agent_options:: + build_retries () const + { + return this->build_retries_; + } + + inline bool agent_options:: + build_retries_specified () const + { + return this->build_retries_specified_; + } + + inline const size_t& agent_options:: + intactive_timeout () const + { + return this->intactive_timeout_; + } + + inline bool agent_options:: + intactive_timeout_specified () const + { + return this->intactive_timeout_specified_; + } + + inline const size_t& agent_options:: + connect_timeout () const + { + return this->connect_timeout_; + } + + inline bool agent_options:: + connect_timeout_specified () const + { + return this->connect_timeout_specified_; + } + + inline const size_t& agent_options:: + request_timeout () const + { + return this->request_timeout_; + } + + inline bool agent_options:: + request_timeout_specified () const + { + return this->request_timeout_specified_; + } + + inline const size_t& agent_options:: + request_retries () const + { + return this->request_retries_; + } + + inline bool agent_options:: + request_retries_specified () const + { + return this->request_retries_specified_; + } + + inline const path& agent_options:: + openssl () const + { + return this->openssl_; + } + + inline bool agent_options:: + openssl_specified () const + { + return this->openssl_specified_; + } + + inline const strings& agent_options:: + openssl_option () const + { + return this->openssl_option_; + } + + inline bool agent_options:: + openssl_option_specified () const + { + return this->openssl_option_specified_; + } + + inline const bool& agent_options:: + dump_machines () const + { + return this->dump_machines_; + } + + inline const bool& agent_options:: + dump_task () const + { + return this->dump_task_; + } + + inline const bool& agent_options:: + dump_result () const + { + return this->dump_result_; + } + + inline const bool& agent_options:: + fake_bootstrap () const + { + return this->fake_bootstrap_; + } + + inline const bool& agent_options:: + fake_build () const + { + return this->fake_build_; + } + + inline const path& agent_options:: + fake_machine () const + { + return this->fake_machine_; + } + + inline bool agent_options:: + fake_machine_specified () const + { + return this->fake_machine_specified_; + } + + inline const path& agent_options:: + fake_request () const + { + return this->fake_request_; + } + + inline bool agent_options:: + fake_request_specified () const + { + return this->fake_request_specified_; + } +} + +// Begin epilogue. +// +// +// End epilogue. diff --git a/bbot/common-options.cxx b/bbot/common-options.cxx new file mode 100644 index 0000000..7f351e9 --- /dev/null +++ b/bbot/common-options.cxx @@ -0,0 +1,740 @@ +// -*- 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 + { + // unknown_option + // + unknown_option:: + ~unknown_option () noexcept + { + } + + void unknown_option:: + print (::std::ostream& os) const + { + os << "unknown option '" << option ().c_str () << "'"; + } + + const char* unknown_option:: + what () const noexcept + { + return "unknown option"; + } + + // unknown_argument + // + unknown_argument:: + ~unknown_argument () noexcept + { + } + + void unknown_argument:: + print (::std::ostream& os) const + { + os << "unknown argument '" << argument ().c_str () << "'"; + } + + const char* unknown_argument:: + what () const noexcept + { + return "unknown argument"; + } + + // missing_value + // + missing_value:: + ~missing_value () noexcept + { + } + + void missing_value:: + print (::std::ostream& os) const + { + os << "missing value for option '" << option ().c_str () << "'"; + } + + const char* missing_value:: + what () const noexcept + { + return "missing option value"; + } + + // invalid_value + // + invalid_value:: + ~invalid_value () noexcept + { + } + + void invalid_value:: + print (::std::ostream& os) const + { + os << "invalid value '" << value ().c_str () << "' for option '" + << option ().c_str () << "'"; + + if (!message ().empty ()) + os << ": " << message ().c_str (); + } + + const char* invalid_value:: + what () const noexcept + { + return "invalid option value"; + } + + // eos_reached + // + void eos_reached:: + print (::std::ostream& os) const + { + os << what (); + } + + const char* eos_reached:: + what () const noexcept + { + return "end of argument stream reached"; + } + + // unexpected_group + // + unexpected_group:: + ~unexpected_group () noexcept + { + } + + void unexpected_group:: + print (::std::ostream& os) const + { + os << "unexpected grouped argument '" << group_ << "' " + << "for argument '" << argument_ << "'"; + } + + const char* unexpected_group:: + what () const noexcept + { + return "unexpected grouped argument"; + } + + // group_separator + // + group_separator:: + ~group_separator () noexcept + { + } + + void group_separator:: + print (::std::ostream& os) const + { + bool ex (!expected_.empty ()); + bool en (!encountered_.empty ()); + + if (ex) + { + os << "expected group separator '" << expected_ << "'"; + if (en) + os << " instead of '" << encountered_ << "'"; + } + else + os << "unexpected group separator '" << encountered_ << "'"; + + if (en) + os << ", use '\\" << encountered_ << "' to escape"; + } + + const char* group_separator:: + what () const noexcept + { + bool ex (!expected_.empty ()); + bool en (!encountered_.empty ()); + + return en + ? ex ? "wrong group separator" : "unexpected group separator" + : ex ? "expected group separator" : ""; + } + + // scanner + // + scanner:: + ~scanner () + { + } + + // argv_scanner + // + bool argv_scanner:: + more () + { + return i_ < argc_; + } + + const char* argv_scanner:: + peek () + { + if (i_ < argc_) + return argv_[i_]; + else + throw eos_reached (); + } + + const char* argv_scanner:: + next () + { + if (i_ < argc_) + { + const char* r (argv_[i_]); + + if (erase_) + { + for (int i (i_ + 1); i < argc_; ++i) + argv_[i - 1] = argv_[i]; + + --argc_; + argv_[argc_] = 0; + } + else + ++i_; + + ++start_position_; + return r; + } + else + throw eos_reached (); + } + + void argv_scanner:: + skip () + { + if (i_ < argc_) + { + ++i_; + ++start_position_; + } + else + throw eos_reached (); + } + + std::size_t argv_scanner:: + position () + { + return start_position_; + } + + // vector_scanner + // + bool vector_scanner:: + more () + { + return i_ < v_.size (); + } + + const char* vector_scanner:: + peek () + { + if (i_ < v_.size ()) + return v_[i_].c_str (); + else + throw eos_reached (); + } + + const char* vector_scanner:: + next () + { + if (i_ < v_.size ()) + return v_[i_++].c_str (); + else + throw eos_reached (); + } + + void vector_scanner:: + skip () + { + if (i_ < v_.size ()) + ++i_; + else + throw eos_reached (); + } + + std::size_t vector_scanner:: + position () + { + return start_position_ + i_; + } + + // group_scanner + // + bool group_scanner:: + more () + { + // We don't want to call scan_group() here since that + // would invalidate references to previous arguments. + // But we do need to check that the previous group was + // handled. + // + if (state_ == scanned) + { + if (group_scan_.end () != group_.size ()) + throw unexpected_group (arg_[i_][j_], group_scan_.next ()); + } + + return j_ != 0 || scan_.more (); + } + + const char* group_scanner:: + peek () + { + if (state_ != peeked) + { + scan_group (); + state_ = peeked; + } + + // Return unescaped. + return arg_[i_][j_ - 1].c_str (); + } + + const char* group_scanner:: + next () + { + if (state_ != peeked) + scan_group (); + state_ = scanned; + // Return unescaped. + return arg_[i_][--j_].c_str (); + } + + void group_scanner:: + skip () + { + if (state_ != peeked) + scan_group (); + state_ = skipped; + --j_; + } + + std::size_t group_scanner:: + position () + { + return j_ == 0 ? scan_.position () : pos_ + (arg_[i_].size () - j_); + } + + void group_scanner:: + scan_group () + { + // If the previous argument has been scanned, then make + // sure the group has been scanned (handled) as well. + // + if (state_ == scanned) + { + if (group_scan_.end () != group_.size ()) + throw unexpected_group (arg_[i_][j_], group_scan_.next ()); + } + + // If we still have arguments in the pack, rewind the group. + // + if (j_ != 0) + { + group_scan_.reset (); + return; + } + + i_ += (i_ == 0 ? 1 : -1); + group_.clear (); + group_scan_.reset (); + pos_ = scan_.position (); + + // Note: using group_ won't cover empty groups and using + // j_ won't cover single-argument packs. + // + bool group (false), pack (false); + + do + { + const char* a (scan_.next ()); + size_t i (*a == '\\' ? 1 : 0); + separator s (sense (a + i)); + + if (s == none || i != 0) + { + if (arg_[i_].size () != 1) + arg_[i_].resize (1); + + arg_[i_][0] = a + (s != none ? i : 0); + j_ = 1; + break; + } + + // Start of a leading group for the next argument or + // argument pack. We will only know which once we see + // the closing separator. + // + if (s != open) + throw group_separator (a, ""); + + size_t n (group_.size ()); + + // Scan the group until the closing separator. + // + s = none; + while (s == none && scan_.more ()) + { + a = scan_.next (); + i = (*a == '\\' ? 1 : 0); + s = sense (a + i); + + if (s == none || i != 0) + { + group_.push_back (a + (s != none ? i : 0)); + s = none; + } + } + + if (s == close) + { + size_t m (group_.size ()); + + j_ = m - n; + if (j_ == 0) + throw group_separator ("{", ""); + + if (arg_[i_].size () != j_) + arg_[i_].resize (j_); + + // Move from group_ to arg_. Add in reverse for ease + // of iteration. + // + for (size_t j (0); j != j_; ++j) + arg_[i_][j] = group_[m - j - 1]; + group_.resize (n); + + pack = true; + break; + } + else if (s == close_plus) + group = true; + else + throw group_separator ((s != none ? a : ""), "}+"); + } + while (scan_.more ()); + + // Handle the case where we have seen the leading group + // but there are no more arguments. + // + if (group && j_ == 0) + throw group_separator ("{", ""); + + // Handle trailing groups, if any. + // + while (scan_.more ()) + { + const char* a (scan_.peek ()); + size_t i (*a == '\\' ? 1 : 0); + separator s (sense (a + i)); + + // Next argument, argument pack, or leading group. + // + if (s == none || s == open || i != 0) + break; + + if (s != open_plus) + throw group_separator (a, ""); + + group = true; + + // Scan the group until the closing separator. + // + scan_.next (); + s = none; + while (s == none && scan_.more ()) + { + a = scan_.next (); + i = (*a == '\\' ? 1 : 0); + s = sense (a + i); + + if (s == none || i != 0) + { + group_.push_back (a + (s != none ? i : 0)); + s = none; + } + } + + if (s != close) + throw group_separator ((s != none ? a : ""), "}"); + } + + // Handle the case where we have seen the argument pack + // without leading or trailing group. + // + if (pack && !group) + throw group_separator ("{", ""); + } + + 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 +{ +} + +// Begin epilogue. +// +// +// End epilogue. + diff --git a/bbot/common-options.hxx b/bbot/common-options.hxx new file mode 100644 index 0000000..e865d6e --- /dev/null +++ b/bbot/common-options.hxx @@ -0,0 +1,450 @@ +// -*- C++ -*- +// +// This file was generated by CLI, a command line interface +// compiler for C++. +// + +#ifndef BBOT_COMMON_OPTIONS_HXX +#define BBOT_COMMON_OPTIONS_HXX + +// Begin prologue. +// +// +// End prologue. + +#include +#include +#include +#include +#include + +#ifndef CLI_POTENTIALLY_UNUSED +# if defined(_MSC_VER) || defined(__xlC__) +# define CLI_POTENTIALLY_UNUSED(x) (void*)&x +# else +# define CLI_POTENTIALLY_UNUSED(x) (void)x +# endif +#endif + +namespace bbot +{ + namespace cli + { + class usage_para + { + public: + enum value + { + none, + text, + option + }; + + usage_para (value); + + operator value () const + { + return v_; + } + + private: + value v_; + }; + + class unknown_mode + { + public: + enum value + { + skip, + stop, + fail + }; + + unknown_mode (value); + + operator value () const + { + return v_; + } + + private: + value v_; + }; + + // Exceptions. + // + + class exception: public std::exception + { + public: + virtual void + print (::std::ostream&) const = 0; + }; + + ::std::ostream& + operator<< (::std::ostream&, const exception&); + + class unknown_option: public exception + { + public: + virtual + ~unknown_option () noexcept; + + unknown_option (const std::string& option); + + const std::string& + option () const; + + virtual void + print (::std::ostream&) const; + + virtual const char* + what () const noexcept; + + private: + std::string option_; + }; + + class unknown_argument: public exception + { + public: + virtual + ~unknown_argument () noexcept; + + unknown_argument (const std::string& argument); + + const std::string& + argument () const; + + virtual void + print (::std::ostream&) const; + + virtual const char* + what () const noexcept; + + private: + std::string argument_; + }; + + class missing_value: public exception + { + public: + virtual + ~missing_value () noexcept; + + missing_value (const std::string& option); + + const std::string& + option () const; + + virtual void + print (::std::ostream&) const; + + virtual const char* + what () const noexcept; + + private: + std::string option_; + }; + + class invalid_value: public exception + { + public: + virtual + ~invalid_value () noexcept; + + invalid_value (const std::string& option, + const std::string& value, + const std::string& message = std::string ()); + + const std::string& + option () const; + + const std::string& + value () const; + + const std::string& + message () const; + + virtual void + print (::std::ostream&) const; + + virtual const char* + what () const noexcept; + + private: + std::string option_; + std::string value_; + std::string message_; + }; + + class eos_reached: public exception + { + public: + virtual void + print (::std::ostream&) const; + + virtual const char* + what () const noexcept; + }; + + class unexpected_group: public exception + { + public: + virtual + ~unexpected_group () noexcept; + + unexpected_group (const std::string& argument, + const std::string& group); + + const std::string& + argument () const; + + const std::string& + group () const; + + virtual void + print (std::ostream&) const; + + virtual const char* + what () const noexcept; + + private: + std::string argument_; + std::string group_; + }; + + class group_separator: public exception + { + public: + virtual + ~group_separator () noexcept; + + // Note: either (but not both) can be empty. + // + group_separator (const std::string& encountered, + const std::string& expected); + + const std::string& + encountered () const; + + const std::string& + expected () const; + + virtual void + print (std::ostream&) const; + + virtual const char* + what () const noexcept; + + private: + std::string encountered_; + std::string expected_; + }; + + // Command line argument scanner interface. + // + // The values returned by next() are guaranteed to be valid + // for the two previous arguments up until a call to a third + // peek() or next(). + // + // The position() function returns a monotonically-increasing + // number which, if stored, can later be used to determine the + // relative position of the argument returned by the following + // call to next(). Note that if multiple scanners are used to + // extract arguments from multiple sources, then the end + // position of the previous scanner should be used as the + // start position of the next. + // + class scanner + { + public: + virtual + ~scanner (); + + virtual bool + more () = 0; + + virtual const char* + peek () = 0; + + virtual const char* + next () = 0; + + virtual void + skip () = 0; + + virtual std::size_t + position () = 0; + }; + + class argv_scanner: public scanner + { + public: + argv_scanner (int& argc, + char** argv, + bool erase = false, + std::size_t start_position = 0); + + argv_scanner (int start, + int& argc, + char** argv, + bool erase = false, + std::size_t start_position = 0); + + int + end () const; + + virtual bool + more (); + + virtual const char* + peek (); + + virtual const char* + next (); + + virtual void + skip (); + + virtual std::size_t + position (); + + protected: + std::size_t start_position_; + int i_; + int& argc_; + char** argv_; + bool erase_; + }; + + class vector_scanner: public scanner + { + public: + vector_scanner (const std::vector&, + std::size_t start = 0, + std::size_t start_position = 0); + + std::size_t + end () const; + + void + reset (std::size_t start = 0, std::size_t start_position = 0); + + virtual bool + more (); + + virtual const char* + peek (); + + virtual const char* + next (); + + virtual void + skip (); + + virtual std::size_t + position (); + + private: + std::size_t start_position_; + const std::vector& v_; + std::size_t i_; + }; + + class group_scanner: public scanner + { + public: + group_scanner (scanner&); + + virtual bool + more (); + + virtual const char* + peek (); + + virtual const char* + next (); + + virtual void + skip (); + + virtual std::size_t + position (); + + // The group is only available after the call to next() + // (and skip() -- in case one needs to make sure the group + // was empty, or some such) and is only valid (and must be + // handled) until the next call to any of the scanner + // functions (including more()). + // + // Note also that argument positions within each group start + // from 0. + // + scanner& + group (); + + // Escape an argument that is a group separator. Return the + // passed string if no escaping is required. + // + static const char* + escape (const char*); + + private: + enum state + { + peeked, // Argument peeked at with peek(). + scanned, // Argument scanned with next(). + skipped, // Argument skipped with skip()/initial. + }; + + enum separator + { + none, + open, // { + close, // } + open_plus, // +{ + close_plus // }+ + }; + + static separator + sense (const char*); + + // Scan the leading groups, the next argument/argument pack, + // and the trailing groups. + // + void + scan_group (); + + scanner& scan_; + state state_; + + // Circular buffer of two arguments. + // + std::vector arg_[2]; + std::size_t i_, j_, pos_; + + std::vector group_; + vector_scanner group_scan_; + }; + + template + struct parser; + } +} + +#include + +namespace bbot +{ +} + +#include + +// Begin epilogue. +// +// +// End epilogue. + +#endif // BBOT_COMMON_OPTIONS_HXX diff --git a/bbot/common-options.ixx b/bbot/common-options.ixx new file mode 100644 index 0000000..3a35de9 --- /dev/null +++ b/bbot/common-options.ixx @@ -0,0 +1,281 @@ +// -*- C++ -*- +// +// This file was generated by CLI, a command line interface +// compiler for C++. +// + +// Begin prologue. +// +// +// End prologue. + +#include + +namespace bbot +{ + namespace cli + { + // usage_para + // + inline usage_para:: + usage_para (value v) + : v_ (v) + { + } + + // unknown_mode + // + inline unknown_mode:: + unknown_mode (value v) + : v_ (v) + { + } + + // exception + // + inline ::std::ostream& + operator<< (::std::ostream& os, const exception& e) + { + e.print (os); + return os; + } + + // unknown_option + // + inline unknown_option:: + unknown_option (const std::string& option) + : option_ (option) + { + } + + inline const std::string& unknown_option:: + option () const + { + return option_; + } + + // unknown_argument + // + inline unknown_argument:: + unknown_argument (const std::string& argument) + : argument_ (argument) + { + } + + inline const std::string& unknown_argument:: + argument () const + { + return argument_; + } + + // missing_value + // + inline missing_value:: + missing_value (const std::string& option) + : option_ (option) + { + } + + inline const std::string& missing_value:: + option () const + { + return option_; + } + + // invalid_value + // + inline invalid_value:: + invalid_value (const std::string& option, + const std::string& value, + const std::string& message) + : option_ (option), + value_ (value), + message_ (message) + { + } + + inline const std::string& invalid_value:: + option () const + { + return option_; + } + + inline const std::string& invalid_value:: + value () const + { + return value_; + } + + inline const std::string& invalid_value:: + message () const + { + return message_; + } + + // unexpected_group + // + inline unexpected_group:: + unexpected_group (const std::string& argument, + const std::string& group) + : argument_ (argument), group_ (group) + { + } + + inline const std::string& unexpected_group:: + argument () const + { + return argument_; + } + + inline const std::string& unexpected_group:: + group () const + { + return group_; + } + + // group_separator + // + inline group_separator:: + group_separator (const std::string& encountered, + const std::string& expected) + : encountered_ (encountered), expected_ (expected) + { + } + + inline const std::string& group_separator:: + encountered () const + { + return encountered_; + } + + inline const std::string& group_separator:: + expected () const + { + return expected_; + } + + // argv_scanner + // + inline argv_scanner:: + argv_scanner (int& argc, + char** argv, + bool erase, + std::size_t sp) + : start_position_ (sp + 1), + i_ (1), + argc_ (argc), + argv_ (argv), + erase_ (erase) + { + } + + inline argv_scanner:: + argv_scanner (int start, + int& argc, + char** argv, + bool erase, + std::size_t sp) + : start_position_ (sp + static_cast (start)), + i_ (start), + argc_ (argc), + argv_ (argv), + erase_ (erase) + { + } + + inline int argv_scanner:: + end () const + { + return i_; + } + + // vector_scanner + // + inline vector_scanner:: + vector_scanner (const std::vector& v, + std::size_t i, + std::size_t sp) + : start_position_ (sp), v_ (v), i_ (i) + { + } + + inline std::size_t vector_scanner:: + end () const + { + return i_; + } + + inline void vector_scanner:: + reset (std::size_t i, std::size_t sp) + { + i_ = i; + start_position_ = sp; + } + + // group_scanner + // + inline group_scanner:: + group_scanner (scanner& s) + : scan_ (s), state_ (skipped), i_ (1), j_ (0), group_scan_ (group_) + { + } + + inline scanner& group_scanner:: + group () + { + assert (state_ == scanned || state_ == skipped); + return group_scan_; + } + + inline const char* group_scanner:: + escape (const char* a) + { + switch (sense (a)) + { + case separator::none: break; + case separator::open: return "\\{"; + case separator::close: return "\\}"; + case separator::open_plus: return "\\+{"; + case separator::close_plus: return "\\}+"; + } + + return a; + } + + inline group_scanner::separator group_scanner:: + sense (const char* s) + { + switch (s[0]) + { + case '{': return s[1] == '\0' ? open : none; + case '}': + { + switch (s[1]) + { + case '+': return s[2] == '\0' ? close_plus : none; + default: return s[1] == '\0' ? close : none; + } + } + case '+': + { + switch (s[1]) + { + case '{': return s[2] == '\0' ? open_plus : none; + default: return none; + } + } + } + + return none; + } + } +} + +namespace bbot +{ +} + +// Begin epilogue. +// +// +// End epilogue. diff --git a/bbot/worker/worker-options.cxx b/bbot/worker/worker-options.cxx new file mode 100644 index 0000000..028f1cb --- /dev/null +++ b/bbot/worker/worker-options.cxx @@ -0,0 +1,690 @@ +// -*- 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 +{ + // worker_options + // + + worker_options:: + worker_options () + : help_ (), + version_ (), + verbose_ (1), + verbose_specified_ (false), + bootstrap_ (), + startup_ (), + systemd_daemon_ (), + build_ (), + build_specified_ (false), + environments_ (), + environments_specified_ (false), + env_script_ (), + env_script_specified_ (false), + env_target_ (), + env_target_specified_ (false), + tftp_host_ ("196.254.111.222"), + tftp_host_specified_ (false) + { + } + + bool worker_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 worker_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 worker_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 worker_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 worker_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 worker_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--bootstrap\033[0m Perform the inital machine bootstrap insteading of" << ::std::endl + << " building." << ::std::endl; + + os << std::endl + << "\033[1m--startup\033[0m Perform the environment setup and then re-execute for" << ::std::endl + << " building." << ::std::endl; + + os << std::endl + << "\033[1m--systemd-daemon\033[0m Run as a simple systemd daemon." << ::std::endl; + + os << std::endl + << "\033[1m--build\033[0m \033[4mdir\033[0m The directory to perform the build in. If not" << ::std::endl + << " specified, then the current working directory is used." << ::std::endl; + + os << std::endl + << "\033[1m--environments\033[0m \033[4mdir\033[0m The directory containing the environment setup" << ::std::endl + << " executables. If not specified, then the user's home" << ::std::endl + << " directory is used." << ::std::endl; + + os << std::endl + << "\033[1m--env-script\033[0m \033[4mpath\033[0m The environment setup executable path. This option is" << ::std::endl + << " normally passed by the worker running in the startup" << ::std::endl + << " mode to the worker executed in the build mode." << ::std::endl; + + os << std::endl + << "\033[1m--env-target\033[0m \033[4mtarget\033[0m The environment setup executable target argument. This" << ::std::endl + << " option is normally passed by the worker running in the" << ::std::endl + << " startup mode to the worker executed in the build mode." << ::std::endl; + + os << std::endl + << "\033[1m--tftp-host\033[0m \033[4maddr\033[0m The TFTP host address and, optionally, port to use to" << ::std::endl + << " download the build task and to upload the build result." << ::std::endl + << " By default the link-local address 196.254.111.222 with" << ::std::endl + << " the standard TFTP port (69) is used." << ::std::endl; + + p = ::bbot::cli::usage_para::option; + + return p; + } + + typedef + std::map + _cli_worker_options_map; + + static _cli_worker_options_map _cli_worker_options_map_; + + struct _cli_worker_options_map_init + { + _cli_worker_options_map_init () + { + _cli_worker_options_map_["--help"] = + &::bbot::cli::thunk< worker_options, &worker_options::help_ >; + _cli_worker_options_map_["--version"] = + &::bbot::cli::thunk< worker_options, &worker_options::version_ >; + _cli_worker_options_map_["--verbose"] = + &::bbot::cli::thunk< worker_options, uint16_t, &worker_options::verbose_, + &worker_options::verbose_specified_ >; + _cli_worker_options_map_["--bootstrap"] = + &::bbot::cli::thunk< worker_options, &worker_options::bootstrap_ >; + _cli_worker_options_map_["--startup"] = + &::bbot::cli::thunk< worker_options, &worker_options::startup_ >; + _cli_worker_options_map_["--systemd-daemon"] = + &::bbot::cli::thunk< worker_options, &worker_options::systemd_daemon_ >; + _cli_worker_options_map_["--build"] = + &::bbot::cli::thunk< worker_options, dir_path, &worker_options::build_, + &worker_options::build_specified_ >; + _cli_worker_options_map_["--environments"] = + &::bbot::cli::thunk< worker_options, dir_path, &worker_options::environments_, + &worker_options::environments_specified_ >; + _cli_worker_options_map_["--env-script"] = + &::bbot::cli::thunk< worker_options, path, &worker_options::env_script_, + &worker_options::env_script_specified_ >; + _cli_worker_options_map_["--env-target"] = + &::bbot::cli::thunk< worker_options, string, &worker_options::env_target_, + &worker_options::env_target_specified_ >; + _cli_worker_options_map_["--tftp-host"] = + &::bbot::cli::thunk< worker_options, string, &worker_options::tftp_host_, + &worker_options::tftp_host_specified_ >; + } + }; + + static _cli_worker_options_map_init _cli_worker_options_map_init_; + + bool worker_options:: + _parse (const char* o, ::bbot::cli::scanner& s) + { + _cli_worker_options_map::const_iterator i (_cli_worker_options_map_.find (o)); + + if (i != _cli_worker_options_map_.end ()) + { + (*(i->second)) (*this, s); + return true; + } + + return false; + } + + bool worker_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_worker_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-worker --help\033[0m" << ::std::endl + << "\033[1mbbot-worker --version\033[0m" << ::std::endl + << "\033[1mbbot-worker --bootstrap\033[0m [\033[4moptions\033[0m]" << ::std::endl + << "\033[1mbbot-worker --startup\033[0m [\033[4moptions\033[0m]" << ::std::endl + << "\033[1mbbot-worker\033[0m [\033[4moptions\033[0m] \033[4mmodule\033[0m... \033[4mcfg-var\033[0m...\033[0m" << ::std::endl + << ::std::endl + << "\033[1mDESCRIPTION\033[0m" << ::std::endl + << ::std::endl + << "\033[1mbbot-worker\033[0m @@ TODO." << ::std::endl + << ::std::endl + << "If the \033[1m--bootstrap\033[0m mode option is specified, then the worker performs the" << ::std::endl + << "initial machine bootstrap and writes the bootstrap result manifest to stdout\033[0m." << ::std::endl + << "If the \033[1m--startup\033[0m mode option is specified, then the worker performs the" << ::std::endl + << "environment setup and then re-executes in the build mode. If neither of the" << ::std::endl + << "mode options is specified, then the worker proceeds to performing the build" << ::std::endl + << "task." << ::std::endl; + + p = ::bbot::worker_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. In the build mode, exit" << ::std::endl + << "code 2 is used to signal abnormal termination where the worker uploaded the" << ::std::endl + << "result manifest itself." << ::std::endl; + + p = ::bbot::cli::usage_para::text; + + return p; + } +} + +// Begin epilogue. +// +// +// End epilogue. + diff --git a/bbot/worker/worker-options.hxx b/bbot/worker/worker-options.hxx new file mode 100644 index 0000000..15e5b66 --- /dev/null +++ b/bbot/worker/worker-options.hxx @@ -0,0 +1,171 @@ +// -*- C++ -*- +// +// This file was generated by CLI, a command line interface +// compiler for C++. +// + +#ifndef BBOT_WORKER_WORKER_OPTIONS_HXX +#define BBOT_WORKER_WORKER_OPTIONS_HXX + +// Begin prologue. +// +// +// End prologue. + +#include + +namespace bbot +{ + class worker_options + { + public: + worker_options (); + + // Return true if anything has been parsed. + // + bool + parse (int& argc, + char** argv, + bool erase = false, + ::bbot::cli::unknown_mode option = ::bbot::cli::unknown_mode::fail, + ::bbot::cli::unknown_mode argument = ::bbot::cli::unknown_mode::stop); + + bool + parse (int start, + int& argc, + char** argv, + bool erase = false, + ::bbot::cli::unknown_mode option = ::bbot::cli::unknown_mode::fail, + ::bbot::cli::unknown_mode argument = ::bbot::cli::unknown_mode::stop); + + bool + parse (int& argc, + char** argv, + int& end, + bool erase = false, + ::bbot::cli::unknown_mode option = ::bbot::cli::unknown_mode::fail, + ::bbot::cli::unknown_mode argument = ::bbot::cli::unknown_mode::stop); + + bool + parse (int start, + int& argc, + char** argv, + int& end, + bool erase = false, + ::bbot::cli::unknown_mode option = ::bbot::cli::unknown_mode::fail, + ::bbot::cli::unknown_mode argument = ::bbot::cli::unknown_mode::stop); + + bool + parse (::bbot::cli::scanner&, + ::bbot::cli::unknown_mode option = ::bbot::cli::unknown_mode::fail, + ::bbot::cli::unknown_mode argument = ::bbot::cli::unknown_mode::stop); + + // Option accessors. + // + const bool& + help () const; + + const bool& + version () const; + + const uint16_t& + verbose () const; + + bool + verbose_specified () const; + + const bool& + bootstrap () const; + + const bool& + startup () const; + + const bool& + systemd_daemon () const; + + const dir_path& + build () const; + + bool + build_specified () const; + + const dir_path& + environments () const; + + bool + environments_specified () const; + + const path& + env_script () const; + + bool + env_script_specified () const; + + const string& + env_target () const; + + bool + env_target_specified () const; + + const string& + tftp_host () const; + + bool + tftp_host_specified () const; + + // Print usage information. + // + static ::bbot::cli::usage_para + print_usage (::std::ostream&, + ::bbot::cli::usage_para = ::bbot::cli::usage_para::none); + + // Implementation details. + // + protected: + bool + _parse (const char*, ::bbot::cli::scanner&); + + private: + bool + _parse (::bbot::cli::scanner&, + ::bbot::cli::unknown_mode option, + ::bbot::cli::unknown_mode argument); + + public: + bool help_; + bool version_; + uint16_t verbose_; + bool verbose_specified_; + bool bootstrap_; + bool startup_; + bool systemd_daemon_; + dir_path build_; + bool build_specified_; + dir_path environments_; + bool environments_specified_; + path env_script_; + bool env_script_specified_; + string env_target_; + bool env_target_specified_; + string tftp_host_; + bool tftp_host_specified_; + }; +} + +// Print page usage information. +// +namespace bbot +{ + ::bbot::cli::usage_para + print_bbot_worker_usage (::std::ostream&, + ::bbot::cli::usage_para = ::bbot::cli::usage_para::none); +} + +#include + +// Begin epilogue. +// +// +// End epilogue. + +#endif // BBOT_WORKER_WORKER_OPTIONS_HXX diff --git a/bbot/worker/worker-options.ixx b/bbot/worker/worker-options.ixx new file mode 100644 index 0000000..bc5b21d --- /dev/null +++ b/bbot/worker/worker-options.ixx @@ -0,0 +1,123 @@ +// -*- C++ -*- +// +// This file was generated by CLI, a command line interface +// compiler for C++. +// + +// Begin prologue. +// +// +// End prologue. + +namespace bbot +{ + // worker_options + // + + inline const bool& worker_options:: + help () const + { + return this->help_; + } + + inline const bool& worker_options:: + version () const + { + return this->version_; + } + + inline const uint16_t& worker_options:: + verbose () const + { + return this->verbose_; + } + + inline bool worker_options:: + verbose_specified () const + { + return this->verbose_specified_; + } + + inline const bool& worker_options:: + bootstrap () const + { + return this->bootstrap_; + } + + inline const bool& worker_options:: + startup () const + { + return this->startup_; + } + + inline const bool& worker_options:: + systemd_daemon () const + { + return this->systemd_daemon_; + } + + inline const dir_path& worker_options:: + build () const + { + return this->build_; + } + + inline bool worker_options:: + build_specified () const + { + return this->build_specified_; + } + + inline const dir_path& worker_options:: + environments () const + { + return this->environments_; + } + + inline bool worker_options:: + environments_specified () const + { + return this->environments_specified_; + } + + inline const path& worker_options:: + env_script () const + { + return this->env_script_; + } + + inline bool worker_options:: + env_script_specified () const + { + return this->env_script_specified_; + } + + inline const string& worker_options:: + env_target () const + { + return this->env_target_; + } + + inline bool worker_options:: + env_target_specified () const + { + return this->env_target_specified_; + } + + inline const string& worker_options:: + tftp_host () const + { + return this->tftp_host_; + } + + inline bool worker_options:: + tftp_host_specified () const + { + return this->tftp_host_specified_; + } +} + +// Begin epilogue. +// +// +// End epilogue. diff --git a/buildfile b/buildfile index 333d727..8a8575d 100644 --- a/buildfile +++ b/buildfile @@ -1,7 +1,7 @@ # file : buildfile # license : MIT; see accompanying LICENSE file -./: {*/ -tests/ -build/} \ +./: {*/ -tests/ -build/ -doc/} \ doc{INSTALL NEWS README} legal{LICENSE} \ manifest diff --git a/repositories.manifest b/repositories.manifest index b10bd68..42644da 100644 --- a/repositories.manifest +++ b/repositories.manifest @@ -3,8 +3,9 @@ summary: build2 build bot repository : role: prerequisite -location: ../libbutl.git##HEAD +location: ../libbutl.git#curl : role: prerequisite -location: ../libbbot.git##HEAD +location: https://stage.build2.org/1 +trust: EC:50:13:E2:3D:F7:92:B4:50:0B:BF:2A:1F:7D:31:04:C6:57:6F:BC:BE:04:2E:E0:58:14:FA:66:66:21:1F:14 -- cgit v1.1