aboutsummaryrefslogtreecommitdiff
path: root/brep
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2017-04-04 20:53:00 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2017-04-19 22:16:46 +0300
commitdbbc19b77dcf6ea828aabd64d7aa8cab9635aaf5 (patch)
treec0b9b449b7064dff3613628022224e6c18148c3e /brep
parentefb9c3e0e6b612d5bfadc7a2b984c14b5439335c (diff)
Implement build task, result and log requests handling
Diffstat (limited to 'brep')
-rw-r--r--brep/.gitignore5
-rw-r--r--brep/build155
-rw-r--r--brep/build.cxx45
-rw-r--r--brep/build.xml64
-rw-r--r--brep/buildfile8
-rw-r--r--brep/common341
-rw-r--r--brep/common.cxx10
-rwxr-xr-xbrep/odb.sh19
-rw-r--r--brep/package338
-rw-r--r--brep/package.cxx2
-rw-r--r--brep/package.xml2
-rw-r--r--brep/utility2
-rw-r--r--brep/version5
13 files changed, 664 insertions, 332 deletions
diff --git a/brep/.gitignore b/brep/.gitignore
index 687b168..9852519 100644
--- a/brep/.gitignore
+++ b/brep/.gitignore
@@ -1,3 +1,8 @@
+common-odb*
+
package-odb*
package.sql
package-extra
+
+build-odb*
+build.sql
diff --git a/brep/build b/brep/build
new file mode 100644
index 0000000..3d969db
--- /dev/null
+++ b/brep/build
@@ -0,0 +1,155 @@
+// file : brep/build -*- C++ -*-
+// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#ifndef BREP_BUILD
+#define BREP_BUILD
+
+#include <chrono>
+
+#include <odb/core.hxx>
+#include <odb/section.hxx>
+
+#include <bbot/manifest>
+
+#include <brep/types>
+#include <brep/utility>
+
+#include <brep/common> // Must be included last (see assert).
+
+// Used by the data migration entries.
+//
+#define LIBBREP_BUILD_SCHEMA_VERSION_BASE 1
+
+#pragma db model version(LIBBREP_BUILD_SCHEMA_VERSION_BASE, 1, open)
+
+// We have to keep these mappings at the global scope instead of inside
+// the brep namespace because they need to be also effective in the
+// bbot namespace from which we "borrow" types (and some of them use the mapped
+// types).
+//
+#pragma db map type(bbot::result_status) as(std::string) \
+ to(to_string (?)) \
+ from(bbot::to_result_status (?))
+
+namespace brep
+{
+ #pragma db value
+ struct build_id
+ {
+ package_id package;
+ string configuration;
+
+ build_id () = default;
+ build_id (package_id p, string c)
+ : package (move (p)), configuration (move (c)) {}
+ };
+
+ inline bool
+ operator< (const build_id& x, const build_id& y)
+ {
+ return
+ x.package < y.package ? true :
+ y.package < x.package ? false :
+ x.configuration < y.configuration;
+ }
+
+ // build_state
+ //
+ enum class build_state: std::uint8_t
+ {
+ untested,
+ testing,
+ tested
+ };
+
+ string
+ to_string (build_state);
+
+ build_state
+ to_build_state (const string&); // May throw invalid_argument.
+
+ inline ostream&
+ operator<< (ostream& os, build_state s) {return os << to_string (s);}
+
+ #pragma db map type(build_state) as(string) \
+ to(to_string (?)) \
+ from(brep::to_build_state (?))
+
+ // result_status
+ //
+ using bbot::result_status;
+
+ using optional_result_status = optional<result_status>;
+
+ #pragma db map type(optional_result_status) as(optional_string) \
+ to((?) ? bbot::to_string (*(?)) : brep::optional_string ()) \
+ from((?) \
+ ? bbot::to_result_status (*(?)) \
+ : brep::optional_result_status ())
+
+ // operation_results
+ //
+ using bbot::operation_result;
+ #pragma db value(operation_result) definition
+
+ using bbot::operation_results;
+
+ #pragma db object pointer(shared_ptr) session
+ class build
+ {
+ public:
+ using timestamp_type = brep::timestamp;
+
+ // Create the build object with the testing state, non-existent status and
+ // the timestamp set to now.
+ //
+ build (string name, version, string configuration);
+
+ build_id id;
+
+ string& package_name; // Tracks id.package.name.
+ upstream_version package_version; // Original of id.package.version.
+ string& configuration; // Tracks id.configuration.
+
+ build_state state;
+
+ // Time of the last state change (the creation time initially).
+ //
+ timestamp_type timestamp;
+
+ // Present only if the state is 'tested'.
+ //
+ optional<result_status> status;
+
+ // Note that the logs are stored as std::string/TEXT which is Ok since
+ // they are UTF-8 and our database is UTF-8.
+ //
+ #pragma db section(results_section)
+ operation_results results;
+
+ #pragma db load(lazy) update(always)
+ odb::section results_section;
+
+ // Database mapping.
+ //
+ #pragma db member(id) id column("")
+
+ #pragma db member(package_name) transient
+ #pragma db member(package_version) \
+ set(this.package_version.init (this.id.package.version, (?)))
+ #pragma db member(configuration) transient
+
+ #pragma db member(results) id_column("") value_column("")
+
+ build (const build&) = delete;
+ build& operator= (const build&) = delete;
+
+ private:
+ friend class odb::access;
+ build ()
+ : package_name (id.package.name), configuration (id.configuration) {}
+ };
+}
+
+#endif // BREP_BUILD
diff --git a/brep/build.cxx b/brep/build.cxx
new file mode 100644
index 0000000..c93c062
--- /dev/null
+++ b/brep/build.cxx
@@ -0,0 +1,45 @@
+// file : brep/build.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#include <brep/build>
+
+namespace brep
+{
+ // build_state
+ //
+ string
+ to_string (build_state s)
+ {
+ switch (s)
+ {
+ case build_state::untested: return "untested";
+ case build_state::testing: return "testing";
+ case build_state::tested: return "tested";
+ }
+
+ return string (); // Should never reach.
+ }
+
+ build_state
+ to_build_state (const string& s)
+ {
+ if (s == "untested") return build_state::untested;
+ else if (s == "testing") return build_state::testing;
+ else if (s == "tested") return build_state::tested;
+ else throw invalid_argument ("invalid build state '" + s + "'");
+ }
+
+ // build
+ //
+ build::
+ build (string pnm, version pvr, string cfg)
+ : id (package_id (move (pnm), pvr), move (cfg)),
+ package_name (id.package.name),
+ package_version (move (pvr)),
+ configuration (id.configuration),
+ state (build_state::testing),
+ timestamp (timestamp_type::clock::now ())
+ {
+ }
+}
diff --git a/brep/build.xml b/brep/build.xml
new file mode 100644
index 0000000..5f75928
--- /dev/null
+++ b/brep/build.xml
@@ -0,0 +1,64 @@
+<changelog xmlns="http://www.codesynthesis.com/xmlns/odb/changelog" database="pgsql" schema-name="build" version="1">
+ <model version="1">
+ <table name="build" kind="object">
+ <column name="package_name" type="TEXT" null="false"/>
+ <column name="package_version_epoch" type="INTEGER" null="false"/>
+ <column name="package_version_canonical_upstream" type="TEXT" null="false"/>
+ <column name="package_version_canonical_release" type="TEXT" null="false" options="COLLATE &quot;C&quot;"/>
+ <column name="package_version_revision" type="INTEGER" null="false"/>
+ <column name="configuration" type="TEXT" null="false"/>
+ <column name="package_version_upstream" type="TEXT" null="false"/>
+ <column name="package_version_release" type="TEXT" null="true"/>
+ <column name="state" type="TEXT" null="false"/>
+ <column name="timestamp" type="BIGINT" null="false"/>
+ <column name="status" type="TEXT" null="true"/>
+ <primary-key>
+ <column name="package_name"/>
+ <column name="package_version_epoch"/>
+ <column name="package_version_canonical_upstream"/>
+ <column name="package_version_canonical_release"/>
+ <column name="package_version_revision"/>
+ <column name="configuration"/>
+ </primary-key>
+ </table>
+ <table name="build_results" kind="container">
+ <column name="package_name" type="TEXT" null="false"/>
+ <column name="package_version_epoch" type="INTEGER" null="false"/>
+ <column name="package_version_canonical_upstream" type="TEXT" null="false"/>
+ <column name="package_version_canonical_release" type="TEXT" null="false" options="COLLATE &quot;C&quot;"/>
+ <column name="package_version_revision" type="INTEGER" null="false"/>
+ <column name="configuration" type="TEXT" null="false"/>
+ <column name="index" type="BIGINT" null="false"/>
+ <column name="operation" type="TEXT" null="false"/>
+ <column name="status" type="TEXT" null="false"/>
+ <column name="log" type="TEXT" null="false"/>
+ <foreign-key name="object_id_fk" on-delete="CASCADE">
+ <column name="package_name"/>
+ <column name="package_version_epoch"/>
+ <column name="package_version_canonical_upstream"/>
+ <column name="package_version_canonical_release"/>
+ <column name="package_version_revision"/>
+ <column name="configuration"/>
+ <references table="build">
+ <column name="package_name"/>
+ <column name="package_version_epoch"/>
+ <column name="package_version_canonical_upstream"/>
+ <column name="package_version_canonical_release"/>
+ <column name="package_version_revision"/>
+ <column name="configuration"/>
+ </references>
+ </foreign-key>
+ <index name="build_results_object_id_i">
+ <column name="package_name"/>
+ <column name="package_version_epoch"/>
+ <column name="package_version_canonical_upstream"/>
+ <column name="package_version_canonical_release"/>
+ <column name="package_version_revision"/>
+ <column name="configuration"/>
+ </index>
+ <index name="build_results_index_i">
+ <column name="index"/>
+ </index>
+ </table>
+ </model>
+</changelog>
diff --git a/brep/buildfile b/brep/buildfile
index a7debc1..aeb1848 100644
--- a/brep/buildfile
+++ b/brep/buildfile
@@ -10,8 +10,14 @@ import int_libs = libodb%lib{odb}
import int_libs += libodb-pgsql%lib{odb-pgsql}
import int_libs += libbutl%lib{butl}
import int_libs += libbpkg%lib{bpkg}
+import int_libs += libbbot%lib{bbot}
lib{brep}: \
+{hxx cxx}{ build } \
+{file }{ build.xml } \
+{hxx ixx cxx}{ build-odb } \
+{hxx cxx}{ common } \
+{hxx ixx cxx}{ common-odb } \
{hxx cxx}{ package } \
{file }{ package.xml } \
{hxx ixx cxx}{ package-odb } \
@@ -23,7 +29,7 @@ lib{brep}: \
{hxx }{ version } \
{hxx }{ wrapper-traits } \
$int_libs \
-sql{package package-extra}
+sql{build package package-extra}
# For pre-releases use the complete version to make sure they cannot be used
# in place of another pre-release or the final version.
diff --git a/brep/common b/brep/common
new file mode 100644
index 0000000..52f225c
--- /dev/null
+++ b/brep/common
@@ -0,0 +1,341 @@
+// file : brep/common -*- C++ -*-
+// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#ifndef BREP_COMMON
+#define BREP_COMMON
+
+#include <ratio>
+#include <chrono>
+#include <type_traits> // static_assert
+
+#include <brep/types>
+#include <brep/utility>
+
+// The uint16_t value range is not fully covered by SMALLINT PostgreSQL type
+// to which uint16_t is mapped by default.
+//
+#pragma db value(uint16_t) type("INTEGER")
+
+namespace brep
+{
+ // Use an image type to map bpkg::version to the database since there
+ // is no way to modify individual components directly.
+ //
+ #pragma db value
+ struct _version
+ {
+ uint16_t epoch;
+ string canonical_upstream;
+ string canonical_release;
+ uint16_t revision;
+ string upstream;
+ optional<string> release;
+ };
+}
+
+#include <bpkg/manifest>
+
+namespace brep
+{
+ using optional_version = optional<bpkg::version>;
+ using _optional_version = optional<_version>;
+}
+
+// Prevent assert() macro expansion in get/set expressions. This should
+// appear after all #include directives since the assert() macro is
+// redefined in each <assert.h> inclusion.
+//
+#ifdef ODB_COMPILER
+# undef assert
+# define assert assert
+void assert (int);
+#endif
+
+// We have to keep these mappings at the global scope instead of inside
+// the brep namespace because they need to be also effective in the
+// bpkg namespace from which we "borrow" types (and some of them use version).
+//
+#pragma db map type(bpkg::version) as(brep::_version) \
+ to(brep::_version{(?).epoch, \
+ (?).canonical_upstream, \
+ (?).canonical_release, \
+ (?).revision, \
+ (?).upstream, \
+ (?).release}) \
+ from(bpkg::version ((?).epoch, \
+ std::move ((?).upstream), \
+ std::move ((?).release), \
+ (?).revision))
+
+#pragma db map type(brep::optional_version) as(brep::_optional_version) \
+ to((?) \
+ ? brep::_version{(?)->epoch, \
+ (?)->canonical_upstream, \
+ (?)->canonical_release, \
+ (?)->revision, \
+ (?)->upstream, \
+ (?)->release} \
+ : brep::_optional_version ()) \
+ from((?) \
+ ? bpkg::version ((?)->epoch, \
+ std::move ((?)->upstream), \
+ std::move ((?)->release), \
+ (?)->revision) \
+ : brep::optional_version ())
+
+namespace brep
+{
+ // path
+ //
+ #pragma db map type(path) as(string) to((?).string ()) from(brep::path (?))
+
+ using optional_path = optional<path>;
+ using optional_string = optional<string>;
+
+ #pragma db map type(optional_path) as(brep::optional_string) \
+ to((?) ? (?)->string () : brep::optional_string ()) \
+ from((?) ? brep::path (*(?)) : brep::optional_path ())
+
+ #pragma db map type(dir_path) as(string) \
+ to((?).string ()) from(brep::dir_path (?))
+
+ // Ensure that timestamp can be represented in nonoseconds without loss of
+ // accuracy, so the following ODB mapping is adequate.
+ //
+ static_assert(
+ std::ratio_greater_equal<timestamp::period,
+ std::chrono::nanoseconds::period>::value,
+ "The following timestamp ODB mapping is invalid");
+
+ // As it pointed out in butl/timestamp 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) \
+ to(std::chrono::duration_cast<std::chrono::nanoseconds> ( \
+ (?).time_since_epoch ()).count ()) \
+ from(brep::timestamp ( \
+ std::chrono::duration_cast<brep::timestamp::duration> ( \
+ std::chrono::nanoseconds (?))))
+
+ // version
+ //
+ using bpkg::version;
+
+ #pragma db value
+ struct canonical_version
+ {
+ uint16_t epoch;
+ string canonical_upstream;
+ string canonical_release;
+ uint16_t revision;
+
+ bool
+ empty () const noexcept
+ {
+ // Note that an empty canonical_upstream doesn't denote an empty
+ // canonical_version. Remeber, that canonical_upstream doesn't include
+ // rightmost digit-only zero components? So non-empty version("0") has
+ // an empty canonical_upstream.
+ //
+ return epoch == 0 && canonical_upstream.empty () &&
+ canonical_release.empty () && revision == 0;
+ }
+
+ // Change collation to ensure the proper comparison of the "absent" release
+ // with a specified one.
+ //
+ // The default collation for UTF8-encoded TEXT columns in PostgreSQL is
+ // UCA-compliant. This makes the statement 'a' < '~' to be false, which
+ // in turn makes the statement 2.1.alpha < 2.1 to be false as well.
+ //
+ // Unicode Collation Algorithm (UCA): http://unicode.org/reports/tr10/
+ //
+ #pragma db member(canonical_release) options("COLLATE \"C\"")
+ };
+
+ #pragma db value transient
+ struct upstream_version: version
+ {
+ #pragma db member(upstream_) virtual(string) \
+ get(this.upstream) \
+ set(this = brep::version (0, std::move (?), std::string (), 0))
+
+ #pragma db member(release_) virtual(optional_string) \
+ get(this.release) \
+ set(this = brep::version ( \
+ 0, std::move (this.upstream), std::move (?), 0))
+
+ upstream_version () = default;
+ upstream_version (version v): version (move (v)) {}
+ upstream_version&
+ operator= (version v) {version& b (*this); b = v; return *this;}
+
+ void
+ init (const canonical_version& cv, const upstream_version& uv)
+ {
+ *this = version (cv.epoch, uv.upstream, uv.release, cv.revision);
+ assert (cv.canonical_upstream == canonical_upstream &&
+ cv.canonical_release == canonical_release);
+ }
+ };
+
+ // Wildcard version. Satisfies any dependency constraint and is represented
+ // as 0+0 (which is also the "stub version"; since a real version is always
+ // greater than the stub version, we reuse it to signify a special case).
+ //
+ extern const version wildcard_version;
+
+ #pragma db value
+ struct package_id
+ {
+ string name;
+ canonical_version version;
+
+ package_id () = default;
+ package_id (string n, const brep::version& v)
+ : name (move (n)),
+ version {
+ v.epoch, v.canonical_upstream, v.canonical_release, v.revision}
+ {
+ }
+ };
+
+ // 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
+ // as well as for comparing canonical_version to version.
+ //
+ template <typename T1, typename T2>
+ inline auto
+ compare_version_eq (const T1& x, const T2& y, bool revision)
+ -> decltype (x.epoch == y.epoch)
+ {
+ // Since we don't quite know what T1 and T2 are (and where the resulting
+ // expression will run), let's not push our luck with something like
+ // (!revision || x.revision == y.revision).
+ //
+ auto r (x.epoch == y.epoch &&
+ x.canonical_upstream == y.canonical_upstream &&
+ x.canonical_release == y.canonical_release);
+
+ return revision
+ ? r && x.revision == y.revision
+ : r;
+ }
+
+ template <typename T1, typename T2>
+ inline auto
+ compare_version_ne (const T1& x, const T2& y, bool revision)
+ -> decltype (x.epoch == y.epoch)
+ {
+ auto r (x.epoch != y.epoch ||
+ x.canonical_upstream != y.canonical_upstream ||
+ x.canonical_release != y.canonical_release);
+
+ return revision
+ ? r || x.revision != y.revision
+ : r;
+ }
+
+ template <typename T1, typename T2>
+ inline auto
+ compare_version_lt (const T1& x, const T2& y, bool revision)
+ -> decltype (x.epoch == y.epoch)
+ {
+ auto r (
+ x.epoch < y.epoch ||
+ (x.epoch == y.epoch && x.canonical_upstream < y.canonical_upstream) ||
+ (x.epoch == y.epoch && x.canonical_upstream == y.canonical_upstream &&
+ x.canonical_release < y.canonical_release));
+
+ return revision
+ ? r ||
+ (x.epoch == y.epoch && x.canonical_upstream == y.canonical_upstream &&
+ x.canonical_release == y.canonical_release && x.revision < y.revision)
+ : r;
+ }
+
+ template <typename T1, typename T2>
+ inline auto
+ compare_version_le (const T1& x, const T2& y, bool revision)
+ -> decltype (x.epoch == y.epoch)
+ {
+ auto r (
+ x.epoch < y.epoch ||
+ (x.epoch == y.epoch && x.canonical_upstream < y.canonical_upstream));
+
+ return revision
+ ? r ||
+ (x.epoch == y.epoch && x.canonical_upstream == y.canonical_upstream &&
+ x.canonical_release < y.canonical_release) ||
+ (x.epoch == y.epoch && x.canonical_upstream == y.canonical_upstream &&
+ x.canonical_release == y.canonical_release && x.revision <= y.revision)
+ : r ||
+ (x.epoch == y.epoch && x.canonical_upstream == y.canonical_upstream &&
+ x.canonical_release <= y.canonical_release);
+ }
+
+ template <typename T1, typename T2>
+ inline auto
+ compare_version_gt (const T1& x, const T2& y, bool revision)
+ -> decltype (x.epoch == y.epoch)
+ {
+ auto r (
+ x.epoch > y.epoch ||
+ (x.epoch == y.epoch && x.canonical_upstream > y.canonical_upstream) ||
+ (x.epoch == y.epoch && x.canonical_upstream == y.canonical_upstream &&
+ x.canonical_release > y.canonical_release));
+
+ return revision
+ ? r ||
+ (x.epoch == y.epoch && x.canonical_upstream == y.canonical_upstream &&
+ x.canonical_release == y.canonical_release && x.revision > y.revision)
+ : r;
+ }
+
+ template <typename T1, typename T2>
+ inline auto
+ compare_version_ge (const T1& x, const T2& y, bool revision)
+ -> decltype (x.epoch == y.epoch)
+ {
+ auto r (
+ x.epoch > y.epoch ||
+ (x.epoch == y.epoch && x.canonical_upstream > y.canonical_upstream));
+
+ return revision
+ ? r ||
+ (x.epoch == y.epoch && x.canonical_upstream == y.canonical_upstream &&
+ x.canonical_release > y.canonical_release) ||
+ (x.epoch == y.epoch && x.canonical_upstream == y.canonical_upstream &&
+ x.canonical_release == y.canonical_release && x.revision >= y.revision)
+ : r ||
+ (x.epoch == y.epoch && x.canonical_upstream == y.canonical_upstream &&
+ x.canonical_release >= y.canonical_release);
+ }
+
+ template <typename T>
+ inline auto
+ order_by_version_desc (const T& x) -> //decltype ("ORDER BY" + x.epoch)
+ decltype (x.epoch == 0)
+ {
+ return "ORDER BY"
+ + x.epoch + "DESC,"
+ + x.canonical_upstream + "DESC,"
+ + x.canonical_release + "DESC,"
+ + x.revision + "DESC";
+ }
+
+ inline bool
+ operator< (const package_id& x, const package_id& y)
+ {
+ if (int r = x.name.compare (y.name))
+ return r < 0;
+
+ return compare_version_lt (x.version, y.version, true);
+ }
+}
+
+#endif // BREP_COMMON
diff --git a/brep/common.cxx b/brep/common.cxx
new file mode 100644
index 0000000..4847977
--- /dev/null
+++ b/brep/common.cxx
@@ -0,0 +1,10 @@
+// file : brep/common.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#include <brep/common>
+
+namespace brep
+{
+ const version wildcard_version (0, "0", nullopt, 0);
+}
diff --git a/brep/odb.sh b/brep/odb.sh
index 3f8cef2..5e16f45 100755
--- a/brep/odb.sh
+++ b/brep/odb.sh
@@ -9,10 +9,17 @@ lib="\
-I$HOME/work/odb/libodb-default \
-I$HOME/work/odb/libodb"
-$odb $lib -d pgsql --std c++11 --generate-query --generate-schema \
- --schema-format sql --schema-format embedded \
+$odb $lib -d pgsql --std c++11 --generate-query \
--odb-epilogue '#include <brep/wrapper-traits>' \
--hxx-prologue '#include <brep/wrapper-traits>' \
+ -I .. -I ../../libbpkg -I ../../libbutl \
+ --hxx-suffix "" --include-with-brackets \
+ --include-prefix brep --guard-prefix BREP \
+ common
+
+$odb $lib -d pgsql --std c++11 --generate-query --generate-schema \
+ --schema-format sql --schema-format embedded --schema-name package \
+ --generate-prepared --odb-epilogue '#include <brep/wrapper-traits>' \
--hxx-prologue '#include <brep/package-traits>' \
-I .. -I ../../libbpkg -I ../../libbutl \
--hxx-suffix "" --include-with-brackets \
@@ -20,3 +27,11 @@ $odb $lib -d pgsql --std c++11 --generate-query --generate-schema \
package
xxd -i <package-extra.sql >package-extra
+
+$odb $lib -d pgsql --std c++11 --generate-query --generate-schema \
+ --schema-format sql --schema-format embedded --schema-name build \
+ --generate-prepared --odb-epilogue '#include <brep/wrapper-traits>' \
+ -I .. -I ../../libbbot -I ../../libbpkg -I ../../libbutl \
+ --hxx-suffix "" --include-with-brackets \
+ --include-prefix brep --guard-prefix BREP \
+ build
diff --git a/brep/package b/brep/package
index 13429d1..d50aa9f 100644
--- a/brep/package
+++ b/brep/package
@@ -6,94 +6,21 @@
#define BREP_PACKAGE
#include <map>
-#include <ratio>
#include <chrono>
-#include <type_traits> // static_assert
#include <odb/core.hxx>
-#include <odb/forward.hxx> // database
#include <odb/nested-container.hxx>
#include <brep/types>
#include <brep/utility>
-// Used by the data migration entries.
-//
-#define LIBBREP_SCHEMA_VERSION_BASE 3
-
-#pragma db model version(LIBBREP_SCHEMA_VERSION_BASE, 3, closed)
+#include <brep/common> // Must be included last (see assert).
-// The uint16_t value range is not fully covered by SMALLINT PostgreSQL type
-// to which uint16_t is mapped by default.
+// Used by the data migration entries.
//
-#pragma db value(uint16_t) type("INTEGER")
-
-namespace brep
-{
- // Use an image type to map bpkg::version to the database since there
- // is no way to modify individual components directly.
- //
- #pragma db value
- struct _version
- {
- uint16_t epoch;
- string canonical_upstream;
- string canonical_release;
- uint16_t revision;
- string upstream;
- optional<string> release;
- };
-}
-
-#include <bpkg/manifest>
-
-namespace brep
-{
- using optional_version = optional<bpkg::version>;
- using _optional_version = optional<_version>;
-}
+#define LIBBREP_PACKAGE_SCHEMA_VERSION_BASE 3
-// Prevent assert() macro expansion in get/set expressions. This should
-// appear after all #include directives since the assert() macro is
-// redefined in each <assert.h> inclusion.
-//
-#ifdef ODB_COMPILER
-# undef assert
-# define assert assert
-void assert (int);
-#endif
-
-// We have to keep these mappings at the global scope instead of inside
-// the brep namespace because they need to be also effective in the
-// bpkg namespace from which we "borrow" types (and some of them use version).
-//
-#pragma db map type(bpkg::version) as(brep::_version) \
- to(brep::_version{(?).epoch, \
- (?).canonical_upstream, \
- (?).canonical_release, \
- (?).revision, \
- (?).upstream, \
- (?).release}) \
- from(bpkg::version ((?).epoch, \
- std::move ((?).upstream), \
- std::move ((?).release), \
- (?).revision))
-
-#pragma db map type(brep::optional_version) as(brep::_optional_version) \
- to((?) \
- ? brep::_version{(?)->epoch, \
- (?)->canonical_upstream, \
- (?)->canonical_release, \
- (?)->revision, \
- (?)->upstream, \
- (?)->release} \
- : brep::_optional_version ()) \
- from((?) \
- ? bpkg::version ((?)->epoch, \
- std::move ((?)->upstream), \
- std::move ((?)->release), \
- (?)->revision) \
- : brep::optional_version ())
+#pragma db model version(LIBBREP_PACKAGE_SCHEMA_VERSION_BASE, 3, closed)
namespace brep
{
@@ -110,106 +37,6 @@ namespace brep
class repository;
class package;
- // path
- //
- #pragma db map type(path) as(string) to((?).string ()) from(brep::path (?))
-
- using optional_path = optional<path>;
- using optional_string = optional<string>;
-
- #pragma db map type(optional_path) as(brep::optional_string) \
- to((?) ? (?)->string () : brep::optional_string ()) \
- from((?) ? brep::path (*(?)) : brep::optional_path ())
-
- #pragma db map type(dir_path) as(string) \
- to((?).string ()) from(brep::dir_path (?))
-
- // Ensure that timestamp can be represented in nonoseconds without loss of
- // accuracy, so the following ODB mapping is adequate.
- //
- static_assert(
- std::ratio_greater_equal<timestamp::period,
- std::chrono::nanoseconds::period>::value,
- "The following timestamp ODB mapping is invalid");
-
- // As it pointed out in butl/timestamp 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) \
- to(std::chrono::duration_cast<std::chrono::nanoseconds> ( \
- (?).time_since_epoch ()).count ()) \
- from(brep::timestamp ( \
- std::chrono::duration_cast<brep::timestamp::duration> ( \
- std::chrono::nanoseconds (?))))
-
- // version
- //
- using bpkg::version;
-
- #pragma db value
- struct canonical_version
- {
- uint16_t epoch;
- string canonical_upstream;
- string canonical_release;
- uint16_t revision;
-
- bool
- empty () const noexcept
- {
- // Note that an empty canonical_upstream doesn't denote an empty
- // canonical_version. Remeber, that canonical_upstream doesn't include
- // rightmost digit-only zero components? So non-empty version("0") has
- // an empty canonical_upstream.
- //
- return epoch == 0 && canonical_upstream.empty () &&
- canonical_release.empty () && revision == 0;
- }
-
- // Change collation to ensure the proper comparison of the "absent" release
- // with a specified one.
- //
- // The default collation for UTF8-encoded TEXT columns in PostgreSQL is
- // UCA-compliant. This makes the statement 'a' < '~' to be false, which
- // in turn makes the statement 2.1.alpha < 2.1 to be false as well.
- //
- // Unicode Collation Algorithm (UCA): http://unicode.org/reports/tr10/
- //
- #pragma db member(canonical_release) options("COLLATE \"C\"")
- };
-
- #pragma db value transient
- struct upstream_version: version
- {
- #pragma db member(upstream_) virtual(string) \
- get(this.upstream) \
- set(this = brep::version (0, std::move (?), std::string (), 0))
-
- #pragma db member(release_) virtual(optional_string) \
- get(this.release) \
- set(this = brep::version ( \
- 0, std::move (this.upstream), std::move (?), 0))
-
- upstream_version () = default;
- upstream_version (version v): version (move (v)) {}
- upstream_version&
- operator= (version v) {version& b (*this); b = v; return *this;}
-
- void
- init (const canonical_version& cv, const upstream_version& uv)
- {
- *this = version (cv.epoch, uv.upstream, uv.release, cv.revision);
- assert (cv.canonical_upstream == canonical_upstream &&
- cv.canonical_release == canonical_release);
- }
- };
-
- // Wildcard version. Satisfies any dependency constraint and is represented
- // as 0+0 (which is also the "stub version"; since a real version is always
- // greater than the stub version, we reuse it to signify a special case).
- //
- extern const version wildcard_version;
-
// priority
//
using bpkg::priority;
@@ -244,21 +71,6 @@ namespace brep
#pragma db value(dependency_constraint) definition
- #pragma db value
- struct package_id
- {
- string name;
- canonical_version version;
-
- package_id () = default;
- package_id (string n, const brep::version& v)
- : name (move (n)),
- version {
- v.epoch, v.canonical_upstream, v.canonical_release, v.revision}
- {
- }
- };
-
// Notes:
//
// 1. Will the package be always resolvable? What if it is in
@@ -670,141 +482,17 @@ namespace brep
package_id id;
};
- // 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
- // as well as for comparing canonical_version to version.
- //
- template <typename T1, typename T2>
- inline auto
- compare_version_eq (const T1& x, const T2& y, bool revision)
- -> decltype (x.epoch == y.epoch)
- {
- // Since we don't quite know what T1 and T2 are (and where the resulting
- // expression will run), let's not push our luck with something like
- // (!revision || x.revision == y.revision).
- //
- auto r (x.epoch == y.epoch &&
- x.canonical_upstream == y.canonical_upstream &&
- x.canonical_release == y.canonical_release);
-
- return revision
- ? r && x.revision == y.revision
- : r;
- }
-
- template <typename T1, typename T2>
- inline auto
- compare_version_ne (const T1& x, const T2& y, bool revision)
- -> decltype (x.epoch == y.epoch)
- {
- auto r (x.epoch != y.epoch ||
- x.canonical_upstream != y.canonical_upstream ||
- x.canonical_release != y.canonical_release);
-
- return revision
- ? r || x.revision != y.revision
- : r;
- }
-
- template <typename T1, typename T2>
- inline auto
- compare_version_lt (const T1& x, const T2& y, bool revision)
- -> decltype (x.epoch == y.epoch)
- {
- auto r (
- x.epoch < y.epoch ||
- (x.epoch == y.epoch && x.canonical_upstream < y.canonical_upstream) ||
- (x.epoch == y.epoch && x.canonical_upstream == y.canonical_upstream &&
- x.canonical_release < y.canonical_release));
-
- return revision
- ? r ||
- (x.epoch == y.epoch && x.canonical_upstream == y.canonical_upstream &&
- x.canonical_release == y.canonical_release && x.revision < y.revision)
- : r;
- }
-
- template <typename T1, typename T2>
- inline auto
- compare_version_le (const T1& x, const T2& y, bool revision)
- -> decltype (x.epoch == y.epoch)
- {
- auto r (
- x.epoch < y.epoch ||
- (x.epoch == y.epoch && x.canonical_upstream < y.canonical_upstream));
-
- return revision
- ? r ||
- (x.epoch == y.epoch && x.canonical_upstream == y.canonical_upstream &&
- x.canonical_release < y.canonical_release) ||
- (x.epoch == y.epoch && x.canonical_upstream == y.canonical_upstream &&
- x.canonical_release == y.canonical_release && x.revision <= y.revision)
- : r ||
- (x.epoch == y.epoch && x.canonical_upstream == y.canonical_upstream &&
- x.canonical_release <= y.canonical_release);
- }
-
- template <typename T1, typename T2>
- inline auto
- compare_version_gt (const T1& x, const T2& y, bool revision)
- -> decltype (x.epoch == y.epoch)
- {
- auto r (
- x.epoch > y.epoch ||
- (x.epoch == y.epoch && x.canonical_upstream > y.canonical_upstream) ||
- (x.epoch == y.epoch && x.canonical_upstream == y.canonical_upstream &&
- x.canonical_release > y.canonical_release));
-
- return revision
- ? r ||
- (x.epoch == y.epoch && x.canonical_upstream == y.canonical_upstream &&
- x.canonical_release == y.canonical_release && x.revision > y.revision)
- : r;
- }
-
- template <typename T1, typename T2>
- inline auto
- compare_version_ge (const T1& x, const T2& y, bool revision)
- -> decltype (x.epoch == y.epoch)
+ #pragma db view object(package)
+ struct package_version
{
- auto r (
- x.epoch > y.epoch ||
- (x.epoch == y.epoch && x.canonical_upstream > y.canonical_upstream));
-
- return revision
- ? r ||
- (x.epoch == y.epoch && x.canonical_upstream == y.canonical_upstream &&
- x.canonical_release > y.canonical_release) ||
- (x.epoch == y.epoch && x.canonical_upstream == y.canonical_upstream &&
- x.canonical_release == y.canonical_release && x.revision >= y.revision)
- : r ||
- (x.epoch == y.epoch && x.canonical_upstream == y.canonical_upstream &&
- x.canonical_release >= y.canonical_release);
- }
-
- template <typename T>
- inline auto
- order_by_version_desc (const T& x) -> //decltype ("ORDER BY" + x.epoch)
- decltype (x.epoch == 0)
- {
- return "ORDER BY"
- + x.epoch + "DESC,"
- + x.canonical_upstream + "DESC,"
- + x.canonical_release + "DESC,"
- + x.revision + "DESC";
- }
-
- inline bool
- operator< (const package_id& x, const package_id& y)
- {
- if (int r = x.name.compare (y.name))
- return r < 0;
+ package_id id;
+ upstream_version version;
- return compare_version_lt (x.version, y.version, true);
- }
+ // Database mapping.
+ //
+ #pragma db member(id) column("")
+ #pragma db member(version) set(this.version.init (this.id.version, (?)))
+ };
}
#endif // BREP_PACKAGE
diff --git a/brep/package.cxx b/brep/package.cxx
index eacfabe..eaf1029 100644
--- a/brep/package.cxx
+++ b/brep/package.cxx
@@ -13,8 +13,6 @@ using namespace odb::core;
namespace brep
{
- const version wildcard_version (0, "0", nullopt, 0);
-
// dependency
//
string dependency::
diff --git a/brep/package.xml b/brep/package.xml
index 69f1a6a..39494ce 100644
--- a/brep/package.xml
+++ b/brep/package.xml
@@ -1,4 +1,4 @@
-<changelog xmlns="http://www.codesynthesis.com/xmlns/odb/changelog" database="pgsql" version="1">
+<changelog xmlns="http://www.codesynthesis.com/xmlns/odb/changelog" database="pgsql" schema-name="package" version="1">
<model version="3">
<table name="repository" kind="object">
<column name="name" type="TEXT" null="false"/>
diff --git a/brep/utility b/brep/utility
index 631af7f..b359fc6 100644
--- a/brep/utility
+++ b/brep/utility
@@ -27,6 +27,6 @@ namespace brep
// <butl/utility>
//
using butl::reverse_iterate;
-};
+}
#endif // BREP_UTILITY
diff --git a/brep/version b/brep/version
index f648b5e..e1db981 100644
--- a/brep/version
+++ b/brep/version
@@ -6,6 +6,7 @@
#include <butl/version> // LIBBUTL_VERSION
#include <bpkg/version> // LIBBPKG_VERSION
+#include <bbot/version> // LIBBBOT_VERSION
// Version format is AABBCCDD where
//
@@ -44,4 +45,8 @@
# error incompatible libbpkg version
#endif
+#if LIBBBOT_VERSION != 49901
+# error incompatible libbbot version
+#endif
+
#endif // BREP_VERSION