From c715379c625935bd4b28bebb35f34721342cc7f3 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 22 Dec 2015 19:29:04 +0200 Subject: Source file names fixup --- brep/buildfile | 42 ++--- brep/database | 25 +++ brep/database.cxx | 48 ++++++ brep/mod-package-details | 36 ++++ brep/mod-package-details.cxx | 242 +++++++++++++++++++++++++++ brep/mod-package-search | 36 ++++ brep/mod-package-search.cxx | 148 ++++++++++++++++ brep/mod-package-version-details | 39 +++++ brep/mod-package-version-details.cxx | 315 +++++++++++++++++++++++++++++++++++ brep/mod-repository-details | 36 ++++ brep/mod-repository-details.cxx | 112 +++++++++++++ brep/mod-repository-root | 53 ++++++ brep/mod-repository-root.cxx | 202 ++++++++++++++++++++++ brep/package-details | 36 ---- brep/package-details.cxx | 242 --------------------------- brep/package-search | 36 ---- brep/package-search.cxx | 148 ---------------- brep/package-version-details | 39 ----- brep/package-version-details.cxx | 315 ----------------------------------- brep/repository-details | 36 ---- brep/repository-details.cxx | 112 ------------- brep/repository-root | 53 ------ brep/repository-root.cxx | 202 ---------------------- brep/services.cxx | 2 +- brep/shared-database | 25 --- brep/shared-database.cxx | 48 ------ 26 files changed, 1314 insertions(+), 1314 deletions(-) create mode 100644 brep/database create mode 100644 brep/database.cxx create mode 100644 brep/mod-package-details create mode 100644 brep/mod-package-details.cxx create mode 100644 brep/mod-package-search create mode 100644 brep/mod-package-search.cxx create mode 100644 brep/mod-package-version-details create mode 100644 brep/mod-package-version-details.cxx create mode 100644 brep/mod-repository-details create mode 100644 brep/mod-repository-details.cxx create mode 100644 brep/mod-repository-root create mode 100644 brep/mod-repository-root.cxx delete mode 100644 brep/package-details delete mode 100644 brep/package-details.cxx delete mode 100644 brep/package-search delete mode 100644 brep/package-search.cxx delete mode 100644 brep/package-version-details delete mode 100644 brep/package-version-details.cxx delete mode 100644 brep/repository-details delete mode 100644 brep/repository-details.cxx delete mode 100644 brep/repository-root delete mode 100644 brep/repository-root.cxx delete mode 100644 brep/shared-database delete mode 100644 brep/shared-database.cxx diff --git a/brep/buildfile b/brep/buildfile index 80949fe..42fe3b5 100644 --- a/brep/buildfile +++ b/brep/buildfile @@ -38,27 +38,27 @@ install.include = $install.include/brep import libs += libstudxml%lib{studxml} gen = {hxx ixx cxx}{ options } -src = \ - {hxx cxx}{ diagnostics } \ - {hxx cxx}{ module } \ - {hxx }{ options-types } \ - {hxx cxx}{ package-details } \ - {hxx cxx}{ package-search } \ - {hxx cxx}{ package-version-details } \ - {hxx cxx}{ page } \ - {hxx cxx}{ repository-details } \ - {hxx cxx}{ repository-root } \ - { cxx}{ services } \ - {hxx cxx}{ shared-database } \ - {hxx cxx}{ types-parsers } \ - {hxx }{ wrapper-traits } \ - ../web/{hxx cxx}{ mime-url-encoding } \ - ../web/{hxx }{ module } \ - ../web/{hxx }{ xhtml } \ -../web/apache/{hxx }{ log } \ -../web/apache/{hxx ixx cxx}{ request } \ -../web/apache/{hxx txx cxx}{ service } \ -../web/apache/{hxx }{ stream } \ +src = \ + {hxx cxx}{ diagnostics } \ + {hxx cxx}{ module } \ + {hxx }{ options-types } \ + {hxx cxx}{ mod-package-details } \ + {hxx cxx}{ mod-package-search } \ + {hxx cxx}{ mod-package-version-details } \ + {hxx cxx}{ page } \ + {hxx cxx}{ mod-repository-details } \ + {hxx cxx}{ mod-repository-root } \ + { cxx}{ services } \ + {hxx cxx}{ database } \ + {hxx cxx}{ types-parsers } \ + {hxx }{ wrapper-traits } \ + ../web/{hxx cxx}{ mime-url-encoding } \ + ../web/{hxx }{ module } \ + ../web/{hxx }{ xhtml } \ +../web/apache/{hxx }{ log } \ +../web/apache/{hxx ixx cxx}{ request } \ +../web/apache/{hxx txx cxx}{ service } \ +../web/apache/{hxx }{ stream } mod{brep}: $src $gen lib{brep} $libs diff --git a/brep/database b/brep/database new file mode 100644 index 0000000..6fdfe0b --- /dev/null +++ b/brep/database @@ -0,0 +1,25 @@ +// file : brep/database -*- C++ -*- +// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#ifndef BREP_DATABASE +#define BREP_DATABASE + +#include // database + +#include + +#include + +namespace brep +{ + // Returns pointer to the shared database instance, creating one on the + // first call. On subsequent calls ensures passed host and port equals + // to ones of the existing database instance throwing runtime_error + // otherwise. Is not thread-safe. + // + shared_ptr + shared_database (const options::db&); +} + +#endif // BREP_DATABASE diff --git a/brep/database.cxx b/brep/database.cxx new file mode 100644 index 0000000..4b7494e --- /dev/null +++ b/brep/database.cxx @@ -0,0 +1,48 @@ +// file : brep/database.cxx -*- C++ -*- +// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#include + +#include // runtime_error + +#include + +#include +#include + +namespace brep +{ + shared_ptr + shared_database (const options::db& o) + { + using odb::pgsql::database; + static weak_ptr db; + + // In C++11, function-static variable initialization is guaranteed to be + // thread-safe, thought this doesn't seem to be enough in our case + // (because we are re-initializing the weak pointer). + // + if (shared_ptr d = db.lock ()) + { + if (o.db_user () != d->user () || + o.db_password () != d->password () || + o.db_name () != d->db () || + o.db_host () != d->host () || + o.db_port () != d->port ()) + throw std::runtime_error ("shared database options mismatch"); + + return d; + } + else + { + d = make_shared (o.db_user (), + o.db_password (), + o.db_name (), + o.db_host (), + o.db_port ()); + db = d; + return d; + } + } +} diff --git a/brep/mod-package-details b/brep/mod-package-details new file mode 100644 index 0000000..e6603f3 --- /dev/null +++ b/brep/mod-package-details @@ -0,0 +1,36 @@ +// file : brep/mod-package-details -*- C++ -*- +// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#ifndef BREP_MOD_PACKAGE_DETAILS +#define BREP_MOD_PACKAGE_DETAILS + +#include // database + +#include + +#include +#include + +namespace brep +{ + class package_details: public module + { + public: + virtual bool + handle (request&, response&); + + virtual const cli::options& + cli_options () const {return options::package_details::description ();} + + private: + virtual void + init (cli::scanner&); + + private: + shared_ptr options_; + shared_ptr db_; + }; +} + +#endif // BREP_MOD_PACKAGE_DETAILS diff --git a/brep/mod-package-details.cxx b/brep/mod-package-details.cxx new file mode 100644 index 0000000..ba6387e --- /dev/null +++ b/brep/mod-package-details.cxx @@ -0,0 +1,242 @@ +// file : brep/mod-package-details.cxx -*- C++ -*- +// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#include + +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +using namespace odb::core; +using namespace brep::cli; + +void brep::package_details:: +init (scanner& s) +{ + MODULE_DIAG; + + options_ = make_shared ( + s, unknown_mode::fail, unknown_mode::fail); + + if (options_->root ().empty ()) + options_->root (dir_path ("/")); + + db_ = shared_database (*options_); +} + +template +static inline query +search_params (const brep::string& n, const brep::string& q) +{ + using query = query; + + return "(" + + (q.empty () + ? query ("NULL") + : "plainto_tsquery (" + query::_val (q) + ")") + + "," + + query::_val (n) + + ")"; +} + +bool brep::package_details:: +handle (request& rq, response& rs) +{ + using namespace web; + using namespace web::xhtml; + + MODULE_DIAG; + + // The module options object is not changed after being created once per + // server process. + // + static const size_t res_page (options_->search_results ()); + static const dir_path& root (options_->root ()); + + const string& name (*rq.path ().rbegin ()); + const string ename (mime_url_encode (name)); + + params::package_details params; + bool full; + + try + { + name_value_scanner s (rq.parameters ()); + params = params::package_details ( + s, unknown_mode::fail, unknown_mode::fail); + + full = params.form () == page_form::full; + } + catch (const cli::exception& e) + { + throw invalid_request (400, e.what ()); + } + + size_t page (params.page ()); + const string& squery (params.query ()); + + auto url ( + [&ename](bool f = false, + const string& q = "", + size_t p = 0, + const string& a = "") -> string + { + string s ("?"); + string u (ename); + + if (f) { u += "?f=full"; s = "&"; } + if (!q.empty ()) { u += s + "q=" + mime_url_encode (q); s = "&"; } + if (p > 0) { u += s + "p=" + to_string (p); s = "&"; } + if (!a.empty ()) { u += '#' + a; } + return u; + }); + + xml::serializer s (rs.content (), name); + + s << HTML + << HEAD + << TITLE + << name; + + if (!squery.empty ()) + s << " " << squery; + + s << ~TITLE + << CSS_LINKS (path ("package-details.css"), root) + << ~HEAD + << BODY + << DIV_HEADER (root) + << DIV(ID="content"); + + if (full) + s << CLASS("full"); + + s << DIV(ID="heading") + << H1 << A(HREF=url ()) << name << ~A << ~H1 + << A(HREF=url (!full, squery, page)) + << (full ? "[brief]" : "[full]") + << ~A + << ~DIV; + + session sn; + transaction t (db_->begin ()); + + shared_ptr pkg; + { + latest_package lp; + if (!db_->query_one ( + query( + "(" + query::_val (name) + ")"), lp)) + throw invalid_request (404, "Package '" + name + "' not found"); + + pkg = db_->load (lp.id); + } + + const auto& licenses (pkg->license_alternatives); + + if (page == 0) + { + // Display package details on the first page only. + // + 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, squery, page, id))); + + s << TABLE(CLASS="proplist", ID="package") + << TBODY + << TR_LICENSE (licenses) + << TR_URL (pkg->url) + << TR_EMAIL (pkg->email) + << TR_TAGS (pkg->tags, root) + << ~TBODY + << ~TABLE; + } + + auto pkg_count ( + db_->query_value ( + search_params (name, squery))); + + s << FORM_SEARCH (squery) + << DIV_COUNTER (pkg_count, "Version", "Versions"); + + // Enclose the subsequent tables to be able to use nth-child CSS selector. + // + s << DIV; + for (const auto& pr: + db_->query ( + search_params (name, squery) + + "ORDER BY rank DESC, version_epoch DESC, " + "version_canonical_upstream DESC, version_revision DESC" + + "OFFSET" + to_string (page * res_page) + + "LIMIT" + to_string (res_page))) + { + shared_ptr p (db_->load (pr.id)); + + s << TABLE(CLASS="proplist version") + << TBODY + << TR_VERSION (name, p->version.string (), root) + + // @@ Shouldn't we skip low priority row ? Don't think so, why? + // + << TR_PRIORITY (p->priority); + + // Comparing objects of the license_alternatives class as being of the + // vector> class, so comments are not considered. + // + if (p->license_alternatives != licenses) + s << TR_LICENSE (p->license_alternatives); + + assert (p->internal ()); + + // @@ Shouldn't we make package location to be a link to the proper + // place of the About page, describing corresponding repository? + // Yes, I think that's sounds reasonable, once we have about. + // Or maybe it can be something more valuable like a link to the + // repository package search page ? + // + // @@ In most cases package location will be the same for all versions + // of the same package. Shouldn't we put package location to the + // package summary part and display it here only if it differs + // from the one in the summary ? + // + // Hm, I am not so sure about this. Consider: stable/testing/unstable. + // + s << TR_LOCATION (p->internal_repository.object_id (), root) + << TR_DEPENDS (p->dependencies, root) + << TR_REQUIRES (p->requirements) + << ~TBODY + << ~TABLE; + } + s << ~DIV; + + t.commit (); + + s << DIV_PAGER (page, pkg_count, res_page, options_->search_pages (), + url (full, squery)) + << ~DIV + << ~BODY + << ~HTML; + + return true; +} diff --git a/brep/mod-package-search b/brep/mod-package-search new file mode 100644 index 0000000..c86d0b5 --- /dev/null +++ b/brep/mod-package-search @@ -0,0 +1,36 @@ +// file : brep/mod-package-search -*- C++ -*- +// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#ifndef BREP_MOD_PACKAGE_SEARCH +#define BREP_MOD_PACKAGE_SEARCH + +#include // database + +#include + +#include +#include + +namespace brep +{ + class package_search: public module + { + public: + virtual bool + handle (request&, response&); + + virtual const cli::options& + cli_options () const {return options::package_search::description ();} + + private: + virtual void + init (cli::scanner&); + + private: + shared_ptr options_; + shared_ptr db_; + }; +} + +#endif // BREP_MOD_PACKAGE_SEARCH diff --git a/brep/mod-package-search.cxx b/brep/mod-package-search.cxx new file mode 100644 index 0000000..6d7bdd6 --- /dev/null +++ b/brep/mod-package-search.cxx @@ -0,0 +1,148 @@ +// file : brep/mod-package-search.cxx -*- C++ -*- +// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#include + +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +using namespace odb::core; +using namespace brep::cli; + +void brep::package_search:: +init (scanner& s) +{ + MODULE_DIAG; + + options_ = make_shared ( + s, unknown_mode::fail, unknown_mode::fail); + + if (options_->root ().empty ()) + options_->root (dir_path ("/")); + + db_ = shared_database (*options_); +} + +template +static inline query +search_param (const brep::string& q) +{ + using query = query; + return "(" + + (q.empty () + ? query ("NULL") + : "plainto_tsquery (" + query::_val (q) + ")") + + ")"; +} + +bool brep::package_search:: +handle (request& rq, response& rs) +{ + using namespace web::xhtml; + + MODULE_DIAG; + + // The module options object is not changed after being created once per + // server process. + // + static const size_t res_page (options_->search_results ()); + static const dir_path& root (options_->root ()); + + params::package_search params; + + try + { + name_value_scanner s (rq.parameters ()); + params = params::package_search (s, unknown_mode::fail, unknown_mode::fail); + } + catch (const unknown_argument& e) + { + throw invalid_request (400, e.what ()); + } + + size_t page (params.page ()); + const string& squery (params.query ()); + string squery_param (squery.empty () + ? "" + : "?q=" + web::mime_url_encode (squery)); + + static const string title ("Packages"); + xml::serializer s (rs.content (), title); + + s << HTML + << HEAD + << TITLE + << title; + + if (!squery.empty ()) + s << " " << squery; + + s << ~TITLE + << CSS_LINKS (path ("package-search.css"), root) + << ~HEAD + << BODY + << DIV_HEADER (root) + << DIV(ID="content"); + + session sn; + transaction t (db_->begin ()); + + auto pkg_count ( + db_->query_value ( + search_param (squery))); + + s << FORM_SEARCH (squery) + << DIV_COUNTER (pkg_count, "Package", "Packages"); + + // Enclose the subsequent tables to be able to use nth-child CSS selector. + // + s << DIV; + for (const auto& pr: + db_->query ( + search_param (squery) + + "ORDER BY rank DESC, name" + + "OFFSET" + to_string (page * res_page) + + "LIMIT" + to_string (res_page))) + { + shared_ptr p (db_->load (pr.id)); + + s << TABLE(CLASS="proplist package") + << TBODY + << TR_NAME (p->id.name, squery_param, root) + << TR_SUMMARY (p->summary) + << TR_LICENSE (p->license_alternatives) + << TR_TAGS (p->tags, root) + << TR_DEPENDS (p->dependencies, root) + << TR_REQUIRES (p->requirements) + << ~TBODY + << ~TABLE; + } + s << ~DIV; + + t.commit (); + + s << DIV_PAGER (page, pkg_count, res_page, options_->search_pages (), + root.string () + squery_param) + << ~DIV + << ~BODY + << ~HTML; + + return true; +} diff --git a/brep/mod-package-version-details b/brep/mod-package-version-details new file mode 100644 index 0000000..48bf453 --- /dev/null +++ b/brep/mod-package-version-details @@ -0,0 +1,39 @@ +// file : brep/mod-package-version-details -*- C++ -*- +// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#ifndef BREP_MOD_PACKAGE_VERSION_DETAILS +#define BREP_MOD_PACKAGE_VERSION_DETAILS + +#include // database + +#include + +#include +#include + +namespace brep +{ + class package_version_details: public module + { + public: + virtual bool + handle (request&, response&); + + virtual const cli::options& + cli_options () const + { + return options::package_version_details::description (); + } + + private: + virtual void + init (cli::scanner&); + + private: + shared_ptr options_; + shared_ptr db_; + }; +} + +#endif // BREP_MOD_PACKAGE_VERSION_DETAILS diff --git a/brep/mod-package-version-details.cxx b/brep/mod-package-version-details.cxx new file mode 100644 index 0000000..54f8f19 --- /dev/null +++ b/brep/mod-package-version-details.cxx @@ -0,0 +1,315 @@ +// file : brep/mod-package-version-details.cxx -*- C++ -*- +// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#include + +#include // invalid_argument + +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +using namespace std; +using namespace odb::core; +using namespace brep::cli; + +void brep::package_version_details:: +init (scanner& s) +{ + MODULE_DIAG; + + options_ = make_shared ( + s, unknown_mode::fail, unknown_mode::fail); + + if (options_->root ().empty ()) + options_->root (dir_path ("/")); + + db_ = shared_database (*options_); +} + +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; + + // The module options object is not changed after being created once per + // server process. + // + static 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) + << 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 pkg; + + session sn; + transaction t (db_->begin ()); + + try + { + pkg = db_->load (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); + + 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 ()) + << ~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 p (d.package.load ()); + assert (p->internal () || !p->other_repositories.empty ()); + + shared_ptr 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; +} diff --git a/brep/mod-repository-details b/brep/mod-repository-details new file mode 100644 index 0000000..71df39b --- /dev/null +++ b/brep/mod-repository-details @@ -0,0 +1,36 @@ +// file : brep/mod-repository-details -*- C++ -*- +// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#ifndef BREP_MOD_REPOSITORY_DETAILS +#define BREP_MOD_REPOSITORY_DETAILS + +#include // database + +#include + +#include +#include + +namespace brep +{ + class repository_details: public module + { + public: + virtual bool + handle (request&, response&); + + virtual const cli::options& + cli_options () const {return options::repository_details::description ();} + + private: + virtual void + init (cli::scanner&); + + private: + shared_ptr options_; + shared_ptr db_; + }; +} + +#endif // BREP_MOD_REPOSITORY_DETAILS diff --git a/brep/mod-repository-details.cxx b/brep/mod-repository-details.cxx new file mode 100644 index 0000000..a1a0fa5 --- /dev/null +++ b/brep/mod-repository-details.cxx @@ -0,0 +1,112 @@ +// file : brep/mod-repository-details.cxx -*- C++ -*- +// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#include + +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +using namespace odb::core; +using namespace brep::cli; + +void brep::repository_details:: +init (scanner& s) +{ + MODULE_DIAG; + + options_ = make_shared ( + s, unknown_mode::fail, unknown_mode::fail); + + if (options_->root ().empty ()) + options_->root (dir_path ("/")); + + db_ = shared_database (*options_); +} + +bool brep::repository_details:: +handle (request& rq, response& rs) +{ + using namespace web::xhtml; + + MODULE_DIAG; + + // The module options object is not changed after being created once per + // server process. + // + static const dir_path& root (options_->root ()); + + // Make sure no parameters passed. + // + try + { + name_value_scanner s (rq.parameters ()); + params::repository_details (s, unknown_mode::fail, unknown_mode::fail); + } + catch (const unknown_argument& e) + { + throw invalid_request (400, e.what ()); + } + + static const string title ("About"); + xml::serializer s (rs.content (), title); + + s << HTML + << HEAD + << TITLE << title << ~TITLE + << CSS_LINKS (path ("repository-details.css"), root) + << ~HEAD + << BODY + << DIV_HEADER (root) + << DIV(ID="content"); + + transaction t (db_->begin ()); + + using query = query; + + for (const auto& r: + db_->query ( + query::internal + "ORDER BY" + query::priority)) + { + //@@ Feels like a lot of trouble (e.g., id_attribute()) for very + // dubious value. A link to the package search page just for + // this repository would probably be more useful. + // + string id (html_id (r.name)); + s << H1(ID=id) + << A(HREF="#" + web::mime_url_encode (id)) << r.display_name << ~A + << ~H1; + + if (r.summary) + s << H2 << *r.summary << ~H2; + + if (r.description) + s << P_DESCRIPTION (*r.description); + + if (r.email) + s << P << A(HREF="mailto:" + *r.email) << *r.email << ~A << ~P; + } + + t.commit (); + + s << ~DIV + << ~BODY + << ~HTML; + + return true; +} diff --git a/brep/mod-repository-root b/brep/mod-repository-root new file mode 100644 index 0000000..9030ee8 --- /dev/null +++ b/brep/mod-repository-root @@ -0,0 +1,53 @@ +// file : brep/mod-repository-root -*- C++ -*- +// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#ifndef BREP_MOD_REPOSITORY_ROOT +#define BREP_MOD_REPOSITORY_ROOT + +#include + +#include +#include + +namespace brep +{ + class package_search; + class package_details; + class package_version_details; + class repository_details; + + class repository_root: public module + { + public: + repository_root (); + + private: + virtual bool + handle (request&, response&); + + virtual const cli::options& + cli_options () const {return options::repository_root::description ();} + + virtual option_descriptions + options (); + + virtual void + init (const name_values&); + + virtual void + init (cli::scanner&); + + virtual void + version (); + + private: + shared_ptr package_search_; + shared_ptr package_details_; + shared_ptr package_version_details_; + shared_ptr repository_details_; + shared_ptr options_; + }; +} + +#endif // BREP_MOD_REPOSITORY_ROOT diff --git a/brep/mod-repository-root.cxx b/brep/mod-repository-root.cxx new file mode 100644 index 0000000..695a5c7 --- /dev/null +++ b/brep/mod-repository-root.cxx @@ -0,0 +1,202 @@ +// file : brep/mod-repository-root.cxx -*- C++ -*- +// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#include + +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace brep::cli; + +namespace brep +{ + // request_proxy + // + class request_proxy: public request + { + public: + request_proxy (request& r, const name_values& p) + : request_ (r), parameters_ (p) {} + + virtual const path_type& + path () {return request_.path ();} + + virtual const name_values& + parameters () {return parameters_;} + + virtual const name_values& + cookies () {return request_.cookies ();} + + virtual istream& + content () {return request_.content ();} + + private: + request& request_; + const name_values& parameters_; + }; + + // repository_root + // + repository_root:: + repository_root () + : package_search_ (make_shared ()), + package_details_ (make_shared ()), + package_version_details_ (make_shared ()), + repository_details_ (make_shared ()) + { + } + + // Return amalgamation of repository_root and all its sub-modules option + // descriptions. + // + option_descriptions repository_root:: + options () + { + option_descriptions r (module::options ()); + append (r, package_search_->options ()); + append (r, package_details_->options ()); + append (r, package_version_details_->options ()); + append (r, repository_details_->options ()); + return r; + } + + // Initialize sub-modules and parse own configuration options. + // + void repository_root:: + init (const name_values& v) + { + auto sub_init ([this, &v](module& m) + { + m.init (filter (v, m.options ()), *log_); + }); + + // Initialize sub-modules. + // + sub_init (*package_search_); + sub_init (*package_details_); + sub_init (*package_version_details_); + sub_init (*repository_details_); + + // Parse own configuration options. + // + module::init ( + filter (v, convert (options::repository_root::description ()))); + } + + void repository_root:: + init (scanner& s) + { + MODULE_DIAG; + + options_ = make_shared ( + s, unknown_mode::fail, unknown_mode::fail); + + if (options_->root ().empty ()) + options_->root (dir_path ("/")); + } + + bool repository_root:: + handle (request& rq, response& rs) + { + MODULE_DIAG; + + static const dir_path& root (options_->root ()); + + const path& rpath (rq.path ()); + if (!rpath.sub (root)) + return false; + + const path& lpath (rpath.leaf (root)); + + // @@ An exception thrown by the selected module handle () function call + // will be attributed to the repository-root service while being logged. + // Could intercept exception handling to add some sub-module attribution, + // but let's not complicate the code for the time being. + // + if (lpath.empty ()) + { + // Dispatch request handling to the repository_details or the + // package_search module depending on the function name passed as a + // first HTTP request parameter. The parameter should have no value + // specified. Example: cppget.org/?about + // + const name_values& params (rq.parameters ()); + if (!params.empty () && !params.front ().value) + { + if (params.front ().name == "about") + { + // Cleanup not to confuse the selected module with the unknown + // parameter. + // + name_values p (params); + p.erase (p.begin ()); + + request_proxy rp (rq, p); + repository_details m (*repository_details_); + return m.handle (rp, rs); + } + + throw invalid_request (400, "unknown function"); + } + else + { + package_search m (*package_search_); + return m.handle (rq, rs); + } + } + else + { + // Dispatch request handling to the package_details or the + // package_version_details module depending on the HTTP request URL path. + // + auto i (lpath.begin ()); + assert (i != lpath.end ()); + + const string& n (*i++); // Package name. + + // Check if this is a package name and not a brep static content files + // (CSS) directory name or a repository directory name. + // + if (n != "@" && n.find_first_not_of ("0123456789") != string::npos) + { + if (i == lpath.end ()) + { + package_details m (*package_details_); + return m.handle (rq, rs); + } + else if (++i == lpath.end ()) + { + package_version_details m (*package_version_details_); + return m.handle (rq, rs); + } + } + } + + return false; + } + + void repository_root:: + version () + { + MODULE_DIAG; + + info << "module " << BREP_VERSION_STR + << ", libbrep " << LIBBREP_VERSION_STR + << ", libbpkg " << LIBBPKG_VERSION_STR + << ", libbutl " << LIBBUTL_VERSION_STR; + } +} diff --git a/brep/package-details b/brep/package-details deleted file mode 100644 index 6766797..0000000 --- a/brep/package-details +++ /dev/null @@ -1,36 +0,0 @@ -// file : brep/package-details -*- C++ -*- -// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd -// license : MIT; see accompanying LICENSE file - -#ifndef BREP_PACKAGE_DETAILS -#define BREP_PACKAGE_DETAILS - -#include // database - -#include - -#include -#include - -namespace brep -{ - class package_details: public module - { - public: - virtual bool - handle (request&, response&); - - virtual const cli::options& - cli_options () const {return options::package_details::description ();} - - private: - virtual void - init (cli::scanner&); - - private: - shared_ptr options_; - shared_ptr db_; - }; -} - -#endif // BREP_PACKAGE_DETAILS diff --git a/brep/package-details.cxx b/brep/package-details.cxx deleted file mode 100644 index a10f668..0000000 --- a/brep/package-details.cxx +++ /dev/null @@ -1,242 +0,0 @@ -// file : brep/package-details.cxx -*- C++ -*- -// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd -// license : MIT; see accompanying LICENSE file - -#include - -#include - -#include -#include -#include - -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include - -using namespace odb::core; -using namespace brep::cli; - -void brep::package_details:: -init (scanner& s) -{ - MODULE_DIAG; - - options_ = make_shared ( - s, unknown_mode::fail, unknown_mode::fail); - - if (options_->root ().empty ()) - options_->root (dir_path ("/")); - - db_ = shared_database (*options_); -} - -template -static inline query -search_params (const brep::string& n, const brep::string& q) -{ - using query = query; - - return "(" + - (q.empty () - ? query ("NULL") - : "plainto_tsquery (" + query::_val (q) + ")") + - "," + - query::_val (n) + - ")"; -} - -bool brep::package_details:: -handle (request& rq, response& rs) -{ - using namespace web; - using namespace web::xhtml; - - MODULE_DIAG; - - // The module options object is not changed after being created once per - // server process. - // - static const size_t res_page (options_->search_results ()); - static const dir_path& root (options_->root ()); - - const string& name (*rq.path ().rbegin ()); - const string ename (mime_url_encode (name)); - - params::package_details params; - bool full; - - try - { - name_value_scanner s (rq.parameters ()); - params = params::package_details ( - s, unknown_mode::fail, unknown_mode::fail); - - full = params.form () == page_form::full; - } - catch (const cli::exception& e) - { - throw invalid_request (400, e.what ()); - } - - size_t page (params.page ()); - const string& squery (params.query ()); - - auto url ( - [&ename](bool f = false, - const string& q = "", - size_t p = 0, - const string& a = "") -> string - { - string s ("?"); - string u (ename); - - if (f) { u += "?f=full"; s = "&"; } - if (!q.empty ()) { u += s + "q=" + mime_url_encode (q); s = "&"; } - if (p > 0) { u += s + "p=" + to_string (p); s = "&"; } - if (!a.empty ()) { u += '#' + a; } - return u; - }); - - xml::serializer s (rs.content (), name); - - s << HTML - << HEAD - << TITLE - << name; - - if (!squery.empty ()) - s << " " << squery; - - s << ~TITLE - << CSS_LINKS (path ("package-details.css"), root) - << ~HEAD - << BODY - << DIV_HEADER (root) - << DIV(ID="content"); - - if (full) - s << CLASS("full"); - - s << DIV(ID="heading") - << H1 << A(HREF=url ()) << name << ~A << ~H1 - << A(HREF=url (!full, squery, page)) - << (full ? "[brief]" : "[full]") - << ~A - << ~DIV; - - session sn; - transaction t (db_->begin ()); - - shared_ptr pkg; - { - latest_package lp; - if (!db_->query_one ( - query( - "(" + query::_val (name) + ")"), lp)) - throw invalid_request (404, "Package '" + name + "' not found"); - - pkg = db_->load (lp.id); - } - - const auto& licenses (pkg->license_alternatives); - - if (page == 0) - { - // Display package details on the first page only. - // - 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, squery, page, id))); - - s << TABLE(CLASS="proplist", ID="package") - << TBODY - << TR_LICENSE (licenses) - << TR_URL (pkg->url) - << TR_EMAIL (pkg->email) - << TR_TAGS (pkg->tags, root) - << ~TBODY - << ~TABLE; - } - - auto pkg_count ( - db_->query_value ( - search_params (name, squery))); - - s << FORM_SEARCH (squery) - << DIV_COUNTER (pkg_count, "Version", "Versions"); - - // Enclose the subsequent tables to be able to use nth-child CSS selector. - // - s << DIV; - for (const auto& pr: - db_->query ( - search_params (name, squery) + - "ORDER BY rank DESC, version_epoch DESC, " - "version_canonical_upstream DESC, version_revision DESC" + - "OFFSET" + to_string (page * res_page) + - "LIMIT" + to_string (res_page))) - { - shared_ptr p (db_->load (pr.id)); - - s << TABLE(CLASS="proplist version") - << TBODY - << TR_VERSION (name, p->version.string (), root) - - // @@ Shouldn't we skip low priority row ? Don't think so, why? - // - << TR_PRIORITY (p->priority); - - // Comparing objects of the license_alternatives class as being of the - // vector> class, so comments are not considered. - // - if (p->license_alternatives != licenses) - s << TR_LICENSE (p->license_alternatives); - - assert (p->internal ()); - - // @@ Shouldn't we make package location to be a link to the proper - // place of the About page, describing corresponding repository? - // Yes, I think that's sounds reasonable, once we have about. - // Or maybe it can be something more valuable like a link to the - // repository package search page ? - // - // @@ In most cases package location will be the same for all versions - // of the same package. Shouldn't we put package location to the - // package summary part and display it here only if it differs - // from the one in the summary ? - // - // Hm, I am not so sure about this. Consider: stable/testing/unstable. - // - s << TR_LOCATION (p->internal_repository.object_id (), root) - << TR_DEPENDS (p->dependencies, root) - << TR_REQUIRES (p->requirements) - << ~TBODY - << ~TABLE; - } - s << ~DIV; - - t.commit (); - - s << DIV_PAGER (page, pkg_count, res_page, options_->search_pages (), - url (full, squery)) - << ~DIV - << ~BODY - << ~HTML; - - return true; -} diff --git a/brep/package-search b/brep/package-search deleted file mode 100644 index 63ec6e0..0000000 --- a/brep/package-search +++ /dev/null @@ -1,36 +0,0 @@ -// file : brep/package-search -*- C++ -*- -// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd -// license : MIT; see accompanying LICENSE file - -#ifndef BREP_PACKAGE_SEARCH -#define BREP_PACKAGE_SEARCH - -#include // database - -#include - -#include -#include - -namespace brep -{ - class package_search: public module - { - public: - virtual bool - handle (request&, response&); - - virtual const cli::options& - cli_options () const {return options::package_search::description ();} - - private: - virtual void - init (cli::scanner&); - - private: - shared_ptr options_; - shared_ptr db_; - }; -} - -#endif // BREP_PACKAGE_SEARCH diff --git a/brep/package-search.cxx b/brep/package-search.cxx deleted file mode 100644 index 0e093b9..0000000 --- a/brep/package-search.cxx +++ /dev/null @@ -1,148 +0,0 @@ -// file : brep/package-search.cxx -*- C++ -*- -// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd -// license : MIT; see accompanying LICENSE file - -#include - -#include - -#include -#include -#include - -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include - -using namespace odb::core; -using namespace brep::cli; - -void brep::package_search:: -init (scanner& s) -{ - MODULE_DIAG; - - options_ = make_shared ( - s, unknown_mode::fail, unknown_mode::fail); - - if (options_->root ().empty ()) - options_->root (dir_path ("/")); - - db_ = shared_database (*options_); -} - -template -static inline query -search_param (const brep::string& q) -{ - using query = query; - return "(" + - (q.empty () - ? query ("NULL") - : "plainto_tsquery (" + query::_val (q) + ")") + - ")"; -} - -bool brep::package_search:: -handle (request& rq, response& rs) -{ - using namespace web::xhtml; - - MODULE_DIAG; - - // The module options object is not changed after being created once per - // server process. - // - static const size_t res_page (options_->search_results ()); - static const dir_path& root (options_->root ()); - - params::package_search params; - - try - { - name_value_scanner s (rq.parameters ()); - params = params::package_search (s, unknown_mode::fail, unknown_mode::fail); - } - catch (const unknown_argument& e) - { - throw invalid_request (400, e.what ()); - } - - size_t page (params.page ()); - const string& squery (params.query ()); - string squery_param (squery.empty () - ? "" - : "?q=" + web::mime_url_encode (squery)); - - static const string title ("Packages"); - xml::serializer s (rs.content (), title); - - s << HTML - << HEAD - << TITLE - << title; - - if (!squery.empty ()) - s << " " << squery; - - s << ~TITLE - << CSS_LINKS (path ("package-search.css"), root) - << ~HEAD - << BODY - << DIV_HEADER (root) - << DIV(ID="content"); - - session sn; - transaction t (db_->begin ()); - - auto pkg_count ( - db_->query_value ( - search_param (squery))); - - s << FORM_SEARCH (squery) - << DIV_COUNTER (pkg_count, "Package", "Packages"); - - // Enclose the subsequent tables to be able to use nth-child CSS selector. - // - s << DIV; - for (const auto& pr: - db_->query ( - search_param (squery) + - "ORDER BY rank DESC, name" + - "OFFSET" + to_string (page * res_page) + - "LIMIT" + to_string (res_page))) - { - shared_ptr p (db_->load (pr.id)); - - s << TABLE(CLASS="proplist package") - << TBODY - << TR_NAME (p->id.name, squery_param, root) - << TR_SUMMARY (p->summary) - << TR_LICENSE (p->license_alternatives) - << TR_TAGS (p->tags, root) - << TR_DEPENDS (p->dependencies, root) - << TR_REQUIRES (p->requirements) - << ~TBODY - << ~TABLE; - } - s << ~DIV; - - t.commit (); - - s << DIV_PAGER (page, pkg_count, res_page, options_->search_pages (), - root.string () + squery_param) - << ~DIV - << ~BODY - << ~HTML; - - return true; -} diff --git a/brep/package-version-details b/brep/package-version-details deleted file mode 100644 index 8057097..0000000 --- a/brep/package-version-details +++ /dev/null @@ -1,39 +0,0 @@ -// file : brep/package-version-details -*- C++ -*- -// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd -// license : MIT; see accompanying LICENSE file - -#ifndef BREP_PACKAGE_VERSION_DETAILS -#define BREP_PACKAGE_VERSION_DETAILS - -#include // database - -#include - -#include -#include - -namespace brep -{ - class package_version_details: public module - { - public: - virtual bool - handle (request&, response&); - - virtual const cli::options& - cli_options () const - { - return options::package_version_details::description (); - } - - private: - virtual void - init (cli::scanner&); - - private: - shared_ptr options_; - shared_ptr db_; - }; -} - -#endif // BREP_PACKAGE_VERSION_DETAILS diff --git a/brep/package-version-details.cxx b/brep/package-version-details.cxx deleted file mode 100644 index 0300b88..0000000 --- a/brep/package-version-details.cxx +++ /dev/null @@ -1,315 +0,0 @@ -// file : brep/package-version-details.cxx -*- C++ -*- -// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd -// license : MIT; see accompanying LICENSE file - -#include - -#include // invalid_argument - -#include - -#include -#include -#include - -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include - -using namespace std; -using namespace odb::core; -using namespace brep::cli; - -void brep::package_version_details:: -init (scanner& s) -{ - MODULE_DIAG; - - options_ = make_shared ( - s, unknown_mode::fail, unknown_mode::fail); - - if (options_->root ().empty ()) - options_->root (dir_path ("/")); - - db_ = shared_database (*options_); -} - -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; - - // The module options object is not changed after being created once per - // server process. - // - static 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) - << 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 pkg; - - session sn; - transaction t (db_->begin ()); - - try - { - pkg = db_->load (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); - - 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 ()) - << ~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 p (d.package.load ()); - assert (p->internal () || !p->other_repositories.empty ()); - - shared_ptr 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; -} diff --git a/brep/repository-details b/brep/repository-details deleted file mode 100644 index 7efc6a6..0000000 --- a/brep/repository-details +++ /dev/null @@ -1,36 +0,0 @@ -// file : brep/repository-details -*- C++ -*- -// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd -// license : MIT; see accompanying LICENSE file - -#ifndef BREP_REPOSITORY_DETAILS -#define BREP_REPOSITORY_DETAILS - -#include // database - -#include - -#include -#include - -namespace brep -{ - class repository_details: public module - { - public: - virtual bool - handle (request&, response&); - - virtual const cli::options& - cli_options () const {return options::repository_details::description ();} - - private: - virtual void - init (cli::scanner&); - - private: - shared_ptr options_; - shared_ptr db_; - }; -} - -#endif // BREP_REPOSITORY_DETAILS diff --git a/brep/repository-details.cxx b/brep/repository-details.cxx deleted file mode 100644 index 0d71ac8..0000000 --- a/brep/repository-details.cxx +++ /dev/null @@ -1,112 +0,0 @@ -// file : brep/repository-details.cxx -*- C++ -*- -// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd -// license : MIT; see accompanying LICENSE file - -#include - -#include - -#include -#include - -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include - -using namespace odb::core; -using namespace brep::cli; - -void brep::repository_details:: -init (scanner& s) -{ - MODULE_DIAG; - - options_ = make_shared ( - s, unknown_mode::fail, unknown_mode::fail); - - if (options_->root ().empty ()) - options_->root (dir_path ("/")); - - db_ = shared_database (*options_); -} - -bool brep::repository_details:: -handle (request& rq, response& rs) -{ - using namespace web::xhtml; - - MODULE_DIAG; - - // The module options object is not changed after being created once per - // server process. - // - static const dir_path& root (options_->root ()); - - // Make sure no parameters passed. - // - try - { - name_value_scanner s (rq.parameters ()); - params::repository_details (s, unknown_mode::fail, unknown_mode::fail); - } - catch (const unknown_argument& e) - { - throw invalid_request (400, e.what ()); - } - - static const string title ("About"); - xml::serializer s (rs.content (), title); - - s << HTML - << HEAD - << TITLE << title << ~TITLE - << CSS_LINKS (path ("repository-details.css"), root) - << ~HEAD - << BODY - << DIV_HEADER (root) - << DIV(ID="content"); - - transaction t (db_->begin ()); - - using query = query; - - for (const auto& r: - db_->query ( - query::internal + "ORDER BY" + query::priority)) - { - //@@ Feels like a lot of trouble (e.g., id_attribute()) for very - // dubious value. A link to the package search page just for - // this repository would probably be more useful. - // - string id (html_id (r.name)); - s << H1(ID=id) - << A(HREF="#" + web::mime_url_encode (id)) << r.display_name << ~A - << ~H1; - - if (r.summary) - s << H2 << *r.summary << ~H2; - - if (r.description) - s << P_DESCRIPTION (*r.description); - - if (r.email) - s << P << A(HREF="mailto:" + *r.email) << *r.email << ~A << ~P; - } - - t.commit (); - - s << ~DIV - << ~BODY - << ~HTML; - - return true; -} diff --git a/brep/repository-root b/brep/repository-root deleted file mode 100644 index 006f163..0000000 --- a/brep/repository-root +++ /dev/null @@ -1,53 +0,0 @@ -// file : brep/repository-root -*- C++ -*- -// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd -// license : MIT; see accompanying LICENSE file - -#ifndef BREP_REPOSITORY_ROOT -#define BREP_REPOSITORY_ROOT - -#include - -#include -#include - -namespace brep -{ - class package_search; - class package_details; - class package_version_details; - class repository_details; - - class repository_root: public module - { - public: - repository_root (); - - private: - virtual bool - handle (request&, response&); - - virtual const cli::options& - cli_options () const {return options::repository_root::description ();} - - virtual option_descriptions - options (); - - virtual void - init (const name_values&); - - virtual void - init (cli::scanner&); - - virtual void - version (); - - private: - shared_ptr package_search_; - shared_ptr package_details_; - shared_ptr package_version_details_; - shared_ptr repository_details_; - shared_ptr options_; - }; -} - -#endif // BREP_REPOSITORY_ROOT diff --git a/brep/repository-root.cxx b/brep/repository-root.cxx deleted file mode 100644 index 5711109..0000000 --- a/brep/repository-root.cxx +++ /dev/null @@ -1,202 +0,0 @@ -// file : brep/repository-root.cxx -*- C++ -*- -// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd -// license : MIT; see accompanying LICENSE file - -#include - -#include - -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -using namespace std; -using namespace brep::cli; - -namespace brep -{ - // request_proxy - // - class request_proxy: public request - { - public: - request_proxy (request& r, const name_values& p) - : request_ (r), parameters_ (p) {} - - virtual const path_type& - path () {return request_.path ();} - - virtual const name_values& - parameters () {return parameters_;} - - virtual const name_values& - cookies () {return request_.cookies ();} - - virtual istream& - content () {return request_.content ();} - - private: - request& request_; - const name_values& parameters_; - }; - - // repository_root - // - repository_root:: - repository_root () - : package_search_ (make_shared ()), - package_details_ (make_shared ()), - package_version_details_ (make_shared ()), - repository_details_ (make_shared ()) - { - } - - // Return amalgamation of repository_root and all its sub-modules option - // descriptions. - // - option_descriptions repository_root:: - options () - { - option_descriptions r (module::options ()); - append (r, package_search_->options ()); - append (r, package_details_->options ()); - append (r, package_version_details_->options ()); - append (r, repository_details_->options ()); - return r; - } - - // Initialize sub-modules and parse own configuration options. - // - void repository_root:: - init (const name_values& v) - { - auto sub_init ([this, &v](module& m) - { - m.init (filter (v, m.options ()), *log_); - }); - - // Initialize sub-modules. - // - sub_init (*package_search_); - sub_init (*package_details_); - sub_init (*package_version_details_); - sub_init (*repository_details_); - - // Parse own configuration options. - // - module::init ( - filter (v, convert (options::repository_root::description ()))); - } - - void repository_root:: - init (scanner& s) - { - MODULE_DIAG; - - options_ = make_shared ( - s, unknown_mode::fail, unknown_mode::fail); - - if (options_->root ().empty ()) - options_->root (dir_path ("/")); - } - - bool repository_root:: - handle (request& rq, response& rs) - { - MODULE_DIAG; - - static const dir_path& root (options_->root ()); - - const path& rpath (rq.path ()); - if (!rpath.sub (root)) - return false; - - const path& lpath (rpath.leaf (root)); - - // @@ An exception thrown by the selected module handle () function call - // will be attributed to the repository-root service while being logged. - // Could intercept exception handling to add some sub-module attribution, - // but let's not complicate the code for the time being. - // - if (lpath.empty ()) - { - // Dispatch request handling to the repository_details or the - // package_search module depending on the function name passed as a - // first HTTP request parameter. The parameter should have no value - // specified. Example: cppget.org/?about - // - const name_values& params (rq.parameters ()); - if (!params.empty () && !params.front ().value) - { - if (params.front ().name == "about") - { - // Cleanup not to confuse the selected module with the unknown - // parameter. - // - name_values p (params); - p.erase (p.begin ()); - - request_proxy rp (rq, p); - repository_details m (*repository_details_); - return m.handle (rp, rs); - } - - throw invalid_request (400, "unknown function"); - } - else - { - package_search m (*package_search_); - return m.handle (rq, rs); - } - } - else - { - // Dispatch request handling to the package_details or the - // package_version_details module depending on the HTTP request URL path. - // - auto i (lpath.begin ()); - assert (i != lpath.end ()); - - const string& n (*i++); // Package name. - - // Check if this is a package name and not a brep static content files - // (CSS) directory name or a repository directory name. - // - if (n != "@" && n.find_first_not_of ("0123456789") != string::npos) - { - if (i == lpath.end ()) - { - package_details m (*package_details_); - return m.handle (rq, rs); - } - else if (++i == lpath.end ()) - { - package_version_details m (*package_version_details_); - return m.handle (rq, rs); - } - } - } - - return false; - } - - void repository_root:: - version () - { - MODULE_DIAG; - - info << "module " << BREP_VERSION_STR - << ", libbrep " << LIBBREP_VERSION_STR - << ", libbpkg " << LIBBPKG_VERSION_STR - << ", libbutl " << LIBBUTL_VERSION_STR; - } -} diff --git a/brep/services.cxx b/brep/services.cxx index dcac22c..b600717 100644 --- a/brep/services.cxx +++ b/brep/services.cxx @@ -6,7 +6,7 @@ #include -#include +#include static brep::repository_root mod; web::apache::service AP_MODULE_DECLARE_DATA brep_module ("brep", mod); diff --git a/brep/shared-database b/brep/shared-database deleted file mode 100644 index b445cc1..0000000 --- a/brep/shared-database +++ /dev/null @@ -1,25 +0,0 @@ -// file : brep/shared-database -*- C++ -*- -// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd -// license : MIT; see accompanying LICENSE file - -#ifndef BREP_SHARED_DATABASE -#define BREP_SHARED_DATABASE - -#include // database - -#include - -#include - -namespace brep -{ - // Returns pointer to the shared database instance, creating one on the - // first call. On subsequent calls ensures passed host and port equals - // to ones of the existing database instance throwing runtime_error - // otherwise. Is not thread-safe. - // - shared_ptr - shared_database (const options::db&); -} - -#endif // BREP_SHARED_DATABASE diff --git a/brep/shared-database.cxx b/brep/shared-database.cxx deleted file mode 100644 index 1389dab..0000000 --- a/brep/shared-database.cxx +++ /dev/null @@ -1,48 +0,0 @@ -// file : brep/shared-database.cxx -*- C++ -*- -// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd -// license : MIT; see accompanying LICENSE file - -#include - -#include // runtime_error - -#include - -#include -#include - -namespace brep -{ - shared_ptr - shared_database (const options::db& o) - { - using odb::pgsql::database; - static weak_ptr db; - - // In C++11, function-static variable initialization is guaranteed to be - // thread-safe, thought this doesn't seem to be enough in our case - // (because we are re-initializing the weak pointer). - // - if (shared_ptr d = db.lock ()) - { - if (o.db_user () != d->user () || - o.db_password () != d->password () || - o.db_name () != d->db () || - o.db_host () != d->host () || - o.db_port () != d->port ()) - throw std::runtime_error ("shared database host/port mismatch"); - - return d; - } - else - { - d = make_shared (o.db_user (), - o.db_password (), - o.db_name (), - o.db_host (), - o.db_port ()); - db = d; - return d; - } - } -} -- cgit v1.1