aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2018-10-28 01:01:53 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2018-10-30 16:20:21 +0300
commit873987793b05fc0d6e9908f5030b2bca145c4e6d (patch)
tree6641e447d892e5b364ae7471e7a0a71581c85e91
parent018603c5529117b993066f4f3a0f45f48f92e801 (diff)
Add tenant object
-rw-r--r--INSTALL13
-rw-r--r--clean/buildfile1
-rw-r--r--clean/clean.cli60
-rw-r--r--clean/clean.cxx573
-rw-r--r--clean/options-types.hxx18
-rw-r--r--clean/types-parsers.cxx60
-rw-r--r--clean/types-parsers.hxx28
-rw-r--r--etc/systemd/brep-clean.service6
-rw-r--r--libbrep/build-extra.sql10
-rw-r--r--libbrep/build-package.hxx82
-rw-r--r--libbrep/build.hxx14
-rw-r--r--libbrep/build.xml2
-rw-r--r--libbrep/package.cxx9
-rw-r--r--libbrep/package.hxx52
-rw-r--r--libbrep/package.xml145
-rw-r--r--load/load.cxx28
-rw-r--r--migrate/migrate.cxx41
-rw-r--r--mod/mod-build-task.cxx2
-rw-r--r--mod/mod-builds.cxx59
19 files changed, 824 insertions, 379 deletions
diff --git a/INSTALL b/INSTALL
index 8c25e99..8110cb4 100644
--- a/INSTALL
+++ b/INSTALL
@@ -394,21 +394,26 @@ our setup. If you still would like to use systemd to run the loader and the
cleaner, then you can set it up as a system-wide service which runs the
utilities as the brep user/group. Otherwise, a cron job is a natural choice.
-Note that the cleaner execution is optional and is only required if the build2
-build bot functionality is enabled (see the build bot documentation for
+Note that the builds cleaner execution is optional and is only required if the
+build2 build bot functionality is enabled (see the build bot documentation for
details). If it is disabled in you setup, then skip the cleaner-related
parts in the subsequent subsections.
+If the CI request functionality is enabled you most likely will want to
+additionally setup the tenants cleanup.
+
+
8.a Setup Periodic Loader and Cleaner Execution with cron
The following crontab entries will execute the loader every five minutes
-and the cleaner once a day at midnight:
+and the tenants and builds cleaners once a day at midnight:
$ crontab -l
MAILTO=<brep-admin-email>
PATH=/usr/local/bin:/bin:/usr/bin
*/5 * * * * $HOME/install/bin/brep-load $HOME/config/loadtab
-0 0 * * * $HOME/install/bin/brep-clean $HOME/config/buildtab
+0 0 * * * $HOME/install/bin/brep-clean tenants 240
+0 0 * * * $HOME/install/bin/brep-clean builds $HOME/config/buildtab
^D
Note that here we assume that bpkg (which is executed by brep-load) is in one
diff --git a/clean/buildfile b/clean/buildfile
index 31a03df..d46a874 100644
--- a/clean/buildfile
+++ b/clean/buildfile
@@ -20,7 +20,6 @@ if $cli.configured
cli.options += -I $src_root --include-with-brackets --include-prefix clean \
--guard-prefix CLEAN --generate-specifier --page-usage print_ --ansi-color \
---cxx-prologue "#include <clean/types-parsers.hxx>" \
--long-usage
# Include the generated cli files into the distribution and don't remove
diff --git a/clean/clean.cli b/clean/clean.cli
index 01bc57c..0e36386 100644
--- a/clean/clean.cli
+++ b/clean/clean.cli
@@ -6,28 +6,41 @@ include <vector>;
include <string>;
include <cstdint>; // uint16_t
-include <clean/options-types.hxx>;
-
"\section=1"
"\name=brep-clean"
-"\summary=clean brep build database"
+"\summary=clean brep databases"
{
- "<options> <buildtab>",
+ "<options> <buildtab> <timeout> <name> <hours>",
"\h|SYNOPSIS|
\c{\b{brep-clean --help}\n
\b{brep-clean --version}\n
- \b{brep-clean} [<options>] <buildtab>}
+ \b{brep-clean} [<options>] builds <buildtab> [<timeout>...]\n
+ \b{brep-clean} [<options>] tenants <timeout>}
\h|DESCRIPTION|
\cb{brep-clean} deletes expired package builds from the brep \cb{build}
- database. The build is considered expired if the package version is not
- in the \cb{package} database, or the configuration is not listed in the
- <buildtab> file, or the timestamp is older than the one specified for
- this build's toolchain (see \cb{--stale-timeout}).
+ database or deletes/archives tenants from the brep \cb{package} database.
+
+ The first form considers a build as expired if the corresponding package
+ version is not in the \cb{package} database, or the configuration is not
+ listed in the <buildtab> file, or its age is older than the specified
+ timeout for this build toolchain.
+
+ Build <timeout>, if specified, should have the \c{[<name>=]<hours>} form.
+ Specify zero for <hours> to make builds for a toolchain to never expire.
+ Omit <name> (including \cb{=}) to specify the default timeout. It will
+ apply to all the toolchains that don't have a toolchain-specific timeout.
+
+ The second form considers a tenant as expired if its age is older than the
+ specified <timeout>.
+
+ If the \cb{--archive} option is specified, then the tenant is archived
+ rather than deleted. In this state the tenant packages (and their builds)
+ are still visible in \cb{brep} but are not (re-)built by build bots.
Note that \cb{brep-clean} expects the \cb{build} and \cb{package} database
schemas to have already been created using \l{brep-migrate(1)}."
@@ -37,49 +50,44 @@ class options
{
"\h|OPTIONS|"
- brep::toolchain_timeouts --stale-timeout
+ bool --archive
{
- "[<name>=]<days>",
- "Number of days to wait before considering builds for the named toolchain
- as stale. Specify zero for <days> to make builds for a toolchain never
- expire. Omit <name> (including \cb{=}) to specify the default timeout.
- It will apply to all the toolchains that don't have a timeout specified
- explicitly. If unspecified, the default timeout is zero (never expire)."
+ "Archive old tenants."
}
std::string --db-user
{
"<user>",
- "Build database user name. If not specified, then operating system (login)
- name is used."
+ "Database user name. If not specified, then operating system (login) name
+ is used."
}
std::string --db-password
{
"<pass>",
- "Build database password. If not specified, then login without password is
+ "Database password. If not specified, then login without password is
expected to work."
}
- std::string --db-name = "brep_build"
+ std::string --db-name
{
"<name>",
- "Build database name. If not specified, then \cb{brep_build} is used by
- default."
+ "Database name. If not specified, then \cb{brep_build} is used for the
+ first form and \cb{brep_package} for the second."
}
std::string --db-host
{
"<host>",
- "Build database host name, address, or socket. If not specified, then
- connect to \cb{localhost} using the operating system-default mechanism
- (Unix-domain socket, etc)."
+ "Database host name, address, or socket. If not specified, then connect to
+ \cb{localhost} using the operating system-default mechanism (Unix-domain
+ socket, etc)."
}
std::uint16_t --db-port = 0
{
"<port>",
- "Build database port number. If not specified, the default port is used."
+ "Database port number. If not specified, the default port is used."
}
std::string --pager // String to allow empty value.
diff --git a/clean/clean.cxx b/clean/clean.cxx
index 102b165..deba1db 100644
--- a/clean/clean.cxx
+++ b/clean/clean.cxx
@@ -2,7 +2,9 @@
// copyright : Copyright (c) 2014-2018 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
+#include <map>
#include <set>
+#include <chrono>
#include <iostream>
#include <odb/database.hxx>
@@ -17,6 +19,8 @@
#include <libbrep/build.hxx>
#include <libbrep/build-odb.hxx>
+#include <libbrep/package.hxx>
+#include <libbrep/package-odb.hxx>
#include <libbrep/build-package.hxx>
#include <libbrep/build-package-odb.hxx>
#include <libbrep/database-lock.hxx>
@@ -25,226 +29,459 @@
using namespace std;
using namespace bbot;
-using namespace brep;
using namespace odb::core;
-// Operation failed, diagnostics has already been issued.
-//
-struct failed {};
+namespace brep
+{
+ // Operation failed, diagnostics has already been issued.
+ //
+ struct failed {};
-static const char* help_info (
- " info: run 'brep-clean --help' for more information");
+ static const char* help_info (
+ " info: run 'brep-clean --help' for more information");
-int
-main (int argc, char* argv[])
-try
-{
- cli::argv_scanner scan (argc, argv, true);
- options ops (scan);
+ static int
+ clean_builds (const options&, cli::argv_scanner&, odb::pgsql::database&);
- // Version.
- //
- if (ops.version ())
+ static int
+ clean_tenants (const options&, cli::argv_scanner&, odb::pgsql::database&);
+
+ static int
+ main (int argc, char* argv[])
+ try
{
- cout << "brep-clean " << BREP_VERSION_ID << endl
- << "libbrep " << LIBBREP_VERSION_ID << endl
- << "libbbot " << LIBBBOT_VERSION_ID << endl
- << "libbpkg " << LIBBPKG_VERSION_ID << endl
- << "libbutl " << LIBBUTL_VERSION_ID << endl
- << "Copyright (c) 2014-2018 Code Synthesis Ltd" << endl
- << "This is free software released under the MIT license." << endl;
+ cli::argv_scanner scan (argc, argv, true);
+ options ops (scan);
- return 0;
- }
+ // Version.
+ //
+ if (ops.version ())
+ {
+ cout << "brep-clean " << BREP_VERSION_ID << endl
+ << "libbrep " << LIBBREP_VERSION_ID << endl
+ << "libbbot " << LIBBBOT_VERSION_ID << endl
+ << "libbpkg " << LIBBPKG_VERSION_ID << endl
+ << "libbutl " << LIBBUTL_VERSION_ID << endl
+ << "Copyright (c) 2014-2018 Code Synthesis Ltd" << endl
+ << "This is free software released under the MIT license." << endl;
+
+ return 0;
+ }
- // Help.
- //
- if (ops.help ())
- {
- butl::pager p ("brep-clean help",
- false,
- ops.pager_specified () ? &ops.pager () : nullptr,
- &ops.pager_option ());
+ // Help.
+ //
+ if (ops.help ())
+ {
+ butl::pager p ("brep-clean help",
+ false,
+ ops.pager_specified () ? &ops.pager () : nullptr,
+ &ops.pager_option ());
+
+ print_usage (p.stream ());
- print_usage (p.stream ());
+ // If the pager failed, assume it has issued some diagnostics.
+ //
+ return p.wait () ? 0 : 1;
+ }
- // If the pager failed, assume it has issued some diagnostics.
+ // Detect the mode.
//
- return p.wait () ? 0 : 1;
- }
+ if (!scan.more ())
+ {
+ cerr << "error: 'builds' or 'tenants' is expected" << endl
+ << help_info << endl;
+ return 1;
+ }
- const toolchain_timeouts& timeouts (ops.stale_timeout ());
+ const string mode (scan.next ());
- auto i (timeouts.find (string ()));
- timestamp default_timeout (i != timeouts.end ()
- ? i->second
- : timestamp_nonexistent);
+ if (mode != "builds" && mode != "tenants")
+ throw cli::unknown_argument (mode);
- // Load configurations names.
- //
- if (!scan.more ())
- {
- cerr << "error: configuration file expected" << endl
- << help_info << endl;
- return 1;
- }
+ const string db_schema (mode == "builds" ? "build" : "package");
- set<string> configs;
- for (auto& c: parse_buildtab (path (scan.next ())))
- configs.emplace (move (c.name));
+ const string& db_name (!ops.db_name ().empty ()
+ ? ops.db_name ()
+ : "brep_" + db_schema);
- if (scan.more ())
- {
- cerr << "error: unexpected argument encountered" << endl
- << help_info << endl;
- return 1;
- }
+ odb::pgsql::database db (
+ ops.db_user (),
+ ops.db_password (),
+ db_name,
+ ops.db_host (),
+ ops.db_port (),
+ "options='-c default_transaction_isolation=serializable'");
- odb::pgsql::database build_db (
- ops.db_user (),
- ops.db_password (),
- ops.db_name (),
- ops.db_host (),
- ops.db_port (),
- "options='-c default_transaction_isolation=serializable'");
+ // Prevent several brep-clean/migrate instances from updating build
+ // database simultaneously.
+ //
+ database_lock l (db);
- // Prevent several brep-clean/migrate instances from updating build database
- // simultaneously.
- //
- database_lock l (build_db);
+ // Check that the database schema matches the current one.
+ //
+ if (schema_catalog::current_version (db, db_schema) !=
+ db.schema_version (db_schema))
+ {
+ cerr << "error: " << db_schema << " database schema differs from the "
+ << "current one" << endl
+ << " info: use brep-migrate to migrate the database" << endl;
+ return 1;
+ }
- // Check that the build database schema matches the current one.
+ return mode == "builds"
+ ? clean_builds (ops, scan, db)
+ : clean_tenants (ops, scan, db);
+ }
+ catch (const database_locked&)
+ {
+ cerr << "brep-clean or brep-migrate is running" << endl;
+ return 2;
+ }
+ catch (const recoverable& e)
+ {
+ cerr << "recoverable database error: " << e << endl;
+ return 3;
+ }
+ catch (const cli::exception& e)
+ {
+ cerr << "error: " << e << endl << help_info << endl;
+ return 1;
+ }
+ catch (const failed&)
+ {
+ return 1; // Diagnostics has already been issued.
+ }
+ // Fully qualified to avoid ambiguity with odb exception.
//
- const string bs ("build");
- if (schema_catalog::current_version (build_db, bs) !=
- build_db.schema_version (bs))
+ catch (const std::exception& e)
{
- cerr << "error: build database schema differs from the current one"
- << endl << " info: use brep-migrate to migrate the database" << endl;
+ cerr << "error: " << e << endl;
return 1;
}
- // Prepare the build prepared query.
+ // Convert timeout duration into the time point. Return
+ // timestamp_nonexistent (never expire) for zero argument. Return nullopt if
+ // the argument is invalid.
//
- // Query package builds in chunks in order not to hold locks for too long.
- // Sort the result by package version to minimize number of queries to the
- // package database.
- //
- using bld_query = query<build>;
- using prep_bld_query = prepared_query<build>;
+ static optional<timestamp>
+ timeout (const string& tm)
+ {
+ char* e (nullptr);
+ uint64_t t (strtoull (tm.c_str (), &e, 10));
- size_t offset (0);
- bld_query bq ("ORDER BY" +
- bld_query::id.package.tenant + "," +
- bld_query::id.package.name +
- order_by_version_desc (bld_query::id.package.version, false) +
- "OFFSET" + bld_query::_ref (offset) + "LIMIT 100");
+ if (*e != '\0' || tm.empty ())
+ return nullopt;
- connection_ptr conn (build_db.connection ());
+ if (t == 0)
+ return timestamp_nonexistent;
- prep_bld_query bld_prep_query (
- conn->prepare_query<build> ("build-query", bq));
+ return system_clock::now () - chrono::hours (t);
+ }
- // Prepare the package version query.
- //
- // Query buildable packages every time the new package name is encountered
- // during iterating over the package builds. Such a query will be made once
- // per package name due to the builds query sorting criteria (see above).
- //
- using pkg_query = query<buildable_package>;
- using prep_pkg_query = prepared_query<buildable_package>;
+ static int
+ clean_builds (const options& ops,
+ cli::argv_scanner& scan,
+ odb::pgsql::database& db)
+ {
+ // Load configurations names.
+ //
+ if (!scan.more ())
+ {
+ cerr << "error: configuration file expected" << endl
+ << help_info << endl;
+ return 1;
+ }
- package_name pkg_name;
- set<version> package_versions;
+ path cp;
- pkg_query pq (
- pkg_query::build_package::id.name == pkg_query::_ref (pkg_name));
+ try
+ {
+ cp = path (scan.next ());
+ }
+ catch (const invalid_path& e)
+ {
+ cerr << "error: configuration file expected instead of '" << e.path
+ << "'" << endl
+ << help_info << endl;
+ return 1;
+ }
- prep_pkg_query pkg_prep_query (
- conn->prepare_query<buildable_package> ("package-query", pq));
+ set<string> configs;
- for (bool ne (true); ne; )
- {
- transaction t (conn->begin ());
+ try
+ {
+ for (auto& c: parse_buildtab (cp))
+ configs.emplace (move (c.name));
+ }
+ catch (const io_error& e)
+ {
+ cerr << "error: unable to read '" << cp << "': " << e << endl;
+ return 1;
+ }
- // Query builds.
+ // Parse timestamps.
//
- auto builds (bld_prep_query.execute ());
+ map<string, timestamp> timeouts; // Toolchain timeouts.
+ timestamp default_timeout; // timestamp_nonexistent
- if ((ne = !builds.empty ()))
+ while (scan.more ())
{
- for (const auto& b: builds)
+ string a (scan.next ());
+
+ string tc;
+ optional<timestamp> to;
+
+ size_t p (a.find ('='));
+
+ if (p == string::npos)
+ to = timeout (a);
+ else if (p > 0) // Note: toolchain name can't be empty.
{
- auto i (timeouts.find (b.toolchain_name));
+ tc = string (a, 0, p);
+ to = timeout (string (a, p + 1));
+ }
- timestamp et (i != timeouts.end ()
- ? i->second
- : default_timeout);
+ // Note that the default timeout can't be zero.
+ //
+ if (!to || (*to == timestamp_nonexistent && tc.empty ()))
+ {
+ cerr << "error: timeout expected instead of '" << a << "'" << endl
+ << help_info << endl;
+ return 1;
+ }
- bool cleanup (
- // Check that the build is not stale.
- //
- b.timestamp <= et ||
+ if (tc.empty ())
+ default_timeout = *to;
- // Check that the build configuration is still present.
- //
- // Note that we unable to detect configuration changes and rely on
- // periodic rebuilds to take care of that.
- //
- configs.find (b.configuration) == configs.end ());
+ timeouts[move (tc)] = move (*to);
+ }
- // Check that the build package still exists.
- //
- if (!cleanup)
+ // Prepare the build prepared query.
+ //
+ // Query package builds in chunks in order not to hold locks for too long.
+ // Sort the result by package version to minimize number of queries to the
+ // package database.
+ //
+ using bld_query = query<build>;
+ using prep_bld_query = prepared_query<build>;
+
+ size_t offset (0);
+ bld_query bq ("ORDER BY" +
+ bld_query::id.package.tenant + "," +
+ bld_query::id.package.name +
+ order_by_version_desc (bld_query::id.package.version,
+ false) +
+ "OFFSET" + bld_query::_ref (offset) + "LIMIT 100");
+
+ connection_ptr conn (db.connection ());
+
+ prep_bld_query bld_prep_query (
+ conn->prepare_query<build> ("build-query", bq));
+
+ // Prepare the package version query.
+ //
+ // Query buildable packages every time the new tenant or package name is
+ // encountered during iterating over the package builds. Such a query will
+ // be made once per tenant package name due to the builds query sorting
+ // criteria (see above).
+ //
+ using pkg_query = query<buildable_package>;
+ using prep_pkg_query = prepared_query<buildable_package>;
+
+ string tnt;
+ package_name pkg_name;
+ set<version> package_versions;
+
+ pkg_query pq (
+ pkg_query::build_package::id.tenant == pkg_query::_ref (tnt) &&
+ pkg_query::build_package::id.name == pkg_query::_ref (pkg_name));
+
+ prep_pkg_query pkg_prep_query (
+ conn->prepare_query<buildable_package> ("package-query", pq));
+
+ for (bool ne (true); ne; )
+ {
+ transaction t (conn->begin ());
+
+ // Query builds.
+ //
+ auto builds (bld_prep_query.execute ());
+
+ if ((ne = !builds.empty ()))
+ {
+ for (const auto& b: builds)
{
- if (pkg_name != b.package_name)
- {
- pkg_name = b.package_name;
- package_versions.clear ();
+ auto i (timeouts.find (b.toolchain_name));
- for (auto& p: pkg_prep_query.execute ())
- package_versions.emplace (move (p.version));
+ timestamp et (i != timeouts.end ()
+ ? i->second
+ : default_timeout);
+
+ bool cleanup (
+ // Check that the build is not stale.
+ //
+ b.timestamp <= et ||
+
+ // Check that the build configuration is still present.
+ //
+ // Note that we unable to detect configuration changes and rely on
+ // periodic rebuilds to take care of that.
+ //
+ configs.find (b.configuration) == configs.end ());
+
+ // Check that the build package still exists.
+ //
+ if (!cleanup)
+ {
+ if (tnt != b.tenant || pkg_name != b.package_name)
+ {
+ tnt = b.tenant;
+ pkg_name = b.package_name;
+ package_versions.clear ();
+
+ for (auto& p: pkg_prep_query.execute ())
+ package_versions.emplace (move (p.version));
+ }
+
+ cleanup = package_versions.find (b.package_version) ==
+ package_versions.end ();
}
- cleanup = package_versions.find (b.package_version) ==
- package_versions.end ();
+ if (cleanup)
+ db.erase (b);
+ else
+ ++offset;
}
-
- if (cleanup)
- build_db.erase (b);
- else
- ++offset;
}
+
+ t.commit ();
}
- t.commit ();
+ return 0;
}
- return 0;
-}
-catch (const database_locked&)
-{
- cerr << "brep-clean or brep-migrate is running" << endl;
- return 2;
-}
-catch (const recoverable& e)
-{
- cerr << "recoverable database error: " << e << endl;
- return 3;
-}
-catch (const cli::exception& e)
-{
- cerr << "error: " << e << endl << help_info << endl;
- return 1;
-}
-catch (const failed&)
-{
- return 1; // Diagnostics has already been issued.
+ static int
+ clean_tenants (const options& ops,
+ cli::argv_scanner& scan,
+ odb::pgsql::database& db)
+ {
+ if (!scan.more ())
+ {
+ cerr << "error: timeout expected" << endl
+ << help_info << endl;
+ return 1;
+ }
+
+ string a (scan.next ());
+ optional<timestamp> to (timeout (a));
+
+ // Note that the timeout can't be zero.
+ //
+ if (!to || *to == timestamp_nonexistent)
+ {
+ cerr << "error: timeout expected instead of '" << a << "'" << endl
+ << help_info << endl;
+ return 1;
+ }
+
+ if (scan.more ())
+ {
+ cerr << "error: unexpected argument encountered" << endl
+ << help_info << endl;
+ return 1;
+ }
+
+ uint64_t ns (
+ chrono::duration_cast<chrono::nanoseconds> (
+ to->time_since_epoch ()).count ());
+
+ // Query tenants in chunks in order not to hold locks for too long.
+ //
+ connection_ptr conn (db.connection ());
+
+ // Archive (rather then delete) old tenants, if requested.
+ //
+ if (ops.archive ())
+ {
+ using query = query<tenant>;
+ using pquery = prepared_query<tenant>;
+
+ query q ((query::creation_timestamp < ns && !query::archived) +
+ "LIMIT 100");
+
+ pquery pq (conn->prepare_query<tenant> ("tenant-query", q));
+
+ for (bool ne (true); ne; )
+ {
+ transaction t (conn->begin ());
+
+ auto tenants (pq.execute ());
+ if ((ne = !tenants.empty ()))
+ {
+ for (auto& t: tenants)
+ {
+ t.archived = true;
+ db.update (t);
+ }
+ }
+
+ t.commit ();
+ }
+
+ return 0;
+ }
+
+ // Delete old tenants.
+ //
+ // Note that we don't delete dangling builds for the deleted packages.
+ // Doing so would require to operate on two databases, complicating the
+ // code and the utility interface. Note that dangling builds are never
+ // considered in the web interface and are always deleted with the
+ // 'brep-clean builds' command.
+ //
+ using query = query<tenant_id>;
+ using pquery = prepared_query<tenant_id>;
+
+ query q ((query::creation_timestamp < ns) + "LIMIT 100");
+ pquery pq (conn->prepare_query<tenant_id> ("tenant-id-query", q));
+
+ for (bool ne (true); ne; )
+ {
+ transaction t (conn->begin ());
+
+ auto tenant_ids (pq.execute ());
+ if ((ne = !tenant_ids.empty ()))
+ {
+ // Cache tenant ids and erase packages, repositories, and tenants at
+ // once.
+ //
+ strings tids;
+ tids.reserve (tenant_ids.size ());
+
+ for (auto& tid: tenant_ids)
+ tids.push_back (move (tid.value));
+
+ using odb::query;
+
+ db.erase_query<package> (
+ query<package>::id.tenant.in_range (tids.begin (), tids.end ()));
+
+ db.erase_query<repository> (
+ query<repository>::id.tenant.in_range (tids.begin (), tids.end ()));
+
+ db.erase_query<tenant> (
+ query<tenant>::id.in_range (tids.begin (), tids.end ()));
+ }
+
+ t.commit ();
+ }
+
+ return 0;
+ }
}
-// Fully qualified to avoid ambiguity with odb exception.
-//
-catch (const std::exception& e)
+
+int
+main (int argc, char* argv[])
{
- cerr << "error: " << e << endl;
- return 1;
+ return brep::main (argc, argv);
}
diff --git a/clean/options-types.hxx b/clean/options-types.hxx
deleted file mode 100644
index 7190396..0000000
--- a/clean/options-types.hxx
+++ /dev/null
@@ -1,18 +0,0 @@
-// file : clean/options-types.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2018 Code Synthesis Ltd
-// license : MIT; see accompanying LICENSE file
-
-#ifndef CLEAN_OPTIONS_TYPES_HXX
-#define CLEAN_OPTIONS_TYPES_HXX
-
-#include <map>
-
-#include <libbrep/types.hxx>
-#include <libbrep/utility.hxx>
-
-namespace brep
-{
- struct toolchain_timeouts: std::map<string, timestamp> {};
-}
-
-#endif // CLEAN_OPTIONS_TYPES_HXX
diff --git a/clean/types-parsers.cxx b/clean/types-parsers.cxx
deleted file mode 100644
index 31f3a8d..0000000
--- a/clean/types-parsers.cxx
+++ /dev/null
@@ -1,60 +0,0 @@
-// file : clean/types-parsers.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2018 Code Synthesis Ltd
-// license : MIT; see accompanying LICENSE file
-
-#include <chrono>
-#include <string> // strtoull()
-
-#include <clean/types-parsers.hxx>
-
-#include <clean/options-types.hxx>
-#include <clean/clean-options.hxx> // cli namespace
-
-using namespace std;
-using namespace brep;
-
-namespace cli
-{
- void parser<toolchain_timeouts>::
- parse (toolchain_timeouts& x, bool& xs, scanner& s)
- {
- const char* o (s.next ());
-
- if (!s.more ())
- throw missing_value (o);
-
- string ov (s.next ());
- size_t p (ov.find ('='));
-
- timestamp now (system_clock::now ());
-
- // Convert timeout duration into the time point.
- //
- auto timeout = [o, &ov, &now] (const string& tm) -> timestamp
- {
- char* e (nullptr);
- uint64_t t (strtoull (tm.c_str (), &e, 10));
-
- if (*e != '\0' || tm.empty ())
- throw invalid_value (o, ov);
-
- if (t == 0)
- return timestamp_nonexistent;
-
- return now - chrono::duration<uint64_t, ratio<86400>> (t);
- };
-
- if (p == string::npos)
- x[string ()] = timeout (ov); // Default timeout.
- else
- {
- string k (ov, 0, p);
- if (k.empty ())
- throw invalid_value (o, ov);
-
- x[k] = timeout (string (ov, p + 1));
- }
-
- xs = true;
- }
-}
diff --git a/clean/types-parsers.hxx b/clean/types-parsers.hxx
deleted file mode 100644
index fe7c77c..0000000
--- a/clean/types-parsers.hxx
+++ /dev/null
@@ -1,28 +0,0 @@
-// file : clean/types-parsers.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2018 Code Synthesis Ltd
-// license : MIT; see accompanying LICENSE file
-
-// CLI parsers, included into the generated source files.
-//
-
-#ifndef CLEAN_TYPES_PARSERS_HXX
-#define CLEAN_TYPES_PARSERS_HXX
-
-#include <clean/options-types.hxx>
-
-namespace cli
-{
- class scanner;
-
- template <typename T>
- struct parser;
-
- template <>
- struct parser<brep::toolchain_timeouts>
- {
- static void
- parse (brep::toolchain_timeouts&, bool&, scanner&);
- };
-}
-
-#endif // CLEAN_TYPES_PARSERS_HXX
diff --git a/etc/systemd/brep-clean.service b/etc/systemd/brep-clean.service
index 0099d62..739a54a 100644
--- a/etc/systemd/brep-clean.service
+++ b/etc/systemd/brep-clean.service
@@ -5,7 +5,11 @@ Description=brep build database cleaner service
Type=oneshot
#User=brep
#Group=brep
-ExecStart=/home/brep/install/bin/brep-clean /home/brep/config/buildtab
+
+# Run both tenants and builds cleaners if CI request functionality is enabled.
+#
+#ExecStart=/home/brep/install/bin/brep-clean tenants 240
+ExecStart=/home/brep/install/bin/brep-clean builds /home/brep/config/buildtab
[Install]
WantedBy=default.target
diff --git a/libbrep/build-extra.sql b/libbrep/build-extra.sql
index 35ba361..6c0d6ef 100644
--- a/libbrep/build-extra.sql
+++ b/libbrep/build-extra.sql
@@ -12,6 +12,16 @@ DROP FOREIGN TABLE IF EXISTS build_package;
DROP FOREIGN TABLE IF EXISTS build_repository;
+DROP FOREIGN TABLE IF EXISTS build_tenant;
+
+-- The foreign table for build_tenant object.
+--
+--
+CREATE FOREIGN TABLE build_tenant (
+ id TEXT NOT NULL,
+ archived BOOLEAN NOT NULL)
+SERVER package_server OPTIONS (table_name 'tenant');
+
-- The foreign table for build_repository object.
--
--
diff --git a/libbrep/build-package.hxx b/libbrep/build-package.hxx
index 0fed500..0d6b5bf 100644
--- a/libbrep/build-package.hxx
+++ b/libbrep/build-package.hxx
@@ -23,7 +23,26 @@ namespace brep
// The mapping is established in build-extra.sql. We also explicitly mark
// non-primary key foreign-mapped members in the source object.
//
- // Foreign object that is mapped to a subset of repository object.
+ // Foreign object that is mapped to a subset of the tenant object.
+ //
+ #pragma db object table("build_tenant") pointer(shared_ptr) readonly
+ class build_tenant
+ {
+ public:
+ string id;
+
+ bool archived;
+
+ // Database mapping.
+ //
+ #pragma db member(id) id
+
+ private:
+ friend class odb::access;
+ build_tenant () = default;
+ };
+
+ // Foreign object that is mapped to a subset of the repository object.
//
#pragma db object table("build_repository") pointer(shared_ptr) readonly
class build_repository
@@ -61,7 +80,7 @@ namespace brep
optional<string> target;
};
- // Foreign object that is mapped to a subset of package object.
+ // Foreign object that is mapped to a subset of the package object.
//
#pragma db object table("build_package") pointer(shared_ptr) readonly
class build_package
@@ -92,14 +111,15 @@ namespace brep
// Note that ADL can't find the equal operator, so we use the function call
// notation.
//
- #pragma db view \
- object(build_package) \
- object(build_repository inner: \
- brep::operator== (build_package::internal_repository, \
- build_repository::id) && \
- brep::compare_version_ne (build_package::id.version, \
- brep::wildcard_version, \
- false))
+ #pragma db view \
+ object(build_package) \
+ object(build_repository inner: \
+ brep::operator== (build_package::internal_repository, \
+ build_repository::id) && \
+ brep::compare_version_ne (build_package::id.version, \
+ brep::wildcard_version, \
+ false)) \
+ object(build_tenant: build_package::id.tenant == build_tenant::id)
struct buildable_package
{
package_id id;
@@ -110,14 +130,15 @@ namespace brep
#pragma db member(version) set(this.version.init (this.id.version, (?)))
};
- #pragma db view \
- object(build_package) \
- object(build_repository inner: \
- brep::operator== (build_package::internal_repository, \
- build_repository::id) && \
- brep::compare_version_ne (build_package::id.version, \
- brep::wildcard_version, \
- false))
+ #pragma db view \
+ object(build_package) \
+ object(build_repository inner: \
+ brep::operator== (build_package::internal_repository, \
+ build_repository::id) && \
+ brep::compare_version_ne (build_package::id.version, \
+ brep::wildcard_version, \
+ false)) \
+ object(build_tenant: build_package::id.tenant == build_tenant::id)
struct buildable_package_count
{
size_t result;
@@ -133,18 +154,19 @@ namespace brep
// (internal and non-stub) packages can have such constraints, so there is
// no need for additional checks.
//
- #pragma db view \
- table("build_package_constraints" = "c") \
- object(build_package = package inner: \
- "c.exclusion AND " \
- "c.tenant = " + package::id.tenant + "AND" + \
- "c.name = " + package::id.name + "AND" + \
- "c.version_epoch = " + package::id.version.epoch + "AND" + \
- "c.version_canonical_upstream = " + \
- package::id.version.canonical_upstream + "AND" + \
- "c.version_canonical_release = " + \
- package::id.version.canonical_release + "AND" + \
- "c.version_revision = " + package::id.version.revision) \
+ #pragma db view \
+ table("build_package_constraints" = "c") \
+ object(build_package inner: \
+ "c.exclusion AND " \
+ "c.tenant = " + build_package::id.tenant + "AND" + \
+ "c.name = " + build_package::id.name + "AND" + \
+ "c.version_epoch = " + build_package::id.version.epoch + "AND" + \
+ "c.version_canonical_upstream = " + \
+ build_package::id.version.canonical_upstream + "AND" + \
+ "c.version_canonical_release = " + \
+ build_package::id.version.canonical_release + "AND" + \
+ "c.version_revision = " + build_package::id.version.revision) \
+ object(build_tenant: build_package::id.tenant == build_tenant::id) \
query(distinct)
struct build_constrained_package
{
diff --git a/libbrep/build.hxx b/libbrep/build.hxx
index fc314eb..279c1d7 100644
--- a/libbrep/build.hxx
+++ b/libbrep/build.hxx
@@ -26,7 +26,7 @@
//
#define LIBBREP_BUILD_SCHEMA_VERSION_BASE 4
-#pragma db model version(LIBBREP_BUILD_SCHEMA_VERSION_BASE, 4, closed)
+#pragma db model version(LIBBREP_BUILD_SCHEMA_VERSION_BASE, 5, 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
@@ -251,7 +251,11 @@ namespace brep
}
};
- #pragma db view object(build) query(distinct)
+ #pragma db view object(build) \
+ object(build_package inner: \
+ brep::operator== (build::id.package, build_package::id) && \
+ build_package::internal_repository.canonical_name.is_not_null ()) \
+ query(distinct)
struct toolchain
{
string name;
@@ -297,7 +301,8 @@ namespace brep
object(build) \
object(build_package inner: \
brep::operator== (build::id.package, build_package::id) && \
- build_package::internal_repository.canonical_name.is_not_null ())
+ build_package::internal_repository.canonical_name.is_not_null ()) \
+ object(build_tenant: build_package::id.tenant == build_tenant::id)
struct package_build
{
shared_ptr<brep::build> build;
@@ -307,7 +312,8 @@ namespace brep
object(build) \
object(build_package inner: \
brep::operator== (build::id.package, build_package::id) && \
- build_package::internal_repository.canonical_name.is_not_null ())
+ build_package::internal_repository.canonical_name.is_not_null ()) \
+ object(build_tenant: build_package::id.tenant == build_tenant::id)
struct package_build_count
{
size_t result;
diff --git a/libbrep/build.xml b/libbrep/build.xml
index 0116374..13b47a6 100644
--- a/libbrep/build.xml
+++ b/libbrep/build.xml
@@ -1,4 +1,6 @@
<changelog xmlns="http://www.codesynthesis.com/xmlns/odb/changelog" database="pgsql" schema-name="build" version="1">
+ <changeset version="5"/>
+
<model version="4">
<table name="build" kind="object">
<column name="package_tenant" type="TEXT" null="false"/>
diff --git a/libbrep/package.cxx b/libbrep/package.cxx
index e3921fe..d10186c 100644
--- a/libbrep/package.cxx
+++ b/libbrep/package.cxx
@@ -38,6 +38,15 @@ namespace brep
return !(x == y);
}
+ // tenant
+ //
+ tenant::
+ tenant (string i)
+ : id (move (i)),
+ creation_timestamp (timestamp::clock::now ())
+ {
+ }
+
// package
//
package::
diff --git a/libbrep/package.hxx b/libbrep/package.hxx
index af4581c..fb44bf3 100644
--- a/libbrep/package.hxx
+++ b/libbrep/package.hxx
@@ -21,7 +21,7 @@
//
#define LIBBREP_PACKAGE_SCHEMA_VERSION_BASE 7
-#pragma db model version(LIBBREP_PACKAGE_SCHEMA_VERSION_BASE, 8, open)
+#pragma db model version(LIBBREP_PACKAGE_SCHEMA_VERSION_BASE, 9, open)
namespace brep
{
@@ -185,6 +185,42 @@ namespace brep
};
#pragma db object pointer(shared_ptr) session
+ class tenant
+ {
+ public:
+ // Create the tenant object with the timestamp set to now and the archived
+ // flag set to false.
+ //
+ explicit
+ tenant (string id);
+
+ string id;
+
+ timestamp creation_timestamp;
+ bool archived = false; // Note: foreign-mapped in build.
+
+ // Database mapping.
+ //
+ #pragma db member(id) id
+
+ private:
+ friend class odb::access;
+ tenant () = default;
+ };
+
+ #pragma db view object(tenant)
+ struct tenant_id
+ {
+ #pragma db column("id")
+ string value;
+ };
+
+ // Tweak repository_id mapping to include a constraint (this only affects
+ // the database schema).
+ //
+ #pragma db member(repository_id::tenant) points_to(tenant)
+
+ #pragma db object pointer(shared_ptr) session
class repository
{
public:
@@ -269,6 +305,15 @@ namespace brep
repository (): tenant (id.tenant), canonical_name (id.canonical_name) {}
};
+ // Used for data migration (see migrate/migrate.cxx for details).
+ //
+ #pragma db view object(repository) query(distinct)
+ struct repository_tenant
+ {
+ #pragma db column("tenant")
+ string id;
+ };
+
// The 'to' expression calls the PostgreSQL to_tsvector(weighted_text)
// function overload (package-extra.sql). Since we are only interested
// in "write-only" members of this type, make the 'from' expression
@@ -289,6 +334,11 @@ namespace brep
string d;
};
+ // Tweak package_id mapping to include a constraint (this only affects the
+ // database schema).
+ //
+ #pragma db member(package_id::tenant) points_to(tenant)
+
#pragma db object pointer(shared_ptr) session
class package
{
diff --git a/libbrep/package.xml b/libbrep/package.xml
index 07c1be7..2b9ebab 100644
--- a/libbrep/package.xml
+++ b/libbrep/package.xml
@@ -1,4 +1,149 @@
<changelog xmlns="http://www.codesynthesis.com/xmlns/odb/changelog" database="pgsql" schema-name="package" version="1">
+ <changeset version="9">
+ <add-table name="tenant" kind="object">
+ <column name="id" type="TEXT" null="false"/>
+ <column name="creation_timestamp" type="BIGINT" null="false"/>
+ <column name="archived" type="BOOLEAN" null="false"/>
+ <primary-key>
+ <column name="id"/>
+ </primary-key>
+ </add-table>
+ <alter-table name="repository">
+ <add-foreign-key name="tenant_fk" deferrable="DEFERRED">
+ <column name="tenant"/>
+ <references table="tenant">
+ <column name="id"/>
+ </references>
+ </add-foreign-key>
+ </alter-table>
+ <alter-table name="repository_complements">
+ <add-foreign-key name="repository_tenant_fk" deferrable="DEFERRED">
+ <column name="repository_tenant"/>
+ <references table="tenant">
+ <column name="id"/>
+ </references>
+ </add-foreign-key>
+ <add-foreign-key name="complement_tenant_fk" deferrable="DEFERRED">
+ <column name="complement_tenant"/>
+ <references table="tenant">
+ <column name="id"/>
+ </references>
+ </add-foreign-key>
+ </alter-table>
+ <alter-table name="repository_prerequisites">
+ <add-foreign-key name="repository_tenant_fk" deferrable="DEFERRED">
+ <column name="repository_tenant"/>
+ <references table="tenant">
+ <column name="id"/>
+ </references>
+ </add-foreign-key>
+ <add-foreign-key name="prerequisite_tenant_fk" deferrable="DEFERRED">
+ <column name="prerequisite_tenant"/>
+ <references table="tenant">
+ <column name="id"/>
+ </references>
+ </add-foreign-key>
+ </alter-table>
+ <alter-table name="package">
+ <add-foreign-key name="tenant_fk" deferrable="DEFERRED">
+ <column name="tenant"/>
+ <references table="tenant">
+ <column name="id"/>
+ </references>
+ </add-foreign-key>
+ <add-foreign-key name="internal_repository_tenant_fk" deferrable="DEFERRED">
+ <column name="internal_repository_tenant"/>
+ <references table="tenant">
+ <column name="id"/>
+ </references>
+ </add-foreign-key>
+ </alter-table>
+ <alter-table name="package_license_alternatives">
+ <add-foreign-key name="tenant_fk" deferrable="DEFERRED">
+ <column name="tenant"/>
+ <references table="tenant">
+ <column name="id"/>
+ </references>
+ </add-foreign-key>
+ </alter-table>
+ <alter-table name="package_licenses">
+ <add-foreign-key name="tenant_fk" deferrable="DEFERRED">
+ <column name="tenant"/>
+ <references table="tenant">
+ <column name="id"/>
+ </references>
+ </add-foreign-key>
+ </alter-table>
+ <alter-table name="package_tags">
+ <add-foreign-key name="tenant_fk" deferrable="DEFERRED">
+ <column name="tenant"/>
+ <references table="tenant">
+ <column name="id"/>
+ </references>
+ </add-foreign-key>
+ </alter-table>
+ <alter-table name="package_dependencies">
+ <add-foreign-key name="tenant_fk" deferrable="DEFERRED">
+ <column name="tenant"/>
+ <references table="tenant">
+ <column name="id"/>
+ </references>
+ </add-foreign-key>
+ </alter-table>
+ <alter-table name="package_dependency_alternatives">
+ <add-foreign-key name="tenant_fk" deferrable="DEFERRED">
+ <column name="tenant"/>
+ <references table="tenant">
+ <column name="id"/>
+ </references>
+ </add-foreign-key>
+ <add-foreign-key name="dep_package_tenant_fk" deferrable="DEFERRED">
+ <column name="dep_package_tenant"/>
+ <references table="tenant">
+ <column name="id"/>
+ </references>
+ </add-foreign-key>
+ </alter-table>
+ <alter-table name="package_requirements">
+ <add-foreign-key name="tenant_fk" deferrable="DEFERRED">
+ <column name="tenant"/>
+ <references table="tenant">
+ <column name="id"/>
+ </references>
+ </add-foreign-key>
+ </alter-table>
+ <alter-table name="package_requirement_alternatives">
+ <add-foreign-key name="tenant_fk" deferrable="DEFERRED">
+ <column name="tenant"/>
+ <references table="tenant">
+ <column name="id"/>
+ </references>
+ </add-foreign-key>
+ </alter-table>
+ <alter-table name="package_build_constraints">
+ <add-foreign-key name="tenant_fk" deferrable="DEFERRED">
+ <column name="tenant"/>
+ <references table="tenant">
+ <column name="id"/>
+ </references>
+ </add-foreign-key>
+ </alter-table>
+ <alter-table name="package_other_repositories">
+ <add-foreign-key name="tenant_fk" deferrable="DEFERRED">
+ <column name="tenant"/>
+ <references table="tenant">
+ <column name="id"/>
+ </references>
+ </add-foreign-key>
+ <add-foreign-key name="repository_tenant_fk" deferrable="DEFERRED">
+ <column name="repository_tenant"/>
+ <references table="tenant">
+ <column name="id"/>
+ </references>
+ </add-foreign-key>
+ </alter-table>
+ </changeset>
+
<changeset version="8"/>
<model version="7">
diff --git a/load/load.cxx b/load/load.cxx
index 24a3bf3..3036daf 100644
--- a/load/load.cxx
+++ b/load/load.cxx
@@ -1101,9 +1101,9 @@ try
// By default the tenant is empty and assumes a single-tenant mode. Let's
// require the specified tenant to be non-empty.
//
- const string& tenant (ops.tenant ());
+ const string& tnt (ops.tenant ());
- if (ops.tenant_specified () && tenant.empty ())
+ if (ops.tenant_specified () && tnt.empty ())
{
cerr << "error: empty tenant" << endl
<< help_info << endl;
@@ -1140,7 +1140,7 @@ try
//
internal_repositories irs (load_repositories (path (argv[1])));
- if (ops.force () || changed (tenant, irs, db))
+ if (ops.force () || changed (tnt, irs, db))
{
// Rebuild repositories persistent state from scratch.
//
@@ -1150,22 +1150,30 @@ try
// multiple tenants). Otherwise, cleanup the specified and the empty
// tenants only.
//
- if (tenant.empty ()) // Single-tenant mode.
+ if (tnt.empty ()) // Single-tenant mode.
{
db.erase_query<package> ();
db.erase_query<repository> ();
+ db.erase_query<tenant> ();
}
else // Multi-tenant mode.
{
- cstrings ts ({tenant.c_str (), ""});
+ cstrings ts ({tnt.c_str (), ""});
db.erase_query<package> (
query<package>::id.tenant.in_range (ts.begin (), ts.end ()));
db.erase_query<repository> (
query<repository>::id.tenant.in_range (ts.begin (), ts.end ()));
+
+ db.erase_query<tenant> (
+ query<tenant>::id.in_range (ts.begin (), ts.end ()));
}
+ // Persist the tenant.
+ //
+ db.persist (tenant (tnt));
+
// On the first pass over the internal repositories we load their
// certificate information and packages.
//
@@ -1181,7 +1189,7 @@ try
ir.fingerprint);
shared_ptr<repository> r (
- make_shared<repository> (tenant,
+ make_shared<repository> (tnt,
ir.location,
move (ir.display_name),
move (ir.cache_location),
@@ -1198,8 +1206,8 @@ try
for (const auto& ir: irs)
{
shared_ptr<repository> r (
- db.load<repository> (repository_id (tenant,
- ir.location.canonical_name ())));
+ db.load<repository> (
+ repository_id (tnt, ir.location.canonical_name ())));
load_repositories (r, db, ops.shallow ());
}
@@ -1213,7 +1221,7 @@ try
for (auto& p:
db.query<package> (
- query::id.tenant == tenant &&
+ query::id.tenant == tnt &&
query::internal_repository.canonical_name.is_not_null ()))
resolve_dependencies (p, db);
@@ -1222,7 +1230,7 @@ try
package_ids chain;
for (const auto& p:
db.query<package> (
- query::id.tenant == tenant &&
+ query::id.tenant == tnt &&
query::internal_repository.canonical_name.is_not_null ()))
detect_dependency_cycle (p.id, chain, db);
}
diff --git a/migrate/migrate.cxx b/migrate/migrate.cxx
index d84e282..d33578a 100644
--- a/migrate/migrate.cxx
+++ b/migrate/migrate.cxx
@@ -15,6 +15,8 @@
#include <libbutl/pager.mxx>
+#include <libbrep/package.hxx>
+#include <libbrep/package-odb.hxx>
#include <libbrep/database-lock.hxx>
#include <migrate/migrate-options.hxx>
@@ -203,6 +205,31 @@ create (database& db, bool extra_only) const
db.execute (s);
}
+// Register the data migration functions for the package database schema.
+//
+template <odb::schema_version v>
+using package_migration_entry_base =
+ odb::data_migration_entry<v, LIBBREP_PACKAGE_SCHEMA_VERSION_BASE>;
+
+template <odb::schema_version v>
+struct package_migration_entry: package_migration_entry_base<v>
+{
+ package_migration_entry (void (*f) (odb::database& db))
+ : package_migration_entry_base<v> (f, "package") {}
+};
+
+// Don't forget to drop the repository_tenant view when stop supporting
+// data migration for this schema version.
+//
+static const package_migration_entry<9>
+package_migrate_v9 ([] (odb::database& db)
+{
+ // Add tenant objects.
+ //
+ for (const auto& t: db.query<repository_tenant> ())
+ db.persist (tenant (t.id));
+});
+
// main() function
//
int
@@ -284,6 +311,15 @@ try
//
database_lock l (db);
+ // Currently we don't support data migration for the manual database scheme
+ // migration.
+ //
+ if (db.schema_migration (db_schema))
+ {
+ cerr << "error: manual database schema migration is not supported" << endl;
+ throw failed ();
+ }
+
// Need to obtain schema version out of the transaction. If the
// schema_version table does not exist, the SQL query fails, which makes the
// transaction useless as all consequitive queries in that transaction will
@@ -363,11 +399,6 @@ try
//
s.drop (db, true /* extra_only */);
- // Register the data migration functions.
- //
- // static const data_migration_entry<2, LIBBREP_XXX_SCHEMA_VERSION_BASE>
- // migrate_v2_entry (&migrate_v2);
- //
schema_catalog::migrate (db, 0, db_schema);
s.create (db, true /* extra_only */);
diff --git a/mod/mod-build-task.cxx b/mod/mod-build-task.cxx
index 77652ce..d3efb41 100644
--- a/mod/mod-build-task.cxx
+++ b/mod/mod-build-task.cxx
@@ -328,7 +328,7 @@ handle (request& rq, response& rs)
using pkg_query = query<buildable_package>;
using prep_pkg_query = prepared_query<buildable_package>;
- pkg_query pq (true);
+ pkg_query pq (!pkg_query::build_tenant::archived);
// Filter by repositories canonical names (if requested).
//
diff --git a/mod/mod-builds.cxx b/mod/mod-builds.cxx
index a55b6f9..4d03987 100644
--- a/mod/mod-builds.cxx
+++ b/mod/mod-builds.cxx
@@ -94,7 +94,8 @@ template <typename T>
static inline query<T>
build_query (const brep::cstrings& configs,
const brep::params::builds& params,
- const brep::optional<brep::string>& tenant)
+ const brep::optional<brep::string>& tenant,
+ const brep::optional<bool>& archived)
{
using namespace brep;
using query = query<T>;
@@ -109,6 +110,9 @@ build_query (const brep::cstrings& configs,
if (tenant)
q = q && pid.tenant == *tenant;
+ if (archived)
+ q = q && query::build_tenant::archived == *archived;
+
// Note that there is no error reported if the filter parameters parsing
// fails. Instead, it is considered that no package builds match such a
// query.
@@ -205,18 +209,23 @@ build_query (const brep::cstrings& configs,
return q;
}
-template <typename T, typename P = typename query<T>::build_package>
+template <typename T>
static inline query<T>
package_query (const brep::params::builds& params,
- const brep::optional<brep::string>& tenant)
+ const brep::optional<brep::string>& tenant,
+ const brep::optional<bool>& archived)
{
using namespace brep;
using query = query<T>;
+ using qp = typename query::build_package;
query q (true);
if (tenant)
- q = q && P::id.tenant == *tenant;
+ q = q && qp::id.tenant == *tenant;
+
+ if (archived)
+ q = q && query::build_tenant::archived == *archived;
// Note that there is no error reported if the filter parameters parsing
// fails. Instead, it is considered that no packages match such a query.
@@ -226,13 +235,13 @@ package_query (const brep::params::builds& params,
// Package name.
//
if (!params.name ().empty ())
- q = q && P::id.name.like (
+ q = q && qp::id.name.like (
package_name (transform (params.name ()), package_name::raw_string));
// Package version.
//
if (!params.version ().empty () && params.version () != "*")
- q = q && compare_version_eq (P::id.version,
+ q = q && compare_version_eq (qp::id.version,
version (params.version ()), // May throw.
true);
}
@@ -344,9 +353,9 @@ handle (request& rq, response& rs)
toolchains r;
for (auto& t: build_db_->query<toolchain> (
- (tn ? query::id.package.tenant == *tn : query (true)) +
- "ORDER BY" + query::toolchain_name +
- order_by_version_desc (query::id.toolchain_version, false)))
+ (tn ? query::build::id.package.tenant == *tn : query (true)) +
+ "ORDER BY" + query::build::toolchain_name +
+ order_by_version_desc (query::build::id.toolchain_version, false)))
r.emplace_back (move (t.name), move (t.version));
return r;
@@ -440,7 +449,8 @@ handle (request& rq, response& rs)
transaction t (build_db_->begin ());
count = build_db_->query_value<package_build_count> (
- build_query<package_build_count> (*build_conf_names_, params, tn));
+ build_query<package_build_count> (
+ *build_conf_names_, params, tn, nullopt /* archived */));
// Print the filter form.
//
@@ -455,7 +465,8 @@ handle (request& rq, response& rs)
//
s << DIV;
for (auto& pb: build_db_->query<package_build> (
- build_query<package_build> (*build_conf_names_, params, tn) +
+ build_query<package_build> (
+ *build_conf_names_, params, tn, nullopt /* archived */) +
"ORDER BY" + query<package_build>::build::timestamp + "DESC" +
"OFFSET" + to_string (page * page_configs) +
"LIMIT" + to_string (page_configs)))
@@ -608,12 +619,12 @@ handle (request& rq, response& rs)
size_t nmax (
config_toolchains.size () *
build_db_->query_value<buildable_package_count> (
- package_query<buildable_package_count> (params, tn)));
+ package_query<buildable_package_count> (
+ params, tn, false /* archived */)));
size_t ncur = build_db_->query_value<package_build_count> (
- build_query<package_build_count> (*build_conf_names_,
- bld_params,
- tn));
+ build_query<package_build_count> (
+ *build_conf_names_, bld_params, tn, false /* archived */));
// From now we will be using specific package name and version for each
// build database query.
@@ -645,7 +656,8 @@ handle (request& rq, response& rs)
//
build_query<package_build_count> (cstrings () /* configs */,
bld_params,
- nullopt /* tenant */));
+ nullopt /* tenant */,
+ false /* archived */));
prep_bld_query bld_prep_query (
build_db_->prepare_query<package_build_count> (
@@ -658,9 +670,9 @@ handle (request& rq, response& rs)
// caching will not be easy as the cached values depend on the filter
// form parameters.
//
- using query = query<build_constrained_package>;
- query q (package_query<build_constrained_package, query> (params,
- tn));
+ query q (
+ package_query<build_constrained_package> (
+ params, tn, false /* archived */));
for (const auto& p: build_db_->query<build_constrained_package> (q))
{
@@ -715,7 +727,8 @@ handle (request& rq, response& rs)
using pkg_query = query<buildable_package>;
using prep_pkg_query = prepared_query<buildable_package>;
- pkg_query pq (package_query<buildable_package> (params, tn));
+ pkg_query pq (
+ package_query<buildable_package> (params, tn, false /* archived */));
// Specify the portion. Note that we will still be querying packages in
// chunks, not to hold locks for too long.
@@ -753,7 +766,8 @@ handle (request& rq, response& rs)
//
build_query<package_build> (*build_conf_names_,
bld_params,
- nullopt /* tenant */));
+ nullopt /* tenant */,
+ false /* archived */));
prep_bld_query bld_prep_query (
conn->prepare_query<package_build> ("mod-builds-build-query", bq));
@@ -767,7 +781,8 @@ handle (request& rq, response& rs)
using prep_ctr_query = prepared_query<build_constrained_package>;
ctr_query cq (
- package_id_eq<build_constrained_package> (ctr_query::id, id));
+ package_id_eq<build_constrained_package> (
+ ctr_query::build_package::id, id));
prep_ctr_query ctr_prep_query (
conn->prepare_query<build_constrained_package> (