From 2700ed6a3e1092a064f28b07f8e2c4e5b9b830e7 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 16 Nov 2015 20:02:06 +0200 Subject: Implement new URL path schema for the web interface --- brep/buildfile | 7 +- brep/diagnostics | 28 +-- brep/diagnostics.cxx | 3 +- brep/module | 29 ++- brep/module.cxx | 13 +- brep/options-types | 19 ++ brep/options.cli | 53 ++--- brep/package | 178 +++++++-------- brep/package-details | 7 +- brep/package-details.cxx | 384 ++++++++++++++++--------------- brep/package-search | 7 +- brep/package-search.cxx | 227 +++++++++---------- brep/package-version-details | 7 +- brep/package-version-details.cxx | 477 +++++++++++++++++++-------------------- brep/package.cxx | 8 +- brep/page | 94 ++++---- brep/page.cxx | 117 +++++----- brep/repository-details | 7 +- brep/repository-details.cxx | 142 ++++++------ brep/repository-root | 31 +++ brep/repository-root.cxx | 119 ++++++++++ brep/services.cxx | 7 + brep/shared-database | 9 +- brep/shared-database.cxx | 6 +- brep/types | 60 +++++ brep/types-parsers | 14 +- brep/types-parsers.cxx | 26 ++- brep/utility | 20 ++ 28 files changed, 1177 insertions(+), 922 deletions(-) create mode 100644 brep/options-types create mode 100644 brep/repository-root create mode 100644 brep/repository-root.cxx create mode 100644 brep/types create mode 100644 brep/utility (limited to 'brep') 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 -#include // uint64_t -#include // move() +#include // forward() #include #include +#include +#include + 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; + using diag_data = vector; // // @@ -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 -#include #include +#include + 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 -#include // move() -#include - #include +#include +#include #include #include @@ -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 void level1 (const F& f) const {if (verb_ >= 1) f ();} template 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 #include -#include -#include #include #include -#include // strncmp() +#include // strchr() #include #include // bind() #include #include +#include +#include #include 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 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 ; -include ; // uint16_t - -include ; +include ; +include ; 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 -#include -#include #include -#include // shared_ptr -#include -#include // size_t -#include // move() -#include // uint16 -#include +#include // ostream #include #include // database -#include #include -#include -#include -#include -#include +#include +#include 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; - 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; - using optional_string = optional; + using optional_string = optional; #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; + using license_alternatives = vector; #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; + lazy_shared_ptr package; optional 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 + class dependency_alternatives: public vector { 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; + using dependencies = vector; // requirements // using bpkg::requirement_alternatives; - using requirements = std::vector; + using requirements = vector; #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 url; + optional url; - // Set only for internal repositories. + // Present only for internal repositories. // - optional email; - optional summary; - optional description; + optional email; + optional summary; + optional 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> complements; - std::vector> prerequisites; + vector> complements; + vector> 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 description, - std::string changes, + optional description, + string changes, url_type, optional package_url, email_type, @@ -408,7 +390,7 @@ namespace brep dependencies_type, requirements_type, optional location, - std::shared_ptr); + shared_ptr); // 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); + package (string name, version_type, shared_ptr); 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 description; - std::string changes; + optional description; + string changes; url_type url; optional package_url; email_type email; optional package_email; dependencies_type dependencies; requirements_type requirements; - odb::lazy_shared_ptr internal_repository; + lazy_shared_ptr internal_repository; - // Path to the package file. Set only for internal packages. + // Path to the package file. Present only for internal packages. // optional location; - std::vector> other_repositories; + vector> other_repositories; // Database mapping. // @@ -454,7 +436,7 @@ namespace brep // license // using _license_key = odb::nested_key; - 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; 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 // shared_ptr - #include // database +#include #include #include @@ -24,8 +23,8 @@ namespace brep init (cli::scanner&); private: - std::shared_ptr options_; - std::shared_ptr db_; + shared_ptr options_; + shared_ptr 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 -#include -#include // make_shared(), shared_ptr -#include // size_t -#include - #include #include @@ -20,222 +15,225 @@ #include #include +#include +#include #include #include #include #include -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 ( + s, unknown_mode::fail, unknown_mode::fail); - options_ = make_shared ( - 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 +static inline query +search_params (const brep::string& n, const brep::string& q) +{ + using query = query; + + return "(" + + (q.empty () + ? query ("NULL") + : "plainto_tsquery (" + query::_val (q) + ")") + + "," + + query::_val (n) + + ")"; +} - template - static inline query - search_params (const string& n, const string& q) - { - using query = query; - - 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 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 ( - query( - "(" + query::_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 pkg; + { + latest_package lp; + if (!db_->query_one ( + query( + "(" + query::_val (name) + ")"), lp)) + throw invalid_request (404, "Package '" + name + "' not found"); - p = db_->load (lp.id); - } + pkg = db_->load (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 ( - search_params (name, sq))); - - auto r ( - db_->query ( - search_params (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 p (db_->load (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 ( + search_params (name, squery))); + + s << FORM_SEARCH (squery) + << DIV_COUNTER (pkg_count, "Version", "Versions"); + + // Enclose the subsequent tables to be able to use nth-child CSS selector. + // + s << DIV; + for (const auto& pr: + db_->query ( + search_params (name, squery) + + "ORDER BY rank DESC, version_epoch DESC, " + "version_canonical_upstream DESC, version_revision DESC" + + "OFFSET" + to_string (page * res_page) + + "LIMIT" + to_string (res_page))) + { + shared_ptr p (db_->load (pr.id)); - // @@ 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> 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> 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 // shared_ptr - #include // database +#include #include #include @@ -24,8 +23,8 @@ namespace brep init (cli::scanner&); private: - std::shared_ptr options_; - std::shared_ptr db_; + shared_ptr options_; + shared_ptr 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 -#include -#include // make_shared(), shared_ptr -#include // size_t - #include #include @@ -19,134 +15,131 @@ #include #include +#include +#include #include #include #include #include -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 ( + s, unknown_mode::fail, unknown_mode::fail); - options_ = make_shared ( - 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 +static inline query +search_param (const brep::string& q) +{ + using query = query; + return "(" + + (q.empty () + ? query ("NULL") + : "plainto_tsquery (" + query::_val (q) + ")") + + ")"; +} + +void brep::package_search:: +handle (request& rq, response& rs) +{ + using namespace web::xhtml; - template - static inline query - 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; - 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 ( + search_param (squery))); + + s << FORM_SEARCH (squery) + << DIV_COUNTER (pkg_count, "Package", "Packages"); + + // Enclose the subsequent tables to be able to use nth-child CSS selector. + // + s << DIV; + for (const auto& pr: + db_->query ( + search_param (squery) + + "ORDER BY rank DESC, name" + + "OFFSET" + to_string (page * res_page) + + "LIMIT" + to_string (res_page))) { - 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 ( - search_param (sq))); - - auto r ( - db_->query ( - search_param (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 p (db_->load (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 p (db_->load (pr.id)); + + s << TABLE(CLASS="proplist package") + << TBODY + << TR_NAME (p->id.name, squery_param, root) + << TR_SUMMARY (p->summary) + << TR_LICENSE (p->license_alternatives) + << TR_TAGS (p->tags, root) + << TR_DEPENDS (p->dependencies, root) + << TR_REQUIRES (p->requirements) + << ~TBODY + << ~TABLE; } + s << ~DIV; + + t.commit (); + + s << DIV_PAGER (page, pkg_count, res_page, options_->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 // shared_ptr - #include // database +#include #include #include @@ -24,8 +23,8 @@ namespace brep init (cli::scanner&); private: - std::shared_ptr options_; - std::shared_ptr db_; + shared_ptr options_; + shared_ptr 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 -#include -#include // shared_ptr, make_shared() -#include #include // invalid_argument #include @@ -20,6 +17,8 @@ #include #include +#include +#include #include #include #include @@ -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 ( - s, unknown_mode::fail, unknown_mode::fail); - - db_ = shared_database (options_->db_host (), options_->db_port ()); - } + options_ = make_shared ( + 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 p; - - session sn; - transaction t (db_->begin ()); - - try - { - p = db_->load (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 pkg; + + session sn; + transaction t (db_->begin ()); + + try + { + pkg = db_->load (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 p (d.package.load ()); + assert (p->internal () || !p->other_repositories.empty ()); - s << ~TH - << TD - << SPAN(CLASS="value"); + shared_ptr 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 p (d.package.load ()); - assert (p->internal () || !p->other_repositories.empty ()); - - shared_ptr r ( - p->internal () - ? p->internal_repository.load () - : p->other_repositories[0].load ()); - - const auto& 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 -#include // move() -#include #include #include +#include +#include #include 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 -#include // size_t - #include +#include #include 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 #include // hex, uppercase, right -#include -#include // shared_ptr -#include // size_t -#include #include #include // setw(), setfill() #include // min() @@ -19,6 +15,8 @@ #include #include +#include +#include #include #include @@ -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 ds; + set 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 (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 // shared_ptr - #include // database +#include #include #include @@ -24,8 +23,8 @@ namespace brep init (cli::scanner&); private: - std::shared_ptr options_; - std::shared_ptr db_; + shared_ptr options_; + shared_ptr 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 -#include -#include // make_shared() - #include #include @@ -17,85 +14,96 @@ #include #include +#include +#include #include #include #include #include -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 ( + s, unknown_mode::fail, unknown_mode::fail); - options_ = make_shared ( - 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; + + for (const auto& r: + db_->query ( + query::internal + "ORDER BY" + query::priority)) + { + //@@ Feels like a lot of trouble (e.g., id_attribute()) for very + // dubious value. A link to the package search page just for + // this repository would probably be more useful. // - 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; - auto rp (db_->query (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 + +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 + +#include +#include + +#include + +#include +#include +#include +#include + +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; + + // Function name to module factory map. + // + const map> + 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 #include +#include #include #include @@ -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 -#include // shared_ptr - #include // database +#include + 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 - shared_database (const std::string& host, unsigned int port); + shared_ptr + 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 -#include // weak_ptr, shared_ptr, make_shared() #include // runtime_error #include -using namespace std; +#include +#include namespace brep { @@ -27,7 +27,7 @@ namespace brep if (shared_ptr 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 +#include +#include // unique_ptr, weak_ptr, shared_ptr +#include // size_t +#include // uint{8,16,32,64}_t + +#include + +#include +#include +#include +#include + +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; + + 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; + + // + // + using butl::path; + using butl::dir_path; + using butl::invalid_path; + + // + // + 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 +#include +#include namespace brep { @@ -20,10 +21,17 @@ namespace brep struct parser; template <> - struct parser + struct parser { static void - parse (butl::dir_path&, scanner&); + parse (dir_path&, scanner&); + }; + + template <> + struct parser + { + 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 -#include - +#include #include -using namespace butl; +using namespace std; namespace brep { namespace cli { + // Parse path. + // template static void parse_path (T& x, scanner& s) @@ -40,5 +41,24 @@ namespace brep { parse_path (x, s); } + + // Parse page_form. + // + void parser:: + 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 // to_string() +#include // make_shared() +#include +#include // move() + +namespace brep +{ + using std::move; + using std::make_shared; + using std::to_string; +}; + +#endif // BREP_UTILITY -- cgit v1.1