aboutsummaryrefslogtreecommitdiff
path: root/bbot/bootstrap-manifest.cxx
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2017-04-06 19:46:03 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2017-04-06 21:20:37 +0300
commitcfd31379be5eefb22a72b5ee90ce8fd17a0802b7 (patch)
tree19fa3727e1799c98938681f79328b60d63afff19 /bbot/bootstrap-manifest.cxx
parente3af4c881790a95be2676a7f4fb8df4136f8a3f3 (diff)
Implement manifests
Diffstat (limited to 'bbot/bootstrap-manifest.cxx')
-rw-r--r--bbot/bootstrap-manifest.cxx260
1 files changed, 260 insertions, 0 deletions
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 <bbot/bootstrap-manifest>
+
+#include <butl/manifest-parser>
+#include <butl/manifest-serializer>
+
+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.
+ }
+}