aboutsummaryrefslogtreecommitdiff
path: root/clean
diff options
context:
space:
mode:
Diffstat (limited to 'clean')
-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
6 files changed, 439 insertions, 301 deletions
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