aboutsummaryrefslogtreecommitdiff
path: root/mod/mod-package-version-details.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'mod/mod-package-version-details.cxx')
-rw-r--r--mod/mod-package-version-details.cxx320
1 files changed, 320 insertions, 0 deletions
diff --git a/mod/mod-package-version-details.cxx b/mod/mod-package-version-details.cxx
new file mode 100644
index 0000000..149c8f9
--- /dev/null
+++ b/mod/mod-package-version-details.cxx
@@ -0,0 +1,320 @@
+// file : mod/mod-package-version-details.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2016 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#include <mod/mod-package-version-details>
+
+#include <xml/serializer>
+
+#include <odb/session.hxx>
+#include <odb/database.hxx>
+#include <odb/transaction.hxx>
+
+#include <web/xhtml>
+#include <web/module>
+#include <web/xhtml-fragment>
+#include <web/mime-url-encoding>
+
+#include <brep/package>
+#include <brep/package-odb>
+
+#include <mod/page>
+#include <mod/options>
+
+using namespace std;
+using namespace odb::core;
+using namespace brep::cli;
+
+// While currently the user-defined copy constructor is not required (we don't
+// need to deep copy nullptr's), it is a good idea to keep the placeholder
+// ready for less trivial cases.
+//
+brep::package_version_details::
+package_version_details (const package_version_details& r)
+ : database_module (r),
+ options_ (r.initialized_ ? r.options_ : nullptr)
+{
+}
+
+void brep::package_version_details::
+init (scanner& s)
+{
+ MODULE_DIAG;
+
+ options_ = make_shared<options::package_version_details> (
+ s, unknown_mode::fail, unknown_mode::fail);
+
+ database_module::init (*options_);
+
+ if (options_->root ().empty ())
+ options_->root (dir_path ("/"));
+}
+
+bool brep::package_version_details::
+handle (request& rq, response& rs)
+{
+ using namespace web;
+ using namespace web::xhtml;
+ using brep::version; // Not to confuse with module::version.
+
+ MODULE_DIAG;
+
+ const dir_path& root (options_->root ());
+
+ auto i (rq.path ().rbegin ());
+ version ver;
+
+ try
+ {
+ ver = version (*i++);
+ }
+ catch (const invalid_argument& )
+ {
+ throw invalid_request (400, "invalid package version format");
+ }
+
+ const string& sver (ver.string ());
+
+ assert (i != rq.path ().rend ());
+ const string& name (*i);
+
+ params::package_version_details params;
+ bool full;
+
+ try
+ {
+ name_value_scanner s (rq.parameters ());
+ params = params::package_version_details (
+ s, unknown_mode::fail, unknown_mode::fail);
+
+ full = params.form () == page_form::full;
+ }
+ catch (const unknown_argument& e)
+ {
+ throw invalid_request (400, e.what ());
+ }
+
+ auto url (
+ [&sver](bool f = false, const string& a = "") -> string
+ {
+ string u (sver);
+
+ if (f) { u += "?f=full"; }
+ if (!a.empty ()) { u += '#' + a; }
+ return u;
+ });
+
+ const string title (name + " " + sver);
+ xml::serializer s (rs.content (), title);
+
+ s << HTML
+ << HEAD
+ << TITLE << title << ~TITLE
+ << CSS_LINKS (path ("package-version-details.css"), root)
+ << ~HEAD
+ << BODY
+ << DIV_HEADER (root, options_->logo (), options_->menu ())
+ << DIV(ID="content");
+
+ if (full)
+ s << CLASS("full");
+
+ s << DIV(ID="heading")
+ << H1
+ << A(HREF=root / path (mime_url_encode (name))) << name << ~A
+ << "/"
+ << A(HREF=url ()) << sver << ~A
+ << ~H1
+ << A(HREF=url (!full)) << (full ? "[brief]" : "[full]") << ~A
+ << ~DIV;
+
+ bool not_found (false);
+ shared_ptr<package> pkg;
+
+ session sn;
+ transaction t (db_->begin ());
+
+ try
+ {
+ pkg = db_->load<package> (package_id (name, ver));
+
+ // If the requested package turned up to be an "external" one just
+ // respond that no "internal" package is present.
+ //
+ not_found = !pkg->internal ();
+ }
+ catch (const object_not_persistent& )
+ {
+ not_found = true;
+ }
+
+ if (not_found)
+ throw invalid_request (404, "Package '" + title + "' not found");
+
+ s << H2 << pkg->summary << ~H2;
+
+ static const string id ("description");
+ if (const auto& d = pkg->description)
+ s << (full
+ ? P_DESCRIPTION (*d, id)
+ : P_DESCRIPTION (*d, options_->package_description (),
+ url (!full, id)));
+
+ assert (pkg->location && pkg->sha256sum);
+
+ s << TABLE(CLASS="proplist", ID="version")
+ << TBODY
+
+ // Repeat version here since it can be cut out in the header.
+ //
+ << TR_VERSION (pkg->version.string ())
+
+ << TR_PRIORITY (pkg->priority)
+ << TR_LICENSES (pkg->license_alternatives)
+ << TR_LOCATION (pkg->internal_repository.object_id (), root)
+ << TR_DOWNLOAD (pkg->internal_repository.load ()->location.string () +
+ "/" + pkg->location->string ())
+ << TR_SHA256SUM (*pkg->sha256sum)
+ << ~TBODY
+ << ~TABLE
+
+ << TABLE(CLASS="proplist", ID="package")
+ << TBODY
+ << TR_URL (pkg->url)
+ << TR_EMAIL (pkg->email);
+
+ const auto& pu (pkg->package_url);
+ if (pu && *pu != pkg->url)
+ s << TR_URL (*pu, "pkg-url");
+
+ const auto& pe (pkg->package_email);
+ if (pe && *pe != pkg->email)
+ s << TR_EMAIL (*pe, "pkg-email");
+
+ s << TR_TAGS (pkg->tags, root)
+ << ~TBODY
+ << ~TABLE;
+
+ const auto& ds (pkg->dependencies);
+ if (!ds.empty ())
+ {
+ s << H3 << "Depends" << ~H3
+ << TABLE(CLASS="proplist", ID="depends")
+ << TBODY;
+
+ for (const auto& da: ds)
+ {
+ s << TR(CLASS="depends")
+ << TH;
+
+ if (da.conditional)
+ s << "?";
+
+ s << ~TH
+ << TD
+ << SPAN(CLASS="value");
+
+ for (const auto& d: da)
+ {
+ if (&d != &da[0])
+ s << " | ";
+
+ shared_ptr<package> p (d.package.load ());
+ assert (p->internal () || !p->other_repositories.empty ());
+
+ shared_ptr<repository> r (
+ p->internal ()
+ ? p->internal_repository.load ()
+ : p->other_repositories[0].load ());
+
+ const auto& dcon (d.constraint);
+ const string& dname (p->id.name);
+ string ename (mime_url_encode (dname));
+
+ if (r->url)
+ {
+ string u (*r->url + ename);
+ s << A(HREF=u) << dname << ~A;
+
+ if (dcon)
+ s << ' ' << A(HREF=u + "/" + p->version.string ()) << *dcon << ~A;
+ }
+ else if (p->internal ())
+ {
+ path u (root / path (ename));
+ s << A(HREF=u) << dname << ~A;
+
+ if (dcon)
+ s << ' ' << A(HREF=u / path (p->version.string ())) << *dcon << ~A;
+ }
+ else
+ // Display the dependency as a plain text if no repository URL
+ // available.
+ //
+ s << d;
+ }
+
+ s << ~SPAN
+ << SPAN_COMMENT (da.comment)
+ << ~TD
+ << ~TR;
+ }
+
+ s << ~TBODY
+ << ~TABLE;
+ }
+
+ t.commit ();
+
+ const auto& rm (pkg->requirements);
+ if (!rm.empty ())
+ {
+ s << H3 << "Requires" << ~H3
+ << TABLE(CLASS="proplist", ID="requires")
+ << TBODY;
+
+ for (const auto& ra: rm)
+ {
+ s << TR(CLASS="requires")
+ << TH;
+
+ if (ra.conditional)
+ s << "?";
+
+ s << ~TH
+ << TD
+ << SPAN(CLASS="value");
+
+ for (const auto& r: ra)
+ {
+ if (&r != &ra[0])
+ s << " | ";
+
+ s << r;
+ }
+
+ s << ~SPAN
+ << SPAN_COMMENT (ra.comment)
+ << ~TD
+ << ~TR;
+ }
+
+ s << ~TBODY
+ << ~TABLE;
+ }
+
+ const auto& ch (pkg->changes);
+ if (!ch.empty ())
+ s << H3 << "Changes" << ~H3
+ << (full
+ ? PRE_CHANGES (ch)
+ : PRE_CHANGES (ch,
+ options_->package_changes (),
+ url (!full, "changes")));
+
+ s << ~DIV
+ << ~BODY
+ << ~HTML;
+
+ return true;
+}