aboutsummaryrefslogtreecommitdiff
path: root/brep
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-11-16 20:02:06 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-11-25 20:35:10 +0200
commit2700ed6a3e1092a064f28b07f8e2c4e5b9b830e7 (patch)
treea54ffc979dde42e609bc9877120fa010887c6b66 /brep
parent48a3c47d34c2acc0a39e2db5acfd437dace499c1 (diff)
Implement new URL path schema for the web interface
Diffstat (limited to 'brep')
-rw-r--r--brep/buildfile7
-rw-r--r--brep/diagnostics28
-rw-r--r--brep/diagnostics.cxx3
-rw-r--r--brep/module29
-rw-r--r--brep/module.cxx13
-rw-r--r--brep/options-types19
-rw-r--r--brep/options.cli53
-rw-r--r--brep/package178
-rw-r--r--brep/package-details7
-rw-r--r--brep/package-details.cxx384
-rw-r--r--brep/package-search7
-rw-r--r--brep/package-search.cxx227
-rw-r--r--brep/package-version-details7
-rw-r--r--brep/package-version-details.cxx477
-rw-r--r--brep/package.cxx8
-rw-r--r--brep/page94
-rw-r--r--brep/page.cxx117
-rw-r--r--brep/repository-details7
-rw-r--r--brep/repository-details.cxx142
-rw-r--r--brep/repository-root31
-rw-r--r--brep/repository-root.cxx119
-rw-r--r--brep/services.cxx7
-rw-r--r--brep/shared-database9
-rw-r--r--brep/shared-database.cxx6
-rw-r--r--brep/types60
-rw-r--r--brep/types-parsers14
-rw-r--r--brep/types-parsers.cxx26
-rw-r--r--brep/utility20
28 files changed, 1177 insertions, 922 deletions
diff --git a/brep/buildfile b/brep/buildfile
index 464118d..e6d9651 100644
--- a/brep/buildfile
+++ b/brep/buildfile
@@ -21,9 +21,10 @@ 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 repository-details shared-database page \
- types-parsers} cli.cxx{options}
+brep = cxx{diagnostics module services repository-root package-search \
+ package-details package-version-details repository-details \
+ shared-database page types-parsers} \
+ cli.cxx{options}
web = ../web/apache/cxx{request service} ../web/cxx{mime-url-encoding}
diff --git a/brep/diagnostics b/brep/diagnostics
index 6e42e82..d077d6d 100644
--- a/brep/diagnostics
+++ b/brep/diagnostics
@@ -5,23 +5,24 @@
#ifndef BREP_DIAGNOSTICS
#define BREP_DIAGNOSTICS
-#include <vector>
-#include <cstdint> // uint64_t
-#include <utility> // move()
+#include <utility> // forward()
#include <sstream>
#include <functional>
+#include <brep/types>
+#include <brep/utility>
+
namespace brep
{
struct location
{
location (): line (0), column (0) {}
- location (std::string f, std::uint64_t l, std::uint64_t c)
- : file (std::move (f)), line (l), column (c) {}
+ location (string f, uint64_t l, uint64_t c)
+ : file (move (f)), line (l), column (c) {}
- std::string file;
- std::uint64_t line;
- std::uint64_t column;
+ string file;
+ uint64_t line;
+ uint64_t column;
};
enum class severity {error, warning, info, trace};
@@ -31,10 +32,10 @@ namespace brep
severity sev;
const char* name {nullptr}; // E.g., a function name in tracing.
location loc;
- std::string msg;
+ string msg;
};
- using diag_data = std::vector<diag_entry>;
+ using diag_data = vector<diag_entry>;
//
//
@@ -93,15 +94,14 @@ namespace brep
@@ libstdc++ doesn't yet have the ostringstream move support.
diag_record (diag_record&& r)
- : data_ (std::move (r.data_)), os_ (std::move (r.os_))
+ : data_ (move (r.data_)), os_ (move (r.os_))
{
epilogue_ = r.epilogue_;
r.data_.clear (); // Empty.
}
*/
- diag_record (diag_record&& r)
- : data_ (std::move (r.data_))
+ diag_record (diag_record&& r): data_ (move (r.data_))
{
if (!data_.empty ())
os_ << r.os_.str ();
@@ -293,7 +293,7 @@ namespace brep
}
static void
- epilogue (diag_data&& d) {throw E (std::move (d));}
+ epilogue (diag_data&& d) {throw E (move (d));}
private:
const diag_epilogue epilogue_ {&epilogue};
diff --git a/brep/diagnostics.cxx b/brep/diagnostics.cxx
index 0278792..4f8e5d6 100644
--- a/brep/diagnostics.cxx
+++ b/brep/diagnostics.cxx
@@ -4,9 +4,10 @@
#include <brep/diagnostics>
-#include <cassert>
#include <exception>
+#include <brep/utility>
+
using namespace std;
namespace brep
diff --git a/brep/module b/brep/module
index 0743598..295744d 100644
--- a/brep/module
+++ b/brep/module
@@ -5,12 +5,10 @@
#ifndef BREP_MODULE
#define BREP_MODULE
-#include <string>
-#include <utility> // move()
-#include <cstdint>
-
#include <web/module>
+#include <brep/types>
+#include <brep/utility>
#include <brep/options>
#include <brep/diagnostics>
@@ -40,7 +38,7 @@ namespace brep
{
diag_data data;
- server_error (diag_data&& d): data (std::move (d)) {}
+ server_error (diag_data&& d): data (move (d)) {}
};
// Every module member function that needs to produce any diagnostics
@@ -81,11 +79,15 @@ namespace brep
//
// While uint8 is more than enough, use uint16 for the ease of printing.
//
- std::uint16_t verb_ {0};
+ uint16_t verb_ {0};
template <class F> void level1 (const F& f) const {if (verb_ >= 1) f ();}
template <class F> void level2 (const F& f) const {if (verb_ >= 2) f ();}
+ // Set to true when the module is successfully initialized.
+ //
+ bool loaded_ {false};
+
// Implementation details.
//
protected:
@@ -117,12 +119,19 @@ namespace brep
bool name_;
};
- private:
+ public:
+ // Can be called normally by the web server or our custom request
+ // dispatching mechanism.
+ //
virtual void
- handle (request&, response&, log&);
+ handle (request&, response&) = 0;
+
+ bool
+ loaded () const noexcept {return loaded_;}
+ private:
virtual void
- handle (request&, response&) = 0;
+ handle (request&, response&, log&);
virtual void
init (const name_values&, log&);
@@ -147,7 +156,7 @@ namespace brep
// Extract function name from a __PRETTY_FUNCTION__.
// Throw std::invalid_argument if fail to parse.
//
- static std::string
+ static string
func_name (const char* pretty_name);
void
diff --git a/brep/module.cxx b/brep/module.cxx
index 850f593..68177b1 100644
--- a/brep/module.cxx
+++ b/brep/module.cxx
@@ -7,17 +7,17 @@
#include <httpd.h>
#include <http_log.h>
-#include <vector>
-#include <string>
#include <ostream>
#include <sstream>
-#include <cstring> // strncmp()
+#include <cstring> // strchr()
#include <stdexcept>
#include <functional> // bind()
#include <web/module>
#include <web/apache/log>
+#include <brep/types>
+#include <brep/utility>
#include <brep/options>
using namespace std;
@@ -32,6 +32,8 @@ namespace brep
void module::
handle (request& rq, response& rs, log& l)
{
+ assert (loaded_);
+
log_ = &l;
try
@@ -84,6 +86,8 @@ namespace brep
void module::
init (const name_values& options, log& log)
{
+ assert (!loaded_);
+
log_ = &log;
vector<const char*> argv;
@@ -119,6 +123,7 @@ namespace brep
options::module o (s, unknown_mode::skip, unknown_mode::skip);
verb_ = o.verb ();
+ loaded_ = true;
}
catch (const server_error& e)
{
@@ -139,7 +144,7 @@ namespace brep
// Custom copy constructor is required to initialize log_writer_ properly.
//
module::
- module (const module& m): module () {verb_ = m.verb_;}
+ module (const module& m): module () {verb_ = m.verb_; loaded_ = m.loaded_;}
// For function func declared like this:
// using B = std::string (*)(int);
diff --git a/brep/options-types b/brep/options-types
new file mode 100644
index 0000000..01b8d0a
--- /dev/null
+++ b/brep/options-types
@@ -0,0 +1,19 @@
+// file : brep/options-types -*- C++ -*-
+// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#ifndef BREP_OPTIONS_TYPES
+#define BREP_OPTIONS_TYPES
+
+namespace brep
+{
+ // brep types
+ //
+ enum class page_form
+ {
+ full,
+ brief
+ };
+}
+
+#endif // BREP_OPTIONS_TYPES
diff --git a/brep/options.cli b/brep/options.cli
index 4126f4a..fa05b56 100644
--- a/brep/options.cli
+++ b/brep/options.cli
@@ -2,10 +2,8 @@
// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
-include <string>;
-include <cstdint>; // uint16_t
-
-include <butl/path>;
+include <brep/types>;
+include <brep/options-types>;
namespace brep
{
@@ -15,33 +13,33 @@ namespace brep
{
class module
{
- std::uint16_t verb = 0;
- butl::dir_path root = "";
+ uint16_t verb;
+ dir_path root;
};
class db
{
- std::string db-host = "localhost";
- std::uint16_t db-port = 5432;
+ string db-host = "localhost";
+ uint16_t db-port = 5432;
};
class package_search: module, db
{
- std::uint16_t results-on-page = 10;
- std::uint16_t pages-in-pager = 10;
+ uint16_t results-on-page = 10;
+ uint16_t pages-in-pager = 5;
};
class package_details: module, db
{
- std::uint16_t results-on-page = 10;
- std::uint16_t pages-in-pager = 10;
- std::uint16_t description-length = 400;
+ uint16_t results-on-page = 10;
+ uint16_t pages-in-pager = 5;
+ uint16_t description-length = 500; // ~ 80 chars x 6 lines.
};
class package_version_details: module, db
{
- std::uint16_t description-length = 400;
- std::uint16_t changes-length = 800;
+ uint16_t description-length = 500; // ~ 80 chars x 6 lines.
+ uint16_t changes-length = 5000; // ~ 80 chars x 60 lines.
};
class repository_details: module, db
@@ -60,36 +58,39 @@ namespace brep
{
// Display package search result list starting from this page.
//
- std::uint16_t page | p = 0;
+ uint16_t page | p;
// Package search criteria.
//
- std::string query | q = "";
+ string query | q;
};
class package_details
{
// Display package version search result list starting from this page.
//
- std::uint16_t page | p = 0;
+ uint16_t page | p;
// Package version search criteria.
//
- std::string query | q = "";
+ string query | q;
- // Full page variant.
- //
- // @@ Shouldn't we use one letter alias for URL as well ?
- // I like full. It is descriptive. q= is kind now a convention.
+ // Page form.
//
- bool full = false;
+ page_form form | f = page_form::brief;
};
class package_version_details
{
- // Full page variant.
+ // Page form.
+ //
+ page_form form | f = page_form::brief;
+ };
+
+ class repository_details
+ {
+ // No parameters so far.
//
- bool full = false;
};
}
}
diff --git a/brep/package b/brep/package
index f56906a..b3d4890 100644
--- a/brep/package
+++ b/brep/package
@@ -6,25 +6,15 @@
#define BREP_PACKAGE
#include <map>
-#include <string>
-#include <vector>
#include <chrono>
-#include <memory> // shared_ptr
-#include <cassert>
-#include <cstddef> // size_t
-#include <utility> // move()
-#include <cstdint> // uint16
-#include <ostream>
+#include <iosfwd> // ostream
#include <odb/core.hxx>
#include <odb/forward.hxx> // database
-#include <odb/lazy-ptr.hxx>
#include <odb/nested-container.hxx>
-#include <butl/path>
-#include <butl/path-io>
-#include <butl/optional>
-#include <butl/timestamp>
+#include <brep/types>
+#include <brep/utility>
namespace brep
{
@@ -34,10 +24,10 @@ namespace brep
#pragma db value
struct _version
{
- std::uint16_t epoch;
- std::string canonical_upstream;
- std::uint16_t revision;
- std::string upstream;
+ uint16_t epoch;
+ string canonical_upstream;
+ uint16_t revision;
+ string upstream;
};
}
@@ -55,9 +45,9 @@ namespace brep
(?).upstream}) \
from(bpkg::version ((?).epoch, std::move ((?).upstream), (?).revision))
-#pragma db map type(bpkg::comparison) as(std::string) \
- to(bpkg::to_string (?)) \
- from(bpkg::to_comparison (?))
+#pragma db map type(bpkg::comparison) as(brep::string) \
+ to(bpkg::to_string (?)) \
+ from(bpkg::to_comparison (?))
namespace brep
{
@@ -76,33 +66,21 @@ namespace brep
class repository;
class package;
- using strings = std::vector<std::string>;
- using butl::optional;
-
// path
//
- using butl::path;
-
- #pragma db map type(path) as(std::string) \
- to((?).string ()) from(brep::path (?))
+ #pragma db map type(path) as(string) to((?).string ()) from(brep::path (?))
using optional_path = optional<path>;
- using optional_string = optional<std::string>;
+ using optional_string = optional<string>;
#pragma db map type(optional_path) as(brep::optional_string) \
to((?) ? (?)->string () : brep::optional_string ()) \
from((?) ? brep::path (*(?)) : brep::optional_path ())
- using butl::dir_path;
-
- #pragma db map type(dir_path) as(std::string) \
+ #pragma db map type(dir_path) as(string) \
to((?).string ()) from(brep::dir_path (?))
- // timestamp
- //
- using butl::timestamp;
-
- #pragma db map type(timestamp) as(std::uint64_t) \
+ #pragma db map type(timestamp) as(uint64_t) \
to(std::chrono::system_clock::to_time_t (?)) \
from(std::chrono::system_clock::from_time_t (?))
@@ -113,9 +91,9 @@ namespace brep
#pragma db value
struct canonical_version
{
- std::uint16_t epoch;
- std::string canonical_upstream;
- std::uint16_t revision;
+ uint16_t epoch;
+ string canonical_upstream;
+ uint16_t revision;
bool
empty () const noexcept
@@ -133,12 +111,12 @@ namespace brep
#pragma db value transient
struct upstream_version: version
{
- #pragma db member(upstream_) virtual(std::string) \
+ #pragma db member(upstream_) virtual(string) \
get(this.upstream) \
set(this = brep::version (0, std::move (?), 0))
upstream_version () = default;
- upstream_version (version v): version (std::move (v)) {}
+ upstream_version (version v): version (move (v)) {}
upstream_version&
operator= (version v) {version& b (*this); b = v; return *this;}
@@ -162,21 +140,19 @@ namespace brep
using bpkg::url;
#pragma db value(url) definition
- #pragma db member(url::value) virtual(std::string) before access(this) \
- column("")
+ #pragma db member(url::value) virtual(string) before access(this) column("")
// email
//
using bpkg::email;
#pragma db value(email) definition
- #pragma db member(email::value) virtual(std::string) before access(this) \
- column("")
+ #pragma db member(email::value) virtual(string) before access(this) column("")
// licenses
//
using bpkg::licenses;
- using license_alternatives = std::vector<licenses>;
+ using license_alternatives = vector<licenses>;
#pragma db value(licenses) definition
@@ -192,12 +168,12 @@ namespace brep
#pragma db value
struct package_id
{
- std::string name;
+ string name;
canonical_version version;
package_id () = default;
- package_id (std::string n, const brep::version& v)
- : name (std::move (n)),
+ package_id (string n, const brep::version& v)
+ : name (move (n)),
version {v.epoch, v.canonical_upstream, v.revision}
{
}
@@ -249,12 +225,12 @@ namespace brep
{
using package_type = brep::package;
- odb::lazy_shared_ptr<package_type> package;
+ lazy_shared_ptr<package_type> package;
optional<dependency_constraint> constraint;
// Prerequisite package name.
//
- std::string
+ string
name () const;
// Database mapping.
@@ -266,25 +242,25 @@ namespace brep
operator<< (std::ostream&, const dependency&);
#pragma db value
- class dependency_alternatives: public std::vector<dependency>
+ class dependency_alternatives: public vector<dependency>
{
public:
bool conditional;
- std::string comment;
+ string comment;
dependency_alternatives () = default;
explicit
- dependency_alternatives (bool d, std::string c)
- : conditional (d), comment (std::move (c)) {}
+ dependency_alternatives (bool d, string c)
+ : conditional (d), comment (move (c)) {}
};
- using dependencies = std::vector<dependency_alternatives>;
+ using dependencies = vector<dependency_alternatives>;
// requirements
//
using bpkg::requirement_alternatives;
- using requirements = std::vector<requirement_alternatives>;
+ using requirements = vector<requirement_alternatives>;
#pragma db value(requirement_alternatives) definition
@@ -292,35 +268,41 @@ namespace brep
//
using bpkg::repository_location;
- #pragma db map type(repository_location) as(std::string) \
+ #pragma db map type(repository_location) as(string) \
to((?).string ()) from(brep::repository_location (?))
- #pragma db object pointer(std::shared_ptr) session
+ #pragma db object pointer(shared_ptr) session
class repository
{
public:
// Create internal repository.
//
repository (repository_location,
- std::string display_name,
- dir_path local_path);
+ string display_name,
+ dir_path local_path,
+ uint16_t priority);
// Create external repository.
//
explicit
repository (repository_location);
- std::string name; // Object id (canonical name).
+ string name; // Object id (canonical name).
repository_location location;
- std::string display_name;
+ string display_name;
+
+ // The order in the internal repositories configuration file, starting from
+ // 1. 0 for external repositories.
+ //
+ uint16_t priority;
- optional<std::string> url;
+ optional<string> url;
- // Set only for internal repositories.
+ // Present only for internal repositories.
//
- optional<std::string> email;
- optional<std::string> summary;
- optional<std::string> description;
+ optional<string> email;
+ optional<string> summary;
+ optional<string> description;
// Non empty for internal repositories and external ones with a filesystem
// path location.
@@ -336,8 +318,8 @@ namespace brep
timestamp repositories_timestamp;
bool internal;
- std::vector<odb::lazy_weak_ptr<repository>> complements;
- std::vector<odb::lazy_weak_ptr<repository>> prerequisites;
+ vector<lazy_weak_ptr<repository>> complements;
+ vector<lazy_weak_ptr<repository>> prerequisites;
// Database mapping.
//
@@ -372,13 +354,13 @@ namespace brep
#pragma db value type("tsvector")
struct weighted_text
{
- std::string a;
- std::string b;
- std::string c;
- std::string d;
+ string a;
+ string b;
+ string c;
+ string d;
};
- #pragma db object pointer(std::shared_ptr) session
+ #pragma db object pointer(shared_ptr) session
class package
{
public:
@@ -393,14 +375,14 @@ namespace brep
// Create internal package object.
//
- package (std::string name,
+ package (string name,
version_type,
priority_type,
- std::string summary,
+ string summary,
license_alternatives_type,
strings tags,
- optional<std::string> description,
- std::string changes,
+ optional<string> description,
+ string changes,
url_type,
optional<url_type> package_url,
email_type,
@@ -408,7 +390,7 @@ namespace brep
dependencies_type,
requirements_type,
optional<path> location,
- std::shared_ptr<repository_type>);
+ shared_ptr<repository_type>);
// Create external package object.
//
@@ -417,7 +399,7 @@ namespace brep
// The only package information required to compose such a link is the
// package name, version, and repository location.
//
- package (std::string name, version_type, std::shared_ptr<repository_type>);
+ package (string name, version_type, shared_ptr<repository_type>);
bool
internal () const noexcept {return internal_repository != nullptr;}
@@ -427,24 +409,24 @@ namespace brep
package_id id;
upstream_version version;
priority_type priority;
- std::string summary;
+ string summary;
license_alternatives_type license_alternatives;
strings tags;
- optional<std::string> description;
- std::string changes;
+ optional<string> description;
+ string changes;
url_type url;
optional<url_type> package_url;
email_type email;
optional<email_type> package_email;
dependencies_type dependencies;
requirements_type requirements;
- odb::lazy_shared_ptr<repository_type> internal_repository;
+ lazy_shared_ptr<repository_type> internal_repository;
- // Path to the package file. Set only for internal packages.
+ // Path to the package file. Present only for internal packages.
//
optional<path> location;
- std::vector<odb::lazy_shared_ptr<repository_type>> other_repositories;
+ vector<lazy_shared_ptr<repository_type>> other_repositories;
// Database mapping.
//
@@ -454,7 +436,7 @@ namespace brep
// license
//
using _license_key = odb::nested_key<licenses>;
- using _licenses_type = std::map<_license_key, std::string>;
+ using _licenses_type = std::map<_license_key, string>;
#pragma db value(_license_key)
#pragma db member(_license_key::outer) column("alternative_index")
@@ -494,18 +476,18 @@ namespace brep
//
using _requirement_key = odb::nested_key<requirement_alternatives>;
using _requirement_alternatives_type =
- std::map<_requirement_key, std::string>;
+ std::map<_requirement_key, string>;
#pragma db value(_requirement_key)
#pragma db member(_requirement_key::outer) column("requirement_index")
#pragma db member(_requirement_key::inner) column("index")
#pragma db member(requirements) id_column("") value_column("")
- #pragma db member(requirement_alternatives) \
- virtual(_requirement_alternatives_type) \
- after(requirements) \
- get(odb::nested_get (this.requirements)) \
- set(odb::nested_set (this.requirements, move (?))) \
+ #pragma db member(requirement_alternatives) \
+ virtual(_requirement_alternatives_type) \
+ after(requirements) \
+ get(odb::nested_get (this.requirements)) \
+ set(odb::nested_set (this.requirements, std::move (?))) \
id_column("") key_column("") value_column("id")
// other_repositories
@@ -550,9 +532,9 @@ namespace brep
query("/*CALL*/ SELECT count(*) FROM search_latest_packages(?)")
struct latest_package_count
{
- std::size_t result;
+ size_t result;
- operator std::size_t () const {return result;}
+ operator size_t () const {return result;}
};
#pragma db view query("/*CALL*/ SELECT * FROM search_packages(?)")
@@ -565,9 +547,9 @@ namespace brep
#pragma db view query("/*CALL*/ SELECT count(*) FROM search_packages(?)")
struct package_count
{
- std::size_t result;
+ size_t result;
- operator std::size_t () const {return result;}
+ operator size_t () const {return result;}
};
#pragma db view query("/*CALL*/ SELECT * FROM latest_package(?)")
diff --git a/brep/package-details b/brep/package-details
index 471dcee..214a0fe 100644
--- a/brep/package-details
+++ b/brep/package-details
@@ -5,10 +5,9 @@
#ifndef BREP_PACKAGE_DETAILS
#define BREP_PACKAGE_DETAILS
-#include <memory> // shared_ptr
-
#include <odb/forward.hxx> // database
+#include <brep/types>
#include <brep/module>
#include <brep/options>
@@ -24,8 +23,8 @@ namespace brep
init (cli::scanner&);
private:
- std::shared_ptr<options::package_details> options_;
- std::shared_ptr<odb::core::database> db_;
+ shared_ptr<options::package_details> options_;
+ shared_ptr<odb::core::database> db_;
};
}
diff --git a/brep/package-details.cxx b/brep/package-details.cxx
index 8be6108..4b99feb 100644
--- a/brep/package-details.cxx
+++ b/brep/package-details.cxx
@@ -4,11 +4,6 @@
#include <brep/package-details>
-#include <string>
-#include <memory> // make_shared(), shared_ptr
-#include <cstddef> // size_t
-#include <cassert>
-
#include <xml/serializer>
#include <odb/session.hxx>
@@ -20,222 +15,225 @@
#include <web/mime-url-encoding>
#include <brep/page>
+#include <brep/types>
+#include <brep/utility>
#include <brep/options>
#include <brep/package>
#include <brep/package-odb>
#include <brep/shared-database>
-using namespace std;
using namespace odb::core;
+using namespace brep::cli;
-namespace brep
+void brep::package_details::
+init (scanner& s)
{
- using namespace cli;
+ MODULE_DIAG;
- void package_details::
- init (scanner& s)
- {
- MODULE_DIAG;
+ options_ = make_shared<options::package_details> (
+ s, unknown_mode::fail, unknown_mode::fail);
- options_ = make_shared<options::package_details> (
- s, unknown_mode::fail, unknown_mode::fail);
+ db_ = shared_database (options_->db_host (), options_->db_port ());
+}
- db_ = shared_database (options_->db_host (), options_->db_port ());
- }
+template <typename T>
+static inline query<T>
+search_params (const brep::string& n, const brep::string& q)
+{
+ using query = query<T>;
+
+ return "(" +
+ (q.empty ()
+ ? query ("NULL")
+ : "plainto_tsquery (" + query::_val (q) + ")") +
+ "," +
+ query::_val (n) +
+ ")";
+}
- template <typename T>
- static inline query<T>
- search_params (const string& n, const string& q)
- {
- using query = query<T>;
-
- return "(" +
- (q.empty ()
- ? query ("NULL")
- : "plainto_tsquery (" + query::_val (q) + ")") +
- "," +
- query::_val (n) +
- ")";
- }
+void brep::package_details::
+handle (request& rq, response& rs)
+{
+ using namespace web;
+ using namespace web::xhtml;
- void package_details::
- handle (request& rq, response& rs)
- {
- using namespace web;
- using namespace web::xhtml;
+ MODULE_DIAG;
- MODULE_DIAG;
+ // The module options object is not changed after being created once per
+ // server process.
+ //
+ static const size_t res_page (options_->results_on_page ());
+ static const dir_path& root (
+ options_->root ().empty ()
+ ? dir_path ("/")
+ : options_->root ());
- // 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 ().empty ()
- ? dir_path ("/")
- : options_->root ());
+ const string& name (*rq.path ().rbegin ());
+ const string ename (mime_url_encode (name));
- const string& name (*rq.path ().rbegin ());
- const string en (mime_url_encode (name));
+ params::package_details params;
+ bool full;
- params::package_details pr;
+ try
+ {
+ param_scanner s (rq.parameters ());
+ params = params::package_details (
+ s, unknown_mode::fail, unknown_mode::fail);
- try
- {
- param_scanner s (rq.parameters ());
- pr = params::package_details (s, unknown_mode::fail, unknown_mode::fail);
- }
- catch (const unknown_argument& e)
- {
- throw invalid_request (400, e.what ());
- }
-
- const string& sq (pr.query ()); // Search query.
- size_t pg (pr.page ());
- bool f (pr.full ());
-
- auto url (
- [&en](bool f = false,
- const string& q = "",
- size_t p = 0,
- const string& a = "") -> string
- {
- string s ("?");
- string u (en);
-
- if (f) { u += "?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);
- const string& title (sq.empty () ? name : name + " " + sq);
- static const path sp ("package-details.css");
-
- s << HTML
- << HEAD
- << TITLE << title << ~TITLE
- << CSS_LINKS (sp, rt)
- << ~HEAD
- << BODY
- << DIV_HEADER (rt)
- << DIV(ID="content");
-
- if (f)
- s << CLASS("full");
-
- s << DIV(ID="heading")
- << H1 << A(HREF=url ()) << name << ~A << ~H1
- << A(HREF=url (!f, sq, pg)) << (f ? "[brief]" : "[full]") << ~A
- << ~DIV;
-
- session sn;
- transaction t (db_->begin ());
-
- shared_ptr<package> p;
+ 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
{
- latest_package lp;
- if (!db_->query_one<latest_package> (
- query<latest_package>(
- "(" + query<latest_package>::_val (name) + ")"), lp))
- {
- throw invalid_request (404, "Package '" + name + "' not found");
- }
+ 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<package> pkg;
+ {
+ latest_package lp;
+ if (!db_->query_one<latest_package> (
+ query<latest_package>(
+ "(" + query<latest_package>::_val (name) + ")"), lp))
+ throw invalid_request (404, "Package '" + name + "' not found");
- p = db_->load<package> (lp.id);
- }
+ pkg = db_->load<package> (lp.id);
+ }
- const auto& ll (p->license_alternatives);
+ const auto& licenses (pkg->license_alternatives);
- if (pg == 0)
- {
- // Display package details on the first page only.
- //
- 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, 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, rt)
- << ~TBODY
- << ~TABLE;
- }
-
- auto pc (
- db_->query_value<package_count> (
- search_params<package_count> (name, sq)));
-
- auto r (
- db_->query<package_search_rank> (
- search_params<package_search_rank> (name, sq) +
- "ORDER BY rank DESC, version_epoch DESC, "
- "version_canonical_upstream DESC, version_revision DESC" +
- "OFFSET" + to_string (pg * rp) +
- "LIMIT" + to_string (rp)));
-
- s << FORM_SEARCH (sq)
- << DIV_COUNTER (pc, "Version", "Versions");
-
- // Enclose the subsequent tables to be able to use nth-child CSS selector.
+ if (page == 0)
+ {
+ // Display package details on the first page only.
//
- s << DIV;
- for (const auto& pr: r)
- {
- shared_ptr<package> p (db_->load<package> (pr.id));
+ 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_->description_length (),
+ 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;
+ }
- s << TABLE(CLASS="proplist version")
- << TBODY
- << TR_VERSION (name, p->version.string (), rt)
+ auto pkg_count (
+ db_->query_value<package_count> (
+ search_params<package_count> (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<package_search_rank> (
+ search_params<package_search_rank> (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<package> p (db_->load<package> (pr.id));
- // @@ Shouldn't we skip low priority row ? Don't think so, why?
- //
- << TR_PRIORITY (p->priority);
+ s << TABLE(CLASS="proplist version")
+ << TBODY
+ << TR_VERSION (name, p->version.string (), root)
- // Comparing objects of the license_alternatives class as being of the
- // vector<vector<string>> class, so comments are not considered.
+ // @@ Shouldn't we skip low priority row ? Don't think so, why?
//
- if (p->license_alternatives != ll)
- s << TR_LICENSE (p->license_alternatives);
+ << TR_PRIORITY (p->priority);
- assert (p->internal ());
+ // Comparing objects of the license_alternatives class as being of the
+ // vector<vector<string>> class, so comments are not considered.
+ //
+ if (p->license_alternatives != licenses)
+ s << TR_LICENSE (p->license_alternatives);
- // @@ 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.
- //
- // @@ 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 differes
- // 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 (), rt)
- << TR_DEPENDS (p->dependencies, rt)
- << TR_REQUIRES (p->requirements)
- << ~TBODY
- << ~TABLE;
- }
- s << ~DIV;
-
- t.commit ();
-
- static const size_t pp (options_->pages_in_pager ());
-
- s << DIV_PAGER (pg, pc, rp, pp, url (f, sq))
- << ~DIV
- << ~BODY
- << ~HTML;
+ 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_->pages_in_pager (),
+ url (full, squery))
+ << ~DIV
+ << ~BODY
+ << ~HTML;
}
diff --git a/brep/package-search b/brep/package-search
index 156ed68..a5c441e 100644
--- a/brep/package-search
+++ b/brep/package-search
@@ -5,10 +5,9 @@
#ifndef BREP_PACKAGE_SEARCH
#define BREP_PACKAGE_SEARCH
-#include <memory> // shared_ptr
-
#include <odb/forward.hxx> // database
+#include <brep/types>
#include <brep/module>
#include <brep/options>
@@ -24,8 +23,8 @@ namespace brep
init (cli::scanner&);
private:
- std::shared_ptr<options::package_search> options_;
- std::shared_ptr<odb::core::database> db_;
+ shared_ptr<options::package_search> options_;
+ shared_ptr<odb::core::database> db_;
};
}
diff --git a/brep/package-search.cxx b/brep/package-search.cxx
index 6a349b0..f2f922c 100644
--- a/brep/package-search.cxx
+++ b/brep/package-search.cxx
@@ -4,10 +4,6 @@
#include <brep/package-search>
-#include <string>
-#include <memory> // make_shared(), shared_ptr
-#include <cstddef> // size_t
-
#include <xml/serializer>
#include <odb/session.hxx>
@@ -19,134 +15,131 @@
#include <web/mime-url-encoding>
#include <brep/page>
+#include <brep/types>
+#include <brep/utility>
#include <brep/options>
#include <brep/package>
#include <brep/package-odb>
#include <brep/shared-database>
-using namespace std;
using namespace odb::core;
+using namespace brep::cli;
-namespace brep
+void brep::package_search::
+init (scanner& s)
{
- using namespace cli;
+ MODULE_DIAG;
- void package_search::
- init (scanner& s)
- {
- MODULE_DIAG;
+ options_ = make_shared<options::package_search> (
+ s, unknown_mode::fail, unknown_mode::fail);
- options_ = make_shared<options::package_search> (
- s, unknown_mode::fail, unknown_mode::fail);
+ db_ = shared_database (options_->db_host (), options_->db_port ());
+}
- db_ = shared_database (options_->db_host (), options_->db_port ());
- }
+template <typename T>
+static inline query<T>
+search_param (const brep::string& q)
+{
+ using query = query<T>;
+ return "(" +
+ (q.empty ()
+ ? query ("NULL")
+ : "plainto_tsquery (" + query::_val (q) + ")") +
+ ")";
+}
+
+void brep::package_search::
+handle (request& rq, response& rs)
+{
+ using namespace web::xhtml;
- template <typename T>
- static inline query<T>
- search_param (const string& q)
+ MODULE_DIAG;
+
+ // The module options object is not changed after being created once per
+ // server process.
+ //
+ static const size_t res_page (options_->results_on_page ());
+ static const dir_path& root (
+ options_->root ().empty ()
+ ? dir_path ("/")
+ : options_->root ());
+
+ params::package_search params;
+
+ try
{
- using query = query<T>;
- return "(" +
- (q.empty ()
- ? query ("NULL")
- : "plainto_tsquery (" + query::_val (q) + ")") +
- ")";
+ param_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 ());
}
- void package_search::
- handle (request& rq, response& rs)
+ 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.empty ();
+
+ 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<latest_package_count> (
+ search_param<latest_package_count> (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<latest_package_search_rank> (
+ search_param<latest_package_search_rank> (squery) +
+ "ORDER BY rank DESC, name" +
+ "OFFSET" + to_string (page * res_page) +
+ "LIMIT" + to_string (res_page)))
{
- using namespace web::xhtml;
-
- 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 ().empty ()
- ? dir_path ("/")
- : options_->root ());
-
- params::package_search pr;
-
- try
- {
- param_scanner s (rq.parameters ());
- pr = params::package_search (s, unknown_mode::fail, unknown_mode::fail);
- }
- catch (const unknown_argument& e)
- {
- throw invalid_request (400, e.what ());
- }
-
- const string& sq (pr.query ()); // Search query.
- string qp (sq.empty () ? "" : "q=" + web::mime_url_encode (sq));
- size_t pg (pr.page ());
-
- xml::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 (sp, rt)
- << ~HEAD
- << BODY
- << DIV_HEADER (rt)
- << DIV(ID="content");
-
- session sn;
- transaction t (db_->begin ());
-
- auto pc (
- db_->query_value<latest_package_count> (
- search_param<latest_package_count> (sq)));
-
- auto r (
- db_->query<latest_package_search_rank> (
- search_param<latest_package_search_rank> (sq) +
- "ORDER BY rank DESC, name" +
- "OFFSET" + to_string (pg * rp) +
- "LIMIT" + to_string (rp)));
-
- s << FORM_SEARCH (sq)
- << DIV_COUNTER (pc, "Package", "Packages");
-
- // Enclose the subsequent tables to be able to use nth-child CSS selector.
- //
- s << DIV;
- for (const auto& pr: r)
- {
- shared_ptr<package> p (db_->load<package> (pr.id));
-
- s << TABLE(CLASS="proplist package")
- << TBODY
- << TR_NAME (p->id.name, qp, rt)
- << TR_SUMMARY (p->summary)
- << TR_LICENSE (p->license_alternatives)
- << TR_TAGS (p->tags, rt)
- << TR_DEPENDS (p->dependencies, rt)
- << TR_REQUIRES (p->requirements)
- << ~TBODY
- << ~TABLE;
- }
- s << ~DIV;
-
- t.commit ();
-
- 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, pp, u)
- << ~DIV
- << ~BODY
- << ~HTML;
+ shared_ptr<package> p (db_->load<package> (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_->pages_in_pager (),
+ root.string () + squery_param)
+ << ~DIV
+ << ~BODY
+ << ~HTML;
}
diff --git a/brep/package-version-details b/brep/package-version-details
index 7917de3..36b7420 100644
--- a/brep/package-version-details
+++ b/brep/package-version-details
@@ -5,10 +5,9 @@
#ifndef BREP_PACKAGE_VERSION_DETAILS
#define BREP_PACKAGE_VERSION_DETAILS
-#include <memory> // shared_ptr
-
#include <odb/forward.hxx> // database
+#include <brep/types>
#include <brep/module>
#include <brep/options>
@@ -24,8 +23,8 @@ namespace brep
init (cli::scanner&);
private:
- std::shared_ptr<options::package_version_details> options_;
- std::shared_ptr<odb::core::database> db_;
+ shared_ptr<options::package_version_details> options_;
+ shared_ptr<odb::core::database> db_;
};
}
diff --git a/brep/package-version-details.cxx b/brep/package-version-details.cxx
index a1fe017..a0ad7d4 100644
--- a/brep/package-version-details.cxx
+++ b/brep/package-version-details.cxx
@@ -4,9 +4,6 @@
#include <brep/package-version-details>
-#include <string>
-#include <memory> // shared_ptr, make_shared()
-#include <cassert>
#include <stdexcept> // invalid_argument
#include <xml/serializer>
@@ -20,6 +17,8 @@
#include <web/mime-url-encoding>
#include <brep/page>
+#include <brep/types>
+#include <brep/utility>
#include <brep/options>
#include <brep/package>
#include <brep/package-odb>
@@ -27,297 +26,285 @@
using namespace std;
using namespace odb::core;
+using namespace brep::cli;
-namespace brep
+void brep::package_version_details::
+init (scanner& s)
{
- using namespace cli;
+ MODULE_DIAG;
- void package_version_details::
- init (scanner& s)
- {
- MODULE_DIAG;
-
- options_ = make_shared<options::package_version_details> (
- s, unknown_mode::fail, unknown_mode::fail);
-
- db_ = shared_database (options_->db_host (), options_->db_port ());
- }
+ options_ = make_shared<options::package_version_details> (
+ s, unknown_mode::fail, unknown_mode::fail);
- void package_version_details::
- handle (request& rq, response& rs)
- {
- using namespace web;
- using namespace web::xhtml;
+ db_ = shared_database (options_->db_host (), options_->db_port ());
+}
- MODULE_DIAG;
+void brep::package_version_details::
+handle (request& rq, response& rs)
+{
+ using namespace web;
+ using namespace web::xhtml;
- // The module options object is not changed after being created once per
- // server process.
- //
- static const dir_path& rt (
- options_->root ().empty ()
- ? dir_path ("/")
- : options_->root ());
+ MODULE_DIAG;
- auto i (rq.path ().rbegin ());
- version v;
+ // The module options object is not changed after being created once per
+ // server process.
+ //
+ static const dir_path& root (
+ options_->root ().empty ()
+ ? dir_path ("/")
+ : options_->root ());
- try
- {
- v = version (*i++);
- }
- catch (const invalid_argument& )
- {
- throw invalid_request (400, "invalid package version format");
- }
+ auto i (rq.path ().rbegin ());
+ version ver;
- const string& vs (v.string ());
+ try
+ {
+ ver = version (*i++);
+ }
+ catch (const invalid_argument& )
+ {
+ throw invalid_request (400, "invalid package version format");
+ }
- assert (i != rq.path ().rend ());
- const string& n (*i); // Package name.
- const string name (n + " " + vs);
+ const string& sver (ver.string ());
- params::package_version_details pr;
+ assert (i != rq.path ().rend ());
+ const string& name (*i);
- try
- {
- param_scanner s (rq.parameters ());
- pr = params::package_version_details (
- s, unknown_mode::fail, unknown_mode::fail);
- }
- catch (const unknown_argument& e)
- {
- throw invalid_request (400, e.what ());
- }
+ params::package_version_details params;
+ bool full;
- bool f (pr.full ());
+ try
+ {
+ param_scanner s (rq.parameters ());
+ params = params::package_version_details (
+ s, unknown_mode::fail, unknown_mode::fail);
- auto url ([&vs](bool f = false, const string& a = "") -> string
- {
- string u (vs);
-
- if (f) { u += "?full"; }
- if (!a.empty ()) { u += '#' + a; }
- return u;
- });
-
- xml::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 (sp, rt)
- << ~HEAD
- << BODY
- << DIV_HEADER (rt)
- << DIV(ID="content");
-
- if (f)
- s << CLASS("full");
-
- s << DIV(ID="heading")
- << H1
- << A(HREF=rt / go / path (mime_url_encode (n))) << n << ~A
- << "/"
- << A(HREF=url ()) << vs << ~A
- << ~H1
- << A(HREF=url (!f)) << (f ? "[brief]" : "[full]") << ~A
- << ~DIV;
-
- bool not_found (false);
- shared_ptr<package> p;
-
- session sn;
- transaction t (db_->begin ());
-
- try
- {
- p = db_->load<package> (package_id (n, v));
+ full = params.form () == page_form::full;
+ }
+ catch (const unknown_argument& e)
+ {
+ throw invalid_request (400, e.what ());
+ }
- // If the requested package turned up to be an "external" one just
- // respond that no "internal" package is present.
- //
- not_found = !p->internal ();
- }
- catch (const object_not_persistent& )
+ auto url (
+ [&sver](bool f = false, const string& a = "") -> string
{
- not_found = true;
- }
-
- if (not_found)
- throw invalid_request (404, "Package '" + name + "' not found");
-
- 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, dl, url (!f, "description")));
+ 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<package> pkg;
+
+ session sn;
+ transaction t (db_->begin ());
+
+ try
+ {
+ pkg = db_->load<package> (package_id (name, ver));
- // Link to download from the internal repository.
+ // If the requested package turned up to be an "external" one just
+ // respond that no "internal" package is present.
//
- assert (p->location);
- const string du (p->internal_repository.load ()->location.string () + "/" +
- p->location->string ());
+ not_found = !pkg->internal ();
+ }
+ catch (const object_not_persistent& )
+ {
+ not_found = true;
+ }
- s << TABLE(CLASS="proplist", ID="version")
- << TBODY
+ if (not_found)
+ throw invalid_request (404, "Package '" + title + "' not found");
- // Repeat version here since it can be cut out in the header.
- //
- << TR_VERSION (p->version.string ())
+ s << H2 << pkg->summary << ~H2;
- << TR_PRIORITY (p->priority)
- << TR_LICENSES (p->license_alternatives)
- << TR_LOCATION (p->internal_repository.object_id (), rt)
- << TR_DOWNLOAD (du)
- << ~TBODY
- << ~TABLE
+ static const string id ("description");
+ if (const auto& d = pkg->description)
+ s << (full
+ ? P_DESCRIPTION (*d, id)
+ : P_DESCRIPTION (*d, options_->description_length (),
+ url (!full, id)));
- << TABLE(CLASS="proplist", ID="package")
- << TBODY
- << TR_URL (p->url)
- << TR_EMAIL (p->email);
+ assert (pkg->location);
- if (p->package_url && *p->package_url != p->url)
- s << TR_URL (*p->package_url, "pkg-url");
+ s << TABLE(CLASS="proplist", ID="version")
+ << TBODY
- if (p->package_email && *p->package_email != p->email)
- s << TR_EMAIL (*p->package_email, "pkg-email");
+ // 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;
- s << TR_TAGS (p->tags, rt)
- << ~TBODY
- << ~TABLE;
+ for (const auto& da: ds)
+ {
+ s << TR(CLASS="depends")
+ << TH;
- const auto& ds (p->dependencies);
+ if (da.conditional)
+ s << "?";
- if (!ds.empty ())
- {
- s << H3 << "Depends" << ~H3
- << TABLE(CLASS="proplist", ID="depends")
- << TBODY;
+ s << ~TH
+ << TD
+ << SPAN(CLASS="value");
- for (const auto& da: ds)
+ for (const auto& d: da)
{
- s << TR(CLASS="depends")
- << TH;
+ if (&d != &da[0])
+ s << " | ";
- if (da.conditional)
- s << "?";
+ shared_ptr<package> p (d.package.load ());
+ assert (p->internal () || !p->other_repositories.empty ());
- s << ~TH
- << TD
- << SPAN(CLASS="value");
+ shared_ptr<repository> r (
+ p->internal ()
+ ? p->internal_repository.load ()
+ : p->other_repositories[0].load ());
- for (const auto& d: da)
+ const auto& dcon (d.constraint);
+ const string& dname (p->id.name);
+ string ename (mime_url_encode (dname));
+
+ if (r->url)
{
- if (&d != &da[0])
- s << " | ";
-
- shared_ptr<package> p (d.package.load ());
- assert (p->internal () || !p->other_repositories.empty ());
-
- shared_ptr<repository> r (
- p->internal ()
- ? p->internal_repository.load ()
- : p->other_repositories[0].load ());
-
- const auto& dc (d.constraint);
- const string& dn (p->id.name);
- string en (mime_url_encode (dn));
-
- if (r->url)
- {
- string u (*r->url + "go/" + en);
- s << A(HREF=u) << dn << ~A;
-
- if (dc)
- s << ' '
- << A
- << 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 if no repository URL
- // available.
- //
- s << d;
+ 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;
- s << ~SPAN
- << SPAN_COMMENT (da.comment)
- << ~TD
- << ~TR;
+ 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 << ~TBODY
- << ~TABLE;
+ s << ~SPAN
+ << SPAN_COMMENT (da.comment)
+ << ~TD
+ << ~TR;
}
- t.commit ();
+ s << ~TBODY
+ << ~TABLE;
+ }
- const auto& rm (p->requirements);
+ t.commit ();
- if (!rm.empty ())
- {
- s << H3 << "Requires" << ~H3
- << TABLE(CLASS="proplist", ID="requires")
- << TBODY;
+ 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;
+ for (const auto& ra: rm)
+ {
+ s << TR(CLASS="requires")
+ << TH;
- if (ra.conditional)
- s << "?";
+ if (ra.conditional)
+ s << "?";
- s << ~TH
- << TD
- << SPAN(CLASS="value");
+ s << ~TH
+ << TD
+ << SPAN(CLASS="value");
- for (const auto& r: ra)
- {
- if (&r != &ra[0])
- s << " | ";
-
- s << r;
- }
+ for (const auto& r: ra)
+ {
+ if (&r != &ra[0])
+ s << " | ";
- s << ~SPAN
- << SPAN_COMMENT (ra.comment)
- << ~TD
- << ~TR;
+ s << r;
}
- s << ~TBODY
- << ~TABLE;
+ s << ~SPAN
+ << SPAN_COMMENT (ra.comment)
+ << ~TD
+ << ~TR;
}
- 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, cl, url (!f, "changes")));
-
- s << ~DIV
- << ~BODY
- << ~HTML;
+ s << ~TBODY
+ << ~TABLE;
}
+
+ const auto& ch (pkg->changes);
+ if (!ch.empty ())
+ s << H3 << "Changes" << ~H3
+ << (full
+ ? PRE_CHANGES (ch)
+ : PRE_CHANGES (ch, options_->description_length (),
+ url (!full, "changes")));
+
+ s << ~DIV
+ << ~BODY
+ << ~HTML;
}
diff --git a/brep/package.cxx b/brep/package.cxx
index d99819c..ecaa369 100644
--- a/brep/package.cxx
+++ b/brep/package.cxx
@@ -4,12 +4,12 @@
#include <brep/package>
-#include <utility> // move()
-#include <cassert>
#include <ostream>
#include <odb/database.hxx>
+#include <brep/types>
+#include <brep/utility>
#include <brep/package-odb>
using namespace std;
@@ -131,10 +131,11 @@ namespace brep
// repository
//
repository::
- repository (repository_location l, string d, dir_path p)
+ repository (repository_location l, string d, dir_path p, uint16_t r)
: name (l.canonical_name ()),
location (move (l)),
display_name (move (d)),
+ priority (r),
local_path (move (p)),
internal (true)
{
@@ -144,6 +145,7 @@ namespace brep
repository (repository_location l)
: name (l.canonical_name ()),
location (move (l)),
+ priority (0),
internal (false)
{
}
diff --git a/brep/page b/brep/page
index 0d0887f..907bc45 100644
--- a/brep/page
+++ b/brep/page
@@ -5,11 +5,9 @@
#ifndef BREP_PAGE
#define BREP_PAGE
-#include <string>
-#include <cstddef> // size_t
-
#include <xml/forward>
+#include <brep/types>
#include <brep/package>
namespace brep
@@ -51,13 +49,13 @@ namespace brep
class FORM_SEARCH
{
public:
- FORM_SEARCH (const std::string& q): query_ (q) {}
+ FORM_SEARCH (const string& q): query_ (q) {}
void
operator() (xml::serializer& s) const;
private:
- const std::string& query_;
+ const string& query_;
};
// Generates counter element.
@@ -69,14 +67,14 @@ namespace brep
class DIV_COUNTER
{
public:
- DIV_COUNTER (std::size_t c, const char* s, const char* p)
+ DIV_COUNTER (size_t c, const char* s, const char* p)
: count_ (c), singular_ (s), plural_ (p) {}
void
operator() (xml::serializer& s) const;
private:
- std::size_t count_;
+ size_t count_;
const char* singular_;
const char* plural_;
};
@@ -86,15 +84,15 @@ namespace brep
class TR_NAME
{
public:
- TR_NAME (const std::string& n, const std::string& q, const dir_path& r)
+ TR_NAME (const string& n, const string& q, const dir_path& r)
: name_ (n), query_param_ (q), root_ (r) {}
void
operator() (xml::serializer& s) const;
private:
- const std::string& name_;
- const std::string& query_param_;
+ const string& name_;
+ const string& query_param_;
const dir_path& root_;
};
@@ -105,22 +103,20 @@ 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,
- const dir_path& r)
+ TR_VERSION (const string& p, const 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)
+ TR_VERSION (const string& v)
: package_ (nullptr), version_ (v), root_ (nullptr) {}
void
operator() (xml::serializer& s) const;
private:
- const std::string* package_;
- const std::string& version_;
+ const string* package_;
+ const string& version_;
const dir_path* root_;
};
@@ -129,13 +125,13 @@ namespace brep
class TR_SUMMARY
{
public:
- TR_SUMMARY (const std::string& s): summary_ (s) {}
+ TR_SUMMARY (const string& s): summary_ (s) {}
void
operator() (xml::serializer& s) const;
private:
- const std::string& summary_;
+ const string& summary_;
};
// Generates package license alternatives element.
@@ -262,14 +258,14 @@ namespace brep
class TR_LOCATION
{
public:
- TR_LOCATION (const std::string& n, const dir_path& r)
+ TR_LOCATION (const string& n, const dir_path& r)
: name_ (n), root_ (r) {}
void
operator() (xml::serializer& s) const;
private:
- const std::string& name_;
+ const string& name_;
const dir_path& root_;
};
@@ -278,13 +274,13 @@ namespace brep
class TR_DOWNLOAD
{
public:
- TR_DOWNLOAD (const std::string& u): url_ (u) {}
+ TR_DOWNLOAD (const string& u): url_ (u) {}
void
operator() (xml::serializer& s) const;
private:
- const std::string& url_;
+ const string& url_;
};
// Generates comment element.
@@ -292,13 +288,13 @@ namespace brep
class SPAN_COMMENT
{
public:
- SPAN_COMMENT (const std::string& c): comment_ (c) {}
+ SPAN_COMMENT (const string& c): comment_ (c) {}
void
operator() (xml::serializer& s) const;
private:
- const std::string& comment_;
+ const string& comment_;
};
// Generates package description element.
@@ -308,22 +304,22 @@ namespace brep
public:
// Genereate full description.
//
- P_DESCRIPTION (const std::string& d, bool u = true)
- : description_ (d), length_ (d.size ()), url_ (nullptr), unique_ (u) {}
+ P_DESCRIPTION (const string& d, const string& id = "")
+ : description_ (d), length_ (d.size ()), url_ (nullptr), id_ (id) {}
// Genereate brief description.
//
- P_DESCRIPTION (const std::string& d, size_t l, const std::string& u)
- : description_ (d), length_ (l), url_ (&u), unique_ (false) {}
+ P_DESCRIPTION (const string& d, size_t l, const string& u)
+ : description_ (d), length_ (l), url_ (&u) {}
void
operator() (xml::serializer& s) const;
private:
- const std::string& description_;
- std::size_t length_;
- const std::string* url_; // Full page url.
- bool unique_;
+ const string& description_;
+ size_t length_;
+ const string* url_; // Full page url.
+ string id_;
};
// Generates package description element.
@@ -333,21 +329,21 @@ namespace brep
public:
// Genereate full changes info.
//
- PRE_CHANGES (const std::string& c)
+ PRE_CHANGES (const string& c)
: changes_ (c), length_ (c.size ()), url_ (nullptr) {}
// Genereate brief changes info.
//
- PRE_CHANGES (const std::string& c, size_t l, const std::string& u)
+ PRE_CHANGES (const string& c, size_t l, const string& u)
: changes_ (c), length_ (l), url_ (&u) {}
void
operator() (xml::serializer& s) const;
private:
- const std::string& changes_;
- std::size_t length_;
- const std::string* url_; // Full page url.
+ const string& changes_;
+ size_t length_;
+ const string* url_; // Full page url.
};
// Generates paging element.
@@ -355,28 +351,28 @@ namespace brep
class DIV_PAGER
{
public:
- DIV_PAGER (std::size_t current_page,
- std::size_t item_count,
- std::size_t item_per_page,
- std::size_t page_number_count,
- const std::string& url);
+ DIV_PAGER (size_t current_page,
+ size_t item_count,
+ size_t item_per_page,
+ size_t page_number_count,
+ const string& url);
void
operator() (xml::serializer& s) const;
private:
- std::size_t current_page_;
- std::size_t item_count_;
- std::size_t item_per_page_;
- std::size_t page_number_count_;
- const std::string& url_;
+ size_t current_page_;
+ size_t item_count_;
+ size_t item_per_page_;
+ size_t page_number_count_;
+ const string& url_;
};
// Convert the argument to a string representing the valid HTML 5 'id'
// attribute value.
//
- std::string
- id_attribute (const std::string& v);
+ string
+ html_id (const string&);
}
#endif // BREP_PAGE
diff --git a/brep/page.cxx b/brep/page.cxx
index 5b650a3..780d759 100644
--- a/brep/page.cxx
+++ b/brep/page.cxx
@@ -6,10 +6,6 @@
#include <set>
#include <ios> // hex, uppercase, right
-#include <string>
-#include <memory> // shared_ptr
-#include <cstddef> // size_t
-#include <cassert>
#include <sstream>
#include <iomanip> // setw(), setfill()
#include <algorithm> // min()
@@ -19,6 +15,8 @@
#include <web/xhtml>
#include <web/mime-url-encoding>
+#include <brep/types>
+#include <brep/utility>
#include <brep/package>
#include <brep/package-odb>
@@ -29,18 +27,16 @@ using namespace web::xhtml;
namespace brep
{
- static const path go ("go");
- static const path about ("about");
-
// CSS_LINKS
//
void CSS_LINKS::
operator() (serializer& s) const
{
- static const path c ("common.css");
+ static const path css ("@");
- s << *LINK(REL="stylesheet", TYPE="text/css", HREF=root_ / c)
- << *LINK(REL="stylesheet", TYPE="text/css", HREF=root_ / path_);
+ s << *LINK(REL="stylesheet", TYPE="text/css",
+ HREF=root_ / css / path ("common.css"))
+ << *LINK(REL="stylesheet", TYPE="text/css", HREF=root_ / css / path_);
}
// DIV_HEADER
@@ -51,7 +47,7 @@ namespace brep
s << DIV(ID="header")
<< DIV(ID="header-menu")
<< A(HREF=root_) << "packages" << ~A
- << A(HREF=root_ / about) << "about" << ~A
+ << A(HREF=root_.string () + "?about") << "about" << ~A
<< ~DIV
<< ~DIV;
}
@@ -105,14 +101,12 @@ namespace brep
<< SPAN(CLASS="value")
<< A
<< HREF
- << root_ / go / path (mime_url_encode (name_));
- // Propagate search criteria to the package details page.
- //
- if (!query_param_.empty ())
- s << "?" << query_param_;
+ // Propagate search criteria to the package details page.
+ //
+ << root_ / path (mime_url_encode (name_)) << query_param_
- s << ~HREF
+ << ~HREF
<< name_
<< ~A
<< ~SPAN
@@ -133,8 +127,9 @@ namespace brep
else
{
assert (root_ != nullptr);
- path p (mime_url_encode (*package_));
- s << A(HREF=*root_ / go / p / path (version_)) << version_ << ~A;
+ s << A(HREF=*root_ / path (mime_url_encode (*package_)) / path (version_))
+ << version_
+ << ~A;
}
s << ~SPAN
@@ -234,8 +229,7 @@ namespace brep
if (&t != &tags_[0])
s << " ";
- s << A
- << HREF << root_ << "?q=" << mime_url_encode (t) << ~HREF
+ s << A << HREF << root_ << "?q=" << mime_url_encode (t) << ~HREF
<< t
<< ~A;
}
@@ -270,25 +264,25 @@ namespace brep
// Suppress package name duplicates.
//
- set<string> ds;
+ set<string> names;
for (const auto& da: d)
- ds.emplace (da.name ());
+ names.emplace (da.name ());
- bool m (ds.size () > 1);
+ bool mult (names.size () > 1);
- if (m)
+ if (mult)
s << "(";
- bool f (true); // First dependency alternative.
+ bool first (true);
for (const auto& da: d)
{
string n (da.name ());
- if (ds.find (n) != ds.end ())
+ if (names.find (n) != names.end ())
{
- ds.erase (n);
+ names.erase (n);
- if (f)
- f = false;
+ if (first)
+ first = false;
else
s << " | ";
@@ -303,9 +297,9 @@ namespace brep
auto en (mime_url_encode (n));
if (r->url)
- s << A << HREF << *r->url << "go/" << en << ~HREF << n << ~A;
+ s << A(HREF=*r->url + en) << n << ~A;
else if (p->internal ())
- s << A(HREF=root_ / go / path (en)) << n << ~A;
+ s << A(HREF=root_ / path (en)) << n << ~A;
else
// Display the dependency as a plain text if no repository URL
// available.
@@ -314,7 +308,7 @@ namespace brep
}
}
- if (m)
+ if (mult)
s << ")";
}
@@ -365,9 +359,9 @@ namespace brep
}
else
{
- bool m (r.size () > 1);
+ bool mult (r.size () > 1);
- if (m)
+ if (mult)
s << "(";
for (const auto& ra: r)
@@ -378,7 +372,7 @@ namespace brep
s << ra;
}
- if (m)
+ if (mult)
s << ")";
}
}
@@ -411,7 +405,7 @@ namespace brep
<< TH << label_ << ~TH
<< TD
<< SPAN(CLASS="value")
- << A << HREF << "mailto:" << email_ << ~HREF << email_ << ~A
+ << A(HREF="mailto:" + email_) << email_ << ~A
<< ~SPAN
<< SPAN_COMMENT (email_.comment)
<< ~TD
@@ -446,7 +440,7 @@ namespace brep
<< SPAN(CLASS="value")
<< A
<< HREF
- << root_ / about << "#" << mime_url_encode (id_attribute (name_))
+ << root_ << "?about#" << mime_url_encode (html_id (name_))
<< ~HREF
<< name_
<< ~A
@@ -475,7 +469,7 @@ namespace brep
{
if (size_t l = comment_.size ())
s << SPAN(CLASS="comment")
- << (comment_[l - 1] == '.' ? string (comment_, 0, l - 1) : comment_)
+ << (comment_.back () == '.' ? string (comment_, 0, l - 1) : comment_)
<< ~SPAN;
}
@@ -488,19 +482,19 @@ namespace brep
return;
auto n (description_.find_first_of (" \t\n", length_));
- bool f (n == string::npos); // Description length is below the limit.
+ bool full (n == string::npos); // Description length is below the limit.
// Truncate description if length exceed the limit.
//
- const string& d (f ? description_ : string (description_, 0, n));
+ const string& d (full ? description_ : string (description_, 0, n));
// Format the description into paragraphs, recognizing a blank line as
// paragraph separator, and replacing single newlines with a space.
//
s << P;
- if (unique_)
- s << ID("description");
+ if (!id_.empty ())
+ s << ID(id_);
bool nl (false); // The previous character is '\n'.
for (const auto& c: d)
@@ -527,7 +521,7 @@ namespace brep
}
}
- if (!f)
+ if (!full)
{
assert (url_ != nullptr);
s << "... " << A(HREF=*url_) << "More" << ~A;
@@ -545,14 +539,14 @@ namespace brep
return;
auto n (changes_.find_first_of (" \t\n", length_));
- bool f (n == string::npos); // Changes length is below the limit.
+ bool full (n == string::npos); // Changes length is below the limit.
// Truncate changes if length exceed the limit.
//
- const string& c (f ? changes_ : string (changes_, 0, n));
+ const string& c (full ? changes_ : string (changes_, 0, n));
s << PRE(ID="changes") << c;
- if (!f)
+ if (!full)
{
assert (url_ != nullptr);
s << "... " << A(HREF=*url_) << "More" << ~A;
@@ -583,14 +577,14 @@ namespace brep
if (item_count_ == 0 || item_per_page_ == 0)
return;
- size_t pc (item_count_ / item_per_page_); // Page count.
+ size_t pcount (item_count_ / item_per_page_); // Page count.
if (item_count_ % item_per_page_)
- ++pc;
+ ++pcount;
- if (pc > 1)
+ if (pcount > 1)
{
- auto u (
+ auto url (
[this](size_t page) -> string
{
return page == 0
@@ -602,17 +596,17 @@ namespace brep
s << DIV(ID="pager");
if (current_page_ > 0)
- s << A(ID="prev", HREF=u (current_page_ - 1)) << "Prev" << ~A;
+ s << A(ID="prev", HREF=url (current_page_ - 1)) << "Prev" << ~A;
if (page_number_count_)
{
size_t offset (page_number_count_ / 2);
- size_t fp (current_page_ > offset ? current_page_ - offset : 0);
- size_t tp (min (fp + page_number_count_, pc));
+ size_t from (current_page_ > offset ? current_page_ - offset : 0);
+ size_t to (min (from + page_number_count_, pcount));
- for (size_t p (fp); p < tp; ++p)
+ for (size_t p (from); p < to; ++p)
{
- s << A(HREF=u (p));
+ s << A(HREF=url (p));
if (p == current_page_)
s << ID("curr");
@@ -622,8 +616,8 @@ namespace brep
}
}
- if (current_page_ < pc - 1)
- s << A(ID="next", HREF=u (current_page_ + 1)) << "Next" << ~A;
+ if (current_page_ < pcount - 1)
+ s << A(ID="next", HREF=url (current_page_ + 1)) << "Next" << ~A;
s << ~DIV;
}
@@ -634,7 +628,7 @@ namespace brep
// http://www.w3.org/TR/html5/dom.html#the-id-attribute.
//
string
- id_attribute (const string& v)
+ html_id (const string& v)
{
ostringstream o;
o << hex << uppercase << right << setfill ('0');
@@ -654,9 +648,8 @@ namespace brep
case '\f':
case '~':
{
- // Intentionally use '~' as an escape character to leave it unescaped
- // being a part of URL. For example
- // http://cppget.org/about#cppget.org%2Fmath~20lab
+ // We use '~' as an escape character because it doesn't require
+ // escaping in URLs.
//
o << "~" << setw (2) << static_cast<unsigned short> (c);
break;
diff --git a/brep/repository-details b/brep/repository-details
index a3008dc..fb41e32 100644
--- a/brep/repository-details
+++ b/brep/repository-details
@@ -5,10 +5,9 @@
#ifndef BREP_REPOSITORY_DETAILS
#define BREP_REPOSITORY_DETAILS
-#include <memory> // shared_ptr
-
#include <odb/forward.hxx> // database
+#include <brep/types>
#include <brep/module>
#include <brep/options>
@@ -24,8 +23,8 @@ namespace brep
init (cli::scanner&);
private:
- std::shared_ptr<options::repository_details> options_;
- std::shared_ptr<odb::core::database> db_;
+ shared_ptr<options::repository_details> options_;
+ shared_ptr<odb::core::database> db_;
};
}
diff --git a/brep/repository-details.cxx b/brep/repository-details.cxx
index 86a6099..eb2885c 100644
--- a/brep/repository-details.cxx
+++ b/brep/repository-details.cxx
@@ -4,9 +4,6 @@
#include <brep/repository-details>
-#include <string>
-#include <memory> // make_shared()
-
#include <xml/serializer>
#include <odb/database.hxx>
@@ -17,85 +14,96 @@
#include <web/mime-url-encoding>
#include <brep/page>
+#include <brep/types>
+#include <brep/utility>
#include <brep/options>
#include <brep/package>
#include <brep/package-odb>
#include <brep/shared-database>
-using namespace std;
using namespace odb::core;
+using namespace brep::cli;
-namespace brep
+void brep::repository_details::
+init (scanner& s)
{
- using namespace cli;
+ MODULE_DIAG;
- void repository_details::
- init (scanner& s)
- {
- MODULE_DIAG;
+ options_ = make_shared<options::repository_details> (
+ s, unknown_mode::fail, unknown_mode::fail);
- options_ = make_shared<options::repository_details> (
- s, unknown_mode::fail, unknown_mode::fail);
+ db_ = shared_database (options_->db_host (), options_->db_port ());
+}
- db_ = shared_database (options_->db_host (), options_->db_port ());
- }
+void brep::repository_details::
+handle (request& rq, response& rs)
+{
+ using namespace web::xhtml;
- void repository_details::
- handle (request&, response& rs)
+ MODULE_DIAG;
+
+ // The module options object is not changed after being created once per
+ // server process.
+ //
+ static const dir_path& root (
+ options_->root ().empty ()
+ ? dir_path ("/")
+ : options_->root ());
+
+ // Make sure no parameters passed.
+ //
+ try
{
- using namespace web::xhtml;
+ param_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 ());
+ }
- MODULE_DIAG;
+ static const string title ("About");
+ xml::serializer s (rs.content (), title);
- // The module options object is not changed after being created once per
- // server process.
+ 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<repository>;
+
+ for (const auto& r:
+ db_->query<repository> (
+ 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.
//
- static const dir_path& rt (
- options_->root ().empty ()
- ? dir_path ("/")
- : options_->root ());
-
- xml::serializer s (rs.content (), "About");
- const string& title (s.output_name ());
- static const path sp ("repository-details.css");
-
- s << HTML
- << HEAD
- << TITLE << title << ~TITLE
- << CSS_LINKS (sp, rt)
- << ~HEAD
- << BODY
- << DIV_HEADER (rt)
- << DIV(ID="content");
-
- transaction t (db_->begin ());
-
- using query = query<repository>;
- auto rp (db_->query<repository> (query::internal + "ORDER BY name"));
-
- for (const auto& r: rp)
- {
- string id (id_attribute (r.name));
- s << H1(ID=id)
- << A(HREF="#" + web::mime_url_encode (id)) << r.name << ~A
- << ~H1;
-
- if (r.summary)
- s << H2 << *r.summary << ~H2;
-
- if (r.description)
- s << P_DESCRIPTION (*r.description, false);
-
- if (r.email)
- s << P
- << A << HREF << "mailto:" << *r.email << ~HREF << *r.email << ~A
- << ~P;
- }
-
- t.commit ();
-
- s << ~DIV
- << ~BODY
- << ~HTML;
+ 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;
}
diff --git a/brep/repository-root b/brep/repository-root
new file mode 100644
index 0000000..e5fba78
--- /dev/null
+++ b/brep/repository-root
@@ -0,0 +1,31 @@
+// 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 <brep/module>
+
+namespace brep
+{
+ class package_search;
+ class repository_details;
+
+ class repository_root: public module
+ {
+ public:
+ repository_root (package_search& ps, repository_details& rd)
+ : package_search_ (ps), repository_details_ (rd) {}
+
+ private:
+ virtual void
+ handle (request&, response&);
+
+ private:
+ package_search& package_search_;
+ repository_details& repository_details_;
+ };
+}
+
+#endif // BREP_REPOSITORY_ROOT
diff --git a/brep/repository-root.cxx b/brep/repository-root.cxx
new file mode 100644
index 0000000..180d61f
--- /dev/null
+++ b/brep/repository-root.cxx
@@ -0,0 +1,119 @@
+// file : brep/repository-root.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#include <brep/repository-root>
+
+#include <map>
+#include <functional>
+
+#include <web/module>
+
+#include <brep/types>
+#include <brep/utility>
+#include <brep/package-search>
+#include <brep/repository-details>
+
+using namespace std;
+
+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
+ //
+ void repository_root::
+ handle (request& rq, response& rs)
+ {
+ MODULE_DIAG;
+
+ // Dispatch request handling to the appropriate module depending on the
+ // function name passed as a first HTTP request parameter. The parameter
+ // should have no value specified. If no function name is passed,
+ // the default handler is selected. Example: cppget.org/?about
+ //
+
+ string func;
+ name_values params (rq.parameters ());
+
+ // Obtain the function name.
+ //
+ if (!params.empty () && !params.front ().value)
+ {
+ func = move (params.front ().name);
+
+ // Cleanup not to confuse the selected handler with the unknown parameter.
+ //
+ params.erase (params.begin ());
+ }
+
+ // To handle the request a new module instance is created as a copy of
+ // the corresponsing exemplar.
+ //
+ using module_ptr = unique_ptr<module>;
+
+ // Function name to module factory map.
+ //
+ const map<string, function<module_ptr()>>
+ handlers ({
+ {
+ "about",
+ [this]() -> module_ptr
+ {return module_ptr (new repository_details (repository_details_));}
+ },
+ {
+ string (), // The default handler.
+ [this]() -> module_ptr
+ {return module_ptr (new package_search (package_search_));}
+ }});
+
+ // Find proper handler.
+ //
+ auto i (handlers.find (func));
+ if (i == handlers.end ())
+ throw invalid_request (400, "unknown function");
+
+ module_ptr m (i->second ());
+ if (m->loaded ())
+ {
+ // Delegate request handling.
+ //
+ // @@ An exception thrown by the handler will be attributed to the
+ // repository-root service while being logged. Could intercept
+ // exception handling to fix that, but let's not complicate the
+ // code for the time being.
+ //
+ //
+ request_proxy rqp (rq, params);
+ m->handle (rqp, rs);
+ }
+ else
+ // The module is not loaded, presumably being disabled in the web server
+ // configuration file.
+ //
+ throw invalid_request (404, "handler not available");
+ }
+}
diff --git a/brep/services.cxx b/brep/services.cxx
index e41d3f3..b214a09 100644
--- a/brep/services.cxx
+++ b/brep/services.cxx
@@ -8,6 +8,7 @@
#include <brep/package-search>
#include <brep/package-details>
+#include <brep/repository-root>
#include <brep/repository-details>
#include <brep/package-version-details>
@@ -37,3 +38,9 @@ service AP_MODULE_DECLARE_DATA repository_details_srv (
"repository-details",
repository_details_mod,
{"root", "db-host", "db-port", "conf"});
+
+static repository_root repository_root_mod (
+ package_search_mod, repository_details_mod);
+service AP_MODULE_DECLARE_DATA repository_root_srv (
+ "repository-root",
+ repository_root_mod);
diff --git a/brep/shared-database b/brep/shared-database
index 36fa0a2..4d8186d 100644
--- a/brep/shared-database
+++ b/brep/shared-database
@@ -5,11 +5,10 @@
#ifndef BREP_SHARED_DATABASE
#define BREP_SHARED_DATABASE
-#include <string>
-#include <memory> // shared_ptr
-
#include <odb/forward.hxx> // database
+#include <brep/types>
+
namespace brep
{
// Returns pointer to the shared database instance, creating one on the
@@ -17,8 +16,8 @@ namespace brep
// to ones of the existing database instance throwing runtime_error
// otherwise. Is not thread-safe.
//
- std::shared_ptr<odb::core::database>
- shared_database (const std::string& host, unsigned int port);
+ shared_ptr<odb::core::database>
+ shared_database (const string& host, unsigned int port);
}
#endif // BREP_SHARED_DATABASE
diff --git a/brep/shared-database.cxx b/brep/shared-database.cxx
index fc17659..c1d128f 100644
--- a/brep/shared-database.cxx
+++ b/brep/shared-database.cxx
@@ -4,12 +4,12 @@
#include <brep/shared-database>
-#include <memory> // weak_ptr, shared_ptr, make_shared()
#include <stdexcept> // runtime_error
#include <odb/pgsql/database.hxx>
-using namespace std;
+#include <brep/types>
+#include <brep/utility>
namespace brep
{
@@ -27,7 +27,7 @@ namespace brep
if (shared_ptr<database> d = db.lock ())
{
if (h != d->host () || p != d->port ())
- throw runtime_error ("shared database host/port mismatch");
+ throw std::runtime_error ("shared database host/port mismatch");
return d;
}
diff --git a/brep/types b/brep/types
new file mode 100644
index 0000000..d3b7b2d
--- /dev/null
+++ b/brep/types
@@ -0,0 +1,60 @@
+// file : brep/types -*- C++ -*-
+// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#ifndef BREP_TYPES
+#define BREP_TYPES
+
+#include <vector>
+#include <string>
+#include <memory> // unique_ptr, weak_ptr, shared_ptr
+#include <cstddef> // size_t
+#include <cstdint> // uint{8,16,32,64}_t
+
+#include <odb/lazy-ptr.hxx>
+
+#include <butl/path>
+#include <butl/path-io>
+#include <butl/optional>
+#include <butl/timestamp>
+
+namespace brep
+{
+ // Commonly-used types
+ //
+ using std::uint8_t;
+ using std::uint16_t;
+ using std::uint32_t;
+ using std::uint64_t;
+ using std::size_t;
+ using std::vector;
+ using std::string;
+
+ using strings = vector<string>;
+
+ using butl::optional;
+ using butl::nullopt;
+
+ // Smart pointers
+ //
+ using std::unique_ptr;
+
+ using std::shared_ptr;
+ using std::weak_ptr;
+
+ using odb::lazy_shared_ptr;
+ using odb::lazy_weak_ptr;
+
+ // <butl/path>
+ //
+ using butl::path;
+ using butl::dir_path;
+ using butl::invalid_path;
+
+ // <butl/timestamp>
+ //
+ using butl::timestamp;
+ using butl::timestamp_nonexistent;
+}
+
+#endif // BREP_TYPES
diff --git a/brep/types-parsers b/brep/types-parsers
index 6d30544..dfe86a6 100644
--- a/brep/types-parsers
+++ b/brep/types-parsers
@@ -8,7 +8,8 @@
#ifndef BREP_TYPES_PARSERS
#define BREP_TYPES_PARSERS
-#include <butl/path>
+#include <brep/types>
+#include <brep/options-types>
namespace brep
{
@@ -20,10 +21,17 @@ namespace brep
struct parser;
template <>
- struct parser<butl::dir_path>
+ struct parser<dir_path>
{
static void
- parse (butl::dir_path&, scanner&);
+ parse (dir_path&, scanner&);
+ };
+
+ template <>
+ struct parser<page_form>
+ {
+ static void
+ parse (page_form&, scanner&);
};
}
}
diff --git a/brep/types-parsers.cxx b/brep/types-parsers.cxx
index 6236000..f7f1c1b 100644
--- a/brep/types-parsers.cxx
+++ b/brep/types-parsers.cxx
@@ -4,16 +4,17 @@
#include <brep/types-parsers>
-#include <butl/path>
-
+#include <brep/types>
#include <brep/options>
-using namespace butl;
+using namespace std;
namespace brep
{
namespace cli
{
+ // Parse path.
+ //
template <typename T>
static void
parse_path (T& x, scanner& s)
@@ -40,5 +41,24 @@ namespace brep
{
parse_path (x, s);
}
+
+ // Parse page_form.
+ //
+ void parser<page_form>::
+ parse (page_form& x, scanner& s)
+ {
+ const char* o (s.next ());
+
+ if (!s.more ())
+ throw missing_value (o);
+
+ const string v (s.next ());
+ if (v == "full")
+ x = page_form::full;
+ else if (v == "brief")
+ x = page_form::brief;
+ else
+ throw invalid_value (o, v);
+ }
}
}
diff --git a/brep/utility b/brep/utility
new file mode 100644
index 0000000..d978e2b
--- /dev/null
+++ b/brep/utility
@@ -0,0 +1,20 @@
+// file : brep/utility -*- C++ -*-
+// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#ifndef BREP_UTILITY
+#define BREP_UTILITY
+
+#include <string> // to_string()
+#include <memory> // make_shared()
+#include <cassert>
+#include <utility> // move()
+
+namespace brep
+{
+ using std::move;
+ using std::make_shared;
+ using std::to_string;
+};
+
+#endif // BREP_UTILITY