aboutsummaryrefslogtreecommitdiff
path: root/brep
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-08-14 13:03:08 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-08-23 13:53:50 +0200
commitbcd246076540a8353fa55fc0a5e19343c1a2dbc9 (patch)
tree9fe2c24ca33b3d670267a5cbc8c8c756589f359b /brep
parent24903813d11813f8ff9ac906d23b21e6c33b981d (diff)
Implement package search service mockup
Diffstat (limited to 'brep')
-rw-r--r--brep/buildfile28
-rw-r--r--brep/module2
-rw-r--r--brep/module.cxx25
-rw-r--r--brep/options.cli34
-rw-r--r--brep/package-search (renamed from brep/search)14
-rw-r--r--brep/package-search.cxx154
-rw-r--r--brep/package-version-search (renamed from brep/view)14
-rw-r--r--brep/package-version-search.cxx73
-rw-r--r--brep/search.cxx169
-rw-r--r--brep/services.cxx26
-rw-r--r--brep/shared-database4
-rw-r--r--brep/shared-database.cxx8
-rw-r--r--brep/view.cxx131
13 files changed, 326 insertions, 356 deletions
diff --git a/brep/buildfile b/brep/buildfile
index 5340d22..9b64ed4 100644
--- a/brep/buildfile
+++ b/brep/buildfile
@@ -6,20 +6,36 @@ using cli
.: libso{brep brep-apache}
-import libs += libbpkg%lib{bpkg}
-import libs += libodb-pgsql%lib{odb-pgsql}
+# brep library build rules.
+#
import libs += libodb%lib{odb}
+import libs += libodb-pgsql%lib{odb-pgsql}
+import libs += libbpkg%lib{bpkg}
brep = cxx{package package-odb}
+
libso{brep}: $brep $libs
libso{brep}: cxx.export.poptions = -I$out_root -I$src_root
-brep = cxx{diagnostics module services search view shared-database} \
- cli.cxx{options}
-web = ../web/apache/cxx{request service}
+# brep-apache library build rules.
+#
+import libs += libstudxml%lib{studxml}
+
+brep = cxx{diagnostics module services package-search package-version-search \
+ shared-database} cli.cxx{options}
+web = ../web/apache/cxx{request service} ../web/cxx{mime-url-encoding}
+
libso{brep-apache}: $brep $web libso{brep} $libs
+# Set option prefix to the empty value to handle all unknown request parameters
+# uniformly with a single catch block.
+#
+# @@ Adding --option-prefix "" leads to appearing the following warnings
+# related to options _parse methed:
+# brep/options.cxx:663:33: warning: unused parameter ‘opt_mode’ [-Wunused-parameter]
+# ::cli::unknown_mode opt_mode,
+#
cli.options += -I $src_root --include-with-brackets --include-prefix brep \
---guard-prefix BREP --generate-file-scanner --suppress-usage
+--guard-prefix BREP --generate-file-scanner --suppress-usage --option-prefix ""
cli.cxx{options}: cli{options}
diff --git a/brep/module b/brep/module
index 08fbfea..0743598 100644
--- a/brep/module
+++ b/brep/module
@@ -92,6 +92,8 @@ namespace brep
module ();
module (const module& );
+ // Can be used by module implementation to parse HTTP request parameters.
+ //
class param_scanner: public cli::scanner
{
public:
diff --git a/brep/module.cxx b/brep/module.cxx
index c52d13a..62c70c9 100644
--- a/brep/module.cxx
+++ b/brep/module.cxx
@@ -22,6 +22,7 @@
using namespace std;
using namespace placeholders; // For std::bind's _1, etc.
+using namespace cli;
namespace brep
{
@@ -98,22 +99,22 @@ namespace brep
{
// Read module implementation configuration.
//
- cli::argv_file_scanner s (0,
- argc,
- const_cast<char**> (argv.data ()),
- "conf");
+ argv_file_scanner s (0,
+ argc,
+ const_cast<char**> (argv.data ()),
+ "conf");
init (s);
}
// Read brep::module configuration.
//
- cli::argv_file_scanner s (0,
- argc,
- const_cast<char**> (argv.data ()),
- "conf");
+ argv_file_scanner s (0,
+ argc,
+ const_cast<char**> (argv.data ()),
+ "conf");
- options::module o (s, cli::unknown_mode::skip, cli::unknown_mode::skip);
+ options::module o (s, unknown_mode::skip, unknown_mode::skip);
verb_ = o.verb ();
}
catch (const server_error& e)
@@ -253,7 +254,7 @@ namespace brep
if (i_ != name_values_.end ())
return name_ ? i_->name.c_str () : i_->value.c_str ();
else
- throw cli::eos_reached ();
+ throw eos_reached ();
}
const char* module::param_scanner::
@@ -270,7 +271,7 @@ namespace brep
return r;
}
else
- throw cli::eos_reached ();
+ throw eos_reached ();
}
void module::param_scanner::
@@ -284,6 +285,6 @@ namespace brep
name_ = !name_;
}
else
- throw cli::eos_reached ();
+ throw eos_reached ();
}
}
diff --git a/brep/options.cli b/brep/options.cli
index 2894979..8062f59 100644
--- a/brep/options.cli
+++ b/brep/options.cli
@@ -3,7 +3,7 @@
// license : MIT; see accompanying LICENSE file
include <string>;
-include <cstdint>;
+include <cstdint>; // uint16_t
namespace brep
{
@@ -22,23 +22,43 @@ namespace brep
std::uint16_t db-port = 5432;
};
- class search: module, db
+ class package_search: module, db
{
- size_t results-on-page = 10;
+ std::uint16_t results-on-page = 10;
};
- class view: module, db
+ class package_version_search: module, db
{
+ std::uint16_t results-on-page = 10;
};
}
- // Web module request parameters.
+ // Web module HTTP request parameters.
//
namespace params
{
- class search
+ // Use parameters long names in the C++ code, short aliases in HTTP URL.
+ //
+ class package_search
{
- size_t page = 0;
+ // Display package search result list starting from this page.
+ //
+ std::uint16_t page | p = 0;
+
+ // Package search criteria.
+ //
+ std::string query | q = "";
+ };
+
+ class package_version_search
+ {
+ // Display package version search result list starting from this page.
+ //
+ std::uint16_t page | p = 0;
+
+ // Package version search criteria.
+ //
+ std::string query | q = "";
};
}
}
diff --git a/brep/search b/brep/package-search
index 0283859..156ed68 100644
--- a/brep/search
+++ b/brep/package-search
@@ -1,20 +1,20 @@
-// file : brep/search -*- C++ -*-
+// file : brep/package-search -*- C++ -*-
// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
-#ifndef BREP_SEARCH
-#define BREP_SEARCH
+#ifndef BREP_PACKAGE_SEARCH
+#define BREP_PACKAGE_SEARCH
#include <memory> // shared_ptr
-#include <odb/database.hxx>
+#include <odb/forward.hxx> // database
#include <brep/module>
#include <brep/options>
namespace brep
{
- class search: public module
+ class package_search: public module
{
private:
virtual void
@@ -24,9 +24,9 @@ namespace brep
init (cli::scanner&);
private:
- std::shared_ptr<options::search> options_;
+ std::shared_ptr<options::package_search> options_;
std::shared_ptr<odb::core::database> db_;
};
}
-#endif // BREP_SEARCH
+#endif // BREP_PACKAGE_SEARCH
diff --git a/brep/package-search.cxx b/brep/package-search.cxx
new file mode 100644
index 0000000..3317d43
--- /dev/null
+++ b/brep/package-search.cxx
@@ -0,0 +1,154 @@
+// file : brep/package-search.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#include <brep/package-search>
+
+#include <string>
+#include <memory> // make_shared()
+
+#include <xml/serializer>
+
+#include <odb/database.hxx>
+#include <odb/transaction.hxx>
+
+#include <web/xhtml>
+#include <web/module>
+#include <web/mime-url-encoding>
+
+#include <brep/package>
+#include <brep/package-odb>
+#include <brep/shared-database>
+
+using namespace std;
+using namespace cli;
+using namespace odb::core;
+
+namespace brep
+{
+ void package_search::
+ init (scanner& s)
+ {
+ MODULE_DIAG;
+
+ options_ = make_shared<options::package_search> (
+ s, unknown_mode::fail, unknown_mode::fail);
+
+ db_ = shared_database (options_->db_host (), options_->db_port ());
+ }
+
+ void package_search::
+ handle (request& rq, response& rs)
+ {
+ using namespace xml;
+ using namespace web;
+ using namespace web::xhtml;
+
+ MODULE_DIAG;
+
+ 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 ());
+ }
+
+ // @@ Would be nice to have a manipulator identing string properly
+ // according to the most nested element identation.
+ //
+ const char* ident ("\n ");
+ const char* title ("Package Search");
+ serializer s (rs.content (), title);
+
+ s << HTML
+ << HEAD
+ << TITLE << title << ~TITLE
+ << STYLE(TYPE="text/css") << ident
+ << ".package {margin: 0 0 0.5em;}" << ident
+ << ".name a {text-decoration: none;}" << ident
+ << ".summary {font-size: small;}"
+ << ~STYLE
+ << ~HEAD
+ << BODY;
+
+ string q (
+ pr.query ().empty () ? "" : "q=" + mime_url_encode (pr.query ()));
+
+ transaction t (db_->begin ());
+
+ // @@ Use appropriate view when clarify which package info to be displayed
+ // and search index structure get implemented.
+ //
+ using query = query<package>;
+ auto r (
+ db_->query<package> (
+ "ORDER BY" + query::name +
+ "OFFSET" + to_string (pr.page () * options_->results_on_page ()) +
+ "LIMIT" + to_string (options_->results_on_page ())));
+
+ for (const auto& p: r)
+ {
+ s << DIV(CLASS="package")
+ << DIV(CLASS="name")
+ << A
+ << HREF
+ << "/go/" << mime_url_encode (p.name);
+
+ // Propagate search criteria to the package version search url.
+ //
+ if (!q.empty ())
+ s << "?" << q;
+
+ s << ~HREF
+ << p.name
+ << ~A
+ << ~DIV
+ << DIV(CLASS="summary")
+ << p.summary
+ << ~DIV
+ << ~DIV;
+ }
+
+ t.commit ();
+
+ if (pr.page () || r.size () == options_->results_on_page ())
+ {
+ s << DIV;
+
+ if (pr.page ())
+ {
+ s << A
+ << HREF << "/?p=" << pr.page () - 1
+ << (q.empty () ? "" : "&" + q)
+ << ~HREF
+ << "Previous"
+ << ~A
+ << " ";
+ }
+
+ // @@ Not ideal as can produce link to an empty page, but easy to fix
+ // and most likelly will be replaced with something more meaningful
+ // based on knowing the total number of matched packages.
+ //
+ if (r.size () == options_->results_on_page ())
+ {
+ s << A
+ << HREF << "/?p=" << pr.page () + 1
+ << (q.empty () ? "" : "&" + q)
+ << ~HREF
+ << "Next"
+ << ~A;
+ }
+
+ s << ~DIV;
+ }
+
+ s << ~BODY
+ << ~HTML;
+ }
+}
diff --git a/brep/view b/brep/package-version-search
index 280b9ab..0292ae0 100644
--- a/brep/view
+++ b/brep/package-version-search
@@ -1,20 +1,20 @@
-// file : brep/view -*- C++ -*-
+// file : brep/package-version-search -*- C++ -*-
// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
-#ifndef BREP_VIEW
-#define BREP_VIEW
+#ifndef BREP_PACKAGE_VERSION_SEARCH
+#define BREP_PACKAGE_VERSION_SEARCH
#include <memory> // shared_ptr
-#include <odb/database.hxx>
+#include <odb/forward.hxx> // database
#include <brep/module>
#include <brep/options>
namespace brep
{
- class view: public module
+ class package_version_search: public module
{
private:
virtual void
@@ -24,9 +24,9 @@ namespace brep
init (cli::scanner&);
private:
- std::shared_ptr<options::view> options_;
+ std::shared_ptr<options::package_version_search> options_;
std::shared_ptr<odb::core::database> db_;
};
}
-#endif // BREP_VIEW
+#endif // BREP_PACKAGE_VERSION_SEARCH
diff --git a/brep/package-version-search.cxx b/brep/package-version-search.cxx
new file mode 100644
index 0000000..a989434
--- /dev/null
+++ b/brep/package-version-search.cxx
@@ -0,0 +1,73 @@
+// file : brep/package-version-search.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#include <brep/package-version-search>
+
+#include <string>
+#include <memory> // make_shared()
+
+#include <xml/serializer>
+
+#include <odb/database.hxx>
+#include <odb/transaction.hxx>
+
+#include <web/xhtml>
+#include <web/module>
+#include <web/mime-url-encoding>
+
+#include <brep/package>
+#include <brep/package-odb>
+#include <brep/shared-database>
+
+using namespace std;
+using namespace cli;
+using namespace odb::core;
+
+namespace brep
+{
+ void package_version_search::
+ init (scanner& s)
+ {
+ MODULE_DIAG;
+
+ options_ = make_shared<options::package_version_search> (
+ s, unknown_mode::fail, unknown_mode::fail);
+
+ db_ = shared_database (options_->db_host (), options_->db_port ());
+ }
+
+ void package_version_search::
+ handle (request& rq, response& rs)
+ {
+ using namespace xml;
+ using namespace web;
+ using namespace web::xhtml;
+
+ MODULE_DIAG;
+
+ const string& name (*rq.path ().rbegin ());
+ params::package_version_search pr;
+
+ try
+ {
+ param_scanner s (rq.parameters ());
+ pr = params::package_version_search (
+ s, unknown_mode::fail, unknown_mode::fail);
+ }
+ catch (const unknown_argument& e)
+ {
+ throw invalid_request (400, e.what ());
+ }
+
+ const char* title ("Package");
+ serializer s (rs.content (), title);
+
+ s << HTML
+ << HEAD
+ << TITLE << title << ~TITLE
+ << ~HEAD
+ << BODY << name << ~BODY
+ << ~HTML;
+ }
+}
diff --git a/brep/search.cxx b/brep/search.cxx
deleted file mode 100644
index 9185aa5..0000000
--- a/brep/search.cxx
+++ /dev/null
@@ -1,169 +0,0 @@
-// file : brep/search.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd
-// license : MIT; see accompanying LICENSE file
-
-#include <brep/search>
-
-#include <memory> // shared_ptr, make_shared()
-#include <chrono>
-#include <ostream>
-
-#include <odb/session.hxx>
-#include <odb/database.hxx>
-#include <odb/transaction.hxx>
-
-#include <butl/path>
-
-#include <web/module>
-
-#include <brep/package>
-#include <brep/package-odb>
-#include <brep/shared-database>
-
-using namespace std;
-using namespace odb::core;
-
-namespace brep
-{
- void search::
- init (cli::scanner& s)
- {
- MODULE_DIAG;
-
- options_ = make_shared<options::search> (s,
- cli::unknown_mode::fail,
- cli::unknown_mode::fail);
-
- db_ = shared_database (options_->db_host (), options_->db_port ());
-
- if (options_->results_on_page () > 30)
- fail << "too many search results on page: "
- << options_->results_on_page ();
- else if (options_->results_on_page () > 10)
- warn << options_->results_on_page ()
- << " search results on page is quite a lot but will try to cope";
- }
-
- void search::
- handle (request& rq, response& rs)
- {
- MODULE_DIAG;
-
- shared_ptr<package> cli (
- make_shared<package> ("cli",
- "CLI is ...",
- strings ({"compiler", "c++"}),
- string ("This is CLI"),
- url (),
- url (),
- email (),
- email ()));
-
- shared_ptr<repository> stable (
- make_shared<repository> (
- repository_location ("http://pkg.cpp.org/1/stable"),
- "Stable",
- dir_path ("/var/pkg/1/stable")));
-
- licenses l;
- l.comment = "License\"A'";
- l.push_back ("XXX");
- l.push_back ("AAA");
- l.push_back ("BBB");
- l.push_back ("CCC");
-
- dependency_alternatives da;
- da.push_back (
- {"icl", version_comparison{version ("1.3.3"), comparison::gt}});
-
- da.push_back (
- {"ocl", version_comparison{version ("1.5.5"), comparison::lt}});
-
- requirement_alternatives ra1;
- ra1.push_back ("TAO");
- ra1.push_back ("ORBacus");
-
- requirement_alternatives ra2;
- ra2.push_back ("Xerces");
-
- shared_ptr<package_version> v (
- make_shared<package_version> (stable,
- cli,
- version ("1.1"),
- priority (),
- license_alternatives ({l}),
- "some changes 1\nsome changes 2",
- dependencies ({da}),
- requirements ({ra1, ra2})));
-
- transaction t (db_->begin ());
-// t.tracer (odb::stderr_full_tracer);
-
- {
- db_->persist (cli);
- db_->persist (stable);
- db_->persist (v);
- }
-
- t.commit ();
-
- chrono::seconds ma (60);
- rs.cookie ("Oh", " Ah\n\n", &ma, "/");
- rs.cookie ("Hm", ";Yes", &ma);
-
- info << "handling search request from "; // << rq.client_ip ();
-
- ostream& o (rs.content ());
-
- o << "<html><head></head><body>";
-
- o << "<b>Options:</b>"
- << "<br>\ntracing verbosity: " << options_->verb ()
- << "<br>\ndb endpoint: " << options_->db_host () << ":"
- << options_->db_port ()
- << "<br>\nsearch results on page: " << options_->results_on_page ();
-
- o << "<p>\n<b>Params:</b>";
-
- const name_values& ps (rq.parameters ());
-
- if (ps.empty ())
- throw invalid_request (422, "search parameters expected");
-
- if (ps.size () > 100)
- fail << "too many parameters: " << ps.size () <<
- info << "are you crazy to specify so many?";
-
- level2 ([&]{trace << "search request with " << ps.size () << " params";});
-
- for (const auto& p: ps)
- {
- o << "<br>\n" << p.name << "=" << p.value;
- }
-
- param_scanner s (ps);
- unique_ptr<params::search> prm;
-
- try
- {
- prm.reset (new params::search (s,
- cli::unknown_mode::fail,
- cli::unknown_mode::fail));
- }
- catch (const cli::unknown_argument& e)
- {
- throw invalid_request (400, e.what ());
- }
-
- o << "<br>\nPage num: " << prm->page ();
- o << "<p>\n<b>Cookies:</b>";
-
- for (const auto& c: rq.cookies ())
- {
- o << "<br>\n" << c.name << "=" << c.value;
- }
-
- o << "<p><a href='view'>View</a>"
- << "</body></html>";
- }
-}
diff --git a/brep/services.cxx b/brep/services.cxx
index 86b27b7..510a231 100644
--- a/brep/services.cxx
+++ b/brep/services.cxx
@@ -1,21 +1,25 @@
-// file : services.cxx -*- C++ -*-
+// file : brep/services.cxx -*- C++ -*-
// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
-#include <brep/view>
-#include <brep/search>
+#include <ap_config.h> // AP_MODULE_DECLARE_DATA
#include <web/apache/service>
+#include <brep/package-search>
+#include <brep/package-version-search>
+
using namespace brep;
using web::apache::service;
-static search search_mod;
-service AP_MODULE_DECLARE_DATA search_srv ("search",
- search_mod,
- {"db-host", "db-port", "conf"});
+static package_search package_search_mod;
+service AP_MODULE_DECLARE_DATA package_search_srv (
+ "package-search",
+ package_search_mod,
+ {"db-host", "db-port", "conf"});
-static view view_mod;
-service AP_MODULE_DECLARE_DATA view_srv ("view",
- view_mod,
- {"db-host", "db-port", "conf"});
+static package_version_search package_version_search_mod;
+service AP_MODULE_DECLARE_DATA package_version_search_srv (
+ "package-version-search",
+ package_version_search_mod,
+ {"db-host", "db-port", "conf"});
diff --git a/brep/shared-database b/brep/shared-database
index cad526f..36fa0a2 100644
--- a/brep/shared-database
+++ b/brep/shared-database
@@ -14,8 +14,8 @@ namespace brep
{
// Returns pointer to the shared database instance, creating one on the
// first call. On subsequent calls ensures passed host and port equals
- // to ones of the shared database instance throwing runtime_error otherwise.
- // Is not thread-safe.
+ // 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);
diff --git a/brep/shared-database.cxx b/brep/shared-database.cxx
index fb952d8..fc17659 100644
--- a/brep/shared-database.cxx
+++ b/brep/shared-database.cxx
@@ -10,14 +10,14 @@
#include <odb/pgsql/database.hxx>
using namespace std;
-using namespace odb;
namespace brep
{
- shared_ptr<database>
- shared_database (const string& host, unsigned int port)
+ shared_ptr<odb::database>
+ shared_database (const string& h, unsigned int p)
{
- static weak_ptr<pgsql::database> db;
+ using odb::pgsql::database;
+ static weak_ptr<database> db;
// In C++11, function-static variable initialization is
// guaranteed to be thread-safe, thought this doesn't
diff --git a/brep/view.cxx b/brep/view.cxx
deleted file mode 100644
index 3098e93..0000000
--- a/brep/view.cxx
+++ /dev/null
@@ -1,131 +0,0 @@
-// file : brep/view.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd
-// license : MIT; see accompanying LICENSE file
-
-#include <brep/view>
-
-#include <memory> // shared_ptr, make_shared()
-#include <ostream>
-
-#include <odb/session.hxx>
-#include <odb/database.hxx>
-#include <odb/transaction.hxx>
-
-#include <web/module>
-
-#include <brep/package>
-#include <brep/package-odb>
-#include <brep/shared-database>
-
-using namespace std;
-using namespace odb::core;
-
-#pragma db namespace session
-namespace brep
-{
- void view::
- init (cli::scanner& s)
- {
- options_ = make_shared<options::view> (s,
- cli::unknown_mode::fail,
- cli::unknown_mode::fail);
-
- db_ = shared_database (options_->db_host (), options_->db_port ());
- }
-
- void view::
- handle (request& rq, response& rs)
- {
- session s;
- transaction t (db_->begin ());
-
- shared_ptr<package> p (db_->load<package> ("cli"));
-
- for (auto& vp: p->versions)
- {
- shared_ptr<package_version> v (vp.load ());
- v->repository.load ();
- v->package.load ();
- }
-
- t.commit ();
-
- ostream& o (rs.content (200, "text/html;charset=utf-8", false));
-
- o << "<html><head></head><body>";
-
- o << "<b>Options:</b>"
- << "<br>\ntracing verbosity: " << options_->verb ()
- << "<br>\ndb endpoint: " << options_->db_host () << ":"
- << options_->db_port ();
-
- o << "<p>\n<b>Cookies:</b>";
-
- for (const auto& c: rq.cookies ())
- {
- o << "<br>\n" << c.name << "=" << c.value;
- }
-
- o << "<p>\n" << p->name << ": " << p->versions.size ();
-
- for (const auto& vp: p->versions)
- {
- // Just finds package_version object in session cache.
- //
- shared_ptr<package_version> v (vp.load ());
-
- assert (v != nullptr);
- assert (v->repository.get_eager () != nullptr);
- assert (v->package.get_eager () != nullptr);
-
- o << "<br>version:" << v->version.string ()
- << "<br>package:" << v->package->name
- << "<br>repo:" << v->repository->display_name
- << "<br>changes:" << v->changes
- << "<br>licenses:" << v->license_alternatives.size ();
-
- for (const auto& la: v->license_alternatives)
- {
- o << "<br>";
-
- for (const auto& l: la)
- {
- o << " |" << l << "|";
- }
- }
-
- o << "<br>deps:" << v->dependencies.size ();
-
- for (const auto& da: v->dependencies)
- {
- o << "<br>";
-
- for (const auto& d: da)
- {
- o << " |" << d.package;
-
- if (d.version)
- {
- o << "," << d.version->value.string () << ","
- << static_cast<int> (d.version->operation) << "|";
- }
- }
- }
-
- o << "<br>requirements:" << v->requirements.size ();
-
- for (const auto& ra: v->requirements)
- {
- o << "<br>";
-
- for (const auto& r: ra)
- {
- o << " |" << r << "|";
- }
- }
- }
-
- o << "<p><a href='search?a=1&b&c=2&d=&&x=a+b'>Search</a>"
- << "</body></html>";
- }
-}