diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2015-11-14 16:29:22 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2015-11-16 16:42:35 +0200 |
commit | 03905bcf1bcfd9e7932fcac4283c5817058a25ce (patch) | |
tree | b643d3bedf436bfcd8956b25133d5674b6b18e36 | |
parent | 96281a6c4f818311a6df90c0d8b8f537a61e1090 (diff) |
Invent root path web interface configuration option
-rw-r--r-- | brep/buildfile | 8 | ||||
-rw-r--r-- | brep/module.cxx | 3 | ||||
-rw-r--r-- | brep/options.cli | 3 | ||||
-rw-r--r-- | brep/package-details.cxx | 42 | ||||
-rw-r--r-- | brep/package-search.cxx | 31 | ||||
-rw-r--r-- | brep/package-version-details.cxx | 81 | ||||
-rw-r--r-- | brep/page | 36 | ||||
-rw-r--r-- | brep/page.cxx | 89 | ||||
-rw-r--r-- | brep/services.cxx | 6 | ||||
-rw-r--r-- | brep/types-parsers | 31 | ||||
-rw-r--r-- | brep/types-parsers.cxx | 47 | ||||
-rwxr-xr-x | build.sh | 5 | ||||
-rwxr-xr-x | etc/apachectl | 5 | ||||
-rw-r--r-- | etc/config | 1 | ||||
-rw-r--r-- | etc/httpd.conf | 19 | ||||
-rw-r--r-- | loader/buildfile | 2 | ||||
-rw-r--r-- | loader/loader.cxx | 14 | ||||
-rw-r--r-- | tests/loader/driver.cxx | 6 | ||||
-rw-r--r-- | tests/loader/external/1/misc/repositories | 2 | ||||
-rw-r--r-- | tests/loader/external/1/testing/repositories | 2 | ||||
-rw-r--r-- | web/apache/service | 2 | ||||
-rw-r--r-- | web/apache/service.cxx | 25 |
22 files changed, 318 insertions, 142 deletions
diff --git a/brep/buildfile b/brep/buildfile index 808de15..6676095 100644 --- a/brep/buildfile +++ b/brep/buildfile @@ -22,7 +22,9 @@ libso{brep}: cxx.export.poptions = -I$out_root -I$src_root import libs += libstudxml%lib{studxml} brep = cxx{diagnostics module services package-search package-details \ - package-version-details shared-database page} cli.cxx{options} + package-version-details shared-database page types-parsers} \ + cli.cxx{options} + web = ../web/apache/cxx{request service} ../web/cxx{mime-url-encoding} libso{brep-apache}: $brep $web libso{brep} $libs @@ -36,6 +38,8 @@ libso{brep-apache}: $brep $web libso{brep} $libs # ::cli::unknown_mode opt_mode, # cli.options += -I $src_root --include-with-brackets --include-prefix brep \ ---guard-prefix BREP --generate-file-scanner --suppress-usage --option-prefix "" +--guard-prefix BREP --cxx-prologue "#include <brep/types-parsers>" \ +--cli-namespace brep::cli --generate-file-scanner --suppress-usage \ +--option-prefix "" cli.cxx{options}: cli{options} diff --git a/brep/module.cxx b/brep/module.cxx index fa7f479..850f593 100644 --- a/brep/module.cxx +++ b/brep/module.cxx @@ -22,10 +22,11 @@ using namespace std; using namespace placeholders; // For std::bind's _1, etc. -using namespace cli; namespace brep { + using namespace cli; + // module // void module:: diff --git a/brep/options.cli b/brep/options.cli index 86cb70c..6c3c7f1 100644 --- a/brep/options.cli +++ b/brep/options.cli @@ -5,6 +5,8 @@ include <string>; include <cstdint>; // uint16_t +include <butl/path>; + namespace brep { // Web module configuration options. @@ -14,6 +16,7 @@ namespace brep class module { std::uint16_t verb = 0; + butl::dir_path root = "/"; }; class db diff --git a/brep/package-details.cxx b/brep/package-details.cxx index 12480c8..ef787b0 100644 --- a/brep/package-details.cxx +++ b/brep/package-details.cxx @@ -7,6 +7,7 @@ #include <string> #include <memory> // make_shared(), shared_ptr #include <cstddef> // size_t +#include <cassert> #include <xml/serializer> @@ -25,11 +26,12 @@ #include <brep/shared-database> using namespace std; -using namespace cli; using namespace odb::core; namespace brep { + using namespace cli; + void package_details:: init (scanner& s) { @@ -65,7 +67,15 @@ namespace brep MODULE_DIAG; + // The module options object is not changed after being created once per + // server process. + // + static const size_t rp (options_->results_on_page ()); + static const dir_path& rt (options_->root ()); + const string& name (*rq.path ().rbegin ()); + const string en (mime_url_encode (name)); + params::package_details pr; try @@ -81,8 +91,6 @@ namespace brep const string& sq (pr.query ()); // Search query. size_t pg (pr.page ()); bool f (pr.full ()); - string en (mime_url_encode (name)); - size_t rp (options_->results_on_page ()); auto url ( [&en](bool f = false, @@ -101,19 +109,20 @@ namespace brep }); serializer s (rs.content (), name); - const string title (sq.empty () ? name : name + " " + sq); + const string& title (sq.empty () ? name : name + " " + sq); + static const path sp ("package-details.css"); s << HTML << HEAD << TITLE << title << ~TITLE - << CSS_LINKS ("/package-details.css") + << CSS_LINKS (sp, rt) << ~HEAD << BODY - << DIV_HEADER () + << DIV_HEADER (rt) << DIV(ID="content"); if (f) - s << CLASS << "full" << ~CLASS; + s << CLASS("full"); s << DIV(ID="heading") << H1 << A(HREF=url ()) << name << ~A << ~H1 @@ -136,7 +145,7 @@ namespace brep p = db_->load<package> (lp.id); } - const license_alternatives& ll (p->license_alternatives); + const auto& ll (p->license_alternatives); if (pg == 0) { @@ -144,20 +153,19 @@ namespace brep // s << H2 << p->summary << ~H2; + static const size_t dl (options_->description_length ()); + if (const auto& d = p->description) s << (f ? P_DESCRIPTION (*d) - : P_DESCRIPTION ( - *d, - options_->description_length (), - url (!f, sq, pg, "description"))); + : P_DESCRIPTION (*d, dl, url (!f, sq, pg, "description"))); s << TABLE(CLASS="proplist", ID="package") << TBODY << TR_LICENSE (ll) << TR_URL (p->url) << TR_EMAIL (p->email) - << TR_TAGS (p->tags) + << TR_TAGS (p->tags, rt) << ~TBODY << ~TABLE; } @@ -186,7 +194,7 @@ namespace brep s << TABLE(CLASS="proplist version") << TBODY - << TR_VERSION (name, p->version.string ()) + << TR_VERSION (name, p->version.string (), rt) // @@ Shouldn't we skip low priority row ? Don't think so, why? // @@ -212,7 +220,7 @@ namespace brep // Hm, I am not so sure about this. Consider: stable/testing/unstable. // s << TR_LOCATION (p->internal_repository.object_id ()) - << TR_DEPENDS (p->dependencies) + << TR_DEPENDS (p->dependencies, rt) << TR_REQUIRES (p->requirements) << ~TBODY << ~TABLE; @@ -221,7 +229,9 @@ namespace brep t.commit (); - s << DIV_PAGER (pg, pc, rp, options_->pages_in_pager (), url (f, sq)) + static const size_t pp (options_->pages_in_pager ()); + + s << DIV_PAGER (pg, pc, rp, pp, url (f, sq)) << ~DIV << ~BODY << ~HTML; diff --git a/brep/package-search.cxx b/brep/package-search.cxx index 47f53e9..b0352f3 100644 --- a/brep/package-search.cxx +++ b/brep/package-search.cxx @@ -5,7 +5,7 @@ #include <brep/package-search> #include <string> -#include <memory> // make_shared() +#include <memory> // make_shared(), shared_ptr #include <cstddef> // size_t #include <xml/serializer> @@ -25,11 +25,12 @@ #include <brep/shared-database> using namespace std; -using namespace cli; using namespace odb::core; namespace brep { + using namespace cli; + void package_search:: init (scanner& s) { @@ -62,6 +63,12 @@ namespace brep MODULE_DIAG; + // The module options object is not changed after being created once per + // server process. + // + static const size_t rp (options_->results_on_page ()); + static const dir_path& rt (options_->root ()); + params::package_search pr; try @@ -75,22 +82,23 @@ namespace brep } const string& sq (pr.query ()); // Search query. - size_t pg (pr.page ()); string qp (sq.empty () ? "" : "q=" + mime_url_encode (sq)); - size_t rp (options_->results_on_page ()); + size_t pg (pr.page ()); serializer s (rs.content (), "Packages"); const string& title ( sq.empty () ? s.output_name () : s.output_name () + " " + sq); + static const path sp ("package-search.css"); + s << HTML << HEAD << TITLE << title << ~TITLE - << CSS_LINKS ("/package-search.css") + << CSS_LINKS (sp, rt) << ~HEAD << BODY - << DIV_HEADER () + << DIV_HEADER (rt) << DIV(ID="content"); session sn; @@ -119,11 +127,11 @@ namespace brep s << TABLE(CLASS="proplist package") << TBODY - << TR_NAME (p->id.name, qp) + << TR_NAME (p->id.name, qp, rt) << TR_SUMMARY (p->summary) << TR_LICENSE (p->license_alternatives) - << TR_TAGS (p->tags) - << TR_DEPENDS (p->dependencies) + << TR_TAGS (p->tags, rt) + << TR_DEPENDS (p->dependencies, rt) << TR_REQUIRES (p->requirements) << ~TBODY << ~TABLE; @@ -132,9 +140,10 @@ namespace brep t.commit (); - string url (qp.empty () ? "/" : ("/?" + qp)); + static const size_t pp (options_->pages_in_pager ()); + const string& u (qp.empty () ? rt.string () : (rt.string () + "?" + qp)); - s << DIV_PAGER (pg, pc, rp, options_->pages_in_pager (), url) + s << DIV_PAGER (pg, pc, rp, pp, u) << ~DIV << ~BODY << ~HTML; diff --git a/brep/package-version-details.cxx b/brep/package-version-details.cxx index ce25a44..b8f30ff 100644 --- a/brep/package-version-details.cxx +++ b/brep/package-version-details.cxx @@ -26,11 +26,12 @@ #include <brep/shared-database> using namespace std; -using namespace cli; using namespace odb::core; namespace brep { + using namespace cli; + void package_version_details:: init (scanner& s) { @@ -51,6 +52,11 @@ namespace brep MODULE_DIAG; + // The module options object is not changed after being created once per + // server process. + // + static const dir_path& rt (options_->root ()); + auto i (rq.path ().rbegin ()); version v; @@ -63,8 +69,11 @@ namespace brep throw invalid_request (400, "invalid package version format"); } + const string& vs (v.string ()); + assert (i != rq.path ().rend ()); const string& n (*i); // Package name. + const string name (n + " " + vs); params::package_version_details pr; @@ -80,7 +89,6 @@ namespace brep } bool f (pr.full ()); - const string& vs (v.string ()); auto url ([&vs](bool f = false, const string& a = "") -> string { @@ -91,27 +99,25 @@ namespace brep return u; }); - const string name (n + " " + vs); serializer s (rs.content (), name); + static const path go ("go"); + static const path sp ("package-version-details.css"); s << HTML << HEAD << TITLE << name << ~TITLE - << CSS_LINKS ("/package-version-details.css") + << CSS_LINKS (sp, rt) << ~HEAD << BODY - << DIV_HEADER () + << DIV_HEADER (rt) << DIV(ID="content"); if (f) - s << CLASS << "full" << ~CLASS; + s << CLASS("full"); s << DIV(ID="heading") << H1 - << A - << HREF << "/go/" << mime_url_encode (n) << ~HREF - << n - << ~A + << A(HREF=rt / go / path (mime_url_encode (n))) << n << ~A << "/" << A(HREF=url ()) << vs << ~A << ~H1 @@ -143,17 +149,18 @@ namespace brep s << H2 << p->summary << ~H2; + static const size_t dl (options_->description_length ()); + if (const auto& d = p->description) s << (f ? P_DESCRIPTION (*d) - : P_DESCRIPTION ( - *d, options_->description_length (), url (!f, "description"))); + : P_DESCRIPTION (*d, dl, url (!f, "description"))); // Link to download from the internal repository. // assert (p->location); - const string du (p->internal_repository.load ()->location.string () + - "/" + p->location->string ()); + const string du (p->internal_repository.load ()->location.string () + "/" + + p->location->string ()); s << TABLE(CLASS="proplist", ID="version") << TBODY @@ -180,7 +187,7 @@ namespace brep if (p->package_email && *p->package_email != p->email) s << TR_EMAIL (*p->package_email, "pkg-email"); - s << TR_TAGS (p->tags) + s << TR_TAGS (p->tags, rt) << ~TBODY << ~TABLE; @@ -210,32 +217,36 @@ namespace brep s << " | "; shared_ptr<package> p (d.package.load ()); - string en (mime_url_encode (p->id.name)); - assert (p->internal () || !p->other_repositories.empty ()); + shared_ptr<repository> r ( p->internal () ? p->internal_repository.load () : p->other_repositories[0].load ()); - optional<string> u (r->url); // Repository web interface URL. - if (!u && p->internal ()) - u = ""; // Make URL to reference the current web interface. + const auto& dc (d.constraint); + const string& dn (p->id.name); + string en (mime_url_encode (dn)); - if (u) + if (r->url) { - s << A << HREF << *u << "/go/" << en << ~HREF << p->id.name << ~A; + string u (*r->url + "go/" + en); + s << A(HREF=u) << dn << ~A; - if (d.constraint) - { + if (dc) s << ' ' << A - << HREF - << *u << "/go/" << en << "/" << p->version.string () - << ~HREF - << *d.constraint + << HREF << u << "/" << p->version.string () << ~HREF + << *dc << ~A; - } + } + else if (p->internal ()) + { + path u (rt / go / path (en)); + s << A(HREF=u) << dn << ~A; + + if (dc) + s << ' ' << A(HREF=u / path (p->version.string ())) << *dc << ~A; } else // Display the dependency as a plain text in no repository URL @@ -256,15 +267,15 @@ namespace brep t.commit (); - const auto& rt (p->requirements); + const auto& rm (p->requirements); - if (!rt.empty ()) + if (!rm.empty ()) { s << H3 << "Requires" << ~H3 << TABLE(CLASS="proplist", ID="requires") << TBODY; - for (const auto& ra: rt) + for (const auto& ra: rm) { s << TR(CLASS="requires") << TH; @@ -294,14 +305,14 @@ namespace brep << ~TABLE; } - const string& ch (p->changes); + static const size_t cl (options_->changes_length ()); + const auto& ch (p->changes); if (!ch.empty ()) s << H3 << "Changes" << ~H3 << (f ? PRE_CHANGES (ch) - : PRE_CHANGES ( - ch, options_->changes_length (), url (!f, "changes"))); + : PRE_CHANGES (ch, cl, url (!f, "changes"))); s << ~DIV << ~BODY @@ -22,21 +22,29 @@ namespace brep class CSS_LINKS { public: - CSS_LINKS (const char* u): url_ (u) {} + CSS_LINKS (const path& p, const dir_path& r): + path_ (p), root_ (r) {} void operator() (xml::serializer& s) const; private: - const char* url_; + const path& path_; + const dir_path& root_; }; // Generates page header element. // - struct DIV_HEADER + class DIV_HEADER { + public: + DIV_HEADER (const dir_path& r): root_ (r) {} + void operator() (xml::serializer& s) const; + + private: + const dir_path& root_; }; // Generates package search form element. @@ -79,8 +87,8 @@ namespace brep class TR_NAME { public: - TR_NAME (const std::string& n, const std::string& q) - : name_ (n), query_param_ (q) {} + TR_NAME (const std::string& n, const std::string& q, const dir_path& r) + : name_ (n), query_param_ (q), root_ (r) {} void operator() (xml::serializer& s) const; @@ -88,6 +96,7 @@ namespace brep private: const std::string& name_; const std::string& query_param_; + const dir_path& root_; }; // Generates package version element. @@ -97,12 +106,15 @@ namespace brep public: // Display the version as a link to the package version details page. // - TR_VERSION (const std::string& p, const std::string& v) - : package_ (&p), version_ (v) {} + TR_VERSION (const std::string& p, + const std::string& v, + const dir_path& r) + : package_ (&p), version_ (v), root_ (&r) {} // Display the version as a regular text. // - TR_VERSION (const std::string& v): package_ (nullptr), version_ (v) {} + TR_VERSION (const std::string& v) + : package_ (nullptr), version_ (v), root_ (nullptr) {} void operator() (xml::serializer& s) const; @@ -110,6 +122,7 @@ namespace brep private: const std::string* package_; const std::string& version_; + const dir_path* root_; }; // Generates package summary element. @@ -160,13 +173,14 @@ namespace brep class TR_TAGS { public: - TR_TAGS (const strings& ts): tags_ (ts) {} + TR_TAGS (const strings& ts, const dir_path& r): tags_ (ts), root_ (r) {} void operator() (xml::serializer& s) const; private: const strings& tags_; + const dir_path& root_; }; // Generates package dependencies element. @@ -174,13 +188,15 @@ namespace brep class TR_DEPENDS { public: - TR_DEPENDS (const dependencies& d): dependencies_ (d) {} + TR_DEPENDS (const dependencies& d, const dir_path& r) + : dependencies_ (d), root_ (r) {} void operator() (xml::serializer& s) const; private: const dependencies& dependencies_; + const dir_path& root_; }; // Generates package requirements element. diff --git a/brep/page.cxx b/brep/page.cxx index 81a7de5..fbbcda8 100644 --- a/brep/page.cxx +++ b/brep/page.cxx @@ -7,8 +7,8 @@ #include <set> #include <string> #include <memory> // shared_ptr +#include <cstddef> // size_t #include <cassert> -#include <utility> // move() #include <algorithm> // min() #include <xml/serializer> @@ -26,13 +26,17 @@ using namespace web::xhtml; namespace brep { + static const path go ("go"); + // CSS_LINKS // void CSS_LINKS:: operator() (serializer& s) const { - s << *LINK(REL="stylesheet", TYPE="text/css", HREF="/common.css") - << *LINK(REL="stylesheet", TYPE="text/css", HREF=url_); + static const path c ("common.css"); + + s << *LINK(REL="stylesheet", TYPE="text/css", HREF=root_ / c) + << *LINK(REL="stylesheet", TYPE="text/css", HREF=root_ / path_); } // DIV_HEADER @@ -40,10 +44,12 @@ namespace brep void DIV_HEADER:: operator() (serializer& s) const { + static const path a ("about"); + s << DIV(ID="header") << DIV(ID="header-menu") - << A(HREF="/") << "packages" << ~A - << A(HREF="/about") << "about" << ~A + << A(HREF=root_) << "packages" << ~A + << A(HREF=root_ / a) << "about" << ~A << ~DIV << ~DIV; } @@ -97,7 +103,7 @@ namespace brep << SPAN(CLASS="value") << A << HREF - << "/go/" << mime_url_encode (name_); + << root_ / go / path (mime_url_encode (name_)); // Propagate search criteria to the package details page. // @@ -123,12 +129,11 @@ namespace brep if (package_ == nullptr) s << version_; else - s << A - << HREF - << "/go/" << mime_url_encode (*package_) << "/" << version_ - << ~HREF - << version_ - << ~A; + { + assert (root_ != nullptr); + path p (mime_url_encode (*package_)); + s << A(HREF=*root_ / go / p / path (version_)) << version_ << ~A; + } s << ~SPAN << ~TD @@ -156,28 +161,28 @@ namespace brep << TD << SPAN(CLASS="value"); - for (const auto& la: licenses_) - { - if (&la != &licenses_[0]) - s << " " << EM << "or" << ~EM << " "; - - bool m (la.size () > 1); + for (const auto& la: licenses_) + { + if (&la != &licenses_[0]) + s << " " << EM << "or" << ~EM << " "; - if (m) - s << "("; + bool m (la.size () > 1); - for (const auto& l: la) - { - if (&l != &la[0]) - s << " " << EM << "and" << ~EM << " "; + if (m) + s << "("; - s << l; - } + for (const auto& l: la) + { + if (&l != &la[0]) + s << " " << EM << "and" << ~EM << " "; - if (m) - s << ")"; + s << l; } + if (m) + s << ")"; + } + s << ~SPAN << ~TD << ~TR; @@ -227,7 +232,10 @@ namespace brep if (&t != &tags_[0]) s << " "; - s << A << HREF << "/?q=" << mime_url_encode (t) << ~HREF << t << ~A; + s << A + << HREF << root_ << "?q=" << mime_url_encode (t) << ~HREF + << t + << ~A; } s << ~SPAN @@ -283,22 +291,19 @@ namespace brep s << " | "; shared_ptr<package> p (da.package.load ()); - assert (p->internal () || !p->other_repositories.empty ()); + shared_ptr<repository> r ( p->internal () ? p->internal_repository.load () : p->other_repositories[0].load ()); - optional<string> u (r->url); // Repository web interface URL. - if (!u && p->internal ()) - u = ""; // Make URL to reference the current web interface. + auto en (mime_url_encode (n)); - if (u) - s << A - << HREF << *u << "/go/" << mime_url_encode (n) << ~HREF - << n - << ~A; + if (r->url) + s << A << HREF << *r->url << "go/" << en << ~HREF << n << ~A; + else if (p->internal ()) + s << A(HREF=root_ / go / path (en)) << n << ~A; else // Display the dependency as a plain text in no repository URL // available. @@ -471,7 +476,7 @@ namespace brep if (description_.empty ()) return; - string::size_type n (description_.find_first_of (" \t\n", length_)); + auto n (description_.find_first_of (" \t\n", length_)); bool f (n == string::npos); // Description length is below the limit. // Truncate description if length exceed the limit. @@ -525,7 +530,7 @@ namespace brep if (changes_.empty ()) return; - string::size_type n (changes_.find_first_of (" \t\n", length_)); + auto n (changes_.find_first_of (" \t\n", length_)); bool f (n == string::npos); // Changes length is below the limit. // Truncate changes if length exceed the limit. @@ -577,7 +582,7 @@ namespace brep return page == 0 ? url_ : url_ + (url_.find ('?') == string::npos ? "?p=" : "&p=") + - to_string (page); + to_string (page); }); s << DIV(ID="pager"); @@ -596,7 +601,7 @@ namespace brep s << A(HREF=u (p)); if (p == current_page_) - s << ID << "curr" << ~ID; + s << ID("curr"); s << p + 1 << ~A; diff --git a/brep/services.cxx b/brep/services.cxx index eb99f3d..9b7043c 100644 --- a/brep/services.cxx +++ b/brep/services.cxx @@ -17,16 +17,16 @@ static package_search package_search_mod; service AP_MODULE_DECLARE_DATA package_search_srv ( "package-search", package_search_mod, - {"db-host", "db-port", "conf"}); + {"root", "db-host", "db-port", "conf"}); static package_details package_details_mod; service AP_MODULE_DECLARE_DATA package_details_srv ( "package-details", package_details_mod, - {"db-host", "db-port", "conf"}); + {"root", "db-host", "db-port", "conf"}); static package_version_details package_version_details_mod; service AP_MODULE_DECLARE_DATA package_version_details_srv ( "package-version-details", package_version_details_mod, - {"db-host", "db-port", "conf"}); + {"root", "db-host", "db-port", "conf"}); diff --git a/brep/types-parsers b/brep/types-parsers new file mode 100644 index 0000000..6d30544 --- /dev/null +++ b/brep/types-parsers @@ -0,0 +1,31 @@ +// file : brep/types-parsers -*- C++ -*- +// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +// CLI parsers, included into the generated source files. +// + +#ifndef BREP_TYPES_PARSERS +#define BREP_TYPES_PARSERS + +#include <butl/path> + +namespace brep +{ + namespace cli + { + class scanner; + + template <typename T> + struct parser; + + template <> + struct parser<butl::dir_path> + { + static void + parse (butl::dir_path&, scanner&); + }; + } +} + +#endif // BREP_TYPES_PARSERS diff --git a/brep/types-parsers.cxx b/brep/types-parsers.cxx new file mode 100644 index 0000000..f7c2f11 --- /dev/null +++ b/brep/types-parsers.cxx @@ -0,0 +1,47 @@ +// file : brep/types-parsers.cxx -*- C++ -*- +// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#include <brep/types-parsers> + +#include <butl/path> + +#include <brep/options> + +using namespace butl; + +namespace brep +{ + namespace cli + { + template <typename T> + static void + parse_path (T& x, scanner& s) + { + const char* o (s.next ()); + + if (!s.more ()) + throw missing_value (o); + + const char* v (s.next ()); + + try + { + x = T (v); + + if (x.empty ()) + throw invalid_value (o, v); + } + catch (const invalid_path&) + { + throw invalid_value (o, v); + } + } + + void parser<dir_path>:: + parse (dir_path& x, scanner& s) + { + parse_path (x, s); + } + } +} @@ -27,7 +27,8 @@ g++ -shared $DEBUG -std=c++11 -I.. -I../../libbpkg \ echo "cli brep-apache options" cli --include-with-brackets --include-prefix brep --hxx-suffix "" \ - --guard-prefix BREP --generate-file-scanner --suppress-usage \ + --guard-prefix BREP --cxx-prologue "#include <brep/types-parsers>" \ + --cli-namespace brep::cli --generate-file-scanner --suppress-usage \ --option-prefix "" ./options.cli echo "g++ libbrep-apache.so" @@ -46,7 +47,7 @@ cd ../loader echo "cli loader options" -cli --hxx-suffix "" ./options.cli +cli --hxx-suffix "" --cli-namespace brep::cli ./options.cli echo "g++ brep-loader" diff --git a/etc/apachectl b/etc/apachectl index e282d9f..895d580 100755 --- a/etc/apachectl +++ b/etc/apachectl @@ -26,10 +26,11 @@ ARGV="$@" -export AP_LOG_LEVEL -export AP_ADMIN_EMAIL export AP_PORT export AP_SERVER_NAME +export AP_ROOT +export AP_ADMIN_EMAIL +export AP_LOG_LEVEL export AP_DB_HOST export AP_DB_PORT export AP_MODULE_DIR @@ -18,6 +18,7 @@ PG_WORKSPACE_DIR="$WORKSPACE_DIR/run/pgsql" # AP_PORT=8080 AP_SERVER_NAME="cppget.org:$AP_PORT" +AP_ROOT="" # Value examples: "", "/foo", "/foo/bar". AP_ADMIN_EMAIL=admin@cppget.org AP_LOG_LEVEL=trace1 AP_DB_HOST="$PG_WORKSPACE_DIR" diff --git a/etc/httpd.conf b/etc/httpd.conf index 1000b04..c8405ed 100644 --- a/etc/httpd.conf +++ b/etc/httpd.conf @@ -5,7 +5,6 @@ ServerAdmin "${AP_ADMIN_EMAIL}" User apache Group apache -DocumentRoot "${AP_WWW_DIR}" CoreDumpDirectory "${AP_WORKSPACE_DIR}" PidFile "${AP_WORKSPACE_DIR}/httpd.pid" @@ -39,43 +38,49 @@ LoadModule deflate_module /usr/lib64/httpd/modules/mod_deflate.so LoadModule authz_host_module /usr/lib64/httpd/modules/mod_authz_host.so LoadModule expires_module /usr/lib64/httpd/modules/mod_expires.so LoadModule dir_module /usr/lib64/httpd/modules/mod_dir.so +LoadModule alias_module /usr/lib64/httpd/modules/mod_alias.so LoadModule package_search_srv ${AP_MODULE_DIR}/libbrep-apache.so <IfModule package_search_srv> + package-search-root ${AP_ROOT}/ package-search-db-host ${AP_DB_HOST} package-search-db-port ${AP_DB_PORT} - package-search-conf "${AP_CONFIG_DIR}/package-search.conf" + package-search-conf ${AP_CONFIG_DIR}/package-search.conf </IfModule> LoadModule package_details_srv ${AP_MODULE_DIR}/libbrep-apache.so <IfModule package_details_srv> + package-details-root ${AP_ROOT}/ package-details-db-host ${AP_DB_HOST} package-details-db-port ${AP_DB_PORT} - package-details-conf "${AP_CONFIG_DIR}/package-details.conf" + package-details-conf ${AP_CONFIG_DIR}/package-details.conf </IfModule> LoadModule package_version_details_srv ${AP_MODULE_DIR}/libbrep-apache.so <IfModule package_version_details_srv> + package-version-details-root ${AP_ROOT}/ package-version-details-db-host ${AP_DB_HOST} package-version-details-db-port ${AP_DB_PORT} - package-version-details-conf "${AP_CONFIG_DIR}/package-version-details.conf" + package-version-details-conf ${AP_CONFIG_DIR}/package-version-details.conf </IfModule> -<LocationMatch ^/$> +<LocationMatch ^${AP_ROOT}/?$> SetHandler package-search </LocationMatch> -<LocationMatch ^/go/[^/]+$> +<LocationMatch ^${AP_ROOT}/go/[^/]+$> SetHandler package-details </LocationMatch> -<LocationMatch ^/go/[^/]+/[^/]+$> +<LocationMatch ^${AP_ROOT}/go/[^/]+/[^/]+$> SetHandler package-version-details </LocationMatch> +AliasMatch ^${AP_ROOT}/(.+) ${AP_WWW_DIR}/$1 + ExtendedStatus On <Location /server-status> diff --git a/loader/buildfile b/loader/buildfile index d4e4678..bb5684e 100644 --- a/loader/buildfile +++ b/loader/buildfile @@ -15,6 +15,6 @@ loader = cxx{loader} cli.cxx{options} exe{brep-loader}: $loader ../brep/libso{brep} $libs cli.options += -I $src_root --include-with-brackets --include-prefix loader \ ---guard-prefix LOADER +--guard-prefix LOADER --cli-namespace brep::cli cli.cxx{options}: cli{options} diff --git a/loader/loader.cxx b/loader/loader.cxx index ee3e5fa..e9f5566 100644 --- a/loader/loader.cxx +++ b/loader/loader.cxx @@ -426,6 +426,20 @@ load_repositories (const shared_ptr<repository>& rp, database& db) // rp->url = move (rm.url); + // @@ Should we throw if url is not available for external repository ? + // Can, basically, repository be available on the web but have no web + // interface associated ? + // + if (rp->url) + { + // Normalize web interface url adding trailing '/' if not present. + // + auto& u (*rp->url); + assert (!u.empty ()); + if (u.back () != '/') + u += '/'; + } + if (rp->internal) { rp->email = move (rm.email); diff --git a/tests/loader/driver.cxx b/tests/loader/driver.cxx index f996ab7..cf81dca 100644 --- a/tests/loader/driver.cxx +++ b/tests/loader/driver.cxx @@ -479,7 +479,7 @@ main (int argc, char* argv[]) assert (cr->location.string () == "http://pkg.cppget.org/external/1/misc"); assert (cr->display_name.empty ()); - assert (cr->url && *cr->url == "http://misc.cppget.org"); + assert (cr->url && *cr->url == "http://misc.cppget.org/"); dir_path crp (cp.directory () / dir_path ("external/1/misc")); assert (cr->local_path == crp.normalize ()); @@ -534,7 +534,7 @@ main (int argc, char* argv[]) assert (tr->location.string () == "http://pkg.cppget.org/external/1/testing"); assert (tr->display_name.empty ()); - assert (tr->url && *tr->url == "http://test.cppget.org"); + assert (tr->url && *tr->url == "http://test.cppget.org/hello/"); dir_path trp (cp.directory () / dir_path ("external/1/testing")); assert (tr->local_path == trp.normalize ()); @@ -567,7 +567,7 @@ main (int argc, char* argv[]) assert (gr->location.string () == "http://pkg.cppget.org/external/1/staging"); assert (gr->display_name.empty ()); - assert (gr->url && *gr->url == "http://stage.cppget.org"); + assert (gr->url && *gr->url == "http://stage.cppget.org/"); dir_path grp (cp.directory () / dir_path ("external/1/staging")); assert (gr->local_path == grp.normalize ()); diff --git a/tests/loader/external/1/misc/repositories b/tests/loader/external/1/misc/repositories index 1b98ebc..1a41290 100644 --- a/tests/loader/external/1/misc/repositories +++ b/tests/loader/external/1/misc/repositories @@ -10,4 +10,4 @@ role: complement : # Local repository manifest (this repository). # -url: http://misc.cppget.org +url: http://misc.cppget.org/ diff --git a/tests/loader/external/1/testing/repositories b/tests/loader/external/1/testing/repositories index 227d5ac..a218d5c 100644 --- a/tests/loader/external/1/testing/repositories +++ b/tests/loader/external/1/testing/repositories @@ -6,4 +6,4 @@ role: complement : # Local repository manifest (this repository). # -url: http://test.cppget.org +url: http://test.cppget.org/hello diff --git a/web/apache/service b/web/apache/service index 7ac01a2..33d5a0a 100644 --- a/web/apache/service +++ b/web/apache/service @@ -112,7 +112,7 @@ namespace web init_worker (log& l) noexcept; static const char* - add_option (cmd_parms *parms, void *mconfig, const char *value) noexcept; + add_option (cmd_parms* parms, void* mconfig, const char* args) noexcept; template <typename M> int handle (request& r, log& l) noexcept; diff --git a/web/apache/service.cxx b/web/apache/service.cxx index 782e09b..42a31bd 100644 --- a/web/apache/service.cxx +++ b/web/apache/service.cxx @@ -10,8 +10,10 @@ #include <httpd.h> #include <http_config.h> -#include <memory> // unique_ptr +#include <memory> // unique_ptr #include <string> +#include <cassert> +#include <cstring> // strlen() #include <exception> using namespace std; @@ -47,7 +49,10 @@ namespace web reinterpret_cast<cmd_func> (add_option), this, RSRC_CONF, - TAKE1, + // Move away from TAKE1 to be able to handle empty string and + // no-value. + // + RAW_ARGS, nullptr }; } @@ -58,19 +63,31 @@ namespace web } const char* service:: - add_option (cmd_parms* parms, void*, const char* value) noexcept + add_option (cmd_parms* parms, void*, const char* args) noexcept { service& srv (*reinterpret_cast<service*> (parms->cmd->cmd_data)); string name (parms->cmd->name + srv.name_.length () + 1); + optional<string> value; + + // 'args' is an optionally double-quoted string. Use double quotes to + // distinguish empty string from no-value case. + // + assert (args != nullptr); + if (auto l = strlen (args)) + value = l >= 2 && args[0] == '"' && args[l - 1] == '"' + ? string (args + 1, l - 2) + : args; for (auto& v: srv.options_) + { if (v.name == name) { v.value = value; return 0; } + } - srv.options_.emplace_back (name, string (value)); + srv.options_.emplace_back (name, value); return 0; } |