From 1367aa09951e0aa7491bc2a5bf7209b0b47be65e Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Thu, 13 Sep 2018 19:27:00 +0300 Subject: Add support for packages and builds global views --- mod/mod-build-log.cxx | 7 ++++-- mod/mod-builds.cxx | 68 +++++++++++++++++++++++++++++++++++---------------- mod/mod-packages.cxx | 35 +++++++++++++++++--------- mod/options.cli | 7 ++++++ mod/page.cxx | 18 ++++++++++++++ mod/page.hxx | 23 +++++++++++++++++ 6 files changed, 124 insertions(+), 34 deletions(-) (limited to 'mod') diff --git a/mod/mod-build-log.cxx b/mod/mod-build-log.cxx index 70e2c7e..ee5d1b2 100644 --- a/mod/mod-build-log.cxx +++ b/mod/mod-build-log.cxx @@ -212,10 +212,13 @@ handle (request& rq, response& rs) // ostream& os (rs.content (200, "text/plain;charset=utf-8", false)); - auto print_header = [&os, &b] () + auto print_header = [&os, &b, this] () { - // @@ Should we print the tenant? How to call it if that's the case? + // Print the build tenant in the multi-tenant mode. // + if (!b->tenant.empty ()) + os << options_->tenant_name () << ": " << b->tenant << endl << endl; + os << "package: " << b->package_name << endl << "version: " << b->package_version << endl << "toolchain: " << b->toolchain_name << '-' << b->toolchain_version diff --git a/mod/mod-builds.cxx b/mod/mod-builds.cxx index d2e3a25..a55b6f9 100644 --- a/mod/mod-builds.cxx +++ b/mod/mod-builds.cxx @@ -94,7 +94,7 @@ template static inline query build_query (const brep::cstrings& configs, const brep::params::builds& params, - const brep::optional& tenant) + const brep::optional& tenant) { using namespace brep; using query = query; @@ -207,12 +207,16 @@ build_query (const brep::cstrings& configs, template ::build_package> static inline query -package_query (const brep::params::builds& params, const string& tenant) +package_query (const brep::params::builds& params, + const brep::optional& tenant) { using namespace brep; using query = query; - query q (P::id.tenant == tenant); + query q (true); + + if (tenant) + q = q && P::id.tenant == *tenant; // Note that there is no error reported if the filter parameters parsing // fails. Instead, it is considered that no packages match such a query. @@ -281,6 +285,7 @@ handle (request& rq, response& rs) const size_t page_configs (options_->build_configurations ()); const string& host (options_->host ()); const dir_path& root (options_->root ()); + const string& tenant_name (options_->tenant_name ()); params::builds params; @@ -321,18 +326,25 @@ handle (request& rq, response& rs) << DIV_HEADER (options_->logo (), options_->menu (), root, tenant) << DIV(ID="content"); + // If the tenant is empty then we are in the global view and will display + // builds from all the tenants. + // + optional tn; + if (!tenant.empty ()) + tn = tenant; + // Return the list of distinct toolchain name/version pairs. The build db // transaction must be started. // using toolchains = vector>; - auto query_toolchains = [this] () -> toolchains + auto query_toolchains = [this, &tn] () -> toolchains { using query = query; toolchains r; for (auto& t: build_db_->query ( - (query::id.package.tenant == tenant) + + (tn ? query::id.package.tenant == *tn : query (true)) + "ORDER BY" + query::toolchain_name + order_by_version_desc (query::id.toolchain_version, false))) r.emplace_back (move (t.name), move (t.version)); @@ -428,7 +440,7 @@ handle (request& rq, response& rs) transaction t (build_db_->begin ()); count = build_db_->query_value ( - build_query (*build_conf_names_, params, tenant)); + build_query (*build_conf_names_, params, tn)); // Print the filter form. // @@ -443,7 +455,7 @@ handle (request& rq, response& rs) // s << DIV; for (auto& pb: build_db_->query ( - build_query (*build_conf_names_, params, tenant) + + build_query (*build_conf_names_, params, tn) + "ORDER BY" + query::build::timestamp + "DESC" + "OFFSET" + to_string (page * page_configs) + "LIMIT" + to_string (page_configs))) @@ -461,8 +473,8 @@ handle (request& rq, response& rs) s << TABLE(CLASS="proplist build") << TBODY - << TR_NAME (b.package_name, string (), root, tenant) - << TR_VERSION (b.package_name, b.package_version, root, tenant) + << TR_NAME (b.package_name, string (), root, b.tenant) + << TR_VERSION (b.package_name, b.package_version, root, b.tenant) << TR_VALUE ("toolchain", b.toolchain_name + '-' + b.toolchain_version.string ()) @@ -470,8 +482,15 @@ handle (request& rq, response& rs) << TR_VALUE ("machine", b.machine) << TR_VALUE ("target", b.target.string ()) << TR_VALUE ("timestamp", ts) - << TR_BUILD_RESULT (b, host, root) - << ~TBODY + << TR_BUILD_RESULT (b, host, root); + + // In the global view mode add the tenant builds link. Note that the + // global view (and the link) makes sense only in the multi-tenant mode. + // + if (!tn && !b.tenant.empty ()) + s << TR_TENANT (tenant_name, "builds", root, b.tenant); + + s << ~TBODY << ~TABLE; } s << ~DIV; @@ -589,12 +608,12 @@ handle (request& rq, response& rs) size_t nmax ( config_toolchains.size () * build_db_->query_value ( - package_query (params, tenant))); + package_query (params, tn))); size_t ncur = build_db_->query_value ( build_query (*build_conf_names_, bld_params, - tenant)); + tn)); // From now we will be using specific package name and version for each // build database query. @@ -641,7 +660,7 @@ handle (request& rq, response& rs) // using query = query; query q (package_query (params, - tenant)); + tn)); for (const auto& p: build_db_->query (q)) { @@ -696,18 +715,17 @@ handle (request& rq, response& rs) using pkg_query = query; using prep_pkg_query = prepared_query; - pkg_query pq (package_query (params, tenant)); + pkg_query pq (package_query (params, tn)); // Specify the portion. Note that we will still be querying packages in // chunks, not to hold locks for too long. // size_t offset (0); - // @@ TENANT: use tenant for sorting when add support for global view. - // pq += "ORDER BY" + pkg_query::build_package::id.name + order_by_version_desc (pkg_query::build_package::id.version, false) + + "," + pkg_query::build_package::id.tenant + "OFFSET" + pkg_query::_ref (offset) + "LIMIT 50"; connection_ptr conn (build_db_->connection ()); @@ -834,14 +852,22 @@ handle (request& rq, response& rs) s << TABLE(CLASS="proplist build") << TBODY - << TR_NAME (id.name, string (), root, tenant) - << TR_VERSION (id.name, p.version, root, tenant) + << TR_NAME (id.name, string (), root, id.tenant) + << TR_VERSION (id.name, p.version, root, id.tenant) << TR_VALUE ("toolchain", string (ct.toolchain_name) + '-' + ct.toolchain_version.string ()) << TR_VALUE ("config", ct.configuration) - << TR_VALUE ("target", i->second->target.string ()) - << ~TBODY + << TR_VALUE ("target", i->second->target.string ()); + + // In the global view mode add the tenant builds link. Note that + // the global view (and the link) makes sense only in the + // multi-tenant mode. + // + if (!tn && !id.tenant.empty ()) + s << TR_TENANT (tenant_name, "builds", root, id.tenant); + + s << ~TBODY << ~TABLE; if (--print == 0) // Bail out the configuration loop. diff --git a/mod/mod-packages.cxx b/mod/mod-packages.cxx index 1515a53..27e1270 100644 --- a/mod/mod-packages.cxx +++ b/mod/mod-packages.cxx @@ -67,7 +67,7 @@ init (scanner& s) template static inline query -search_param (const brep::string& q, const brep::string& t) +search_param (const brep::string& q, const brep::optional& t) { using query = query; return "(" + @@ -75,7 +75,7 @@ search_param (const brep::string& q, const brep::string& t) ? query ("NULL") : "plainto_tsquery (" + query::_val (q) + ")") + "," + - query::_val (t) + + (!t ? query ("NULL") : query (query::_val (*t))) + ")"; } @@ -89,6 +89,7 @@ handle (request& rq, response& rs) const size_t res_page (options_->search_results ()); const dir_path& root (options_->root ()); const string& title (options_->search_title ()); + const string& tenant_name (options_->tenant_name ()); params::packages params; @@ -135,25 +136,30 @@ handle (request& rq, response& rs) << DIV_HEADER (options_->logo (), options_->menu (), root, tenant) << DIV(ID="content"); + // If the tenant is empty then we are in the global view and will display + // packages from all the tenants. + // + optional tn; + if (!tenant.empty ()) + tn = tenant; + session sn; transaction t (package_db_->begin ()); auto pkg_count ( package_db_->query_value ( - search_param (squery, tenant))); + search_param (squery, tn))); s << FORM_SEARCH (squery, "packages") << DIV_COUNTER (pkg_count, "Package", "Packages"); // Enclose the subsequent tables to be able to use nth-child CSS selector. // - // @@ TENANT: use tenant for sorting when add support for global view. - // s << DIV; for (const auto& pr: package_db_->query ( - search_param (squery, tenant) + - "ORDER BY rank DESC, name" + + search_param (squery, tn) + + "ORDER BY rank DESC, name, tenant" + "OFFSET" + to_string (page * res_page) + "LIMIT" + to_string (res_page))) { @@ -161,13 +167,20 @@ handle (request& rq, response& rs) s << TABLE(CLASS="proplist package") << TBODY - << TR_NAME (p->name, equery, root, tenant) + << TR_NAME (p->name, equery, root, p->tenant) << TR_SUMMARY (p->summary) << TR_LICENSE (p->license_alternatives) << TR_TAGS (p->project, p->tags, root, tenant) - << TR_DEPENDS (p->dependencies, root, tenant) - << TR_REQUIRES (p->requirements) - << ~TBODY + << TR_DEPENDS (p->dependencies, root, p->tenant) + << TR_REQUIRES (p->requirements); + + // In the global view mode add the tenant packages link. Note that the + // global view (and the link) makes sense only in the multi-tenant mode. + // + if (!tn && !p->tenant.empty ()) + s << TR_TENANT (tenant_name, "packages", root, p->tenant); + + s << ~TBODY << ~TABLE; } s << ~DIV; diff --git a/mod/options.cli b/mod/options.cli index 5fbd117..c78af73 100644 --- a/mod/options.cli +++ b/mod/options.cli @@ -46,6 +46,13 @@ namespace brep (\cb{http://example.org/})." } + string tenant-name = "tenant" + { + "", + "Name to call the tenant values on web pages. If not specified, then + \cb{tenant} is used." + } + uint16_t verbosity = 0 { "", diff --git a/mod/page.cxx b/mod/page.cxx index ce12da6..1b2faae 100644 --- a/mod/page.cxx +++ b/mod/page.cxx @@ -182,6 +182,24 @@ namespace brep << ~TR; } + // TR_TENANT + // + void TR_TENANT:: + operator() (serializer& s) const + { + s << TR(CLASS="tenant") + << TH << name_ << ~TH + << TD + << SPAN(CLASS="value") + << A + << HREF << tenant_dir (root_, tenant_) << '?' << service_ << ~HREF + << tenant_ + << ~A + << ~SPAN + << ~TD + << ~TR; + } + // TR_NAME // void TR_NAME:: diff --git a/mod/page.hxx b/mod/page.hxx index d9f4249..4b59e7d 100644 --- a/mod/page.hxx +++ b/mod/page.hxx @@ -162,6 +162,29 @@ namespace brep const vector>& options_; }; + // Generates tenant id element. + // + // Displays a link to the service page for the specified tenant. + // + class TR_TENANT + { + public: + TR_TENANT (const string& n, + const string& s, + const dir_path& r, + const string& t) + : name_ (n), service_ (s), root_ (r), tenant_ (t) {} + + void + operator() (xml::serializer&) const; + + private: + const string& name_; + const string& service_; + const dir_path& root_; + const string& tenant_; + }; + // Generates package name element with an optional search criteria. The // search string should be url-encoded, if specified. // -- cgit v1.1