aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libbrep/build-extra.sql21
-rw-r--r--libbrep/build-package.hxx46
-rw-r--r--libbrep/build.hxx2
-rw-r--r--libbrep/build.xml2
-rw-r--r--libbrep/common.hxx21
-rw-r--r--libbrep/package.cxx2
-rw-r--r--libbrep/package.hxx16
-rw-r--r--libbrep/package.xml47
-rw-r--r--load/load.cxx1
-rw-r--r--mod/build-config.cxx122
-rw-r--r--mod/build-config.hxx31
-rw-r--r--mod/mod-build-configs.cxx7
-rw-r--r--mod/mod-build-result.cxx23
-rw-r--r--mod/mod-build-task.cxx2
-rw-r--r--mod/mod-builds.cxx250
-rw-r--r--mod/mod-package-version-details.cxx66
-rw-r--r--tests/load/1/math/libfoo-1.0.tar.gzbin219 -> 278 bytes
-rw-r--r--tests/load/1/math/packages.manifest4
-rw-r--r--tests/load/1/stable/libfoo-1.0.tar.gzbin219 -> 278 bytes
-rw-r--r--tests/load/1/stable/packages.manifest4
-rw-r--r--tests/load/1/stable/signature.manifest20
-rw-r--r--tests/load/driver.cxx2
22 files changed, 488 insertions, 201 deletions
diff --git a/libbrep/build-extra.sql b/libbrep/build-extra.sql
index 6c0d6ef..1ada713 100644
--- a/libbrep/build-extra.sql
+++ b/libbrep/build-extra.sql
@@ -8,6 +8,8 @@
DROP FOREIGN TABLE IF EXISTS build_package_constraints;
+DROP FOREIGN TABLE IF EXISTS build_package_builds;
+
DROP FOREIGN TABLE IF EXISTS build_package;
DROP FOREIGN TABLE IF EXISTS build_repository;
@@ -49,6 +51,22 @@ CREATE FOREIGN TABLE build_package (
internal_repository_canonical_name TEXT NULL)
SERVER package_server OPTIONS (table_name 'package');
+-- The foreign table for the build_package object builds member (that is of a
+-- container type).
+--
+--
+CREATE FOREIGN TABLE build_package_builds (
+ tenant TEXT NOT NULL,
+ name CITEXT NOT NULL,
+ version_epoch INTEGER NOT NULL,
+ version_canonical_upstream TEXT NOT NULL,
+ version_canonical_release TEXT NOT NULL COLLATE "C",
+ version_revision INTEGER NOT NULL,
+ index BIGINT NOT NULL,
+ expression TEXT NOT NULL,
+ comment TEXT NOT NULL)
+SERVER package_server OPTIONS (table_name 'package_builds');
+
-- The foreign table for the build_package object constraints member (that is
-- of a container type).
--
@@ -63,5 +81,6 @@ CREATE FOREIGN TABLE build_package_constraints (
index BIGINT NOT NULL,
exclusion BOOLEAN NOT NULL,
config TEXT NOT NULL,
- target TEXT NULL)
+ target TEXT NULL,
+ comment TEXT NOT NULL)
SERVER package_server OPTIONS (table_name 'package_build_constraints');
diff --git a/libbrep/build-package.hxx b/libbrep/build-package.hxx
index 0d6b5bf..4294106 100644
--- a/libbrep/build-package.hxx
+++ b/libbrep/build-package.hxx
@@ -69,17 +69,6 @@ namespace brep
build_repository (): canonical_name (id.canonical_name) {}
};
- // "Foreign" value type that is mapped to a subset of the build_constraint
- // value type (see libbpkg/manifest.hxx for details).
- //
- #pragma db value
- struct build_constraint_subset
- {
- bool exclusion;
- string config;
- optional<string> target;
- };
-
// Foreign object that is mapped to a subset of the package object.
//
#pragma db object table("build_package") pointer(shared_ptr) readonly
@@ -90,15 +79,21 @@ namespace brep
upstream_version version;
lazy_shared_ptr<build_repository> internal_repository;
- // Mapped to a subset of the package object build_constraints member
- // using the PostgreSQL foreign table mechanism.
+ // Mapped to the package object builds member using the PostgreSQL foreign
+ // table mechanism.
+ //
+ build_class_exprs builds;
+
+ // Mapped to the package object build_constraints member using the
+ // PostgreSQL foreign table mechanism.
//
- vector<build_constraint_subset> constraints;
+ build_constraints constraints;
// Database mapping.
//
#pragma db member(id) id column("")
#pragma db member(version) set(this.version.init (this.id.version, (?)))
+ #pragma db member(builds) id_column("") value_column("")
#pragma db member(constraints) id_column("") value_column("")
private:
@@ -149,29 +144,6 @@ namespace brep
//
#pragma db member(result) column("count(" + build_package::id.name + ")")
};
-
- // Packages that have the build constraints. Note that only buildable
- // (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 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
- {
- shared_ptr<build_package> package;
- };
}
#endif // LIBBREP_BUILD_PACKAGE_HXX
diff --git a/libbrep/build.hxx b/libbrep/build.hxx
index 279c1d7..03807fa 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, 5, open)
+#pragma db model version(LIBBREP_BUILD_SCHEMA_VERSION_BASE, 6, 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
diff --git a/libbrep/build.xml b/libbrep/build.xml
index 13b47a6..434eac2 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="6"/>
+
<changeset version="5"/>
<model version="4">
diff --git a/libbrep/common.hxx b/libbrep/common.hxx
index b9adee8..b2e2052 100644
--- a/libbrep/common.hxx
+++ b/libbrep/common.hxx
@@ -267,6 +267,27 @@ namespace brep
: tenant (move (t)), canonical_name (move (n)) {}
};
+ // build_class_expr
+ //
+ using bpkg::build_class_expr;
+ using build_class_exprs = vector<build_class_expr>;
+
+ #pragma db value(build_class_expr) definition
+
+ #pragma db member(build_class_expr::expr) transient
+ #pragma db member(build_class_expr::underlying_classes) transient
+
+ #pragma db member(build_class_expr::expression) virtual(string) before \
+ get(this.string ()) \
+ set(this = brep::build_class_expr ((?), "" /* comment */))
+
+ // build_constraints
+ //
+ using bpkg::build_constraint;
+ using build_constraints = vector<build_constraint>;
+
+ #pragma db value(build_constraint) definition
+
// Version comparison operators.
//
// They allow comparing objects that have epoch, canonical_upstream,
diff --git a/libbrep/package.cxx b/libbrep/package.cxx
index 0a711ba..5b7c716 100644
--- a/libbrep/package.cxx
+++ b/libbrep/package.cxx
@@ -70,6 +70,7 @@ namespace brep
optional<email_type> bee,
dependencies_type dp,
requirements_type rq,
+ build_class_exprs bs,
build_constraints_type bc,
optional<path> lc,
optional<string> fr,
@@ -97,6 +98,7 @@ namespace brep
build_error_email (move (bee)),
dependencies (move (dp)),
requirements (move (rq)),
+ builds (move (bs)),
build_constraints (version.compare (wildcard_version, true) != 0
? move (bc)
: build_constraints_type ()),
diff --git a/libbrep/package.hxx b/libbrep/package.hxx
index 97ea864..73dfd14 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, 10, open)
+#pragma db model version(LIBBREP_PACKAGE_SCHEMA_VERSION_BASE, 11, open)
namespace brep
{
@@ -164,13 +164,6 @@ namespace brep
#pragma db value(requirement_alternatives) definition
- // build_constraints
- //
- using bpkg::build_constraint;
- using build_constraints = vector<build_constraint>;
-
- #pragma db value(build_constraint) definition
-
// certificate
//
#pragma db value
@@ -376,6 +369,7 @@ namespace brep
optional<email_type> build_error_email,
dependencies_type,
requirements_type,
+ build_class_exprs,
build_constraints_type,
optional<path> location,
optional<string> fragment,
@@ -425,6 +419,7 @@ namespace brep
dependencies_type dependencies;
requirements_type requirements;
+ build_class_exprs builds; // Note: foreign-mapped in build.
build_constraints_type build_constraints; // Note: foreign-mapped in build.
odb::section build_section;
@@ -511,6 +506,11 @@ namespace brep
set(odb::nested_set (this.requirements, std::move (?))) \
id_column("") key_column("") value_column("id")
+ // builds
+ //
+ #pragma db member(builds) id_column("") value_column("") \
+ section(build_section)
+
// build_constraints
//
#pragma db member(build_constraints) id_column("") value_column("") \
diff --git a/libbrep/package.xml b/libbrep/package.xml
index dff6a47..e90a3a1 100644
--- a/libbrep/package.xml
+++ b/libbrep/package.xml
@@ -1,4 +1,51 @@
<changelog xmlns="http://www.codesynthesis.com/xmlns/odb/changelog" database="pgsql" schema-name="package" version="1">
+ <changeset version="11">
+ <add-table name="package_builds" kind="container">
+ <column name="tenant" type="TEXT" null="false"/>
+ <column name="name" type="CITEXT" null="false"/>
+ <column name="version_epoch" type="INTEGER" null="false"/>
+ <column name="version_canonical_upstream" type="TEXT" null="false"/>
+ <column name="version_canonical_release" type="TEXT" null="false" options="COLLATE &quot;C&quot;"/>
+ <column name="version_revision" type="INTEGER" null="false"/>
+ <column name="index" type="BIGINT" null="false"/>
+ <column name="expression" type="TEXT" null="false"/>
+ <column name="comment" type="TEXT" null="false"/>
+ <foreign-key name="tenant_fk" deferrable="DEFERRED">
+ <column name="tenant"/>
+ <references table="tenant">
+ <column name="id"/>
+ </references>
+ </foreign-key>
+ <foreign-key name="object_id_fk" on-delete="CASCADE">
+ <column name="tenant"/>
+ <column name="name"/>
+ <column name="version_epoch"/>
+ <column name="version_canonical_upstream"/>
+ <column name="version_canonical_release"/>
+ <column name="version_revision"/>
+ <references table="package">
+ <column name="tenant"/>
+ <column name="name"/>
+ <column name="version_epoch"/>
+ <column name="version_canonical_upstream"/>
+ <column name="version_canonical_release"/>
+ <column name="version_revision"/>
+ </references>
+ </foreign-key>
+ <index name="package_builds_object_id_i">
+ <column name="tenant"/>
+ <column name="name"/>
+ <column name="version_epoch"/>
+ <column name="version_canonical_upstream"/>
+ <column name="version_canonical_release"/>
+ <column name="version_revision"/>
+ </index>
+ <index name="package_builds_index_i">
+ <column name="index"/>
+ </index>
+ </add-table>
+ </changeset>
+
<changeset version="10">
<alter-table name="package">
<add-column name="build_warning_email" type="TEXT" null="true"/>
diff --git a/load/load.cxx b/load/load.cxx
index c032137..9316300 100644
--- a/load/load.cxx
+++ b/load/load.cxx
@@ -489,6 +489,7 @@ load_packages (const shared_ptr<repository>& rp, database& db)
move (pm.build_error_email),
move (ds),
move (pm.requirements),
+ move (pm.builds),
move (pm.build_constraints),
move (pm.location),
move (pm.fragment),
diff --git a/mod/build-config.cxx b/mod/build-config.cxx
index e838a59..5d3f46b 100644
--- a/mod/build-config.cxx
+++ b/mod/build-config.cxx
@@ -6,9 +6,10 @@
#include <map>
#include <sstream>
+#include <algorithm> // find()
#include <libbutl/sha256.mxx>
-#include <libbutl/utility.mxx> // throw_generic_error()
+#include <libbutl/utility.mxx> // throw_generic_error(), alpha(), etc.
#include <libbutl/openssl.mxx>
#include <libbutl/filesystem.mxx>
@@ -150,21 +151,116 @@ namespace brep
}
bool
- match (const string& config_pattern,
- const optional<string>& target_pattern,
- const build_config& c)
+ exclude (const build_class_exprs& exprs,
+ const build_constraints& constrs,
+ const build_config& cfg,
+ string* reason)
{
- return path_match (config_pattern, c.name) &&
- (!target_pattern || path_match (*target_pattern, c.target.string ()));
- }
+ // Save the first sentence of the reason, lower-case the first letter if
+ // the beginning looks like a word (the second character is the
+ // lower-case letter or space).
+ //
+ auto sanitize = [] (const string& reason)
+ {
+ string r (reason.substr (0, reason.find ('.')));
- bool
- exclude (const build_package& p, const build_config& c)
- {
- for (const auto& bc: p.constraints)
+ char c;
+ size_t n (r.size ());
+
+ if (n > 0 &&
+ alpha (c = r[0]) &&
+ c == ucase (c) &&
+ (n == 1 || (alpha (c = r[1]) && c == lcase (c)) || c == ' '))
+ r[0] = lcase (r[0]);
+
+ return r;
+ };
+
+ bool r (false);
+
+ // First, match the configuration against the package underlying build
+ // class set and expressions.
+ //
+ // Determine the underlying class set. Note that in the future we can
+ // potentially extend the underlying set with the special classes.
+ //
+ build_class_expr ucs (
+ !exprs.empty () && !exprs.front ().underlying_classes.empty ()
+ ? exprs.front ()
+ : build_class_expr ("default", "Default"));
+
+ // Transform the combined package build configuration class expression,
+ // making the underlying class set a starting set for the original
+ // expression and a restricting set, simultaneously. For example, for the
+ // expression:
+ //
+ // default legacy : -msvc
+ //
+ // the resulting expression will be:
+ //
+ // +default +legacy -msvc &( +default +legacy )
+ //
+ //
+ build_class_exprs es;
+ es.emplace_back (ucs.underlying_classes, '+', ucs.comment);
+ es.insert (es.end (), exprs.begin (), exprs.end ());
+ es.emplace_back (ucs.underlying_classes, '&', ucs.comment);
+
+ // We will use a comment of the first encountered excluding expression
+ // (changing the result from true to false) or non-including one (leaving
+ // the false result) as an exclusion reason.
+ //
+ for (const build_class_expr& e: es)
+ {
+ bool pr (r);
+ e.match (cfg.classes, r);
+
+ if (reason != nullptr)
+ {
+ // Reset the reason which, if saved, makes no sense anymore.
+ //
+ if (r)
+ {
+ reason->clear ();
+ }
+ else if (reason->empty () &&
+ //
+ // Exclusion.
+ //
+ (pr ||
+ //
+ // Non-inclusion. Make sure that the build class expression
+ // is empty or starts with an addition (+...).
+ //
+ e.expr.empty () ||
+ e.expr.front ().operation == '+'))
+ {
+ *reason = sanitize (e.comment);
+ }
+ }
+ }
+
+ if (!r)
+ return true;
+
+ // Now check if the configuration is excluded/included via the patterns.
+ //
+ const string& cn (cfg.name);
+ string tg (cfg.target.string ());
+
+ for (const build_constraint& c: constrs)
{
- if (match (bc.config, bc.target, c))
- return bc.exclusion;
+ if (path_match (c.config, cn) &&
+ (!c.target || path_match (*c.target, tg)))
+ {
+ if (!c.exclusion)
+ return false;
+
+ if (reason != nullptr)
+ *reason = sanitize (c.comment);
+
+ return true;
+ }
}
return false;
diff --git a/mod/build-config.hxx b/mod/build-config.hxx
index cdc7efb..e7ee9eb 100644
--- a/mod/build-config.hxx
+++ b/mod/build-config.hxx
@@ -6,6 +6,7 @@
#define MOD_BUILD_CONFIG_HXX
#include <map>
+#include <algorithm> // find()
#include <libbbot/build-config.hxx>
@@ -21,6 +22,8 @@
//
namespace brep
{
+ using bbot::build_config;
+
// Return pointer to the shared build configurations instance, creating one
// on the first call. Throw tab_parsing on parsing error, io_error on the
// underlying OS error. Is not thread-safe.
@@ -52,17 +55,31 @@ namespace brep
string
force_rebuild_url (const string& host, const dir_path& root, const build&);
- // Match a build configuration against the name and target patterns.
+ // Check if the configuration belongs to the specified class.
//
- bool
- match (const string& config_pattern,
- const optional<string>& target_pattern,
- const bbot::build_config&);
+ inline bool
+ belongs (const build_config& cfg, const char* cls)
+ {
+ const strings& cs (cfg.classes);
+ return find (cs.begin (), cs.end (), cls) != cs.end ();
+ }
- // Return true if a package excludes the specified build configuration.
+ // Return true if the specified build configuration is excluded by a package
+ // based on its underlying build class set, build class expressions, and
+ // build constraints, potentially extending the underlying set with the
+ // special classes. Set the exclusion reason if requested.
//
bool
- exclude (const build_package&, const bbot::build_config&);
+ exclude (const build_class_exprs&,
+ const build_constraints&,
+ const build_config&,
+ string* reason = nullptr);
+
+ inline bool
+ exclude (const build_package& p, const build_config& c, string* r = nullptr)
+ {
+ return exclude (p.builds, p.constraints, c, r);
+ }
}
#endif // MOD_BUILD_CONFIG_HXX
diff --git a/mod/mod-build-configs.cxx b/mod/mod-build-configs.cxx
index 63bbe0b..d3d5191 100644
--- a/mod/mod-build-configs.cxx
+++ b/mod/mod-build-configs.cxx
@@ -89,9 +89,10 @@ handle (request& rq, response& rs)
for (const build_config& c: *build_conf_)
{
- s << TR(CLASS="config")
- << TD << SPAN(CLASS="value") << c.name << ~SPAN << ~TD
- << ~TR;
+ if (belongs (c, "all"))
+ s << TR(CLASS="config")
+ << TD << SPAN(CLASS="value") << c.name << ~SPAN << ~TD
+ << ~TR;
}
s << ~TBODY
diff --git a/mod/mod-build-result.cxx b/mod/mod-build-result.cxx
index 8b985be..177e67f 100644
--- a/mod/mod-build-result.cxx
+++ b/mod/mod-build-result.cxx
@@ -225,11 +225,17 @@ handle (request& rq, response&)
// Make sure the build configuration still exists.
//
- if (build_conf_map_->find (id.configuration.c_str ()) ==
- build_conf_map_->end ())
+ const bbot::build_config* cfg;
{
- warn_expired ("no build configuration");
- return true;
+ auto i (build_conf_map_->find (id.configuration.c_str ()));
+
+ if (i == build_conf_map_->end ())
+ {
+ warn_expired ("no build configuration");
+ return true;
+ }
+
+ cfg = i->second;
}
// Load the built package (if present).
@@ -261,7 +267,8 @@ handle (request& rq, response&)
// Load and update the package build configuration (if present).
//
// NULL if the package build doesn't exist or is not updated for any reason
- // (authentication failed, etc).
+ // (authentication failed, etc) or the configuration is excluded by the
+ // package.
//
shared_ptr<build> bld;
@@ -390,7 +397,11 @@ handle (request& rq, response&)
build_db_->update (b);
- bld = move (b);
+ shared_ptr<build_package> p (
+ build_db_->load<build_package> (b->id.package));
+
+ if (belongs (*cfg, "all") && !exclude (*p, *cfg))
+ bld = move (b);
}
}
diff --git a/mod/mod-build-task.cxx b/mod/mod-build-task.cxx
index d3efb41..03c053a 100644
--- a/mod/mod-build-task.cxx
+++ b/mod/mod-build-task.cxx
@@ -328,6 +328,8 @@ handle (request& rq, response& rs)
using pkg_query = query<buildable_package>;
using prep_pkg_query = prepared_query<buildable_package>;
+ // Exclude archived tenants.
+ //
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 fbdae4c..30d3696 100644
--- a/mod/mod-builds.cxx
+++ b/mod/mod-builds.cxx
@@ -5,6 +5,7 @@
#include <mod/mod-builds.hxx>
#include <set>
+#include <algorithm> // find_if()
#include <libstudxml/serializer.hxx>
@@ -441,37 +442,167 @@ handle (request& rq, response& rs)
s << DIV_COUNTER (build_count, "Build", "Builds");
};
+ // We will not display hidden configurations, unless the configuration is
+ // specified explicitly.
+ //
+ cstrings conf_names;
+
+ if (params.configuration ().empty () ||
+ params.configuration ().find_first_of ("*?") != string::npos)
+ {
+ for (const auto& c: *build_conf_map_)
+ {
+ if (belongs (*c.second, "all"))
+ conf_names.push_back (c.first);
+ }
+ }
+ else
+ conf_names = *build_conf_names_;
+
size_t count;
size_t page (params.page ());
- if (params.result () != "unbuilt")
+ if (params.result () != "unbuilt") // Print package build configurations.
{
- transaction t (build_db_->begin ());
+ // It seems impossible to filter out the package-excluded configuration
+ // builds via the database query. Thus, we will traverse through builds
+ // that pass the form filter and match them against expressions and
+ // constraints of a package they are builds of.
+ //
+ // We will calculate the total builds count and cache build objects for
+ // printing on the same pass. Note that we need to print the count before
+ // printing the builds.
+ //
+ count = 0;
+ vector<shared_ptr<build>> builds;
- count = build_db_->query_value<package_build_count> (
- build_query<package_build_count> (
- *build_conf_names_, params, tn, nullopt /* archived */));
+ // Prepare the package build prepared query.
+ //
+ using query = query<package_build>;
+ using prep_query = prepared_query<package_build>;
- // Print the filter form.
+ query q (build_query<package_build> (
+ conf_names, params, tn, nullopt /* archived */));
+
+ // Specify the portion. Note that we will be querying builds in chunks,
+ // not to hold locks for too long.
//
- print_form (query_toolchains (), count);
+ size_t offset (0);
// Print package build configurations ordered by the timestamp (later goes
// first).
//
+ q += "ORDER BY" + query::build::timestamp + "DESC" +
+ "OFFSET" + query::_ref (offset) + "LIMIT 50";
+
+ connection_ptr conn (build_db_->connection ());
+
+ prep_query pq (
+ conn->prepare_query<package_build> ("mod-builds-query", q));
+
+ // Note that we can't skip the proper number of builds in the database
+ // query for a page numbers greater than one. So we will query builds from
+ // the very beginning and skip the appropriate number of them while
+ // iterating through the query result.
+ //
+ size_t skip (page * page_configs);
+ size_t print (page_configs);
+
+ // Note that adjacent builds may well relate to the same package. We will
+ // use this fact for a cheap optimization, loading the build package only
+ // if it differs from the previous one.
+ //
+ shared_ptr<build_package> p;
+
+ for (bool ne (true); ne; )
+ {
+ transaction t (conn->begin ());
+
+ // Query package builds (and cache the result).
+ //
+ auto bs (pq.execute ());
+
+ if ((ne = !bs.empty ()))
+ {
+ offset += bs.size ();
+
+ // Iterate over builds and cache build objects that should be printed.
+ // Skip the appropriate number of them (for page number greater than
+ // one).
+ //
+ for (auto& pb: bs)
+ {
+ shared_ptr<build>& b (pb.build);
+
+ // Prior to loading the package object check if it is already
+ // loaded.
+ //
+ if (p == nullptr || p->id != b->id.package)
+ p = build_db_->load<build_package> (b->id.package);
+
+ auto i (build_conf_map_->find (b->configuration.c_str ()));
+ assert (i != build_conf_map_->end ());
+
+ // Match the configuration against the package build
+ // expressions/constraints.
+ //
+ if (!exclude (*p, *i->second))
+ {
+ if (skip != 0)
+ --skip;
+ else if (print != 0)
+ {
+ // As we query builds in multiple transactions we may see the
+ // same build multiple times. Let's skip the duplicates. Note:
+ // we don't increment the counter in this case.
+ //
+ if (find_if (builds.begin (),
+ builds.end (),
+ [&b] (const shared_ptr<build>& pb)
+ {
+ return b->id == pb->id;
+ }) != builds.end ())
+ continue;
+
+ if (b->state == build_state::built)
+ {
+ build_db_->load (*b, b->results_section);
+
+ // Let's clear unneeded result logs for builds being cached.
+ //
+ for (operation_result& r: b->results)
+ r.log.clear ();
+ }
+
+ builds.push_back (move (b));
+
+ --print;
+ }
+
+ ++count;
+ }
+ }
+ }
+
+ // Print the filter form after the build count is calculated. Note:
+ // query_toolchains() must be called inside the build db transaction.
+ //
+ else
+ print_form (query_toolchains (), count);
+
+ t.commit ();
+ }
+
+ // Finally, print the cached package build configurations.
+ //
timestamp now (system_clock::now ());
// Enclose the subsequent tables to be able to use nth-child CSS selector.
//
s << DIV;
- for (auto& pb: build_db_->query<package_build> (
- 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)))
+ for (const shared_ptr<build>& pb: builds)
{
- build& b (*pb.build);
+ const build& b (*pb);
string ts (butl::to_string (b.timestamp,
"%Y-%m-%d %H:%M:%S %Z",
@@ -479,9 +610,6 @@ handle (request& rq, response& rs)
true) +
" (" + butl::to_string (now - b.timestamp, false) + " ago)");
- if (b.state == build_state::built)
- build_db_->load (b, b.results_section);
-
s << TABLE(CLASS="proplist build")
<< TBODY
<< TR_NAME (b.package_name, string (), root, b.tenant)
@@ -505,8 +633,6 @@ handle (request& rq, response& rs)
<< ~TABLE;
}
s << ~DIV;
-
- t.commit ();
}
else // Print unbuilt package configurations.
{
@@ -609,12 +735,12 @@ handle (request& rq, response& rs)
//
// Note that we also need to deduct the package-excluded configurations
// count from the maximum possible number of unbuilt configurations. The
- // only way to achieve this is to traverse through the build-constrained
- // packages and match their constraints against our configurations.
+ // only way to achieve this is to traverse through the packages and
+ // match their build expressions/constraints against our configurations.
//
// Also note that some existing builds can now be excluded by packages
- // due to the build configuration target change. We should deduct such
- // builds count from the number of existing package builds.
+ // due to the build configuration target or class set change. We should
+ // deduct such builds count from the number of existing package builds.
//
size_t nmax (
config_toolchains.size () *
@@ -624,7 +750,7 @@ handle (request& rq, response& rs)
size_t ncur = build_db_->query_value<package_build_count> (
build_query<package_build_count> (
- *build_conf_names_, bld_params, tn, false /* archived */));
+ conf_names, bld_params, tn, false /* archived */));
// From now we will be using specific package name and version for each
// build database query.
@@ -665,23 +791,23 @@ handle (request& rq, response& rs)
size_t nt (tc == "*" ? toolchains.size () : 1);
- // The number of build-constrained packages can potentially be large,
- // and we may implement some caching in the future. However, the
- // caching will not be easy as the cached values depend on the filter
- // form parameters.
+ // The number of packages can potentially be large, and we may
+ // implement some caching in the future. However, the caching will not
+ // be easy as the cached values depend on the filter form parameters.
//
- query<build_constrained_package> q (
- package_query<build_constrained_package> (
+ query<buildable_package> q (
+ package_query<buildable_package> (
params, tn, false /* archived */));
- for (const auto& p: build_db_->query<build_constrained_package> (q))
+ for (auto& bp: build_db_->query<buildable_package> (q))
{
- const build_package& bp (*p.package);
- id = bp.id;
+ id = move (bp.id);
+
+ shared_ptr<build_package> p (build_db_->load<build_package> (id));
for (const auto& c: configs)
{
- if (exclude (bp, *c))
+ if (exclude (*p, *c))
{
nmax -= nt;
@@ -706,9 +832,10 @@ handle (request& rq, response& rs)
//
// 1: package name
// 2: package version (descending)
- // 3: configuration name
- // 4: toolchain name
- // 5: toolchain version (descending)
+ // 3: package tenant
+ // 4: configuration name
+ // 5: toolchain name
+ // 6: toolchain version (descending)
//
// Prepare the build package prepared query.
//
@@ -764,30 +891,12 @@ handle (request& rq, response& rs)
// Note that the query already constrains the tenant via the build
// package id.
//
- build_query<package_build> (*build_conf_names_,
- bld_params,
- nullopt /* tenant */,
- false /* archived */));
+ build_query<package_build> (
+ conf_names, bld_params, nullopt /* tenant */, false /* archived */));
prep_bld_query bld_prep_query (
conn->prepare_query<package_build> ("mod-builds-build-query", bq));
- // Prepare the build-constrained package prepared query.
- //
- // For each build-constrained package we will exclude the corresponding
- // configurations from being printed.
- //
- using ctr_query = query<build_constrained_package>;
- using prep_ctr_query = prepared_query<build_constrained_package>;
-
- ctr_query cq (
- package_id_eq<build_constrained_package> (
- ctr_query::build_package::id, id));
-
- prep_ctr_query ctr_prep_query (
- conn->prepare_query<build_constrained_package> (
- "mod-builds-build-constrained-package-query", cq));
-
size_t skip (page * page_configs);
size_t print (page_configs);
@@ -816,29 +925,20 @@ handle (request& rq, response& rs)
id = move (p.id);
// Copy configuration/toolchain combinations for this package,
- // skipping explicitly excluded configurations.
+ // skipping excluded configurations.
//
set<config_toolchain> unbuilt_configs;
{
- build_constrained_package p;
- if (ctr_prep_query.execute_one (p))
+ shared_ptr<build_package> p (build_db_->load<build_package> (id));
+
+ for (const auto& ct: config_toolchains)
{
- const build_package& bp (*p.package);
- for (const auto& ct: config_toolchains)
- {
- auto i (build_conf_map_->find (ct.configuration.c_str ()));
- assert (i != build_conf_map_->end ());
+ auto i (build_conf_map_->find (ct.configuration.c_str ()));
+ assert (i != build_conf_map_->end ());
- if (!exclude (bp, *i->second))
- unbuilt_configs.insert (ct);
- }
+ if (!exclude (*p, *i->second))
+ unbuilt_configs.insert (ct);
}
- else
- // For libc++, the set's copy-assignment operator requires the
- // element type to be copy-assignable, for some reason.
- //
- unbuilt_configs.insert (config_toolchains.begin (),
- config_toolchains.end ());
}
// Iterate through the package configuration builds and erase them
@@ -856,7 +956,7 @@ handle (request& rq, response& rs)
//
for (const auto& ct: unbuilt_configs)
{
- if (skip > 0)
+ if (skip != 0)
{
--skip;
continue;
diff --git a/mod/mod-package-version-details.cxx b/mod/mod-package-version-details.cxx
index bafe8f7..9566c8f 100644
--- a/mod/mod-package-version-details.cxx
+++ b/mod/mod-package-version-details.cxx
@@ -10,8 +10,6 @@
#include <odb/database.hxx>
#include <odb/transaction.hxx>
-#include <libbutl/utility.mxx> // alpha(), ucase(), lcase()
-
#include <web/xhtml.hxx>
#include <web/module.hxx>
#include <web/mime-url-encoding.hxx>
@@ -390,24 +388,48 @@ handle (request& rq, response& rs)
if (builds)
{
+ using bbot::build_config;
+
s << H3 << "Builds" << ~H3
<< DIV(ID="builds");
+ auto exclude = [&pkg] (const build_config& cfg, string* reason = nullptr)
+ {
+ return brep::exclude (pkg->builds, pkg->build_constraints, cfg, reason);
+ };
+
timestamp now (system_clock::now ());
transaction t (build_db_->begin ());
- // Print built package configurations.
+ // Print built package configurations, except those that are hidden or
+ // excluded by the package.
//
+ cstrings conf_names;
+
+ for (const auto& c: *build_conf_map_)
+ {
+ if (belongs (*c.second, "all"))
+ conf_names.push_back (c.first);
+ }
+
using query = query<build>;
for (auto& b: build_db_->query<build> (
(query::id.package == pkg->id &&
- query::id.configuration.in_range (build_conf_names_->begin (),
- build_conf_names_->end ())) +
+ query::id.configuration.in_range (conf_names.begin (),
+ conf_names.end ())) +
"ORDER BY" + query::timestamp + "DESC"))
{
+ auto i (build_conf_map_->find (b.configuration.c_str ()));
+ assert (i != build_conf_map_->end ());
+
+ const build_config& cfg (*i->second);
+
+ if (exclude (cfg))
+ continue;
+
string ts (butl::to_string (b.timestamp,
"%Y-%m-%d %H:%M:%S %Z",
true,
@@ -430,42 +452,12 @@ handle (request& rq, response& rs)
<< ~TABLE;
}
- // Print configurations that are excluded by the package.
+ // Print the package build exclusions that belong to the 'default' class.
//
- auto excluded = [&pkg] (const bbot::build_config& c, string& reason)
- {
- for (const auto& bc: pkg->build_constraints)
- {
- if (match (bc.config, bc.target, c))
- {
- if (!bc.exclusion)
- return false;
-
- // Save the first sentence of the exclusion comment, lower-case the
- // first letter if the beginning looks like a word (the second
- // character is the lower-case letter or space).
- //
- reason = bc.comment.substr (0, bc.comment.find ('.'));
-
- char c;
- size_t n (reason.size ());
- if (n > 0 && alpha (c = reason[0]) && c == ucase (c) &&
- (n == 1 ||
- (alpha (c = reason[1]) && c == lcase (c)) ||
- c == ' '))
- reason[0] = lcase (reason[0]);
-
- return true;
- }
- }
-
- return false;
- };
-
for (const auto& c: *build_conf_)
{
string reason;
- if (excluded (c, reason))
+ if (belongs (c, "default") && exclude (c, &reason))
{
s << TABLE(CLASS="proplist build")
<< TBODY
diff --git a/tests/load/1/math/libfoo-1.0.tar.gz b/tests/load/1/math/libfoo-1.0.tar.gz
index 2014fc1..e951386 100644
--- a/tests/load/1/math/libfoo-1.0.tar.gz
+++ b/tests/load/1/math/libfoo-1.0.tar.gz
Binary files differ
diff --git a/tests/load/1/math/packages.manifest b/tests/load/1/math/packages.manifest
index fea801f..df3b083 100644
--- a/tests/load/1/math/packages.manifest
+++ b/tests/load/1/math/packages.manifest
@@ -29,8 +29,10 @@ name: libfoo
version: 1.0
summary: The Foo Library
license: MIT
+build-email: foo-builds@example.com
+builds: default legacy : -32; 64-bit targets only
location: libfoo-1.0.tar.gz
-sha256sum: 0df6d45a3514c6101609bdcfefe7659b5754e505c6cf6b4107141d8217bb981d
+sha256sum: 3d32793e7b800837682ffa1dad794df7c9e2bb7a54504552a5bd261b5ec064e5
:
name: libfoo
version: 1.2.4+1
diff --git a/tests/load/1/stable/libfoo-1.0.tar.gz b/tests/load/1/stable/libfoo-1.0.tar.gz
index 2014fc1..e951386 100644
--- a/tests/load/1/stable/libfoo-1.0.tar.gz
+++ b/tests/load/1/stable/libfoo-1.0.tar.gz
Binary files differ
diff --git a/tests/load/1/stable/packages.manifest b/tests/load/1/stable/packages.manifest
index 0161a46..797b214 100644
--- a/tests/load/1/stable/packages.manifest
+++ b/tests/load/1/stable/packages.manifest
@@ -5,8 +5,10 @@ name: libfoo
version: 1.0
summary: The Foo Library
license: MIT
+build-email: foo-builds@example.com
+builds: default legacy : -32; 64-bit targets only
location: libfoo-1.0.tar.gz
-sha256sum: 0df6d45a3514c6101609bdcfefe7659b5754e505c6cf6b4107141d8217bb981d
+sha256sum: 3d32793e7b800837682ffa1dad794df7c9e2bb7a54504552a5bd261b5ec064e5
:
name: libfoo
version: 1.2.2-alpha.1
diff --git a/tests/load/1/stable/signature.manifest b/tests/load/1/stable/signature.manifest
index 34fc749..2678657 100644
--- a/tests/load/1/stable/signature.manifest
+++ b/tests/load/1/stable/signature.manifest
@@ -1,13 +1,13 @@
: 1
-sha256sum: ce908ea7ed5fb96a8ad246bd492956013589fcf9d82319b8cc0d572453e16fe5
+sha256sum: 4957fe28799fe3a037c3112c8122d216fb1d25b48c1028979e5a8738683cb1a5
signature: \
-RO0heyLVCNV6BWU/wTEYx/L8IS0vNJDHYgcgJmdV8bPygkMrdH3V/YMzWBcHwfyvTKoBIIMHheQK
-2/rQtB51UHQKp+TENpHqdvxV2lUb8nmGmYVo00eLh1L6u50sUYrXfP8RIHD7n2OfBglYc2mKuyXp
-FJU1B04SUnrcmceax5VtwKVd1Iote9ZxgKekgMzIgDZl80DeIBZfcmKmvE/QOWP8E6DKVxurkFyC
-LkWTdavOfaCTb9F+zdzMzFgcrS9fRXIPPFjsVPkx/EeJV8//NRj8mBUqs/avyX2LqE6hk5TvKYyS
-0hnfiWhA0lh/XD9J5irhHKPjpPnuLAjtwhOi2n/113A5EtBTfct3rQSL8/rEejSgC1HILpjwMZ7K
-91xtTB9zbrYchX7BEh++r9fcHH3vF5rc6nOaJhwjZzH50OftMQVYifYRXP19R1H7usAuXwoXoM2a
-Z3BMNP9npzSbQmu6xCLImg2Vqr+GHl9iPgzB8jfmnn5L48I0LeAXeiNANeZGAA7hcD3UehNvaT4q
-58fw5hyKY/CWDa5LeGLmuiEsy8UaPdppZjy6ROVwiRsC0uAZZU/rbg57tJkXMtE/ZgNKCJF0pCVu
-badHFxqy4JIUP1hZfKlm43Lb5HGb15HENBTxBom0QAU0Q3IiUGG6RUQOrxYddDO2WG0Xwv9Ddng=
+Dxc/W3NM0ZZ/Aytrxpptgcg8pg6tteT9rVoFm3mxaXsLMoEzjEEHq1ruI3kbmIVHQIBYymvpj5FS
+JUeKdmtkNOZA7DqbdT5njEarKGoLE4awqsZ4yAWMKpmHNxAl/dYNIQ0l5YdsAq7+c3/lCwha9SlB
+QcZrKDxZ7DrhcdiI0eQej08n0X45OA1451VLnSkjHsLXXCO0qnj2o+WVKJE/lWz46Z6FCm9wlLQC
+cxaamInFeL5s/eZmn7j5Eo+v2y1v/zufeCr5W6feKlFau156G43ZROPUoqVl+ZxuSAR1gKalVjny
+jH1adjEkwqtxXN0fvT2pQ0XU/gn/s7PTiGR9PnKytrAFemO3hbd62PAcFRk17NV8qworyBdLMHgA
+V4/CyDCItOgAzfenbjPHfxEkm+qKcK4Y6NlUQSqcHDW8kxMv6iuVw8s0o5ij9frY5XLg2h39O/Lw
+I4tDO0lg8k2vxKJVxKk85uElJ+kuBG4353PP3G11uzZpah4X9zqh21TBP+rx+L1gefHwjew+ZwQi
+qtOedbzrJlgLgTDK3Q+yMN2i9YOIe+D5vB4Gr97y1lL0qVS3zm/4CjLo6kj13ngGXxivGLbtDlX9
+v4COE/+PtwGS2ubmku1QMwZuXyJfjKG9lGgoNoARML17EzzMIFXnzII0uSP+NUKrT3jLdEbOlQs=
\
diff --git a/tests/load/driver.cxx b/tests/load/driver.cxx
index 7009d9e..8a592d6 100644
--- a/tests/load/driver.cxx
+++ b/tests/load/driver.cxx
@@ -405,7 +405,7 @@ test_pkg_repos (const cstrings& loader_args,
assert (check_location (fpv1));
assert (fpv1->sha256sum && *fpv1->sha256sum ==
- "0df6d45a3514c6101609bdcfefe7659b5754e505c6cf6b4107141d8217bb981d");
+ "3d32793e7b800837682ffa1dad794df7c9e2bb7a54504552a5bd261b5ec064e5");
// libfoo-1.2.2
//