aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2024-03-08 20:24:35 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2024-03-12 16:27:58 +0300
commited8e64ca8525872c97f9331cb5c882b40864b84e (patch)
tree62abb95ed6dac0a8b25c7f5123d2093d5d26628c
parent1d30ee0f8a017be6611e2eebffc5c539a8b1d12c (diff)
Add support for build auxiliary machines related manifest values
-rw-r--r--libbbot/manifest.cxx145
-rw-r--r--libbbot/manifest.hxx81
-rw-r--r--tests/manifest/machine-header.testscript18
-rw-r--r--tests/manifest/task-request.testscript16
-rw-r--r--tests/manifest/task.testscript30
5 files changed, 288 insertions, 2 deletions
diff --git a/libbbot/manifest.cxx b/libbbot/manifest.cxx
index be642a0..ab392e4 100644
--- a/libbbot/manifest.cxx
+++ b/libbbot/manifest.cxx
@@ -7,11 +7,13 @@
#include <vector>
#include <string>
#include <cctype> // isxdigit()
+#include <limits> // numeric_limits
#include <cassert>
#include <sstream>
#include <cstddef> // size_t
#include <utility> // move()
#include <cstdint> // uint64_t
+#include <cstdlib> // strtoull()
#include <algorithm> // find_if()
#include <stdexcept> // invalid_argument
@@ -37,6 +39,29 @@ namespace bbot
using butl::optional;
+ // machine_role
+ //
+ string
+ to_string (machine_role r)
+ {
+ switch (r)
+ {
+ case machine_role::build: return "build";
+ case machine_role::auxiliary: return "auxiliary";
+ }
+
+ assert (false);
+ return string ();
+ }
+
+ machine_role
+ to_machine_role (const string& s)
+ {
+ if (s == "build") return machine_role::build;
+ else if (s == "auxiliary") return machine_role::auxiliary;
+ else throw invalid_argument ("invalid machine role '" + s + '\'');
+ }
+
// result_status
//
string
@@ -134,6 +159,29 @@ namespace bbot
return true;
}
+ // Return nullopt if the string is not a valid 64-bit unsigned integer.
+ //
+ static optional<uint64_t>
+ parse_uint64 (const string& s)
+ {
+ if (!s.empty () && s[0] != '-' && s[0] != '+') // strtoull() allows these.
+ {
+ const char* b (s.c_str ());
+ char* e (nullptr);
+ errno = 0; // We must clear it according to POSIX.
+ uint64_t v (strtoull (b, &e, 10)); // Can't throw.
+
+ if (errno != ERANGE &&
+ e == b + s.size () &&
+ v <= numeric_limits<uint64_t>::max ())
+ {
+ return static_cast<uint64_t> (v);
+ }
+ }
+
+ return nullopt;
+ }
+
// machine_header_manifest
//
machine_header_manifest::
@@ -207,6 +255,40 @@ namespace bbot
summary = move (v);
}
+ else if (n == "role")
+ {
+ if (role)
+ bad_name ("machine role redefinition");
+
+ try
+ {
+ role = to_machine_role (v);
+ }
+ catch (const invalid_argument& e)
+ {
+ bad_value (e.what ());
+ }
+ }
+ else if (n == "ram-minimum")
+ {
+ if (ram_minimum)
+ bad_name ("machine minimum RAM redefinition");
+
+ ram_minimum = parse_uint64 (v);
+
+ if (!ram_minimum)
+ bad_value ("machine minimum RAM should be 64-bit unsigned integer");
+ }
+ else if (n == "ram-maximum")
+ {
+ if (ram_maximum)
+ bad_name ("machine maximum RAM redefinition");
+
+ ram_maximum = parse_uint64 (v);
+
+ if (!ram_maximum)
+ bad_value ("machine maximum RAM should be 64-bit unsigned integer");
+ }
else
{
switch (m)
@@ -247,6 +329,15 @@ namespace bbot
s.next ("name", name);
s.next ("summary", summary);
+ if (role)
+ s.next ("role", to_string (*role));
+
+ if (ram_minimum)
+ s.next ("ram-minimum", std::to_string (*ram_minimum));
+
+ if (ram_maximum)
+ s.next ("ram-maximum", std::to_string (*ram_maximum));
+
if (end_of_manifest)
s.next ("", ""); // End of manifest.
}
@@ -358,6 +449,17 @@ namespace bbot
fingerprint = move (v);
}
+ else if (n == "auxiliary-ram")
+ {
+ if (auxiliary_ram)
+ bad_name ("auxiliary machines RAM limit redefinition");
+
+ auxiliary_ram = parse_uint64 (v);
+
+ if (!auxiliary_ram)
+ bad_value (
+ "auxiliary machines RAM limit should be 64-bit unsigned integer");
+ }
else if (!iu)
bad_name ("unknown name '" + n + "' in task request manifest");
}
@@ -423,6 +525,9 @@ namespace bbot
if (fingerprint)
s.next ("fingerprint", *fingerprint);
+ if (auxiliary_ram)
+ s.next ("auxiliary-ram", std::to_string (*auxiliary_ram));
+
s.next ("", ""); // End of manifest.
for (const machine_header_manifest& m: machines)
@@ -644,6 +749,26 @@ namespace bbot
machine = move (v);
}
+ else if (n == "auxiliary-machine" ||
+ (n.size () > 18 && n.compare (0, 18, "auxiliary-machine-") == 0))
+ {
+ if (v.empty ())
+ bad_value ("empty task auxiliary machine name");
+
+ auxiliary_machine m {move (v),
+ n.size () > 18 ? string (n, 18) : string ()};
+
+ if (find_if (auxiliary_machines.begin (), auxiliary_machines.end (),
+ [&m] (const auxiliary_machine& am)
+ {
+ return am.environment_name == m.environment_name;
+ }) != auxiliary_machines.end ())
+ {
+ bad_name ("task auxiliary machine environment redefinition");
+ }
+
+ auxiliary_machines.push_back (move (m));
+ }
else if (n == "target")
{
if (!target.empty ())
@@ -668,6 +793,16 @@ namespace bbot
environment = move (v);
}
+ else if (n == "auxiliary-environment")
+ {
+ if (auxiliary_environment)
+ bad_name ("task auxiliary environment redefinition");
+
+ if (v.empty ())
+ bad_value ("empty task auxiliary environment");
+
+ auxiliary_environment = move (v);
+ }
else if (n == "config" || // @@ TMP Until toolchain 0.16.0 is released.
n == "target-config")
{
@@ -815,11 +950,21 @@ namespace bbot
s.next ("dependency-checksum", *dependency_checksum);
s.next ("machine", machine);
+
+ for (const auxiliary_machine& am: auxiliary_machines)
+ s.next ((!am.environment_name.empty ()
+ ? "auxiliary-machine-" + am.environment_name
+ : "auxiliary-machine"),
+ am.name);
+
s.next ("target", target.string ());
if (environment)
s.next ("environment", *environment);
+ if (auxiliary_environment)
+ s.next ("auxiliary-environment", *auxiliary_environment);
+
// Serialize an optional value of the strings type as a space-separated
// string list.
//
diff --git a/libbbot/manifest.hxx b/libbbot/manifest.hxx
index 5807aed..a815d3e 100644
--- a/libbbot/manifest.hxx
+++ b/libbbot/manifest.hxx
@@ -6,6 +6,7 @@
#include <string>
#include <vector>
+#include <cstdint> // uint*_t
#include <ostream>
#include <libbutl/optional.hxx>
@@ -24,15 +25,57 @@ namespace bbot
{
using strings = std::vector<std::string>;
+ // 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<machine_role> role;
+ butl::optional<std::uint64_t> ram_minimum; // In KiB.
+ butl::optional<std::uint64_t> ram_maximum; // In KiB.
- machine_header_manifest (std::string i, std::string n, std::string s)
- : id (std::move (i)), name (std::move (n)), summary (std::move (s)) {}
+ // 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<machine_role> r,
+ butl::optional<std::uint64_t> rmn,
+ butl::optional<std::uint64_t> 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.
@@ -106,6 +149,8 @@ namespace bbot
//
butl::optional<std::string> fingerprint;
+ butl::optional<std::uint64_t> auxiliary_ram; // In KiB.
+
machine_header_manifests machines;
// Return the effective interactive build mode. If the mode is not
@@ -125,6 +170,7 @@ namespace bbot
butl::optional<interactive_mode_type> im,
butl::optional<std::string> il,
butl::optional<std::string> fp,
+ butl::optional<std::uint64_t> ar,
machine_header_manifests ms)
: agent (std::move (ag)),
toolchain_name (std::move (tn)),
@@ -132,6 +178,7 @@ namespace bbot
interactive_mode (std::move (im)),
interactive_login (std::move (il)),
fingerprint (std::move (fp)),
+ auxiliary_ram (ar),
machines (std::move (ms)) {}
public:
@@ -149,6 +196,14 @@ namespace bbot
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:
@@ -174,10 +229,28 @@ namespace bbot
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_machine> auxiliary_machines;
+
butl::target_triplet target; // Build target.
butl::optional<std::string> environment; // Build environment name.
+ // The environment variables describing the auxiliary machines.
+ //
+ butl::optional<std::string> auxiliary_environment;
+
// Build system configuration variables (in addition to build environment
// configuration variables).
//
@@ -218,8 +291,10 @@ namespace bbot
butl::small_vector<bpkg::test_dependency, 1> ts,
butl::optional<std::string> dc,
std::string mn,
+ std::vector<auxiliary_machine> ams,
butl::target_triplet tg,
butl::optional<std::string> en,
+ butl::optional<std::string> ae,
strings tc,
std::string pc,
butl::optional<bool> ht,
@@ -234,8 +309,10 @@ namespace bbot
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)),
diff --git a/tests/manifest/machine-header.testscript b/tests/manifest/machine-header.testscript
index 84295d2..559a107 100644
--- a/tests/manifest/machine-header.testscript
+++ b/tests/manifest/machine-header.testscript
@@ -13,6 +13,8 @@ test.options += -m
id: a2b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
name: windows_10-msvc_14
summary: Windows 10 build 1607 with VC 14 update 3
+ role: build
+ ram-minimum: 4194304
EOF
}
@@ -52,6 +54,22 @@ EOI
summary: Windows
summary: Windows
EOI
+
+ : ram-maximum
+ :
+ $* <<EOI 2>'stdin:3:1: error: machine maximum RAM redefinition' == 1
+ : 1
+ ram-maximum: 4194304
+ ram-maximum: 4194304
+ EOI
+
+ : role
+ :
+ $* <<EOI 2>'stdin:3:1: error: machine role redefinition' == 1
+ : 1
+ role: build
+ role: auxiliary
+ EOI
}
: empty
diff --git a/tests/manifest/task-request.testscript b/tests/manifest/task-request.testscript
index 85801a9..79f3982 100644
--- a/tests/manifest/task-request.testscript
+++ b/tests/manifest/task-request.testscript
@@ -18,6 +18,7 @@ test.options += -tq
interactive-mode: both
interactive-login: 10.5.0.1:5901
fingerprint: 1105fb394ee870adb154b7abfbbae5755df7dcef6c81db34e8d1b68d2653734e
+ auxiliary-ram: 41943040
:
id: a2b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
name: windows_10-msvc_14
@@ -72,6 +73,14 @@ test.options += -tq
fingerprint: 1105fb394ee870adb154b7abfbbae5755df7dcef6c81db34e8d1b68d2653734e
fingerprint: 1105fb394ee870adb154b7abfbbae5755df7dcef6c81db34e8d1b68d2653734e
EOI
+
+ : auxiliary-ram
+ :
+ $* <<EOI 2>'stdin:3:1: error: auxiliary machines RAM limit redefinition' == 1
+ : 1
+ auxiliary-ram: 41943040
+ auxiliary-ram: 41943040
+ EOI
}
: empty
@@ -90,6 +99,13 @@ test.options += -tq
: 1
toolchain-name:
EOI
+
+ : auxiliary-ram
+ :
+ $* <<EOI 2>'stdin:2:15: error: auxiliary machines RAM limit should be 64-bit unsigned integer' == 1
+ : 1
+ auxiliary-ram:
+ EOI
}
: invalid-toolchain-version
diff --git a/tests/manifest/task.testscript b/tests/manifest/task.testscript
index d224124..8320f59 100644
--- a/tests/manifest/task.testscript
+++ b/tests/manifest/task.testscript
@@ -22,8 +22,14 @@ test.options += -t
examples: foo-examples
dependency-checksum: 12345
machine: windows_10-msvc_14
+ auxiliary-machine-pgsql: x86_64-linux_debian_12-postgresql_16
+ auxiliary-machine: x86_64-linux_debian_12-mysql*
target: x86_64-microsoft-win32-msvc14.0
environment: lld
+ auxiliary-environment:\
+ PGSQL_DATABASE_HOST=192.168.0.1
+ PGSQL_DATABASE_PORT=1245
+ \
target-config: config.cc.coptions=/Z7 config.cc.loptions=/DEBUG
package-config: config.foo.network=true
warning-regex: '^warning: ' '^.+: warning: '
@@ -248,6 +254,14 @@ test.options += -t
machine: windows_10-msvc_14
EOI
+ : auxiliary-machine
+ :
+ $* <<EOI 2>'stdin:3:1: error: task auxiliary machine environment redefinition' == 1
+ : 1
+ auxiliary-machine-pgsql: x86_64-linux_debian_12-postgresql_16
+ auxiliary-machine-pgsql: x86_64-linux_debian_12-postgresql_14
+ EOI
+
: target
:
$* <<EOI 2>'stdin:3:1: error: task target redefinition' == 1
@@ -256,6 +270,22 @@ test.options += -t
target: x86_64-microsoft-win32-msvc14.0
EOI
+ : auxiliary-environment
+ :
+ $* <<EOI 2>'stdin:7:1: error: task auxiliary environment redefinition' == 1
+ : 1
+ auxiliary-environment:
+ \
+ PGSQL_DATABASE_HOST=192.168.0.1
+ PGSQL_DATABASE_PORT=1245
+ \
+ auxiliary-environment:
+ \
+ PGSQL_DATABASE_HOST=192.168.0.1
+ PGSQL_DATABASE_PORT=1245
+ \
+ EOI
+
: config
:
$* <<EOI 2>'stdin:3:1: error: task target configuration redefinition' == 1