aboutsummaryrefslogtreecommitdiff
path: root/libbrep/common.hxx
diff options
context:
space:
mode:
Diffstat (limited to 'libbrep/common.hxx')
-rw-r--r--libbrep/common.hxx457
1 files changed, 440 insertions, 17 deletions
diff --git a/libbrep/common.hxx b/libbrep/common.hxx
index 6dc4870..1433c8c 100644
--- a/libbrep/common.hxx
+++ b/libbrep/common.hxx
@@ -1,14 +1,19 @@
// file : libbrep/common.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#ifndef LIBBREP_COMMON_HXX
#define LIBBREP_COMMON_HXX
+#include <map>
#include <ratio>
#include <chrono>
#include <type_traits> // static_assert
+#include <odb/query.hxx>
+#include <odb/nested-container.hxx>
+
+#include <libbutl/target-triplet.hxx>
+
#include <libbpkg/package-name.hxx>
#include <libbrep/types.hxx>
@@ -112,7 +117,7 @@ namespace brep
std::chrono::nanoseconds::period>::value,
"The following timestamp ODB mapping is invalid");
- // As it pointed out in libbutl/timestamp.mxx we will overflow in year 2262,
+ // As it pointed out in libbutl/timestamp.hxx we will overflow in year 2262,
// but by that time some larger basic type will be available for mapping.
//
#pragma db map type(timestamp) as(uint64_t) \
@@ -122,6 +127,20 @@ namespace brep
std::chrono::duration_cast<brep::timestamp::duration> ( \
std::chrono::nanoseconds (?))))
+ using optional_timestamp = optional<timestamp>;
+ using optional_uint64 = optional<uint64_t>;
+
+ #pragma db map type(optional_timestamp) as(brep::optional_uint64) \
+ to((?) \
+ ? std::chrono::duration_cast<std::chrono::nanoseconds> ( \
+ (?)->time_since_epoch ()).count () \
+ : brep::optional_uint64 ()) \
+ from((?) \
+ ? brep::timestamp ( \
+ std::chrono::duration_cast<brep::timestamp::duration> ( \
+ std::chrono::nanoseconds (*(?)))) \
+ : brep::optional_timestamp ())
+
// version
//
using bpkg::version;
@@ -227,6 +246,12 @@ namespace brep
//
extern const version wildcard_version;
+ // target_triplet
+ //
+ using butl::target_triplet;
+
+ #pragma db value(target_triplet) type("TEXT")
+
// package_name
//
using bpkg::package_name;
@@ -301,6 +326,19 @@ namespace brep
: tenant (move (t)), canonical_name (move (n)) {}
};
+ // public_key_id
+ //
+ #pragma db value
+ struct public_key_id
+ {
+ string tenant;
+ string fingerprint;
+
+ public_key_id () = default;
+ public_key_id (string t, string f)
+ : tenant (move (t)), fingerprint (move (f)) {}
+ };
+
// build_class_expr
//
using bpkg::build_class_expr;
@@ -322,15 +360,326 @@ namespace brep
#pragma db value(build_constraint) definition
+ // build_auxiliaries
+ //
+ using bpkg::build_auxiliary;
+ using build_auxiliaries = vector<build_auxiliary>;
+
+ #pragma db value(build_auxiliary) definition
+
+ // build_toolchain
+ //
+ #pragma db value
+ struct build_toolchain
+ {
+ string name;
+ brep::version version;
+ };
+
+ // email
+ //
+ using bpkg::email;
+
+ #pragma db value(email) definition
+ #pragma db member(email::value) virtual(string) before access(this) column("")
+
+ // build_package_config_template
+ //
+ using bpkg::build_package_config_template;
+
+ // 1 for the default configuration which is always present.
+ //
+ template <typename K>
+ using build_package_configs_template =
+ small_vector<build_package_config_template<K>, 1>;
+
+ // Return the address of the configuration object with the specified name,
+ // if present, and NULL otherwise.
+ //
+ template <typename K>
+ inline build_package_config_template<K>*
+ find (const string& name, build_package_configs_template<K>& cs)
+ {
+ auto i (find_if (cs.begin (), cs.end (),
+ [&name] (const build_package_config_template<K>& c)
+ {return c.name == name;}));
+
+ return i != cs.end () ? &*i : nullptr;
+ }
+
+ // Note that ODB doesn't support containers of value types which contain
+ // containers. Thus, we will persist/load
+ // build_package_config_template<K>::{builds,constraint,auxiliaries,bot_keys}
+ // via the separate nested containers using the adapter classes.
+ //
+
+ // build_package_config_template<K>::builds
+ //
+ using build_class_expr_key = odb::nested_key<build_class_exprs>;
+ using build_class_exprs_map = std::map<build_class_expr_key, build_class_expr>;
+
+ #pragma db value(build_class_expr_key)
+ #pragma db member(build_class_expr_key::outer) column("config_index")
+ #pragma db member(build_class_expr_key::inner) column("index")
+
+ // Adapter for build_package_config_template<K>::builds.
+ //
+ // Note: 1 as for build_package_configs_template.
+ //
+ class build_package_config_builds: public small_vector<build_class_exprs, 1>
+ {
+ public:
+ build_package_config_builds () = default;
+
+ template <typename K>
+ explicit
+ build_package_config_builds (const build_package_configs_template<K>& cs)
+ {
+ reserve (cs.size ());
+ for (const build_package_config_template<K>& c: cs)
+ push_back (c.builds);
+ }
+
+ template <typename K>
+ void
+ to_configs (build_package_configs_template<K>& cs) &&
+ {
+ // Note that the empty trailing entries will be missing (see ODB's
+ // nested-container.hxx for details).
+ //
+ assert (size () <= cs.size ());
+
+ auto i (cs.begin ());
+ for (build_class_exprs& ces: *this)
+ i++->builds = move (ces);
+ }
+ };
+
+ // build_package_config_template<K>::constraints
+ //
+ using build_constraint_key = odb::nested_key<build_constraints>;
+ using build_constraints_map = std::map<build_constraint_key, build_constraint>;
+
+ #pragma db value(build_constraint_key)
+ #pragma db member(build_constraint_key::outer) column("config_index")
+ #pragma db member(build_constraint_key::inner) column("index")
+
+ // Adapter for build_package_config_template<K>::constraints.
+ //
+ // Note: 1 as for build_package_configs_template.
+ //
+ class build_package_config_constraints:
+ public small_vector<build_constraints, 1>
+ {
+ public:
+ build_package_config_constraints () = default;
+
+ template <typename K>
+ explicit
+ build_package_config_constraints (
+ const build_package_configs_template<K>& cs)
+ {
+ reserve (cs.size ());
+ for (const build_package_config_template<K>& c: cs)
+ push_back (c.constraints);
+ }
+
+ template <typename K>
+ void
+ to_configs (build_package_configs_template<K>& cs) &&
+ {
+ // Note that the empty trailing entries will be missing (see ODB's
+ // nested-container.hxx for details).
+ //
+ assert (size () <= cs.size ());
+
+ auto i (cs.begin ());
+ for (build_constraints& bcs: *this)
+ i++->constraints = move (bcs);
+ }
+ };
+
+ // build_package_config_template<K>::auxiliaries
+ //
+ using build_auxiliary_key = odb::nested_key<build_auxiliaries>;
+ using build_auxiliaries_map = std::map<build_auxiliary_key, build_auxiliary>;
+
+ #pragma db value(build_auxiliary_key)
+ #pragma db member(build_auxiliary_key::outer) column("config_index")
+ #pragma db member(build_auxiliary_key::inner) column("index")
+
+ // Adapter for build_package_config_template<K>::auxiliaries.
+ //
+ // Note: 1 as for build_package_configs_template.
+ //
+ class build_package_config_auxiliaries:
+ public small_vector<build_auxiliaries, 1>
+ {
+ public:
+ build_package_config_auxiliaries () = default;
+
+ template <typename K>
+ explicit
+ build_package_config_auxiliaries (
+ const build_package_configs_template<K>& cs)
+ {
+ reserve (cs.size ());
+ for (const build_package_config_template<K>& c: cs)
+ push_back (c.auxiliaries);
+ }
+
+ template <typename K>
+ void
+ to_configs (build_package_configs_template<K>& cs) &&
+ {
+ // Note that the empty trailing entries will be missing (see ODB's
+ // nested-container.hxx for details).
+ //
+ assert (size () <= cs.size ());
+
+ auto i (cs.begin ());
+ for (build_auxiliaries& bas: *this)
+ i++->auxiliaries = move (bas);
+ }
+ };
+
+ // build_package_config_template<K>::bot_keys
+ //
+ // Adapter for build_package_config_template<K>::bot_keys.
+ //
+ // Note: 1 as for build_package_configs_template.
+ //
+ template <typename K>
+ class build_package_config_bot_keys: public small_vector<vector<K>, 1>
+ {
+ public:
+ build_package_config_bot_keys () = default;
+
+ explicit
+ build_package_config_bot_keys (const build_package_configs_template<K>& cs)
+ {
+ this->reserve (cs.size ());
+ for (const build_package_config_template<K>& c: cs)
+ this->push_back (c.bot_keys);
+ }
+
+ void
+ to_configs (build_package_configs_template<K>& cs) &&
+ {
+ // Note that the empty trailing entries will be missing (see ODB's
+ // nested-container.hxx for details).
+ //
+ assert (this->size () <= cs.size ());
+
+ auto i (cs.begin ());
+ for (vector<K>& bks: *this)
+ i++->bot_keys = move (bks);
+ }
+ };
+
+ // The primary reason why a package is unbuildable by the build bot
+ // controller service.
+ //
+ enum class unbuildable_reason: std::uint8_t
+ {
+ stub, // A stub, otherwise
+ test, // A separate test (built as part of primary), otherwise
+ external, // From an external repository, otherwise
+ unbuildable // From an internal unbuildable repository.
+ };
+
+ string
+ to_string (unbuildable_reason);
+
+ unbuildable_reason
+ to_unbuildable_reason (const string&); // May throw invalid_argument.
+
+ inline ostream&
+ operator<< (ostream& os, unbuildable_reason r) {return os << to_string (r);}
+
+ using optional_unbuildable_reason = optional<unbuildable_reason>;
+
+ #pragma db map type(unbuildable_reason) as(string) \
+ to(to_string (?)) \
+ from(brep::to_unbuildable_reason (?))
+
+ #pragma db map type(optional_unbuildable_reason) as(brep::optional_string) \
+ to((?) ? to_string (*(?)) : brep::optional_string ()) \
+ from((?) \
+ ? brep::to_unbuildable_reason (*(?)) \
+ : brep::optional_unbuildable_reason ()) \
+
+ // version_constraint
+ //
+ using bpkg::version_constraint;
+
+ #pragma db value(version_constraint) definition
+
+ // test_dependency_type
+ //
+ using bpkg::test_dependency_type;
+ using bpkg::to_test_dependency_type;
+
+ #pragma db map type(test_dependency_type) as(string) \
+ to(to_string (?)) \
+ from(brep::to_test_dependency_type (?))
+
+ // requirements
+ //
+ // Note that this is a 2-level nested container (see package.hxx for
+ // details).
+ //
+ using bpkg::requirement_alternative;
+ using bpkg::requirement_alternatives;
+ using requirements = vector<requirement_alternatives>;
+
+ #pragma db value(requirement_alternative) definition
+ #pragma db value(requirement_alternatives) definition
+
+ using requirement_alternative_key =
+ odb::nested_key<requirement_alternatives>;
+
+ using requirement_alternatives_map =
+ std::map<requirement_alternative_key, requirement_alternative>;
+
+ #pragma db value(requirement_alternative_key)
+ #pragma db member(requirement_alternative_key::outer) column("requirement_index")
+ #pragma db member(requirement_alternative_key::inner) column("index")
+
+ using requirement_key = odb::nested2_key<requirement_alternatives>;
+
+ using requirement_alternative_requirements_map =
+ std::map<requirement_key, string>;
+
+ #pragma db value(requirement_key)
+ #pragma db member(requirement_key::outer) column("requirement_index")
+ #pragma db member(requirement_key::middle) column("alternative_index")
+ #pragma db member(requirement_key::inner) column("index")
+
+ // Third-party service state which may optionally be associated with a
+ // tenant (see also mod/tenant-service.hxx for background).
+ //
+ #pragma db value
+ struct tenant_service
+ {
+ string id;
+ string type;
+ optional<string> data;
+
+ tenant_service () = default;
+
+ tenant_service (string i, string t, optional<string> d = nullopt)
+ : id (move (i)), type (move (t)), data (move (d)) {}
+ };
+
// Version comparison operators.
//
- // They allow comparing objects that have epoch, canonical_upstream,
- // canonical_release, and revision data members. The idea is that this
- // works for both query members of types version and canonical_version.
- // Note, though, that the object revisions should be comparable (both
- // optional, numeric, etc), so to compare version to query member or
- // canonical_version you may need to explicitly convert the version object
- // to canonical_version.
+ // Compare objects that have epoch, canonical_upstream, canonical_release,
+ // and revision data members. The idea is that this works for both query
+ // members of types version and canonical_version. Note, though, that the
+ // object revisions should be comparable (both optional, numeric, etc), so
+ // to compare version to query member or canonical_version you may need to
+ // explicitly convert the version object to canonical_version.
//
template <typename T1, typename T2>
inline auto
@@ -482,10 +831,9 @@ namespace brep
return compare_version_lt (x.version, y.version, true);
}
- // They allow comparing objects that have tenant, name, and version data
- // members. The idea is that this works for both query members of package id
- // types (in particular in join conditions) as well as for values of
- // package_id type.
+ // Compare objects that have tenant, name, and version data members. The
+ // idea is that this works for both query members of package id types (in
+ // particular in join conditions) as well as for values of package_id type.
//
template <typename T1, typename T2>
inline auto
@@ -511,6 +859,49 @@ namespace brep
compare_version_ne (x.version, y.version, true);
}
+ // Allow comparing the query members with the query parameters bound by
+ // reference to variables of the canonical version type (in particular in
+ // the prepared queries).
+ //
+ // Note that it is not operator==() since the query template parameter type
+ // can not be deduced from the function parameter types and needs to be
+ // specified explicitly.
+ //
+ template <typename T, typename V>
+ inline auto
+ equal (const V& x, const canonical_version& y)
+ -> decltype (x.epoch == odb::query<T>::_ref (y.epoch))
+ {
+ using query = odb::query<T>;
+
+ return x.epoch == query::_ref (y.epoch) &&
+ x.canonical_upstream == query::_ref (y.canonical_upstream) &&
+ x.canonical_release == query::_ref (y.canonical_release) &&
+ x.revision == query::_ref (y.revision);
+ }
+
+ // Allow comparing the query members with the query parameters bound by
+ // reference to variables of the package id type (in particular in the
+ // prepared queries).
+ //
+ // Note that it is not operator==() since the query template parameter type
+ // can not be deduced from the function parameter types and needs to be
+ // specified explicitly.
+ //
+ template <typename T, typename ID>
+ inline auto
+ equal (const ID& x, const package_id& y)
+ -> decltype (x.tenant == odb::query<T>::_ref (y.tenant) &&
+ x.name == odb::query<T>::_ref (y.name) &&
+ x.version.epoch == odb::query<T>::_ref (y.version.epoch))
+ {
+ using query = odb::query<T>;
+
+ return x.tenant == query::_ref (y.tenant) &&
+ x.name == query::_ref (y.name) &&
+ equal<T> (x.version, y.version);
+ }
+
// Repository id comparison operators.
//
inline bool
@@ -522,10 +913,10 @@ namespace brep
return x.canonical_name.compare (y.canonical_name) < 0;
}
- // They allow comparing objects that have tenant and canonical_name data
- // members. The idea is that this works for both query members of repository
- // id types (in particular in join conditions) as well as for values of
- // repository_id type.
+ // Compare objects that have tenant and canonical_name data members. The
+ // idea is that this works for both query members of repository id types (in
+ // particular in join conditions) as well as for values of repository_id
+ // type.
//
template <typename T1, typename T2>
inline auto
@@ -542,6 +933,38 @@ namespace brep
{
return x.tenant != y.tenant || x.canonical_name != y.canonical_name;
}
+
+ // Public key id comparison operators.
+ //
+ inline bool
+ operator< (const public_key_id& x, const public_key_id& y)
+ {
+ if (int r = x.tenant.compare (y.tenant))
+ return r < 0;
+
+ return x.fingerprint.compare (y.fingerprint) < 0;
+ }
+
+ // Compare objects that have tenant and fingerprint data members. The idea
+ // is that this works for both query members of public key id types (in
+ // particular in join conditions) as well as for values of public_key_id
+ // type.
+ //
+ template <typename T1, typename T2>
+ inline auto
+ operator== (const T1& x, const T2& y)
+ -> decltype (x.tenant == y.tenant && x.fingerprint == y.fingerprint)
+ {
+ return x.tenant == y.tenant && x.fingerprint == y.fingerprint;
+ }
+
+ template <typename T1, typename T2>
+ inline auto
+ operator!= (const T1& x, const T2& y)
+ -> decltype (x.tenant == y.tenant && x.fingerprint == y.fingerprint)
+ {
+ return x.tenant != y.tenant || x.fingerprint != y.fingerprint;
+ }
}
#endif // LIBBREP_COMMON_HXX