aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-11-14 16:29:22 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-11-16 16:42:35 +0200
commit03905bcf1bcfd9e7932fcac4283c5817058a25ce (patch)
treeb643d3bedf436bfcd8956b25133d5674b6b18e36
parent96281a6c4f818311a6df90c0d8b8f537a61e1090 (diff)
Invent root path web interface configuration option
-rw-r--r--brep/buildfile8
-rw-r--r--brep/module.cxx3
-rw-r--r--brep/options.cli3
-rw-r--r--brep/package-details.cxx42
-rw-r--r--brep/package-search.cxx31
-rw-r--r--brep/package-version-details.cxx81
-rw-r--r--brep/page36
-rw-r--r--brep/page.cxx89
-rw-r--r--brep/services.cxx6
-rw-r--r--brep/types-parsers31
-rw-r--r--brep/types-parsers.cxx47
-rwxr-xr-xbuild.sh5
-rwxr-xr-xetc/apachectl5
-rw-r--r--etc/config1
-rw-r--r--etc/httpd.conf19
-rw-r--r--loader/buildfile2
-rw-r--r--loader/loader.cxx14
-rw-r--r--tests/loader/driver.cxx6
-rw-r--r--tests/loader/external/1/misc/repositories2
-rw-r--r--tests/loader/external/1/testing/repositories2
-rw-r--r--web/apache/service2
-rw-r--r--web/apache/service.cxx25
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
diff --git a/brep/page b/brep/page
index 309caa9..c968389 100644
--- a/brep/page
+++ b/brep/page
@@ -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);
+ }
+ }
+}
diff --git a/build.sh b/build.sh
index 77437db..9596589 100755
--- a/build.sh
+++ b/build.sh
@@ -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
diff --git a/etc/config b/etc/config
index 70fe961..dd89ee1 100644
--- a/etc/config
+++ b/etc/config
@@ -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;
}