From d1fae6b26e0820dee76e396c540bb1de90038917 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 22 Sep 2015 12:31:42 +0200 Subject: Implement package version detals page --- brep/package | 12 +-- brep/package-search.cxx | 45 +++----- brep/package-version-details.cxx | 222 ++++++++++++++++++++++++++++++++++++--- brep/package-version-search.cxx | 67 ++++-------- brep/package.cxx | 7 +- brep/page | 34 +++--- brep/page.cxx | 54 ++++++---- 7 files changed, 304 insertions(+), 137 deletions(-) (limited to 'brep') diff --git a/brep/package b/brep/package index 75920c4..ddfc179 100644 --- a/brep/package +++ b/brep/package @@ -348,7 +348,7 @@ namespace brep dependencies_type, requirements_type, optional location, - odb::lazy_shared_ptr); + std::shared_ptr); // Manifest data. // @@ -446,10 +446,8 @@ namespace brep set(_set (this.requirements, (?))) \ id_column("") key_column("") value_column("id") - #pragma db member(external_repositories) \ - id_column("") \ - value_column("repository") \ - value_not_null + #pragma db member(external_repositories) \ + id_column("") value_column("repository") value_not_null private: friend class odb::access; @@ -479,6 +477,8 @@ namespace brep get() set(_id (std::move (?))) }; + // Find the latest version of an internal package. + // #pragma db view object(package_version = version) \ object(package_version = v: \ version::id.data.package == v::id.data.package && \ @@ -492,7 +492,7 @@ namespace brep object(package inner: version::id.data.package == package::name && \ version::internal_repository.is_not_null () && \ v::id.data.package.is_null ()) - struct internal_package + struct latest_internal_package_version { using package_type = brep::package; std::shared_ptr package; diff --git a/brep/package-search.cxx b/brep/package-search.cxx index a840687..9b3fb2c 100644 --- a/brep/package-search.cxx +++ b/brep/package-search.cxx @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -72,11 +73,11 @@ namespace brep << TITLE << title << ~TITLE << CSS_STYLE << ident << A_STYLE () << ident - << PAGER_STYLE () << ident - << ".packages {font-size: x-large;}" << ident + << DIV_PAGER_STYLE () << ident + << "#packages {font-size: x-large;}" << ident << ".package {margin: 0.5em 0 0;}" << ident << ".name {font-size: x-large;}" << ident - << ".dependencies {margin: 0.3em 0 0;}" << ident + << ".tags {margin: 0.3em 0 0;}" << ~CSS_STYLE << ~HEAD << BODY; @@ -92,18 +93,14 @@ namespace brep // size_t pc (db_->query_value ().count); - s << DIV(CLASS="packages") - << "Packages (" << pc << ")" - << ~DIV; + s << DIV(ID="packages") << "Packages (" << pc << ")" << ~DIV; - // @@ Use appropriate view when clarify which package info to be displayed - // and search index structure get implemented. Query will also - // include search criteria if specified. + // @@ Query will also include search criteria if specified. // - using query = query; + using query = query; auto r ( - db_->query ( + db_->query ( "ORDER BY" + query::package::name + "OFFSET" + to_string (pr.page () * rop) + "LIMIT" + to_string (rop))); @@ -127,34 +124,20 @@ namespace brep << p.name << ~A << ~DIV - << DIV(CLASS="summary") - << p.summary - << ~DIV + << DIV(CLASS="summary") << p.summary << ~DIV + << DIV_TAGS (p.tags) + << DIV_LICENSES (v.license_alternatives) << DIV(CLASS="dependencies") << "Dependencies: " << v.dependencies.size () << ~DIV - << LICENSES (v.license_alternatives) - << TAGS (p.tags); - - s << ~DIV; + << ~DIV; } t.commit (); - auto u ( - [&q](size_t p) - { - string url ("/"); - if (p > 0) - url += "?p=" + to_string (p); - - if (!q.empty ()) - url += string (p > 0 ? "&" : "?") + q; - - return url; - }); + string u (q.empty () ? "/" : ("/?" + q)); - s << PAGER (pr.page (), pc, rop, options_->pages_in_pager (), u) + s << DIV_PAGER (pr.page (), pc, rop, options_->pages_in_pager (), u) << ~BODY << ~HTML; } diff --git a/brep/package-version-details.cxx b/brep/package-version-details.cxx index 0faecd2..162e783 100644 --- a/brep/package-version-details.cxx +++ b/brep/package-version-details.cxx @@ -5,7 +5,7 @@ #include #include -#include // make_shared() +#include // shared_ptr, make_shared() #include #include // invalid_argument @@ -18,6 +18,8 @@ #include #include +#include +#include #include #include #include @@ -48,12 +50,12 @@ namespace brep MODULE_DIAG; - path::reverse_iterator i (rq.path ().rbegin ()); - version ver; + auto i (rq.path ().rbegin ()); + version v; try { - ver = version (*i++); + v = version (*i++); } catch (const invalid_argument& ) { @@ -61,7 +63,7 @@ namespace brep } assert (i != rq.path ().rend ()); - const string& package (*i); + const string& p (*i); params::package_version_details pr; @@ -77,7 +79,8 @@ namespace brep } const char* ident ("\n "); - const string name (package + "-" + ver.string ()); + const string& vs (v.string ()); + const string name (p + " " + vs); const string title ("Package Version " + name); serializer s (rs.content (), title); @@ -85,17 +88,212 @@ namespace brep << HEAD << TITLE << title << ~TITLE << CSS_STYLE << ident - << "a {text-decoration: none;}" << ident - << "a:hover {text-decoration: underline;}" << ident - << ".name {font-size: xx-large; font-weight: bold;}" + << A_STYLE () << ident + << "#name {font-size: xx-large; font-weight: bold;}" << ident + << ".url {margin: 0.3em 0 0;}" << ident + << ".priority, #licenses, #dependencies, #requirements, " + "#locations, #changes {" << ident + << " font-size: x-large;" << ident + << " margin: 0.5em 0 0;" << ident + << "}" << ident + << ".comment {font-size: medium;}" << ident + << "ul {margin: 0; padding: 0 0 0 1em;}" << ident + << "li {font-size: large; margin: 0.1em 0 0;}" << ident + << ".conditional {font-weight: bold;}" << ident + << "pre {font-size: medium; margin: 0.1em 0 0 1em;}" << ~CSS_STYLE << ~HEAD - << BODY; + << BODY + << DIV(ID="name") + << A << HREF << "/go/" << mime_url_encode (p) << ~HREF << p << ~A + << " " << vs + << ~DIV; - s << DIV(CLASS="name") - << name + bool not_found (false); + shared_ptr pv; + + transaction t (db_->begin ()); //@@ Not committed, other places? + + try + { + package_version_id id { + p, v.epoch (), v.canonical_upstream (), v.revision ()}; + + pv = db_->load (id); + + // If the requested package version turned up to be an "external" one + // just respond that no "internal" package version is present. + // + not_found = pv->internal_repository == nullptr; + } + catch (const object_not_persistent& ) + { + not_found = true; + } + + if (not_found) + throw invalid_request (404, "Package '" + name + "' not found"); + + assert (pv->location); + const string url (pv->internal_repository.load ()->location.string () + + "/" + pv->location->string ()); + + const priority& pt (pv->priority); + + s << DIV(CLASS="url") << A << HREF << url << ~HREF << url << ~A << ~DIV + << DIV_PRIORITY (pt); + + if (!pt.comment.empty ()) + s << DIV(CLASS="comment") << pt.comment << ~DIV; + + const auto& ls (pv->license_alternatives); + + s << DIV(ID="licenses") + << "Licenses:" + << UL; + + for (const auto& la: ls) + { + s << LI; + + for (const auto& l: la) + { + if (&l != &la[0]) + s << " & "; + + s << l; + } + + if (!la.comment.empty ()) + s << DIV(CLASS="comment") << la.comment << ~DIV; + + s << ~LI; + } + + s << ~UL << ~DIV; + const auto& ds (pv->dependencies); + + if (!ds.empty ()) + { + s << DIV(ID="dependencies") + << "Dependencies:" + << UL; + + for (const auto& da: ds) + { + s << LI; + + if (da.conditional) + s << SPAN(CLASS="conditional") << "? " << ~SPAN; + + for (const auto& d: da) + { + if (&d != &da[0]) + s << " | "; + + // @@ Should it be a link to package version search page on the + // corresponding repository site ? + // + s << d.package; + + if (d.version) + { + static const strings operations ({"==", "<", ">", "<=", ">="}); + size_t op (static_cast (d.version->operation)); + assert (op < operations.size ()); + + // @@ Should it be a link to the best matching package version + // details page on the corresponding repository site ? + // + s << " " << operations[op] << " " << d.version->value.string (); + } + } + + if (!da.comment.empty ()) + s << DIV(CLASS="comment") << da.comment << ~DIV; + + s << ~LI; + } + + s << ~UL + << ~DIV; + } + + const auto& rm (pv->requirements); + + if (!rm.empty ()) + { + s << DIV(ID="requirements") + << "Requirements:" + << UL; + + for (const auto& ra: rm) + { + s << LI; + + if (ra.conditional) + s << SPAN(CLASS="conditional") << "? " << ~SPAN; + + if (ra.empty ()) + // If there is no requirement alternatives specified, then + // print the comment instead. + // + s << ra.comment; + else + { + for (const auto& r: ra) + { + if (&r != &ra[0]) + s << " | "; + + s << r; + } + + if (!ra.comment.empty ()) + s << DIV(CLASS="comment") << ra.comment << ~DIV; + } + + s << ~LI; + } + + s << ~UL + << ~DIV; + } + + const auto& er (pv->external_repositories); + + if (!er.empty ()) + { + s << DIV(ID="locations") + << "Alternative Locations:" + << UL; + + for (const auto& r: er) + { + repository_location l (move (r.load ()->location)); + assert (l.remote ()); + + string u ("http://" + l.host ()); + if (l.port () != 0) + u += ":" + to_string (l.port ()); + + u += "/go/" + mime_url_encode (p) + "/" + vs; + s << LI << A << HREF << u << ~HREF << u << ~A << ~LI; + } + + s << ~UL + << ~DIV; + } + + t.commit (); + + const string& ch (pv->changes); + + if (!ch.empty ()) + s << DIV(ID="changes") << "Changes:" << PRE << ch << ~PRE << ~DIV; + s << ~BODY << ~HTML; } diff --git a/brep/package-version-search.cxx b/brep/package-version-search.cxx index 336650e..166f116 100644 --- a/brep/package-version-search.cxx +++ b/brep/package-version-search.cxx @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -71,24 +72,25 @@ namespace brep << TITLE << title << ~TITLE << CSS_STYLE << ident << A_STYLE () << ident - << PAGER_STYLE () << ident - << ".name {font-size: xx-large; font-weight: bold;}" << ident - << ".summary {font-size: x-large; margin: 0.2em 0 0;}" << ident - << ".url {font-size: 90%;}" << ident - << ".email {font-size: 90%;}" << ident - << ".description {margin: 0.5em 0 0;}" << ident + << DIV_PAGER_STYLE () << ident + << "#name {font-size: xx-large; font-weight: bold;}" << ident + << "#summary {font-size: x-large; margin: 0.2em 0 0;}" << ident + << ".url {margin: 0.3em 0 0;}" << ident + << "#description {margin: 0.5em 0 0;}" << ident << ".tags {margin: 0.3em 0 0;}" << ident - << ".versions {font-size: x-large; margin: 0.5em 0 0;}" << ident + << "#versions {font-size: x-large; margin: 0.5em 0 0;}" << ident << ".package_version {margin: 0.5em 0 0;}" << ident << ".version {font-size: x-large;}" << ident << ".priority {margin: 0.3em 0 0;}" << ~CSS_STYLE << ~HEAD - << BODY; - - transaction t (db_->begin ()); + << BODY + << DIV(ID="name") << name << ~DIV; shared_ptr p; + size_t rop (options_->results_on_page ()); + + transaction t (db_->begin ()); try { @@ -99,12 +101,7 @@ namespace brep throw invalid_request (404, "Package '" + name + "' not found"); } - s << DIV(CLASS="name") - << name - << ~DIV - << DIV(CLASS="summary") - << p->summary - << ~DIV + s << DIV(ID="summary") << p->summary << ~DIV << DIV(CLASS="url") << A << HREF << p->url << ~HREF << p->url << ~A << ~DIV @@ -113,11 +110,9 @@ namespace brep << ~DIV; if (p->description) - s << DIV(CLASS="description") - << *p->description - << ~DIV; + s << DIV(ID="description") << *p->description << ~DIV; - s << TAGS (p->tags); + s << DIV_TAGS (p->tags); size_t pvc; { @@ -130,9 +125,7 @@ namespace brep query::internal_repository.is_not_null ()).count; } - s << DIV(CLASS="versions") - << "Versions (" << pvc << ")" - << ~DIV; + s << DIV(ID="versions") << "Versions (" << pvc << ")" << ~DIV; if (p->package_url) s << DIV(CLASS="url") @@ -147,8 +140,6 @@ namespace brep << ~A << ~DIV; - size_t rop (options_->results_on_page ()); - // @@ Use appropriate view when clarify which package version info to be // displayed and search index structure get implemented. Query will also // include search criteria if specified. @@ -171,37 +162,25 @@ namespace brep s << DIV(CLASS="package_version") << DIV(CLASS="version") << A - << HREF - << "/go/" << mime_url_encode (name) << "/" << vs - << ~HREF + << HREF << "/go/" << mime_url_encode (name) << "/" << vs << ~HREF << vs << ~A << ~DIV - << PRIORITY (v.priority) + << DIV_PRIORITY (v.priority) + << DIV_LICENSES (v.license_alternatives) << DIV(CLASS="dependencies") << "Dependencies: " << v.dependencies.size () << ~DIV - << LICENSES (v.license_alternatives) << ~DIV; } t.commit (); - auto u ( - [&name, &pr](size_t p) - { - string url (name); - if (p > 0) - url += "?p=" + to_string (p); - - if (!pr.query ().empty ()) - url += - string (p > 0 ? "&" : "?") + "q=" + mime_url_encode (pr.query ()); - - return url; - }); + string u (mime_url_encode (name)); + if (!pr.query ().empty ()) + u += "?q=" + mime_url_encode (pr.query ()); - s << PAGER (pr.page (), pvc, rop, options_->pages_in_pager (), u) + s << DIV_PAGER (pr.page (), pvc, rop, options_->pages_in_pager (), u) << ~BODY << ~HTML; } diff --git a/brep/package.cxx b/brep/package.cxx index 59efbfb..8b9a219 100644 --- a/brep/package.cxx +++ b/brep/package.cxx @@ -63,7 +63,7 @@ namespace brep dependencies_type dp, requirements_type rq, optional lc, - lazy_shared_ptr rp) + shared_ptr rp) : package (move (pk)), version (move (vr)), priority (move (pr)), @@ -73,7 +73,10 @@ namespace brep requirements (move (rq)), location (move (lc)) { - if (rp.load ()->internal) + //@@ Can't be sure we are in transaction. Instead, make caller + // pass shared_ptr. + // + if (rp->internal) internal_repository = move (rp); else external_repositories.emplace_back (move (rp)); diff --git a/brep/page b/brep/page index 06f3350..c7febd8 100644 --- a/brep/page +++ b/brep/page @@ -7,7 +7,6 @@ #include #include // size_t -#include #include @@ -28,16 +27,14 @@ namespace brep // Generates paging element. // - class PAGER + class DIV_PAGER { public: - using get_url_type = std::function; - - PAGER (std::size_t current_page, - std::size_t item_count, - std::size_t item_per_page, - std::size_t page_number_count, - get_url_type get_url); + DIV_PAGER (std::size_t current_page, + std::size_t item_count, + std::size_t item_per_page, + std::size_t page_number_count, + const std::string& url); void operator() (xml::serializer& s) const; @@ -47,12 +44,12 @@ namespace brep std::size_t item_count_; std::size_t item_per_page_; std::size_t page_number_count_; - get_url_type get_url_; + const std::string& url_; }; - // PAGER element default style. + // DIV_PAGER element default style. // - struct PAGER_STYLE + struct DIV_PAGER_STYLE { void operator() (xml::serializer& s) const; @@ -60,10 +57,10 @@ namespace brep // Generates package tags element. // - class TAGS + class DIV_TAGS { public: - TAGS (const strings& ts): tags_ (ts) {} + DIV_TAGS (const strings& ts): tags_ (ts) {} void operator() (xml::serializer& s) const; @@ -74,11 +71,10 @@ namespace brep // Generates package version license alternatives element. // - class LICENSES + class DIV_LICENSES { public: - LICENSES (const license_alternatives& la) - : license_alternatives_ (la) {} + DIV_LICENSES (const license_alternatives& l): license_alternatives_ (l) {} void operator() (xml::serializer& s) const; @@ -89,10 +85,10 @@ namespace brep // Generates package version priority element. // - class PRIORITY + class DIV_PRIORITY { public: - PRIORITY (const priority& pr): priority_ (pr) {} + DIV_PRIORITY (const priority& p): priority_ (p) {} void operator() (xml::serializer& s) const; diff --git a/brep/page.cxx b/brep/page.cxx index ad93e7c..552be3c 100644 --- a/brep/page.cxx +++ b/brep/page.cxx @@ -4,6 +4,7 @@ #include +#include #include #include // move() #include // min() @@ -30,23 +31,23 @@ namespace brep << "a:hover {text-decoration: underline;}"; } - // PAGER + // DIV_PAGER // - PAGER:: - PAGER (size_t current_page, - size_t item_count, - size_t item_per_page, - size_t page_number_count, - get_url_type get_url) + DIV_PAGER:: + DIV_PAGER (size_t current_page, + size_t item_count, + size_t item_per_page, + size_t page_number_count, + const string& url) : current_page_ (current_page), item_count_ (item_count), item_per_page_ (item_per_page), page_number_count_ (page_number_count), - get_url_ (move (get_url)) + url_ (url) { } - void PAGER:: + void DIV_PAGER:: operator() (serializer& s) const { if (item_count_ == 0 || item_per_page_ == 0) @@ -59,13 +60,22 @@ namespace brep if (pc > 1) { + auto u ( + [this](size_t page) -> string + { + return page == 0 + ? url_ + : url_ + (url_.find ('?') == string::npos ? "?p=" : "&p=") + + to_string (page); + }); + // Can consider customizing class names if use-case appear. // s << DIV(CLASS="pager"); if (current_page_ > 0) s << A(CLASS="pg-prev") - << HREF << get_url_ (current_page_ - 1) << ~HREF + << HREF << u (current_page_ - 1) << ~HREF << "<<" << ~A << " "; @@ -79,12 +89,10 @@ namespace brep for (size_t p (fp); p < tp; ++p) { if (p == current_page_) - s << SPAN(CLASS="pg-cpage") - << p + 1 - << ~SPAN; + s << SPAN(CLASS="pg-cpage") << p + 1 << ~SPAN; else s << A(CLASS="pg-page") - << HREF << get_url_ (p) << ~HREF + << HREF << u (p) << ~HREF << p + 1 << ~A; @@ -94,7 +102,7 @@ namespace brep if (current_page_ < pc - 1) s << A(CLASS="pg-next") - << HREF << get_url_ (current_page_ + 1) << ~HREF + << HREF << u (current_page_ + 1) << ~HREF << ">>" << ~A; @@ -102,9 +110,9 @@ namespace brep } } - // PAGER_STYLE + // DIV_PAGER_STYLE // - void PAGER_STYLE:: + void DIV_PAGER_STYLE:: operator() (xml::serializer& s) const { const char* ident ("\n "); @@ -114,9 +122,9 @@ namespace brep << ".pg-cpage {padding: 0 0.3em 0 0; font-weight: bold;}"; } - // LICENSES + // DIV_LICENSES // - void LICENSES:: + void DIV_LICENSES:: operator() (serializer& s) const { s << DIV(CLASS="licenses") @@ -139,9 +147,9 @@ namespace brep s << ~DIV; } - // TAGS + // DIV_TAGS // - void TAGS:: + void DIV_TAGS:: operator() (serializer& s) const { if (!tags_.empty ()) @@ -156,9 +164,9 @@ namespace brep } } - // PRIORITY + // DIV_PRIORITY // - void PRIORITY:: + void DIV_PRIORITY:: operator() (serializer& s) const { static const strings priority_names ( -- cgit v1.1