diff options
Diffstat (limited to 'libbrep/common.hxx')
-rw-r--r-- | libbrep/common.hxx | 457 |
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 |