diff options
-rw-r--r-- | libbrep/build-extra.sql | 21 | ||||
-rw-r--r-- | libbrep/build-package.hxx | 46 | ||||
-rw-r--r-- | libbrep/build.hxx | 2 | ||||
-rw-r--r-- | libbrep/build.xml | 2 | ||||
-rw-r--r-- | libbrep/common.hxx | 21 | ||||
-rw-r--r-- | libbrep/package.cxx | 2 | ||||
-rw-r--r-- | libbrep/package.hxx | 16 | ||||
-rw-r--r-- | libbrep/package.xml | 47 | ||||
-rw-r--r-- | load/load.cxx | 1 | ||||
-rw-r--r-- | mod/build-config.cxx | 122 | ||||
-rw-r--r-- | mod/build-config.hxx | 31 | ||||
-rw-r--r-- | mod/mod-build-configs.cxx | 7 | ||||
-rw-r--r-- | mod/mod-build-result.cxx | 23 | ||||
-rw-r--r-- | mod/mod-build-task.cxx | 2 | ||||
-rw-r--r-- | mod/mod-builds.cxx | 250 | ||||
-rw-r--r-- | mod/mod-package-version-details.cxx | 66 | ||||
-rw-r--r-- | tests/load/1/math/libfoo-1.0.tar.gz | bin | 219 -> 278 bytes | |||
-rw-r--r-- | tests/load/1/math/packages.manifest | 4 | ||||
-rw-r--r-- | tests/load/1/stable/libfoo-1.0.tar.gz | bin | 219 -> 278 bytes | |||
-rw-r--r-- | tests/load/1/stable/packages.manifest | 4 | ||||
-rw-r--r-- | tests/load/1/stable/signature.manifest | 20 | ||||
-rw-r--r-- | tests/load/driver.cxx | 2 |
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 "C""/> + <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 Binary files differindex 2014fc1..e951386 100644 --- a/tests/load/1/math/libfoo-1.0.tar.gz +++ b/tests/load/1/math/libfoo-1.0.tar.gz 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 Binary files differindex 2014fc1..e951386 100644 --- a/tests/load/1/stable/libfoo-1.0.tar.gz +++ b/tests/load/1/stable/libfoo-1.0.tar.gz 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 // |