aboutsummaryrefslogtreecommitdiff
path: root/brep
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-09-22 12:31:42 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-09-24 11:49:02 +0200
commitd1fae6b26e0820dee76e396c540bb1de90038917 (patch)
treee6a145e0901b6eeb118a03c6a616a763de79e42e /brep
parent675e973bf8e0e24593552f596eb3d81e57e19c94 (diff)
Implement package version detals page
Diffstat (limited to 'brep')
-rw-r--r--brep/package12
-rw-r--r--brep/package-search.cxx45
-rw-r--r--brep/package-version-details.cxx222
-rw-r--r--brep/package-version-search.cxx67
-rw-r--r--brep/package.cxx7
-rw-r--r--brep/page34
-rw-r--r--brep/page.cxx54
7 files changed, 304 insertions, 137 deletions
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<path> location,
- odb::lazy_shared_ptr<repository_type>);
+ std::shared_ptr<repository_type>);
// 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_type> 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 <web/mime-url-encoding>
#include <brep/page>
+#include <brep/options>
#include <brep/package>
#include <brep/package-odb>
#include <brep/shared-database>
@@ -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<internal_package_count> ().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<internal_package>;
+ using query = query<latest_internal_package_version>;
auto r (
- db_->query<internal_package> (
+ db_->query<latest_internal_package_version> (
"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 <brep/package-version-details>
#include <string>
-#include <memory> // make_shared()
+#include <memory> // shared_ptr, make_shared()
#include <cassert>
#include <stdexcept> // invalid_argument
@@ -18,6 +18,8 @@
#include <web/module>
#include <web/mime-url-encoding>
+#include <brep/page>
+#include <brep/options>
#include <brep/package>
#include <brep/package-odb>
#include <brep/shared-database>
@@ -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<package_version> 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<package_version> (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<size_t> (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 <web/mime-url-encoding>
#include <brep/page>
+#include <brep/options>
#include <brep/package>
#include <brep/package-odb>
#include <brep/shared-database>
@@ -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<package> 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<path> lc,
- lazy_shared_ptr<repository_type> rp)
+ shared_ptr<repository_type> 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 <string>
#include <cstddef> // size_t
-#include <functional>
#include <xml/forward>
@@ -28,16 +27,14 @@ namespace brep
// Generates paging element.
//
- class PAGER
+ class DIV_PAGER
{
public:
- using get_url_type = std::function<std::string(std::size_t page)>;
-
- 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 <brep/page>
+#include <string>
#include <cassert>
#include <utility> // move()
#include <algorithm> // 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 (