// file : libbbot/manifest.hxx -*- C++ -*- // license : MIT; see accompanying LICENSE file #ifndef LIBBBOT_MANIFEST_HXX #define LIBBBOT_MANIFEST_HXX #include #include #include // uint*_t #include #include #include #include #include #include #include // version, repository_location #include #include #include namespace bbot { using strings = std::vector; // The machine's role. // enum class machine_role: std::uint8_t { build, auxiliary }; LIBBBOT_EXPORT std::string to_string (machine_role); LIBBBOT_EXPORT machine_role to_machine_role (const std::string&); // May throw invalid_argument. inline std::ostream& operator<< (std::ostream& os, machine_role r) { return os << to_string (r); } class LIBBBOT_EXPORT machine_header_manifest { public: std::string id; std::string name; std::string summary; butl::optional role; butl::optional ram_minimum; // In KiB, non-zero. butl::optional ram_maximum; // In KiB, non-zero. // Return the effective machine role. If the role is not explicitly // specified, then the build role is assumed. // machine_role effective_role () const noexcept { return role ? *role : machine_role::build; } machine_header_manifest (std::string i, std::string n, std::string s, butl::optional r, butl::optional rmn, butl::optional rmx) : id (std::move (i)), name (std::move (n)), summary (std::move (s)), role (r), ram_minimum (rmn), ram_maximum (rmx) {} public: machine_header_manifest () = default; // VC export. machine_header_manifest ( butl::manifest_parser&, butl::manifest_unknown_mode = butl::manifest_unknown_mode::fail); machine_header_manifest ( butl::manifest_parser&, butl::manifest_name_value start, butl::manifest_unknown_mode = butl::manifest_unknown_mode::fail, butl::manifest_name_value* end = nullptr); // Wrapper-ctor. Primarily for use in template functions parameterized // with the manifest type. // machine_header_manifest (butl::manifest_parser& p, bool ignore_unknown) : machine_header_manifest (p, ignore_unknown ? butl::manifest_unknown_mode::skip : butl::manifest_unknown_mode::fail) {} void serialize (butl::manifest_serializer&, bool end_of_manifest = true) const; }; using machine_header_manifests = std::vector; // Agent's capability to perform (non-)interactive builds. // enum class interactive_mode: std::uint8_t { false_, true_, both }; LIBBBOT_EXPORT std::string to_string (interactive_mode); LIBBBOT_EXPORT interactive_mode to_interactive_mode (const std::string&); // May throw invalid_argument. inline std::ostream& operator<< (std::ostream& os, interactive_mode m) { return os << to_string (m); } class LIBBBOT_EXPORT task_request_manifest { public: using interactive_mode_type = bbot::interactive_mode; std::string agent; std::string toolchain_name; butl::standard_version toolchain_version; butl::optional interactive_mode; butl::optional interactive_login; // Agent's public key SHA256 fingerprint. // // @@ How the fingerpring for openssl public key will be produced? Seems // there is no "standard" for it. Possibly we will use the following // command result (plain SHA256). // // $ cat key.pub | openssl sha256 // butl::optional fingerprint; butl::optional auxiliary_ram; // In KiB. machine_header_manifests machines; // Return the effective interactive build mode. If the mode is not // explicitly specified, then false is assumed. // interactive_mode_type effective_interactive_mode () const noexcept { return interactive_mode ? *interactive_mode : interactive_mode_type::false_; } task_request_manifest (std::string ag, std::string tn, butl::standard_version tv, butl::optional im, butl::optional il, butl::optional fp, butl::optional ar, machine_header_manifests ms) : agent (std::move (ag)), toolchain_name (std::move (tn)), toolchain_version (std::move (tv)), interactive_mode (std::move (im)), interactive_login (std::move (il)), fingerprint (std::move (fp)), auxiliary_ram (ar), machines (std::move (ms)) {} public: task_request_manifest () = default; // VC export. task_request_manifest (butl::manifest_parser&, bool ignore_unknown = false); void serialize (butl::manifest_serializer&) const; }; struct package { bpkg::package_name name; bpkg::version version; }; // Note: corresponds to build_auxiliary in the package manifest. // struct auxiliary_machine { std::string name; std::string environment_name; }; class LIBBBOT_EXPORT task_manifest { public: // Package to build. // bpkg::package_name name; bpkg::version version; bpkg::repository_location repository; // Remote or absolute. // The SHA256 repositories certificates fingerprints to trust. The special // 'yes' value can be specified instead of fingerprint (in which case all // repositories will be trusted without authentication). // strings trust; // The subset of the build task-relevant package manifest values (see // bpkg::package_manifest for their semantics). // std::vector requirements; butl::small_vector tests; butl::optional dependency_checksum; std::string machine; // Build machine to use for building the package. // The list of build auxiliary machines. // // Note that all entries in this list must have distinct environment names // (with empty name being one of the possibilities). // // Also note that some auxiliary machines can potentially be used by the // main package and some by the test packages. It is such package author's // responsibility to make sure that the environment names specified in // multiple package manifests do not clash. It is bbot controller's // responsibility to verify that there is no clash, aborting the task if // there is. // std::vector auxiliary_machines; butl::target_triplet target; // Build target. butl::optional environment; // Build environment name. // The environment variables describing the auxiliary machines. // butl::optional auxiliary_environment; // Build system configuration variables (in addition to build environment // configuration variables). // // Note: could be quoted. // strings target_config; // Whitespace separated list of potentially double/single-quoted package // configuration arguments for bpkg-pkg-build command. // std::string package_config; // If true, then this configuration is self-hosted. // butl::optional host; // Regular expressions for detecting warnings in the operation result logs // (in addition to the default list of expressions). // Note: could be quoted. // strings warning_regex; butl::optional interactive; // Interactive build breakpoint. butl::optional worker_checksum; strings unquoted_target_config () const; strings unquoted_warning_regex () const; task_manifest (bpkg::package_name nm, bpkg::version vr, bpkg::repository_location rl, strings tr, std::vector ra, butl::small_vector ts, butl::optional dc, std::string mn, std::vector ams, butl::target_triplet tg, butl::optional en, butl::optional ae, strings tc, std::string pc, butl::optional ht, strings wr, butl::optional ir, butl::optional wc) : name (std::move (nm)), version (std::move (vr)), repository (std::move (rl)), trust (std::move (tr)), requirements (std::move (ra)), tests (std::move (ts)), dependency_checksum (std::move (dc)), machine (std::move (mn)), auxiliary_machines (std::move (ams)), target (std::move (tg)), environment (std::move (en)), auxiliary_environment (std::move (ae)), target_config (std::move (tc)), package_config (std::move (pc)), host (std::move (ht)), warning_regex (std::move (wr)), interactive (std::move (ir)), worker_checksum (std::move (wc)) {} public: task_manifest () = default; // VC export. task_manifest (butl::manifest_parser&, bool ignore_unknown = false); task_manifest (butl::manifest_parser&, butl::manifest_name_value start, bool ignore_unknown = false); void serialize (butl::manifest_serializer&) const; // Check that a string is a valid (ECMAScript) regular expression. Throw // invalid_argument if that's not the case. // static void validate_regex (const std::string&); }; class upload_url { public: std::string url; std::string type; upload_url (std::string u, std::string t) : url (std::move (u)), type (std::move (t)) {} }; class LIBBBOT_EXPORT task_response_manifest { public: // If empty then no task available. // std::string session; // Challenge, result url, and task are absent and upload urls list is // empty if session is empty. // butl::optional challenge; butl::optional result_url; std::vector upload_urls; // -upload-url: butl::optional agent_checksum; butl::optional task; task_response_manifest (std::string s, butl::optional c, butl::optional u, std::vector uus, butl::optional ac, butl::optional t) : session (std::move (s)), challenge (std::move (c)), result_url (std::move (u)), upload_urls (std::move (uus)), agent_checksum (std::move (ac)), task (std::move (t)) {} public: task_response_manifest () = default; // VC export. task_response_manifest (butl::manifest_parser&, bool ignore_unknown = false); void serialize (butl::manifest_serializer&) const; }; // Build task or operation result status. // enum class result_status: std::uint8_t { // The order of the enumerators is arranged so that their integral values // indicate whether one "overrides" the other in the "merge" operator| // (see below). // skip, success, warning, error, abort, abnormal, interrupt }; LIBBBOT_EXPORT std::string to_string (result_status); LIBBBOT_EXPORT result_status to_result_status (const std::string&); // May throw invalid_argument. inline std::ostream& operator<< (std::ostream& os, result_status s) {return os << to_string (s);} inline result_status& operator|= (result_status& l, result_status r) { if (static_cast (r) > static_cast (l)) l = r; return l; } // Return true if the result is "bad", that is, error or worse. // inline bool operator! (result_status s) { return static_cast (s) >= static_cast (result_status::error); } struct operation_result { std::string operation; // "configure", "update", "test", etc. result_status status; std::string log; }; using operation_results = std::vector; class LIBBBOT_EXPORT result_manifest { public: // Built package. // // If the version is 0 (which signifies a stub package that cannot be // possibly built) then both name and version are "unknown". This is used // by the worker to signal abnormal termination before being able to // obtain the package name/version. // bpkg::package_name name; bpkg::version version; result_status status; // Ordered (ascending) by operation value. May not contain all the // operations if the task failed in the middle, but should have no gaps // (operation can not start unless all previous ones succeeded). // operation_results results; butl::optional worker_checksum; butl::optional dependency_checksum; result_manifest (bpkg::package_name n, bpkg::version v, result_status s, operation_results r, butl::optional wc, butl::optional dc) : name (std::move (n)), version (std::move (v)), status (s), results (std::move (r)), worker_checksum (std::move (wc)), dependency_checksum (std::move (dc)) {} public: result_manifest () = default; // VC export. result_manifest (butl::manifest_parser&, bool ignore_unknown = false); result_manifest (butl::manifest_parser&, butl::manifest_name_value start, bool ignore_unknown = false); void serialize (butl::manifest_serializer&) const; }; class LIBBBOT_EXPORT result_request_manifest { public: std::string session; // The task response session. // The answer to challenge in the task response. // butl::optional> challenge; std::string agent_checksum; result_manifest result; result_request_manifest (std::string s, butl::optional> c, std::string ac, result_manifest r) : session (std::move (s)), challenge (std::move (c)), agent_checksum (std::move (ac)), result (std::move (r)) {} public: result_request_manifest () = default; // VC export. result_request_manifest (butl::manifest_parser&, bool ignore_unknown = false); void serialize (butl::manifest_serializer&) const; }; } #endif // LIBBBOT_MANIFEST_HXX