aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2018-12-07 23:12:05 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2018-12-11 14:05:48 +0300
commit294c558d577cd4acb2ee8e94e0dfd6acdb946c6c (patch)
tree02742141dad6cf91040eb48eca54b718dee8ad55
parent7dabb6e931740b2777be5dca53c3cec0b984f0fb (diff)
Add support for build configuration class inheritance
-rw-r--r--mod/build-config-module.cxx (renamed from mod/build-config.cxx)197
-rw-r--r--mod/build-config-module.hxx96
-rw-r--r--mod/build-config.hxx99
-rw-r--r--mod/build.cxx53
-rw-r--r--mod/build.hxx31
-rw-r--r--mod/database-module.cxx66
-rw-r--r--mod/database-module.hxx28
-rw-r--r--mod/mod-build-configs.cxx25
-rw-r--r--mod/mod-build-configs.hxx6
-rw-r--r--mod/mod-build-force.cxx8
-rw-r--r--mod/mod-build-force.hxx3
-rw-r--r--mod/mod-build-log.cxx8
-rw-r--r--mod/mod-build-log.hxx3
-rw-r--r--mod/mod-build-result.cxx21
-rw-r--r--mod/mod-build-result.hxx3
-rw-r--r--mod/mod-build-task.cxx21
-rw-r--r--mod/mod-build-task.hxx3
-rw-r--r--mod/mod-builds.cxx15
-rw-r--r--mod/mod-builds.hxx3
-rw-r--r--mod/mod-package-version-details.cxx16
-rw-r--r--mod/mod-package-version-details.hxx4
-rw-r--r--mod/page.cxx4
-rw-r--r--tests/load/1/math/libfoo-1.0.tar.gzbin278 -> 327 bytes
-rw-r--r--tests/load/1/math/packages.manifest6
-rw-r--r--tests/load/1/stable/libfoo-1.0.tar.gzbin278 -> 327 bytes
-rw-r--r--tests/load/1/stable/packages.manifest6
-rw-r--r--tests/load/1/stable/signature.manifest20
-rw-r--r--tests/load/driver.cxx2
28 files changed, 418 insertions, 329 deletions
diff --git a/mod/build-config.cxx b/mod/build-config-module.cxx
index 7e1416d..57c035f 100644
--- a/mod/build-config.cxx
+++ b/mod/build-config-module.cxx
@@ -1,30 +1,31 @@
-// file : mod/build-config.cxx -*- C++ -*-
+// file : mod/build-config-module.cxx -*- C++ -*-
// copyright : Copyright (c) 2014-2018 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
-#include <mod/build-config.hxx>
+#include <mod/build-config-module.hxx>
+
+#include <errno.h> // EIO
#include <map>
#include <sstream>
-#include <algorithm> // replace()
#include <libbutl/sha256.mxx>
#include <libbutl/utility.mxx> // throw_generic_error(), alpha(), etc.
#include <libbutl/openssl.mxx>
#include <libbutl/filesystem.mxx>
-#include <web/mime-url-encoding.hxx>
-
-#include <mod/utility.hxx>
-
namespace brep
{
using namespace std;
- using namespace web;
using namespace butl;
+ using namespace bpkg;
using namespace bbot;
- shared_ptr<const build_configs>
+ // Return pointer to the shared build configurations instance, creating one
+ // on the first call. Throw tab_parsing on parsing error, io_error on the
+ // underlying OS error. Note: not thread-safe.
+ //
+ static shared_ptr<const build_configs>
shared_build_config (const path& p)
{
static map<path, weak_ptr<build_configs>> configs;
@@ -43,19 +44,25 @@ namespace brep
return c;
}
- shared_ptr<const bot_agent_keys>
+ // Return pointer to the shared build bot agent public keys map, creating
+ // one on the first call. Throw system_error on the underlying openssl or OS
+ // error. Note: not thread-safe.
+ //
+ using bot_agent_key_map = map<string, path>;
+
+ static shared_ptr<const bot_agent_key_map>
shared_bot_agent_keys (const options::openssl_options& o, const dir_path& d)
{
- static map<dir_path, weak_ptr<bot_agent_keys>> keys;
+ static map<dir_path, weak_ptr<bot_agent_key_map>> keys;
auto i (keys.find (d));
if (i != keys.end ())
{
- if (shared_ptr<bot_agent_keys> k = i->second.lock ())
+ if (shared_ptr<bot_agent_key_map> k = i->second.lock ())
return k;
}
- shared_ptr<bot_agent_keys> ak (make_shared<bot_agent_keys> ());
+ shared_ptr<bot_agent_key_map> ak (make_shared<bot_agent_key_map> ());
// Intercept exception handling to make error descriptions more
// informative.
@@ -111,50 +118,55 @@ namespace brep
return ak;
}
- string
- build_log_url (const string& host, const dir_path& root,
- const build& b,
- const string* op)
+ void build_config_module::
+ init (const options::build& bo)
{
- // Note that '+' is the only package version character that potentially
- // needs to be url-encoded, and only in the query part of the URL. We embed
- // the package version into the URL path part and so don't encode it.
- //
- string url (host + tenant_dir (root, b.tenant).representation () +
- mime_url_encode (b.package_name.string (), false) + '/' +
- b.package_version.string () + "/log/" +
- mime_url_encode (b.configuration, false) + '/' +
- b.toolchain_version.string ());
+ try
+ {
+ build_conf_ = shared_build_config (bo.build_config ());
+ }
+ catch (const io_error& e)
+ {
+ ostringstream os;
+ os << "unable to read build configuration '" << bo.build_config ()
+ << "': " << e;
+
+ throw_generic_error (EIO, os.str ().c_str ());
+ }
- if (op != nullptr)
+ if (bo.build_bot_agent_keys_specified ())
+ bot_agent_key_map_ =
+ shared_bot_agent_keys (bo, bo.build_bot_agent_keys ());
+
+ cstrings conf_names;
+
+ using conf_map_type = map<const char*,
+ const build_config*,
+ compare_c_string>;
+
+ conf_map_type conf_map;
+
+ for (const auto& c: *build_conf_)
{
- url += '/';
- url += *op;
+ const char* cn (c.name.c_str ());
+ conf_map[cn] = &c;
+ conf_names.push_back (cn);
}
- return url;
+ build_conf_names_ = make_shared<cstrings> (move (conf_names));
+ build_conf_map_ = make_shared<conf_map_type> (move (conf_map));
}
- string
- force_rebuild_url (const string& host, const dir_path& root, const build& b)
- {
- // Note that '+' is the only package version character that potentially
- // needs to be url-encoded, and only in the query part of the URL. However
- // we embed the package version into the URL query part, where it is not
- // encoded by design.
- //
- return host + tenant_dir (root, b.tenant).string () +
- "?build-force&pn=" + mime_url_encode (b.package_name.string ()) +
- "&pv=" + b.package_version.string () +
- "&cf=" + mime_url_encode (b.configuration) +
- "&tc=" + b.toolchain_version.string () + "&reason=";
- }
+ // The default underlying class set expression (see below).
+ //
+ static const build_class_expr default_ucs_expr (
+ {"default"}, '+', "Default.");
- bool
- exclude (const build_class_exprs& exprs,
- const build_constraints& constrs,
+ bool build_config_module::
+ exclude (const vector<build_class_expr>& exprs,
+ const vector<build_constraint>& constrs,
const build_config& cfg,
- string* reason)
+ string* reason) const
{
// Save the first sentence of the reason, lower-case the first letter if
// the beginning looks like a word (all subsequent characters until a
@@ -189,50 +201,29 @@ namespace brep
return r;
};
- bool r (false);
-
// First, match the configuration against the package underlying build
// class set and expressions.
//
- // Determine the underlying class set. Note that in the future we can
- // potentially extend the underlying set with the special classes.
- //
- build_class_expr ucs (
- !exprs.empty () && !exprs.front ().underlying_classes.empty ()
- ? exprs.front ()
- : build_class_expr ("default", "Default"));
+ bool m (false);
- // Transform the combined package build configuration class expression,
- // making the underlying class set a starting set for the original
- // expression and a restricting set, simultaneously. For example, for the
- // expression:
- //
- // default legacy : -msvc
- //
- // the resulting expression will be:
- //
- // +default +legacy -msvc &( +default +legacy )
+ // Match the configuration against an expression, updating the match
+ // result.
//
- //
- build_class_exprs es;
- es.emplace_back (ucs.underlying_classes, '+', ucs.comment);
- es.insert (es.end (), exprs.begin (), exprs.end ());
- es.emplace_back (ucs.underlying_classes, '&', ucs.comment);
-
// We will use a comment of the first encountered excluding expression
// (changing the result from true to false) or non-including one (leaving
// the false result) as an exclusion reason.
//
- for (const build_class_expr& e: es)
+ auto match = [&cfg, &m, reason, &sanitize, this]
+ (const build_class_expr& e)
{
- bool pr (r);
- e.match (cfg.classes, r);
+ bool pm (m);
+ e.match (cfg.classes, build_conf_->class_inheritance_map, m);
if (reason != nullptr)
{
// Reset the reason which, if saved, makes no sense anymore.
//
- if (r)
+ if (m)
{
reason->clear ();
}
@@ -240,7 +231,7 @@ namespace brep
//
// Exclusion.
//
- (pr ||
+ (pm ||
//
// Non-inclusion. Make sure that the build class expression
// is empty or starts with an addition (+...).
@@ -251,9 +242,54 @@ namespace brep
*reason = sanitize (e.comment);
}
}
+ };
+
+ // Determine the underlying class set. Note that in the future we can
+ // potentially extend the underlying set with special classes.
+ //
+ const build_class_expr* ucs (
+ !exprs.empty () && !exprs.front ().underlying_classes.empty ()
+ ? &exprs.front ()
+ : nullptr);
+
+ // Note that the combined package build configuration class expression can
+ // be represented as the underlying class set used as a starting set for
+ // the original expressions and a restricting set, simultaneously. For
+ // example, for the expression:
+ //
+ // default legacy : -msvc
+ //
+ // the resulting expression will be:
+ //
+ // +( +default +legacy ) -msvc &( +default +legacy )
+ //
+ // Let's, however, optimize it a bit based on the following facts:
+ //
+ // - If the underlying class set expression (+default +legacy in the above
+ // example) evaluates to false, then the resulting expression also
+ // evaluates to false due to the trailing '&' operation. Thus, we don't
+ // need to evaluate further if that's the case.
+ //
+ // - On the other hand, if the underlying class set expression evaluates
+ // to true, then we don't need to apply the trailing '&' operation as it
+ // cannot affect the result.
+ //
+ const build_class_expr& ucs_expr (
+ ucs != nullptr
+ ? build_class_expr (ucs->underlying_classes, '+', ucs->comment)
+ : default_ucs_expr);
+
+ match (ucs_expr);
+
+ if (m)
+ {
+ for (const build_class_expr& e: exprs)
+ match (e);
}
- if (!r)
+ // Exclude the configuration if it doesn't match the compound expression.
+ //
+ if (!m)
return true;
// Now check if the configuration is excluded/included via the patterns.
@@ -266,6 +302,7 @@ namespace brep
// the build configuration name/target (illegal) are invalid paths, then
// we assume no match.
//
+ if (!constrs.empty ())
try
{
path cn (dash_components_to_path (cfg.name));
@@ -298,7 +335,7 @@ namespace brep
return false;
}
- path
+ path build_config_module::
dash_components_to_path (const string& s)
{
string r;
diff --git a/mod/build-config-module.hxx b/mod/build-config-module.hxx
new file mode 100644
index 0000000..bd6e0b0
--- /dev/null
+++ b/mod/build-config-module.hxx
@@ -0,0 +1,96 @@
+// file : mod/build-config-module.hxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2018 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#ifndef MOD_BUILD_CONFIG_MODULE_HXX
+#define MOD_BUILD_CONFIG_MODULE_HXX
+
+#include <map>
+#include <algorithm> // find()
+
+#include <libbutl/utility.mxx> // compare_c_string
+
+#include <libbpkg/manifest.hxx>
+
+#include <libbbot/build-config.hxx>
+
+#include <libbrep/types.hxx>
+#include <libbrep/utility.hxx>
+
+#include <mod/module.hxx>
+#include <mod/options.hxx>
+
+// Base class for modules that utilize the build controller configuration.
+//
+// Specifically, it loads build controller configuration and provides various
+// build configuration-related utilities. Note that the configuration is
+// shared across multiple modules once loaded.
+//
+// Note that the build database is in the database_module.
+//
+namespace brep
+{
+ class build_config_module
+ {
+ protected:
+ // Parse build configuration file and establish mapping of build bot agent
+ // public keys fingerprints to their paths. Throw tab_parsing on parsing
+ // error, system_error on the underlying OS error.
+ //
+ void
+ init (const options::build&);
+
+ // Return true if the specified build configuration is excluded by a
+ // package based on its underlying build class set, build class
+ // expressions, and build constraints, potentially extending the
+ // underlying set with the special classes. Set the exclusion reason if
+ // requested.
+ //
+ bool
+ exclude (const vector<bpkg::build_class_expr>&,
+ const vector<bpkg::build_constraint>&,
+ const bbot::build_config&,
+ string* reason = nullptr) const;
+
+ // Check if the configuration belongs to the specified class.
+ //
+ // Note that the configuration base classes are not checked.
+ //
+ static bool
+ belongs (const bbot::build_config& cfg, const char* cls)
+ {
+ const strings& cs (cfg.classes);
+ return std::find (cs.begin (), cs.end (), cls) != cs.end ();
+ }
+
+ // Convert dash-separated components (target, build configuration name,
+ // machine name) or a pattern thereof into a path, replacing dashes with
+ // slashes (directory separators), `**` with `*/**/*`, and appending the
+ // trailing slash for a subsequent match using the path_match()
+ // functionality (the idea here is for `linux**` to match `linux-gcc`
+ // which is quite natural to expect). Throw invalid_path if the resulting
+ // path is invalid.
+ //
+ // Note that the match_absent path match flag must be used for the above
+ // `**` transformation to work.
+ //
+ static path
+ dash_components_to_path (const string&);
+
+ protected:
+ // Build configurations.
+ //
+ shared_ptr<const bbot::build_configs> build_conf_;
+ shared_ptr<const cstrings> build_conf_names_;
+
+ shared_ptr<const std::map<const char*,
+ const bbot::build_config*,
+ butl::compare_c_string>> build_conf_map_;
+
+ // Map of build bot agent public keys fingerprints to the key file paths.
+ //
+ shared_ptr<const std::map<string, path>> bot_agent_key_map_;
+ };
+}
+
+#endif // MOD_BUILD_CONFIG_MODULE_HXX
diff --git a/mod/build-config.hxx b/mod/build-config.hxx
deleted file mode 100644
index 6eece1d..0000000
--- a/mod/build-config.hxx
+++ /dev/null
@@ -1,99 +0,0 @@
-// file : mod/build-config.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2018 Code Synthesis Ltd
-// license : MIT; see accompanying LICENSE file
-
-#ifndef MOD_BUILD_CONFIG_HXX
-#define MOD_BUILD_CONFIG_HXX
-
-#include <map>
-#include <algorithm> // find()
-
-#include <libbbot/build-config.hxx>
-
-#include <libbrep/types.hxx>
-#include <libbrep/utility.hxx>
-
-#include <libbrep/build.hxx>
-#include <libbrep/build-package.hxx>
-
-#include <mod/options.hxx>
-
-// Various build-related state and utilities.
-//
-namespace brep
-{
- using bbot::build_config;
-
- // Return pointer to the shared build configurations instance, creating one
- // on the first call. Throw tab_parsing on parsing error, io_error on the
- // underlying OS error. Is not thread-safe.
- //
- shared_ptr<const bbot::build_configs>
- shared_build_config (const path&);
-
- // Map of build bot agent public keys fingerprints to the key file paths.
- //
- using bot_agent_keys = std::map<string, path>;
-
- // Return pointer to the shared build bot agent public keys map, creating
- // one on the first call. Throw system_error on the underlying openssl or OS
- // error. Not thread-safe.
- //
- shared_ptr<const bot_agent_keys>
- shared_bot_agent_keys (const options::openssl_options&, const dir_path&);
-
- // Return the package configuration build log url. By default the url is to
- // the operations combined log.
- //
- string
- build_log_url (const string& host, const dir_path& root,
- const build&,
- const string* operation = nullptr);
-
- // Return the package configuration forced rebuild url.
- //
- string
- force_rebuild_url (const string& host, const dir_path& root, const build&);
-
- // Check if the configuration belongs to the specified class.
- //
- inline bool
- belongs (const build_config& cfg, const char* cls)
- {
- const strings& cs (cfg.classes);
- return find (cs.begin (), cs.end (), cls) != cs.end ();
- }
-
- // Return true if the specified build configuration is excluded by a package
- // based on its underlying build class set, build class expressions, and
- // build constraints, potentially extending the underlying set with the
- // special classes. Set the exclusion reason if requested.
- //
- bool
- exclude (const build_class_exprs&,
- const build_constraints&,
- const build_config&,
- string* reason = nullptr);
-
- inline bool
- exclude (const build_package& p, const build_config& c, string* r = nullptr)
- {
- return exclude (p.builds, p.constraints, c, r);
- }
-
- // Convert dash-separated components (target, build configuration name,
- // machine name) or a pattern thereof into a path, replacing dashes with
- // slashes (directory separators), `**` with `*/**/*`, and appending the
- // trailing slash for a subsequent match using the path_match()
- // functionality (the idea here is for `linux**` to match `linux-gcc` which
- // is quite natural to expect). Throw invalid_path if the resulting path is
- // invalid.
- //
- // Note that the match_absent path match flag must be used for the above
- // `**` transformation to work.
- //
- path
- dash_components_to_path (const string&);
-}
-
-#endif // MOD_BUILD_CONFIG_HXX
diff --git a/mod/build.cxx b/mod/build.cxx
new file mode 100644
index 0000000..6ad2b93
--- /dev/null
+++ b/mod/build.cxx
@@ -0,0 +1,53 @@
+// file : mod/build.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2018 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#include <mod/build.hxx>
+
+#include <web/mime-url-encoding.hxx>
+
+#include <mod/utility.hxx>
+
+namespace brep
+{
+ using namespace web;
+
+ string
+ build_log_url (const string& host, const dir_path& root,
+ const build& b,
+ const string* op)
+ {
+ // Note that '+' is the only package version character that potentially
+ // needs to be url-encoded, and only in the query part of the URL. We embed
+ // the package version into the URL path part and so don't encode it.
+ //
+ string url (host + tenant_dir (root, b.tenant).representation () +
+ mime_url_encode (b.package_name.string (), false) + '/' +
+ b.package_version.string () + "/log/" +
+ mime_url_encode (b.configuration, false) + '/' +
+ b.toolchain_version.string ());
+
+ if (op != nullptr)
+ {
+ url += '/';
+ url += *op;
+ }
+
+ return url;
+ }
+
+ string
+ build_force_url (const string& host, const dir_path& root, const build& b)
+ {
+ // Note that '+' is the only package version character that potentially
+ // needs to be url-encoded, and only in the query part of the URL. However
+ // we embed the package version into the URL query part, where it is not
+ // encoded by design.
+ //
+ return host + tenant_dir (root, b.tenant).string () +
+ "?build-force&pn=" + mime_url_encode (b.package_name.string ()) +
+ "&pv=" + b.package_version.string () +
+ "&cf=" + mime_url_encode (b.configuration) +
+ "&tc=" + b.toolchain_version.string () + "&reason=";
+ }
+}
diff --git a/mod/build.hxx b/mod/build.hxx
new file mode 100644
index 0000000..94c270b
--- /dev/null
+++ b/mod/build.hxx
@@ -0,0 +1,31 @@
+// file : mod/build.hxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2018 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#ifndef MOD_BUILD_HXX
+#define MOD_BUILD_HXX
+
+#include <libbrep/types.hxx>
+#include <libbrep/utility.hxx>
+
+#include <libbrep/build.hxx>
+
+// Various package build-related utilities.
+//
+namespace brep
+{
+ // Return the package build log url. By default the url is to the operations
+ // combined log.
+ //
+ string
+ build_log_url (const string& host, const dir_path& root,
+ const build&,
+ const string* operation = nullptr);
+
+ // Return the package build forced rebuild url.
+ //
+ string
+ build_force_url (const string& host, const dir_path& root, const build&);
+}
+
+#endif // MOD_BUILD_HXX
diff --git a/mod/database-module.cxx b/mod/database-module.cxx
index 137d7ef..07037cd 100644
--- a/mod/database-module.cxx
+++ b/mod/database-module.cxx
@@ -4,24 +4,13 @@
#include <mod/database-module.hxx>
-#include <errno.h> // EIO
-
-#include <sstream>
-
#include <odb/exceptions.hxx>
-#include <libbutl/utility.mxx> // throw_generic_error()
-
#include <mod/options.hxx>
#include <mod/database.hxx>
-#include <mod/build-config.hxx>
namespace brep
{
- using namespace std;
- using namespace butl;
- using namespace bbot;
-
// While currently the user-defined copy constructor is not required (we
// don't need to deep copy nullptr's), it is a good idea to keep the
// placeholder ready for less trivial cases.
@@ -31,11 +20,7 @@ namespace brep
: handler (r),
retry_ (r.retry_),
package_db_ (r.initialized_ ? r.package_db_ : nullptr),
- build_db_ (r.initialized_ ? r.build_db_ : nullptr),
- build_conf_ (r.initialized_ ? r.build_conf_ : nullptr),
- build_conf_names_ (r.initialized_ ? r.build_conf_names_ : nullptr),
- build_conf_map_ (r.initialized_ ? r.build_conf_map_ : nullptr),
- bot_agent_keys_ (r.initialized_ ? r.bot_agent_keys_ : nullptr)
+ build_db_ (r.initialized_ ? r.build_db_ : nullptr)
{
}
@@ -54,48 +39,15 @@ namespace brep
}
void database_module::
- init (const options::build& bo, const options::build_db& dbo, size_t retry)
+ init (const options::build_db& o, size_t retry)
{
- try
- {
- build_conf_ = shared_build_config (bo.build_config ());
- }
- catch (const io_error& e)
- {
- ostringstream os;
- os << "unable to read build configuration '" << bo.build_config ()
- << "': " << e;
-
- throw_generic_error (EIO, os.str ().c_str ());
- }
-
- if (bo.build_bot_agent_keys_specified ())
- bot_agent_keys_ = shared_bot_agent_keys (bo, bo.build_bot_agent_keys ());
-
- cstrings conf_names;
-
- using conf_map_type = map<const char*,
- const build_config*,
- compare_c_string>;
- conf_map_type conf_map;
-
- for (const auto& c: *build_conf_)
- {
- const char* cn (c.name.c_str ());
- conf_map[cn] = &c;
- conf_names.push_back (cn);
- }
-
- build_conf_names_ = make_shared<cstrings> (move (conf_names));
- build_conf_map_ = make_shared<conf_map_type> (move (conf_map));
-
- build_db_ = shared_database (dbo.build_db_user (),
- dbo.build_db_role (),
- dbo.build_db_password (),
- dbo.build_db_name (),
- dbo.build_db_host (),
- dbo.build_db_port (),
- dbo.build_db_max_connections ());
+ build_db_ = shared_database (o.build_db_user (),
+ o.build_db_role (),
+ o.build_db_password (),
+ o.build_db_name (),
+ o.build_db_host (),
+ o.build_db_port (),
+ o.build_db_max_connections ());
retry_ = retry_ < retry ? retry : retry_;
}
diff --git a/mod/database-module.hxx b/mod/database-module.hxx
index 70ae004..9791ece 100644
--- a/mod/database-module.hxx
+++ b/mod/database-module.hxx
@@ -5,20 +5,13 @@
#ifndef MOD_DATABASE_MODULE_HXX
#define MOD_DATABASE_MODULE_HXX
-#include <map>
-
#include <odb/forward.hxx> // database
-#include <libbutl/utility.mxx> // compare_c_string
-
#include <libbrep/types.hxx>
#include <libbrep/utility.hxx>
-#include <libbbot/build-config.hxx>
-
#include <mod/module.hxx>
#include <mod/options.hxx>
-#include <mod/build-config.hxx>
namespace brep
{
@@ -49,12 +42,11 @@ namespace brep
void
init (const options::package_db&, size_t retry);
- // Initialize the build database instance and parse build configuration
- // file. Throw odb::exception on database failure, tab_parsing on parsing
- // error, system_error on the underlying OS error.
+ // Initialize the build database instance. Throw odb::exception on
+ // database failure.
//
void
- init (const options::build&, const options::build_db&, size_t retry);
+ init (const options::build_db&, size_t retry);
virtual bool
handle (request&, response&) = 0;
@@ -63,19 +55,7 @@ namespace brep
size_t retry_ = 0; // Max of all retries.
shared_ptr<odb::core::database> package_db_;
-
- // These are NULL if not building.
- //
- shared_ptr<odb::core::database> build_db_;
- shared_ptr<const bbot::build_configs> build_conf_;
- shared_ptr<const cstrings> build_conf_names_;
-
- shared_ptr<const std::map<const char*,
- const bbot::build_config*,
- butl::compare_c_string>>
- build_conf_map_;
-
- shared_ptr<const bot_agent_keys> bot_agent_keys_;
+ shared_ptr<odb::core::database> build_db_; // NULL if not building.
private:
virtual bool
diff --git a/mod/mod-build-configs.cxx b/mod/mod-build-configs.cxx
index 99a092d..826bb87 100644
--- a/mod/mod-build-configs.cxx
+++ b/mod/mod-build-configs.cxx
@@ -11,7 +11,6 @@
#include <mod/page.hxx>
#include <mod/options.hxx>
-#include <mod/build-config.hxx>
using namespace std;
using namespace bbot;
@@ -24,8 +23,8 @@ using namespace brep::cli;
brep::build_configs::
build_configs (const build_configs& r)
: handler (r),
- options_ (r.initialized_ ? r.options_ : nullptr),
- build_conf_ (r.initialized_ ? r.build_conf_ : nullptr)
+ build_config_module (r),
+ options_ (r.initialized_ ? r.options_ : nullptr)
{
}
@@ -38,15 +37,7 @@ init (scanner& s)
s, unknown_mode::fail, unknown_mode::fail);
if (options_->build_config_specified ())
- try
- {
- build_conf_ = shared_build_config (options_->build_config ());
- }
- catch (const io_error& e)
- {
- fail << "unable to read build configuration '"
- << options_->build_config () << "': " << e;
- }
+ build_config_module::init (static_cast<options::build> (*options_));
}
bool brep::build_configs::
@@ -133,7 +124,17 @@ handle (request& rq, response& rs)
{
if (!classes.empty ())
classes += ' ';
+
classes += cls;
+
+ // Append the base class, if present.
+ //
+ auto i (build_conf_->class_inheritance_map.find (cls));
+ if (i != build_conf_->class_inheritance_map.end ())
+ {
+ classes += ':';
+ classes += i->second;
+ }
}
s << TABLE(CLASS="proplist config")
diff --git a/mod/mod-build-configs.hxx b/mod/mod-build-configs.hxx
index 0c57359..754c596 100644
--- a/mod/mod-build-configs.hxx
+++ b/mod/mod-build-configs.hxx
@@ -8,14 +8,13 @@
#include <libbrep/types.hxx>
#include <libbrep/utility.hxx>
-#include <libbbot/build-config.hxx>
-
#include <mod/module.hxx>
#include <mod/options.hxx>
+#include <mod/build-config-module.hxx>
namespace brep
{
- class build_configs: public handler
+ class build_configs: public handler, private build_config_module
{
public:
build_configs () = default;
@@ -41,7 +40,6 @@ namespace brep
private:
shared_ptr<options::build_configs> options_;
- shared_ptr<const bbot::build_configs> build_conf_;
};
}
diff --git a/mod/mod-build-force.cxx b/mod/mod-build-force.cxx
index ddc1301..3a92b53 100644
--- a/mod/mod-build-force.cxx
+++ b/mod/mod-build-force.cxx
@@ -28,6 +28,7 @@ using namespace odb::core;
brep::build_force::
build_force (const build_force& r)
: database_module (r),
+ build_config_module (r),
options_ (r.initialized_ ? r.options_ : nullptr)
{
}
@@ -41,9 +42,12 @@ init (scanner& s)
s, unknown_mode::fail, unknown_mode::fail);
if (options_->build_config_specified ())
- database_module::init (static_cast<options::build> (*options_),
- static_cast<options::build_db> (*options_),
+ {
+ database_module::init (static_cast<options::build_db> (*options_),
options_->build_db_retry ());
+
+ build_config_module::init (static_cast<options::build> (*options_));
+ }
}
bool brep::build_force::
diff --git a/mod/mod-build-force.hxx b/mod/mod-build-force.hxx
index 1af7723..5448026 100644
--- a/mod/mod-build-force.hxx
+++ b/mod/mod-build-force.hxx
@@ -10,10 +10,11 @@
#include <mod/options.hxx>
#include <mod/database-module.hxx>
+#include <mod/build-config-module.hxx>
namespace brep
{
- class build_force: public database_module
+ class build_force: public database_module, private build_config_module
{
public:
build_force () = default;
diff --git a/mod/mod-build-log.cxx b/mod/mod-build-log.cxx
index ee5d1b2..63b2f75 100644
--- a/mod/mod-build-log.cxx
+++ b/mod/mod-build-log.cxx
@@ -30,6 +30,7 @@ using namespace odb::core;
brep::build_log::
build_log (const build_log& r)
: database_module (r),
+ build_config_module (r),
options_ (r.initialized_ ? r.options_ : nullptr)
{
}
@@ -43,10 +44,13 @@ init (scanner& s)
s, unknown_mode::fail, unknown_mode::fail);
if (options_->build_config_specified ())
- database_module::init (static_cast<options::build> (*options_),
- static_cast<options::build_db> (*options_),
+ {
+ database_module::init (static_cast<options::build_db> (*options_),
options_->build_db_retry ());
+ build_config_module::init (*options_);
+ }
+
if (options_->root ().empty ())
options_->root (dir_path ("/"));
}
diff --git a/mod/mod-build-log.hxx b/mod/mod-build-log.hxx
index 154403e..9c31286 100644
--- a/mod/mod-build-log.hxx
+++ b/mod/mod-build-log.hxx
@@ -10,10 +10,11 @@
#include <mod/options.hxx>
#include <mod/database-module.hxx>
+#include <mod/build-config-module.hxx>
namespace brep
{
- class build_log: public database_module
+ class build_log: public database_module, private build_config_module
{
public:
build_log () = default;
diff --git a/mod/mod-build-result.cxx b/mod/mod-build-result.cxx
index 177e67f..5f671d3 100644
--- a/mod/mod-build-result.cxx
+++ b/mod/mod-build-result.cxx
@@ -23,8 +23,8 @@
#include <libbrep/package.hxx>
#include <libbrep/package-odb.hxx>
+#include <mod/build.hxx> // *_url()
#include <mod/options.hxx>
-#include <mod/build-config.hxx> // *_url()
using namespace std;
using namespace butl;
@@ -39,6 +39,7 @@ using namespace odb::core;
brep::build_result::
build_result (const build_result& r)
: database_module (r),
+ build_config_module (r),
options_ (r.initialized_ ? r.options_ : nullptr)
{
}
@@ -55,10 +56,13 @@ init (scanner& s)
options_->package_db_retry ());
if (options_->build_config_specified ())
- database_module::init (static_cast<options::build> (*options_),
- static_cast<options::build_db> (*options_),
+ {
+ database_module::init (static_cast<options::build_db> (*options_),
options_->build_db_retry ());
+ build_config_module::init (static_cast<options::build> (*options_));
+ }
+
if (options_->root ().empty ())
options_->root (dir_path ("/"));
}
@@ -312,18 +316,18 @@ handle (request& rq, response&)
warn_auth (rqm.challenge
? "unexpected challenge"
: "challenge is expected");
- else if (bot_agent_keys_ == nullptr) // Authentication is disabled.
+ else if (bot_agent_key_map_ == nullptr) // Authentication is disabled.
auth = true;
else if (!b->agent_challenge) // Authentication is recently enabled.
warn_auth ("challenge is required now");
else
{
assert (b->agent_fingerprint && rqm.challenge);
- auto i (bot_agent_keys_->find (*b->agent_fingerprint));
+ auto i (bot_agent_key_map_->find (*b->agent_fingerprint));
// The agent's key is recently replaced.
//
- if (i == bot_agent_keys_->end ())
+ if (i == bot_agent_key_map_->end ())
warn_auth ("agent's public key not found");
else
{
@@ -400,7 +404,8 @@ handle (request& rq, response&)
shared_ptr<build_package> p (
build_db_->load<build_package> (b->id.package));
- if (belongs (*cfg, "all") && !exclude (*p, *cfg))
+ if (belongs (*cfg, "all") &&
+ !exclude (p->builds, p->constraints, *cfg))
bld = move (b);
}
}
@@ -458,7 +463,7 @@ handle (request& rq, response&)
os << "Force rebuild (enter the reason, use '+' instead of spaces):"
<< endl << endl
- << " " << force_rebuild_url (host, root, *bld) << endl;
+ << " " << build_force_url (host, root, *bld) << endl;
}
sm.out.close ();
diff --git a/mod/mod-build-result.hxx b/mod/mod-build-result.hxx
index 2c24436..86542e7 100644
--- a/mod/mod-build-result.hxx
+++ b/mod/mod-build-result.hxx
@@ -10,10 +10,11 @@
#include <mod/options.hxx>
#include <mod/database-module.hxx>
+#include <mod/build-config-module.hxx>
namespace brep
{
- class build_result: public database_module
+ class build_result: public database_module, private build_config_module
{
public:
build_result () = default;
diff --git a/mod/mod-build-task.cxx b/mod/mod-build-task.cxx
index 14c72ac..1736869 100644
--- a/mod/mod-build-task.cxx
+++ b/mod/mod-build-task.cxx
@@ -45,6 +45,7 @@ using namespace odb::core;
brep::build_task::
build_task (const build_task& r)
: database_module (r),
+ build_config_module (r),
options_ (r.initialized_ ? r.options_ : nullptr)
{
}
@@ -59,8 +60,7 @@ init (scanner& s)
if (options_->build_config_specified ())
{
- database_module::init (static_cast<options::build> (*options_),
- static_cast<options::build_db> (*options_),
+ database_module::init (static_cast<options::build_db> (*options_),
options_->build_db_retry ());
// Check that the database 'build' schema matches the current one. It's
@@ -72,6 +72,8 @@ init (scanner& s)
build_db_->schema_version (ds))
fail << "database 'build' schema differs from the current one (module "
<< BREP_VERSION_ID << ")";
+
+ build_config_module::init (static_cast<options::build> (*options_));
}
if (options_->root ().empty ())
@@ -124,10 +126,11 @@ handle (request& rq, response& rs)
//
optional<string> agent_fp;
- if (bot_agent_keys_ != nullptr)
+ if (bot_agent_key_map_ != nullptr)
{
if (!tqm.fingerprint ||
- bot_agent_keys_->find (*tqm.fingerprint) == bot_agent_keys_->end ())
+ bot_agent_key_map_->find (*tqm.fingerprint) ==
+ bot_agent_key_map_->end ())
throw invalid_request (401, "unauthorized");
agent_fp = move (tqm.fingerprint);
@@ -220,7 +223,7 @@ handle (request& rq, response& rs)
move (fp),
cm.machine->name,
cm.config->target,
- cm.config->vars,
+ cm.config->args,
cm.config->warning_regexes);
return task_response_manifest (move (session),
@@ -476,7 +479,11 @@ handle (request& rq, response& rs)
auto i (configs.begin ());
auto e (configs.end ());
- for (; i != e && exclude (*p, *i->second.config); ++i) ;
+
+ for (;
+ i != e &&
+ exclude (p->builds, p->constraints, *i->second.config);
+ ++i) ;
if (i != e)
{
@@ -632,7 +639,7 @@ handle (request& rq, response& rs)
if (p != nullptr &&
p->internal_repository != nullptr &&
- !exclude (*p, *cm.config))
+ !exclude (p->builds, p->constraints, *cm.config))
{
assert (b->status);
diff --git a/mod/mod-build-task.hxx b/mod/mod-build-task.hxx
index 75383f0..d907ee7 100644
--- a/mod/mod-build-task.hxx
+++ b/mod/mod-build-task.hxx
@@ -10,10 +10,11 @@
#include <mod/options.hxx>
#include <mod/database-module.hxx>
+#include <mod/build-config-module.hxx>
namespace brep
{
- class build_task: public database_module
+ class build_task: public database_module, private build_config_module
{
public:
build_task () = default;
diff --git a/mod/mod-builds.cxx b/mod/mod-builds.cxx
index 6ad5a0e..6f027d2 100644
--- a/mod/mod-builds.cxx
+++ b/mod/mod-builds.cxx
@@ -28,7 +28,6 @@
#include <mod/page.hxx>
#include <mod/options.hxx>
-#include <mod/build-config.hxx> // *_url()
using namespace std;
using namespace butl;
@@ -44,6 +43,7 @@ using namespace brep::cli;
brep::builds::
builds (const builds& r)
: database_module (r),
+ build_config_module (r),
options_ (r.initialized_ ? r.options_ : nullptr)
{
}
@@ -57,10 +57,13 @@ init (scanner& s)
s, unknown_mode::fail, unknown_mode::fail);
if (options_->build_config_specified ())
- database_module::init (static_cast<options::build> (*options_),
- static_cast<options::build_db> (*options_),
+ {
+ database_module::init (static_cast<options::build_db> (*options_),
options_->build_db_retry ());
+ build_config_module::init (static_cast<options::build> (*options_));
+ }
+
if (options_->root ().empty ())
options_->root (dir_path ("/"));
}
@@ -550,7 +553,7 @@ handle (request& rq, response& rs)
// Match the configuration against the package build
// expressions/constraints.
//
- if (!exclude (*p, *i->second))
+ if (!exclude (p->builds, p->constraints, *i->second))
{
if (skip != 0)
--skip;
@@ -813,7 +816,7 @@ handle (request& rq, response& rs)
for (const auto& c: configs)
{
- if (exclude (*p, *c))
+ if (exclude (p->builds, p->constraints, *c))
{
nmax -= nt;
@@ -942,7 +945,7 @@ handle (request& rq, response& rs)
auto i (build_conf_map_->find (ct.configuration.c_str ()));
assert (i != build_conf_map_->end ());
- if (!exclude (*p, *i->second))
+ if (!exclude (p->builds, p->constraints, *i->second))
unbuilt_configs.insert (ct);
}
}
diff --git a/mod/mod-builds.hxx b/mod/mod-builds.hxx
index 4b2441a..cf4020e 100644
--- a/mod/mod-builds.hxx
+++ b/mod/mod-builds.hxx
@@ -10,10 +10,11 @@
#include <mod/options.hxx>
#include <mod/database-module.hxx>
+#include <mod/build-config-module.hxx>
namespace brep
{
- class builds: public database_module
+ class builds: public database_module, private build_config_module
{
public:
builds () = default;
diff --git a/mod/mod-package-version-details.cxx b/mod/mod-package-version-details.cxx
index 9566c8f..cbe338e 100644
--- a/mod/mod-package-version-details.cxx
+++ b/mod/mod-package-version-details.cxx
@@ -34,6 +34,7 @@ using namespace brep::cli;
brep::package_version_details::
package_version_details (const package_version_details& r)
: database_module (r),
+ build_config_module (r),
options_ (r.initialized_ ? r.options_ : nullptr)
{
}
@@ -46,13 +47,17 @@ init (scanner& s)
options_ = make_shared<options::package_version_details> (
s, unknown_mode::fail, unknown_mode::fail);
- database_module::init (*options_, options_->package_db_retry ());
+ database_module::init (static_cast<options::package_db> (*options_),
+ options_->package_db_retry ());
if (options_->build_config_specified ())
- database_module::init (static_cast<options::build> (*options_),
- static_cast<options::build_db> (*options_),
+ {
+ database_module::init (static_cast<options::build_db> (*options_),
options_->build_db_retry ());
+ build_config_module::init (static_cast<options::build> (*options_));
+ }
+
if (options_->root ().empty ())
options_->root (dir_path ("/"));
}
@@ -393,9 +398,10 @@ handle (request& rq, response& rs)
s << H3 << "Builds" << ~H3
<< DIV(ID="builds");
- auto exclude = [&pkg] (const build_config& cfg, string* reason = nullptr)
+ auto exclude = [&pkg, this] (const build_config& cfg,
+ string* reason = nullptr)
{
- return brep::exclude (pkg->builds, pkg->build_constraints, cfg, reason);
+ return this->exclude (pkg->builds, pkg->build_constraints, cfg, reason);
};
timestamp now (system_clock::now ());
diff --git a/mod/mod-package-version-details.hxx b/mod/mod-package-version-details.hxx
index 0451e99..c15d746 100644
--- a/mod/mod-package-version-details.hxx
+++ b/mod/mod-package-version-details.hxx
@@ -10,10 +10,12 @@
#include <mod/options.hxx>
#include <mod/database-module.hxx>
+#include <mod/build-config-module.hxx>
namespace brep
{
- class package_version_details: public database_module
+ class package_version_details: public database_module,
+ private build_config_module
{
public:
package_version_details () = default;
diff --git a/mod/page.cxx b/mod/page.cxx
index eab28c6..7cfce62 100644
--- a/mod/page.cxx
+++ b/mod/page.cxx
@@ -18,8 +18,8 @@
#include <libbrep/package.hxx>
#include <libbrep/package-odb.hxx>
+#include <mod/build.hxx> // build_log_url()
#include <mod/utility.hxx>
-#include <mod/build-config.hxx> // build_log_url()
using namespace std;
using namespace xml;
@@ -718,7 +718,7 @@ namespace brep
s << SPAN(CLASS="pending") << "pending" << ~SPAN;
else
s << A
- << HREF << force_rebuild_url (host_, root_, build_) << ~HREF
+ << HREF << build_force_url (host_, root_, build_) << ~HREF
<< "rebuild"
<< ~A;
diff --git a/tests/load/1/math/libfoo-1.0.tar.gz b/tests/load/1/math/libfoo-1.0.tar.gz
index e951386..2d445ec 100644
--- a/tests/load/1/math/libfoo-1.0.tar.gz
+++ b/tests/load/1/math/libfoo-1.0.tar.gz
Binary files differ
diff --git a/tests/load/1/math/packages.manifest b/tests/load/1/math/packages.manifest
index 0bbf6d4..d1c972d 100644
--- a/tests/load/1/math/packages.manifest
+++ b/tests/load/1/math/packages.manifest
@@ -32,9 +32,11 @@ version: 1.0
summary: The Foo Library
license: MIT
build-email: foo-builds@example.com
-builds: default legacy : -32; 64-bit targets only
+builds: default legacy; Stable configurations only.
+builds: -32; 64-bit targets only
+builds: &msvc_13_up; Not too old MSVC.
location: libfoo-1.0.tar.gz
-sha256sum: 3d32793e7b800837682ffa1dad794df7c9e2bb7a54504552a5bd261b5ec064e5
+sha256sum: e89c6d746f8b1ea3ec58d294946d2f683d133438d2ac8c88549ba24c19627e76
:
name: libfoo
version: 1.2.4+1
diff --git a/tests/load/1/stable/libfoo-1.0.tar.gz b/tests/load/1/stable/libfoo-1.0.tar.gz
index e951386..2d445ec 100644
--- a/tests/load/1/stable/libfoo-1.0.tar.gz
+++ b/tests/load/1/stable/libfoo-1.0.tar.gz
Binary files differ
diff --git a/tests/load/1/stable/packages.manifest b/tests/load/1/stable/packages.manifest
index 797b214..4c83ed5 100644
--- a/tests/load/1/stable/packages.manifest
+++ b/tests/load/1/stable/packages.manifest
@@ -6,9 +6,11 @@ version: 1.0
summary: The Foo Library
license: MIT
build-email: foo-builds@example.com
-builds: default legacy : -32; 64-bit targets only
+builds: default legacy; Stable configurations only.
+builds: -32; 64-bit targets only
+builds: &msvc_13_up; Not too old MSVC.
location: libfoo-1.0.tar.gz
-sha256sum: 3d32793e7b800837682ffa1dad794df7c9e2bb7a54504552a5bd261b5ec064e5
+sha256sum: e89c6d746f8b1ea3ec58d294946d2f683d133438d2ac8c88549ba24c19627e76
:
name: libfoo
version: 1.2.2-alpha.1
diff --git a/tests/load/1/stable/signature.manifest b/tests/load/1/stable/signature.manifest
index 2678657..decdf5b 100644
--- a/tests/load/1/stable/signature.manifest
+++ b/tests/load/1/stable/signature.manifest
@@ -1,13 +1,13 @@
: 1
-sha256sum: 4957fe28799fe3a037c3112c8122d216fb1d25b48c1028979e5a8738683cb1a5
+sha256sum: f48f71ccb83024007dedc63148d4682e7b2a478a3ca78583e3562ea4bcf396a5
signature: \
-Dxc/W3NM0ZZ/Aytrxpptgcg8pg6tteT9rVoFm3mxaXsLMoEzjEEHq1ruI3kbmIVHQIBYymvpj5FS
-JUeKdmtkNOZA7DqbdT5njEarKGoLE4awqsZ4yAWMKpmHNxAl/dYNIQ0l5YdsAq7+c3/lCwha9SlB
-QcZrKDxZ7DrhcdiI0eQej08n0X45OA1451VLnSkjHsLXXCO0qnj2o+WVKJE/lWz46Z6FCm9wlLQC
-cxaamInFeL5s/eZmn7j5Eo+v2y1v/zufeCr5W6feKlFau156G43ZROPUoqVl+ZxuSAR1gKalVjny
-jH1adjEkwqtxXN0fvT2pQ0XU/gn/s7PTiGR9PnKytrAFemO3hbd62PAcFRk17NV8qworyBdLMHgA
-V4/CyDCItOgAzfenbjPHfxEkm+qKcK4Y6NlUQSqcHDW8kxMv6iuVw8s0o5ij9frY5XLg2h39O/Lw
-I4tDO0lg8k2vxKJVxKk85uElJ+kuBG4353PP3G11uzZpah4X9zqh21TBP+rx+L1gefHwjew+ZwQi
-qtOedbzrJlgLgTDK3Q+yMN2i9YOIe+D5vB4Gr97y1lL0qVS3zm/4CjLo6kj13ngGXxivGLbtDlX9
-v4COE/+PtwGS2ubmku1QMwZuXyJfjKG9lGgoNoARML17EzzMIFXnzII0uSP+NUKrT3jLdEbOlQs=
+K+F80RQE97ZmEVAl2wQwyYaw/SzviqfuR7FBTdF3PtnIorCxeokwvDL0ip7PiEJRp7QF5V0T69F+
+35MqTrRm/cLdKsxk1vsG8KWMuoK3LSXj+jcPkxKGmVoI09MvPxIQNgHKe/gk1f7uBExnpeOdfHyV
+2zP6GMOhZIY4SScNeFr5lo/4bpEEtLNH1TbiYHaaGlBQDmzGzY+kdCrzZ/nWEBaWIHdT8GcqQF1D
+P+KWYFoOoT5DnZtfk3ohTI1YHdDQWyWq8vFqkfpRDwxqtHltGeNLjmlwxF6gPJq9H6UZMZfEHGvs
+qAScoiA5ozdPt1UXiYtPXpDoweHKcoVPHyqMxcciMTx8BYXDqY8V9EKwd/F3rD0ITzXW3eaRNygo
+Jh6w6tjhZjFQ+NJ9GgsxE7NNU1dYhXuzKyBwus0GkGHriGTU7L0t2MoY/1GXihexwz3fHAmkOYxe
+Iz4Xt+SZeRSLa5VFFjyEOtbtvbVv8R2WngG4xwNH0b3nMJ8Baa87rajSIfIoXJaeNFWhpEBwCToz
+59aJXl76+0kQL40+wSO7+/o8LnLS2sW6+ooMjM8RLRBLTzNqSsVH5kA+W0qF8e0j7AJ0qcqU5HKZ
+MzhB7jPyQ82LBq/eU29bgM9hLkOiJpqwplmiRyby98jBz4ppnIytfQeD52PtDCf4yWT9p3PsKmg=
\
diff --git a/tests/load/driver.cxx b/tests/load/driver.cxx
index a36416b..17da60e 100644
--- a/tests/load/driver.cxx
+++ b/tests/load/driver.cxx
@@ -405,7 +405,7 @@ test_pkg_repos (const cstrings& loader_args,
assert (check_location (fpv1));
assert (fpv1->sha256sum && *fpv1->sha256sum ==
- "3d32793e7b800837682ffa1dad794df7c9e2bb7a54504552a5bd261b5ec064e5");
+ "e89c6d746f8b1ea3ec58d294946d2f683d133438d2ac8c88549ba24c19627e76");
// libfoo-1.2.2
//