From cfd31379be5eefb22a72b5ee90ce8fd17a0802b7 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Thu, 6 Apr 2017 19:46:03 +0300 Subject: Implement manifests --- bbot/bootstrap-manifest | 32 +++++- bbot/bootstrap-manifest.cxx | 260 ++++++++++++++++++++++++++++++++++++++++++++ bbot/buildfile | 2 +- bbot/utility | 3 +- 4 files changed, 294 insertions(+), 3 deletions(-) create mode 100644 bbot/bootstrap-manifest.cxx (limited to 'bbot') diff --git a/bbot/bootstrap-manifest b/bbot/bootstrap-manifest index 502127b..c29406a 100644 --- a/bbot/bootstrap-manifest +++ b/bbot/bootstrap-manifest @@ -7,6 +7,8 @@ #include +#include + #include #include @@ -23,6 +25,16 @@ namespace bbot // Toolchain id (SHAXXX). // string id; + + public: + toolchain_manifest () = default; // VC export. + toolchain_manifest (butl::manifest_parser&, bool ignore_unknown = false); + toolchain_manifest (butl::manifest_parser&, + butl::manifest_name_value start, + bool ignore_unknown = false); + + void + serialize (butl::manifest_serializer&) const; }; // Bootstrap result manifest. Uploaded by the worker to the agent's TFTP @@ -40,10 +52,20 @@ namespace bbot // bbot-version: 1010200 # 1.1.2 // std::map versions; + + public: + bootstrap_manifest () = default; // VC export. + bootstrap_manifest (butl::manifest_parser&, bool ignore_unknown = false); + bootstrap_manifest (butl::manifest_parser&, + butl::manifest_name_value start, + bool ignore_unknown = false); + + void + serialize (butl::manifest_serializer&) const; }; // The manifest stored in -/ consists of the machine - // manifest (original), toolchain manifest, and bootstrap result manifest. + // manifest (original), toolchain manifest, and bootstrap manifest. // class bootstrapped_machine_manifest { @@ -51,6 +73,14 @@ namespace bbot machine_manifest machine; toolchain_manifest toolchain; bootstrap_manifest bootstrap; + + public: + bootstrapped_machine_manifest () = default; // VC export. + bootstrapped_machine_manifest (butl::manifest_parser&, + bool ignore_unknown = false); + + void + serialize (butl::manifest_serializer&) const; }; } diff --git a/bbot/bootstrap-manifest.cxx b/bbot/bootstrap-manifest.cxx new file mode 100644 index 0000000..7d635ca --- /dev/null +++ b/bbot/bootstrap-manifest.cxx @@ -0,0 +1,260 @@ +// file : bbot/bootstrap-manifest.cxx -*- C++ -*- +// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#include + +#include +#include + +using namespace butl; + +namespace bbot +{ + using parser = manifest_parser; + using parsing = manifest_parsing; + using serializer = manifest_serializer; + using serialization = manifest_serialization; + using name_value = manifest_name_value; + + // toolchain_manifest + // + toolchain_manifest:: + toolchain_manifest (parser& p, bool iu) + : toolchain_manifest (p, p.next (), iu) + { + // Make sure this is the end. + // + name_value nv (p.next ()); + if (!nv.empty ()) + throw parsing (p.name (), nv.name_line, nv.name_column, + "single toolchain manifest expected"); + } + + toolchain_manifest:: + toolchain_manifest (parser& p, name_value nv, bool iu) + { + auto bad_name = [&p, &nv] (const string& d) + { + throw parsing (p.name (), nv.name_line, nv.name_column, d); + }; + + auto bad_value = [&p, &nv] (const string& d) + { + throw parsing (p.name (), nv.value_line, nv.value_column, d); + }; + + // Make sure this is the start and we support the version. + // + if (!nv.name.empty ()) + bad_name ("start of toolchain manifest expected"); + + if (nv.value != "1") + bad_value ("unsupported format version"); + + // Parse the toolchain manifest. + // + for (nv = p.next (); !nv.empty (); nv = p.next ()) + { + string& n (nv.name); + string& v (nv.value); + + if (n == "id") + { + if (!id.empty ()) + bad_name ("toolchain id redefinition"); + + if (v.empty ()) + bad_value ("empty toolchain id"); + + id = move (v); + } + else if (!iu) + bad_name ("unknown name '" + n + "' in toolchain manifest"); + } + + // Verify all non-optional values were specified. + // + if (id.empty ()) + bad_value ("no toolchain id specified"); + } + + void toolchain_manifest:: + serialize (serializer& s) const + { + // @@ Should we check that all non-optional values are specified? + // + s.next ("", "1"); // Start of manifest. + s.next ("id", id); + s.next ("", ""); // End of manifest. + } + + // bootstrap_manifest + // + bootstrap_manifest:: + bootstrap_manifest (parser& p, bool iu) + : bootstrap_manifest (p, p.next (), iu) + { + // Make sure this is the end. + // + name_value nv (p.next ()); + if (!nv.empty ()) + throw parsing (p.name (), nv.name_line, nv.name_column, + "single bootstrap manifest expected"); + } + + bootstrap_manifest:: + bootstrap_manifest (parser& p, name_value nv, bool iu) + { + auto bad_name = [&p, &nv] (const string& d) + { + throw parsing (p.name (), nv.name_line, nv.name_column, d); + }; + + auto bad_value = [&p, &nv] (const string& d) + { + throw parsing (p.name (), nv.value_line, nv.value_column, d); + }; + + // Make sure this is the start and we support the version. + // + if (!nv.name.empty ()) + bad_name ("start of bootstrap manifest expected"); + + if (nv.value != "1") + bad_value ("unsupported format version"); + + // Parse the bootstrap manifest. + // + for (nv = p.next (); !nv.empty (); nv = p.next ()) + { + string& n (nv.name); + string& v (nv.value); + + size_t nn (n.size ()); // Name length. + + // Note: returns false if nothing preceeds a suffix. + // + auto suffix = [&n, nn] (const char* s, size_t sn) -> bool + { + return nn > sn && n.compare (nn - sn, sn, s) == 0; + }; + + size_t sn; + if (suffix ("-version", sn = 8)) + { + string pn (n, 0, nn - sn); // Package name. + + // Package version. + // + size_t vn; + uint64_t pv (stoull (v, &vn)); + if (vn != v.size ()) + bad_value ("invalid package version"); + + // Make sure the package version is not redefined. + // + if (!versions.emplace (move (pn), pv).second) + bad_name (n + " redefinition"); + } + else if (!iu) + bad_name ("unknown name '" + n + "' in bootstrap manifest"); + } + + // Verify all non-optional values were specified. + // + if (versions.empty ()) + bad_value ("no package versions specified"); + } + + void bootstrap_manifest:: + serialize (serializer& s) const + { + // @@ Should we check that all non-optional values are specified? + // + s.next ("", "1"); // Start of manifest. + + // Serialize *-version values. + // + for (const auto& v: versions) + s.next (v.first + "-version", to_string (v.second)); + + s.next ("", ""); // End of manifest. + } + + // bootstrapped_machine_manifest + // + bootstrapped_machine_manifest:: + bootstrapped_machine_manifest (parser& p, bool iu) + { + name_value nv (p.next ()); + + auto bad_name = [&p, &nv] (const string& d) + { + throw parsing (p.name (), nv.name_line, nv.name_column, d); + }; + + auto bad_value = [&p, &nv] (const string& d) + { + throw parsing (p.name (), nv.value_line, nv.value_column, d); + }; + + // Make sure this is the start and we support the version. + // + if (!nv.name.empty ()) + bad_name ("start of bootstrapped machine manifest expected"); + + if (nv.value != "1") + bad_value ("unsupported format version"); + + // Parse the bootstrapped machine manifest. Currently there is no values + // expected. + // + for (nv = p.next (); !nv.empty (); nv = p.next ()) + { + if (!iu) + bad_name ("unknown name '" + nv.name + + "' in bootstrapped machine manifest"); + } + + nv = p.next (); + if (nv.empty ()) + bad_value ("machine manifest expected"); + + machine = machine_manifest (p, nv, false, iu); + + nv = p.next (); + if (nv.empty ()) + bad_value ("toolchain manifest expected"); + + toolchain = toolchain_manifest (p, nv, iu); + + nv = p.next (); + if (nv.empty ()) + bad_value ("bootstrap manifest expected"); + + bootstrap = bootstrap_manifest (p, nv, iu); + + // Make sure this is the end. + // + nv = p.next (); + if (!nv.empty ()) + throw parsing (p.name (), nv.name_line, nv.name_column, + "single bootstrapped machine manifest expected"); + } + + void bootstrapped_machine_manifest:: + serialize (serializer& s) const + { + // @@ Should we check that all non-optional values are specified? + // + s.next ("", "1"); // Start of manifest. + s.next ("", ""); // End of manifest. + + machine.serialize (s); + toolchain.serialize (s); + bootstrap.serialize (s); + + s.next ("", ""); // End of stream. + } +} diff --git a/bbot/buildfile b/bbot/buildfile index c2d5d05..4045888 100644 --- a/bbot/buildfile +++ b/bbot/buildfile @@ -26,7 +26,7 @@ if ($cxx.target.class == "linux") exe{bbot-agent}: \ { cxx}{ agent } {hxx ixx cxx}{ agent-options } \ - {hxx ixx cxx}{ common-options } \ + {hxx cxx}{ bootstrap-manifest } {hxx ixx cxx}{ common-options } \ {hxx cxx}{ diagnostics } \ {hxx }{ types } \ {hxx cxx}{ types-parsers } \ diff --git a/bbot/utility b/bbot/utility index 032ffca..81c6c87 100644 --- a/bbot/utility +++ b/bbot/utility @@ -6,7 +6,7 @@ #define BBOT_UTILITY #include // make_shared() -#include // to_string() +#include // to_string(), stoull() #include // move(), forward(), declval(), make_pair() #include // assert() #include // make_move_iterator() @@ -30,6 +30,7 @@ namespace bbot using std::make_shared; using std::make_move_iterator; using std::to_string; + using std::stoull; // // -- cgit v1.1