From cff0e40a337f06857cef72da9105ea235214ee8c Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Tue, 25 Apr 2023 20:35:12 +0300 Subject: Generate bindist-result.manifest if bbot.bindist.upload worker step is enabled --- bbot/worker/worker.cxx | 185 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 164 insertions(+), 21 deletions(-) (limited to 'bbot') diff --git a/bbot/worker/worker.cxx b/bbot/worker/worker.cxx index f9550f8..4895c76 100644 --- a/bbot/worker/worker.cxx +++ b/bbot/worker/worker.cxx @@ -17,10 +17,11 @@ #include #include #include -#include // to_utf8(), eof() +#include // to_utf8(), eof() #include #include #include +#include #include @@ -1189,12 +1190,15 @@ static const string worker_checksum ("5"); // Logic version. static int bbot:: build (size_t argc, const char* argv[]) { - using namespace bpkg; + using std::map; + using std::multimap; using string_parser::unquote; - using std::map; - using std::multimap; + using serializer = manifest_serializer; + using serialization = manifest_serialization; + + using namespace bpkg; tracer trace ("build"); @@ -3818,7 +3822,7 @@ build (size_t argc, const char* argv[]) // Generate the binary distribution package. // // Note that if bbot.bindist.upload step is enabled, it makes sense to - // only copy all the generated binary distribution files to the + // only copy the generated binary distribution files to the // upload/bindist// directory after the binary // distribution packages are testes, i.e. after the potential // bbot.sys-uninstall.* steps. @@ -3828,20 +3832,32 @@ build (size_t argc, const char* argv[]) // of the bpkg-pkg-bindist(1) man page. Note: needed later for // uninstall, upload. // + struct bindist_os_release + { + string name_id; + optional version_id; + }; + struct bindist_file { - bbot::path path; // Absolute and normalized. - string system_name; + string type; + bbot::path path; // Absolute and normalized. + optional system_name; }; struct bindist_package { + string name; + string version; + optional system_version; vector files; }; struct bindist_result_type { string distribution; + string architecture; + bindist_os_release os_release; bindist_package package; vector dependencies; }; @@ -3958,6 +3974,36 @@ build (size_t argc, const char* argv[]) move (d)); }; + // Parse bindist_os_release object. + // + auto parse_os_release = [&p] () + { + // enter: after begin_object + // leave: after end_object + + bindist_os_release r; + + // Skip unknown/uninteresting members. + // + while (p.next_expect (event::name, event::end_object)) + { + const string& n (p.name ()); + + if (n == "name_id") + { + r.name_id = p.next_expect_string (); + } + else if (n == "version_id") + { + r.version_id = p.next_expect_string (); + } + else + p.next_expect_value_skip (); + } + + return r; + }; + // Parse a bindist_file object. // auto parse_file = [&p, &bad_json] () @@ -3973,7 +4019,11 @@ build (size_t argc, const char* argv[]) { const string& n (p.name ()); - if (n == "path") + if (n == "type") + { + r.type = p.next_expect_string (); + } + else if (n == "path") { try { @@ -4011,7 +4061,19 @@ build (size_t argc, const char* argv[]) { const string& n (p.name ()); - if (n == "files") + if (n == "name") + { + r.name = p.next_expect_string (); + } + else if (n == "version") + { + r.version = p.next_expect_string (); + } + else if (n == "system_version") + { + r.system_version = p.next_expect_string (); + } + else if (n == "files") { p.next_expect (event::begin_array); @@ -4027,6 +4089,11 @@ build (size_t argc, const char* argv[]) // Parse the bindist_result. // + // Note that if the bbot.bindist.upload step is enabled, then we + // require bindist_result.os_release.version_id to be present. This + // way the uploaded binary package can be published for a specific + // version of the distribution. + // p.next_expect (event::begin_object); while (p.next_expect (event::name, event::end_object)) @@ -4041,6 +4108,19 @@ build (size_t argc, const char* argv[]) bad_json ("expected distribution '" + distribution + "' instead of '" + bindist_result.distribution + "'"); } + else if (n == "architecture") + { + bindist_result.architecture = p.next_expect_string (); + } + else if (n == "os_release") + { + p.next_expect (event::begin_object); + bindist_result.os_release = parse_os_release (); + + if (!bindist_result.os_release.version_id && bindist_upload) + bad_json ("version_id must be present if bbot.bindist.upload " + "step is enabled"); + } else if (n == "package") { p.next_expect (event::begin_object); @@ -4131,7 +4211,7 @@ build (size_t argc, const char* argv[]) { for (const bindist_file& f: bfs) { - if (!f.system_name.empty ()) + if (f.system_name) pfs.push_back (f.path.string ().c_str ()); } }; @@ -5205,8 +5285,8 @@ build (size_t argc, const char* argv[]) { for (const bindist_file& f: bfs) { - if (!f.system_name.empty ()) - pns.push_back (f.system_name.c_str ()); + if (f.system_name) + pns.push_back (f.system_name->c_str ()); } }; @@ -5352,8 +5432,10 @@ build (size_t argc, const char* argv[]) // Prepare the bindist artifacts. // - // Move all the generated binary distribution files and + // Move the binary distribution files generated for the main package and // bindist-result.json to the upload/bindist// directory. + // Also serialize the subset of the bindist result as + // bindist-result.manifest. // // Fail if the breakpoint refers to the bbot.bindist.upload step since // it has no specific command associated. @@ -5401,18 +5483,79 @@ build (size_t argc, const char* argv[]) cp_into (trace, &r.log, rp, d); }; - auto move_files = [&mv] (const vector& bfs) + // Main package files. + // + for (const bindist_file& f: bindist_result.package.files) + mv (f.path); + + // Bindist result JSON. + // + mv (bindist_result_file); + + // Bindist result manifest. + // + path mf (d / "bindist-result.manifest"); + + try { - for (const bindist_file& f: bfs) - mv (f.path); - }; + ofdstream os (mf); + serializer s (os, mf.string ()); - move_files (bindist_result.package.files); + // Serialize package manifest. + // + s.next ("", "1"); // Start of manifest. - for (const bindist_package& d: bindist_result.dependencies) - move_files (d.files); + s.next ("distribution", bindist_result.distribution); + s.next ("architecture", bindist_result.architecture); - mv (bindist_result_file); + s.next ("os-release-name-id", bindist_result.os_release.name_id); + + // Should have failed earlier. + // + assert (bindist_result.os_release.version_id); + + s.next ("os-release-version-id", + *bindist_result.os_release.version_id); + + s.next ("package-name", bindist_result.package.name); + s.next ("package-version", bindist_result.package.version); + + if (bindist_result.package.system_version) + s.next ("package-system-version", + *bindist_result.package.system_version); + + s.next ("", ""); // End of manifest. + + // Serialize package file manifests. + // + for (const bindist_file& f: bindist_result.package.files) + { + s.next ("", "1"); // Start of manifest. + + s.next ("package-file-type", f.type); + + // Note: the simple path representation is POSIX. + // + s.next ("package-file-path", f.path.leaf ().string ()); + + if (f.system_name) + s.next ("package-file-system-name", *f.system_name); + + s.next ("", ""); // End of manifest. + } + + s.next ("", ""); // End of stream. + + os.close (); + } + catch (const io_error& e) + { + fail << "unable to write to '" << mf << "': " << e; + } + catch (const serialization& e) + { + fail << "unable to serialize bindist result: " << e; + } } // Create the archive of the build artifacts for subsequent upload, if -- cgit v1.1