aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-11-05 17:41:16 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-11-11 17:52:19 +0200
commitaacff79e854d6d4eb22540339bc88c3efab353a2 (patch)
tree042ac3a493dcf0ddd72f19c572159a1cea4aa5f4
parente70163685afe5cae1ebe055a53ce353ae9cbe590 (diff)
Implement package dependency resolution
-rw-r--r--brep/package124
-rw-r--r--brep/package-details.cxx24
-rw-r--r--brep/package-search.cxx17
-rw-r--r--brep/package-version-details.cxx35
-rw-r--r--brep/package.cxx10
-rw-r--r--brep/page.cxx27
-rw-r--r--loader/loader.cxx266
-rw-r--r--tests/loader/driver.cxx366
-rw-r--r--tests/loader/external/1/staging/packages17
-rw-r--r--tests/loader/external/1/testing/packages6
-rw-r--r--tests/loader/internal/1/math/packages16
-rw-r--r--tests/loader/internal/1/stable/packages15
-rw-r--r--web/module5
13 files changed, 644 insertions, 284 deletions
diff --git a/brep/package b/brep/package
index 719a906..ef73542 100644
--- a/brep/package
+++ b/brep/package
@@ -10,6 +10,7 @@
#include <vector>
#include <chrono>
#include <memory> // shared_ptr
+#include <cassert>
#include <cstddef> // size_t
#include <utility> // move()
#include <cstdint> // uint16
@@ -75,13 +76,11 @@ namespace brep
class package;
using strings = std::vector<std::string>;
-
- template <typename T>
- using optional = butl::optional<T>;
+ using butl::optional;
// path
//
- using path = butl::path;
+ using butl::path;
#pragma db map type(path) as(std::string) \
to((?).string ()) from(brep::path (?))
@@ -93,14 +92,14 @@ namespace brep
to((?) ? (?)->string () : brep::optional_string ()) \
from((?) ? brep::path (*(?)) : brep::optional_path ())
- using dir_path = butl::dir_path;
+ using butl::dir_path;
#pragma db map type(dir_path) as(std::string) \
to((?).string ()) from(brep::dir_path (?))
// timestamp
//
- using timestamp = butl::timestamp;
+ using butl::timestamp;
#pragma db map type(timestamp) as(std::uint64_t) \
to(std::chrono::system_clock::to_time_t (?)) \
@@ -108,7 +107,7 @@ namespace brep
// version
//
- using version = bpkg::version;
+ using bpkg::version;
#pragma db value
struct canonical_version
@@ -116,6 +115,18 @@ namespace brep
std::uint16_t epoch;
std::string canonical_upstream;
std::uint16_t revision;
+
+ bool
+ empty () const noexcept
+ {
+ // No sense to test epoch and revision for 0 as a valid canonical_version
+ // object can not have them different from 0 if canonical_upstream is
+ // empty. The predicate semantics is equal to the one of the
+ // bpkg::version class.
+ //
+ assert (!canonical_upstream.empty () || (epoch == 0 && revision == 0));
+ return canonical_upstream.empty ();
+ }
};
#pragma db value transient
@@ -140,14 +151,14 @@ namespace brep
// priority
//
- using priority = bpkg::priority;
+ using bpkg::priority;
#pragma db value(priority) definition
#pragma db member(priority::value) column("")
// url
//
- using url = bpkg::url;
+ using bpkg::url;
#pragma db value(url) definition
#pragma db member(url::value) virtual(std::string) before access(this) \
@@ -155,7 +166,7 @@ namespace brep
// email
//
- using email = bpkg::email;
+ using bpkg::email;
#pragma db value(email) definition
#pragma db member(email::value) virtual(std::string) before access(this) \
@@ -163,17 +174,33 @@ namespace brep
// licenses
//
- using licenses = bpkg::licenses;
+ using bpkg::licenses;
using license_alternatives = std::vector<licenses>;
#pragma db value(licenses) definition
// dependencies
//
- using comparison = bpkg::comparison;
- using dependency_constraint = bpkg::dependency_constraint;
+ using bpkg::comparison;
+ using bpkg::dependency_constraint;
#pragma db value(dependency_constraint) definition
+ #pragma db member(dependency_constraint::operation) column("")
+ #pragma db member(dependency_constraint::version) column("")
+
+ #pragma db value
+ struct package_id
+ {
+ std::string name;
+ canonical_version version;
+
+ package_id () = default;
+ package_id (std::string n, const brep::version& v)
+ : name (std::move (n)),
+ version {v.epoch, v.canonical_upstream, v.revision}
+ {
+ }
+ };
// Notes:
//
@@ -215,24 +242,51 @@ namespace brep
// * No need to complicate persisted object model with repository
// relations otherwise required just for dependency resolution.
//
- using dependency = bpkg::dependency;
- using dependency_alternatives = bpkg::dependency_alternatives;
- using dependencies = std::vector<dependency_alternatives>;
- #pragma db value(dependency) definition
- #pragma db member(dependency::constraint) column("")
- #pragma db value(dependency_alternatives) definition
+ #pragma db value
+ struct dependency
+ {
+ using package_type = brep::package;
+
+ odb::lazy_shared_ptr<package_type> package;
+ optional<dependency_constraint> constraint;
+
+ // Prerequisite package name.
+ //
+ std::string
+ name () const;
+
+ // Database mapping.
+ //
+ #pragma db member(package) column("") not_null
+ };
+
+ #pragma db value
+ class dependency_alternatives: public std::vector<dependency>
+ {
+ public:
+ bool conditional;
+ std::string comment;
+
+ dependency_alternatives () = default;
+
+ explicit
+ dependency_alternatives (bool d, std::string c)
+ : conditional (d), comment (std::move (c)) {}
+ };
+
+ using dependencies = std::vector<dependency_alternatives>;
// requirements
//
- using requirement_alternatives = bpkg::requirement_alternatives;
+ using bpkg::requirement_alternatives;
using requirements = std::vector<requirement_alternatives>;
#pragma db value(requirement_alternatives) definition
// repository_location
//
- using repository_location = bpkg::repository_location;
+ using bpkg::repository_location;
#pragma db map type(repository_location) as(std::string) \
to((?).string ()) from(brep::repository_location (?))
@@ -270,6 +324,8 @@ namespace brep
timestamp repositories_timestamp;
bool internal;
+ std::vector<odb::lazy_weak_ptr<repository>> complements;
+ std::vector<odb::lazy_weak_ptr<repository>> prerequisites;
// Database mapping.
//
@@ -279,25 +335,17 @@ namespace brep
set(this.location = std::move (?); \
assert (this.name == this.location.canonical_name ()))
+ #pragma db member(complements) id_column("repository") \
+ value_column("complement") value_not_null
+
+ #pragma db member(prerequisites) id_column("repository") \
+ value_column("prerequisite") value_not_null
+
private:
friend class odb::access;
repository () = default;
};
- #pragma db value
- struct package_id
- {
- std::string name;
- canonical_version version;
-
- package_id () = default;
- package_id (std::string n, const brep::version& v)
- : name (std::move (n)),
- version {v.epoch, v.canonical_upstream, v.revision}
- {
- }
- };
-
// The 'to' expression calls the PostgreSQL to_tsvector(weighted_text)
// function overload (package-extra.sql). Since we are only interested
// in "write-only" members of this type, make the 'from' expression
@@ -382,7 +430,7 @@ namespace brep
//
optional<path> location;
- std::vector<odb::lazy_shared_ptr<repository_type>> external_repositories;
+ std::vector<odb::lazy_shared_ptr<repository_type>> other_repositories;
// Database mapping.
//
@@ -446,9 +494,9 @@ namespace brep
set(odb::nested_set (this.requirements, move (?))) \
id_column("") key_column("") value_column("id")
- // external_repositories
+ // other_repositories
//
- #pragma db member(external_repositories) \
+ #pragma db member(other_repositories) \
id_column("") value_column("repository") value_not_null
// search_index
diff --git a/brep/package-details.cxx b/brep/package-details.cxx
index f814ef8..0424d5b 100644
--- a/brep/package-details.cxx
+++ b/brep/package-details.cxx
@@ -10,6 +10,7 @@
#include <xml/serializer>
+#include <odb/session.hxx>
#include <odb/database.hxx>
#include <odb/transaction.hxx>
@@ -119,6 +120,7 @@ namespace brep
<< A(HREF=url (!f, sq, pg)) << (f ? "[brief]" : "[full]") << ~A
<< ~DIV;
+ session sn;
transaction t (db_->begin ());
shared_ptr<package> p;
@@ -172,13 +174,12 @@ namespace brep
"OFFSET" + to_string (pg * rp) +
"LIMIT" + to_string (rp)));
- s << FORM_SEARCH (sq.c_str ())
- << DIV_COUNTER (pc, "Version", "Versions")
-
- // Enclose the subsequent tables to be able to use nth-child CSS selector.
- //
- << DIV;
+ s << FORM_SEARCH (sq)
+ << DIV_COUNTER (pc, "Version", "Versions");
+ // Enclose the subsequent tables to be able to use nth-child CSS selector.
+ //
+ s << DIV;
for (const auto& pr: r)
{
shared_ptr<package> p (db_->load<package> (pr.id));
@@ -187,7 +188,7 @@ namespace brep
<< TBODY
<< TR_VERSION (name, p->version.string ())
- // @@ Shouldn't we skip low priority row ?
+ // @@ Shouldn't we skip low priority row ? Don't think so, why?
//
<< TR_PRIORITY (p->priority);
@@ -200,24 +201,27 @@ namespace brep
assert (p->internal_repository != nullptr);
// @@ Shouldn't we make package location to be a link to the proper
- // place of the About page, describing corresponding repository ?
+ // 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 ())
<< TR_DEPENDS (p->dependencies)
<< TR_REQUIRES (p->requirements)
<< ~TBODY
<< ~TABLE;
}
+ s << ~DIV;
t.commit ();
- s << ~DIV
- << DIV_PAGER (pg, pc, rp, options_->pages_in_pager (), url (f, sq))
+ s << DIV_PAGER (pg, pc, rp, options_->pages_in_pager (), url (f, sq))
<< ~DIV
<< ~BODY
<< ~HTML;
diff --git a/brep/package-search.cxx b/brep/package-search.cxx
index 64e43f1..47f53e9 100644
--- a/brep/package-search.cxx
+++ b/brep/package-search.cxx
@@ -10,6 +10,7 @@
#include <xml/serializer>
+#include <odb/session.hxx>
#include <odb/database.hxx>
#include <odb/transaction.hxx>
@@ -92,6 +93,7 @@ namespace brep
<< DIV_HEADER ()
<< DIV(ID="content");
+ session sn;
transaction t (db_->begin ());
auto pc (
@@ -105,13 +107,12 @@ namespace brep
"OFFSET" + to_string (pg * rp) +
"LIMIT" + to_string (rp)));
- s << FORM_SEARCH (sq.c_str ())
- << DIV_COUNTER (pc, "Package", "Packages")
-
- // Enclose the subsequent tables to be able to use nth-child CSS selector.
- //
- << DIV;
+ s << FORM_SEARCH (sq)
+ << DIV_COUNTER (pc, "Package", "Packages");
+ // Enclose the subsequent tables to be able to use nth-child CSS selector.
+ //
+ s << DIV;
for (const auto& pr: r)
{
shared_ptr<package> p (db_->load<package> (pr.id));
@@ -127,13 +128,13 @@ namespace brep
<< ~TBODY
<< ~TABLE;
}
+ s << ~DIV;
t.commit ();
string url (qp.empty () ? "/" : ("/?" + qp));
- s << ~DIV
- << DIV_PAGER (pg, pc, rp, options_->pages_in_pager (), url)
+ s << DIV_PAGER (pg, pc, rp, options_->pages_in_pager (), url)
<< ~DIV
<< ~BODY
<< ~HTML;
diff --git a/brep/package-version-details.cxx b/brep/package-version-details.cxx
index 71559b9..a4fa95a 100644
--- a/brep/package-version-details.cxx
+++ b/brep/package-version-details.cxx
@@ -11,6 +11,7 @@
#include <xml/serializer>
+#include <odb/session.hxx>
#include <odb/database.hxx>
#include <odb/transaction.hxx>
@@ -63,7 +64,7 @@ namespace brep
}
assert (i != rq.path ().rend ());
- const string& n (*i);
+ const string& n (*i); // Package name.
params::package_version_details pr;
@@ -120,6 +121,7 @@ namespace brep
bool not_found (false);
shared_ptr<package> p;
+ session sn;
transaction t (db_->begin ());
try
@@ -153,8 +155,6 @@ namespace brep
const string du (p->internal_repository.load ()->location.string () +
"/" + p->location->string ());
- t.commit ();
-
s << TABLE(CLASS="proplist", ID="version")
<< TBODY
@@ -209,7 +209,32 @@ namespace brep
if (&d != &da[0])
s << " | ";
- s << d; // @@ Should it be a link ?
+ shared_ptr<package> p (d.package.load ());
+ string en (mime_url_encode (p->id.name));
+
+ if (p->internal_repository != nullptr)
+ s << A << HREF << "/go/" << en << ~HREF << p->id.name << ~A;
+ else
+ // @@ Refer to package repository URL when supported in repository
+ // manifest.
+ //
+ s << p->id.name;
+
+ if (d.constraint)
+ {
+ s << ' ';
+
+ if (p->internal_repository != nullptr)
+ s << A
+ << HREF << "/go/" << en << "/" << p->version.string () << ~HREF
+ << *d.constraint
+ << ~A;
+ else
+ // @@ Refer to package repository URL when supported in
+ // repository manifest.
+ //
+ s << *d.constraint;
+ }
}
s << ~SPAN
@@ -222,6 +247,8 @@ namespace brep
<< ~TABLE;
}
+ t.commit ();
+
const auto& rt (p->requirements);
if (!rt.empty ())
diff --git a/brep/package.cxx b/brep/package.cxx
index 9b7d24a..3c65ed8 100644
--- a/brep/package.cxx
+++ b/brep/package.cxx
@@ -16,6 +16,14 @@ using namespace odb::core;
namespace brep
{
+ // dependency
+ //
+ string dependency::
+ name () const
+ {
+ return package.object_id ().name;
+ }
+
// package
//
package::
@@ -63,7 +71,7 @@ namespace brep
version (move (vr))
{
assert (!rp->internal);
- external_repositories.emplace_back (move (rp));
+ other_repositories.emplace_back (move (rp));
}
weighted_text package::
diff --git a/brep/page.cxx b/brep/page.cxx
index a23ce17..deee055 100644
--- a/brep/page.cxx
+++ b/brep/page.cxx
@@ -6,6 +6,7 @@
#include <set>
#include <string>
+#include <memory> // shared_ptr
#include <cassert>
#include <utility> // move()
#include <algorithm> // min()
@@ -16,6 +17,7 @@
#include <web/mime-url-encoding>
#include <brep/package>
+#include <brep/package-odb>
using namespace std;
using namespace xml;
@@ -51,7 +53,7 @@ namespace brep
void FORM_SEARCH::
operator() (serializer& s) const
{
- // The 'action' attribute is optional in HTML5. While the standard don't
+ // The 'action' attribute is optional in HTML5. While the standard doesn't
// specify browser behavior explicitly for the case the attribute is
// ommited, the only reasonable behavior is to default it to the current
// document URL.
@@ -260,26 +262,35 @@ namespace brep
//
set<string> ds;
for (const auto& da: d)
- ds.emplace (da.name);
+ ds.emplace (da.name ());
bool m (ds.size () > 1);
if (m)
s << "(";
- bool first (true);
+ bool f (true); // First dependency alternative.
for (const auto& da: d)
{
- if (ds.find (da.name) != ds.end ())
+ string n (da.name ());
+ if (ds.find (n) != ds.end ())
{
- ds.erase (da.name);
+ ds.erase (n);
- if (first)
- first = false;
+ if (f)
+ f = false;
else
s << " | ";
- s << da.name; // @@ Make it a link.
+ shared_ptr<package> p (da.package.load ());
+
+ if (p->internal_repository != nullptr)
+ s << A << HREF << "/go/" << mime_url_encode (n) << ~HREF << n << ~A;
+ else
+ // @@ Refer to package repository URL when supported in repository
+ // manifest.
+ //
+ s << n;
}
}
diff --git a/loader/loader.cxx b/loader/loader.cxx
index ecc6032..74844f5 100644
--- a/loader/loader.cxx
+++ b/loader/loader.cxx
@@ -12,7 +12,9 @@
#include <fstream>
#include <iostream>
#include <stdexcept> // runtime_error, invalid_argument
+#include <algorithm> // find(), find_if()
+#include <odb/session.hxx>
#include <odb/database.hxx>
#include <odb/transaction.hxx>
@@ -319,6 +321,22 @@ load_packages (const shared_ptr<repository>& rp, database& db)
}
}
+ dependencies ds;
+ for (auto& pda: pm.dependencies)
+ {
+ ds.emplace_back (pda.conditional, move (pda.comment));
+
+ for (auto& pd: pda)
+ // Proper version will be assigned during dependency resolution
+ // procedure. Here we rely on the fact the foreign key constraint
+ // check is deferred until the current transaction commit.
+ //
+ ds.back ().push_back ({
+ lazy_shared_ptr<package> (
+ db, package_id (move (pd.name), version ())),
+ move (pd.constraint)});
+ }
+
p = make_shared<package> (
move (pm.name),
move (pm.version),
@@ -332,7 +350,7 @@ load_packages (const shared_ptr<repository>& rp, database& db)
move (pm.package_url),
move (pm.email),
move (pm.package_email),
- move (pm.dependencies),
+ move (ds),
move (pm.requirements),
move (pm.location),
rp);
@@ -351,21 +369,13 @@ load_packages (const shared_ptr<repository>& rp, database& db)
// for this purpose.
//
- if (rp->internal)
- {
- // Just skip the duplicate.
- //
+ // As soon as internal repositories get loaded first, the internal
+ // package can duplicate an internal package only.
+ //
+ assert (!rp->internal || p->internal_repository != nullptr);
- // As soon as internal repositories get loaded first, the internal
- // package can duplicate an internal package only.
- //
- assert (p->internal_repository != nullptr);
- }
- else
- {
- p->external_repositories.push_back (rp);
- db.update (p);
- }
+ p->other_repositories.push_back (rp);
+ db.update (p);
}
}
@@ -374,7 +384,8 @@ load_packages (const shared_ptr<repository>& rp, database& db)
// Load the prerequsite repositories and their complements state from the
// 'repositories' file. Update the repository persistent state to save
-// repositories_timestamp member. Should be called once per internal repository.
+// repositories_timestamp, prerequsites, and complements members.
+// Should be called once per persisted internal repository.
//
static void
load_prerequisites (const shared_ptr<repository>& rp, database& db)
@@ -389,13 +400,16 @@ load_prerequisites (const shared_ptr<repository>& rp, database& db)
//
assert (!rp->local_path.empty ());
+ // Repository is already persisted by the load_packages() function call.
+ //
+ assert (db.find<repository> (rp->name) != nullptr);
+
repository_manifests rpm;
{
ifstream ifs;
path p (rp->local_path / path ("repositories"));
rp->repositories_timestamp = manifest_stream (p, ifs);
- db.update (rp);
manifest_parser mp (ifs, p.string ());
rpm = repository_manifests (mp);
@@ -408,6 +422,8 @@ load_prerequisites (const shared_ptr<repository>& rp, database& db)
rm.effective_role () == repository_role::prerequisite))
continue; // Ignore entry for this repository.
+ assert (rm.effective_role () != repository_role::base);
+
repository_location rl;
auto bad_location (
@@ -438,7 +454,18 @@ load_prerequisites (const shared_ptr<repository>& rp, database& db)
bad_location ();
}
- shared_ptr<repository> pr (db.find<repository> (rl.canonical_name ()));
+ const auto& cn (rl.canonical_name ());
+
+ // Add repository to prerequisites or complements member of the dependent
+ // repository.
+ //
+ auto& rs (rm.effective_role () == repository_role::prerequisite
+ ? rp->prerequisites
+ : rp->complements);
+
+ rs.emplace_back (db, cn);
+
+ shared_ptr<repository> pr (db.find<repository> (cn));
if (pr != nullptr)
// The prerequisite repository is already loaded.
@@ -473,6 +500,189 @@ load_prerequisites (const shared_ptr<repository>& rp, database& db)
load_packages (pr, db);
load_prerequisites (pr, db);
}
+
+ db.update (rp);
+}
+
+static ostream&
+operator<< (ostream& o,
+ const brep::dependency& d) // Ambiguity with bpkg::dependency.
+{
+ o << d.name ();
+
+ if (d.constraint)
+ o << ' ' << *d.constraint;
+
+ return o;
+}
+
+// Check if the package is available from the specified repository,
+// its prerequisite repositories, or one of their complements,
+// recursively.
+//
+static bool
+find (const lazy_shared_ptr<repository>& r,
+ const package& p,
+ bool prereq = true)
+{
+ assert (r != nullptr);
+
+ const auto& o (p.other_repositories);
+ if (r == p.internal_repository || find (o.begin (), o.end (), r) != o.end ())
+ return true;
+
+ auto rp (r.load ());
+ for (const auto& cr: rp->complements)
+ {
+ if (find (lazy_shared_ptr<repository> (cr), p, false))
+ return true;
+ }
+
+ if (prereq)
+ {
+ for (auto pr: rp->prerequisites)
+ {
+ if (find (lazy_shared_ptr<repository> (pr), p, false))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Resolve package dependencies. Ensure that the best matching dependency
+// belongs to the package repositories, their immediate prerequisite
+// repositories, or their complements, recursively. Should be called once per
+// internal package.
+//
+static void
+resolve_dependencies (package& p, database& db)
+{
+ // Resolve dependencies for internal packages only.
+ //
+ // @@ add package::internal() predicate? Lots of place where you do
+ // (p.internal_repository != nullptr).
+ //
+ assert (p.internal_repository != nullptr);
+
+ if (p.dependencies.empty ())
+ return;
+
+ for (auto& da: p.dependencies)
+ {
+ for (auto& d: da)
+ {
+ // Dependency should not be resolved yet.
+ //
+ assert (d.package.object_id ().version.empty ());
+
+ using query = query<package>;
+ query q (query::id.name == d.name ());
+
+ if (d.constraint)
+ {
+ auto c (*d.constraint);
+ switch (c.operation)
+ {
+ case comparison::eq: q = q && query::id.version == c.version; break;
+ case comparison::lt: q = q && query::id.version < c.version; break;
+ case comparison::gt: q = q && query::id.version > c.version; break;
+ case comparison::le: q = q && query::id.version <= c.version; break;
+ case comparison::ge: q = q && query::id.version >= c.version; break;
+ }
+ }
+
+ auto r (
+ db.query<package> (q + order_by_version_desc (query::id.version)));
+
+ for (const auto& pp: r)
+ {
+ if (find (p.internal_repository, pp))
+ {
+ d.package.reset (db, pp.id);
+ break;
+ }
+ }
+
+ if (d.package.object_id ().version.empty ())
+ {
+ ostringstream o;
+ o << "can't resolve dependency " << d << " of the package "
+ << p.id.name << " " << p.version.string ()
+ << " (" << p.internal_repository.load ()->name << ")";
+
+ // Practically it is enough to resolve at least one dependency
+ // alternative to build a package. Meanwhile here we consider an error
+ // specifying in the manifest file an alternative which can't be
+ // resolved.
+ //
+ throw runtime_error (o.str ());
+ }
+ }
+ }
+
+ db.update (p); // Update the package state.
+}
+
+using package_ids = vector<package_id>;
+
+// Ensure the package dependency chain do not contain the package id. Throw
+// runtime_error otherwise. Continue the chain with the package id and call
+// itself recursively for each prerequisite of the package. Should be called
+// once per internal package.
+//
+// @@ This should probably be eventually moved to bpkg.
+//
+static void
+detect_dependency_cycle (const package_id& id, package_ids& chain, database& db)
+{
+ // Package of one version depending on the same package of another version
+ // is something obscure. So the comparison is made up to a package name.
+ //
+ auto pr ([&id](const package_id& i) -> bool {return i.name == id.name;});
+ auto i (find_if (chain.begin (), chain.end (), pr));
+
+ if (i != chain.end ())
+ {
+ ostringstream o;
+ o << "package dependency cycle: ";
+
+ auto prn (
+ [&o, &db](const package_id& id)
+ {
+ shared_ptr<package> p (db.load<package> (id));
+
+ assert (p->internal_repository != nullptr ||
+ !p->other_repositories.empty ());
+
+ shared_ptr<repository> r (
+ p->internal_repository != nullptr
+ ? p->internal_repository.load ()
+ : p->other_repositories[0].load ());
+
+ o << id.name << " " << p->version.string () << " (" << r->name << ")";
+ });
+
+ for (; i != chain.end (); ++i)
+ {
+ prn (*i);
+ o << " -> ";
+ }
+
+ prn (id);
+ throw runtime_error (o.str ());
+ }
+
+ chain.push_back (id);
+
+ shared_ptr<package> p (db.load<package> (id));
+ for (const auto& da: p->dependencies)
+ {
+ for (const auto& d: da)
+ detect_dependency_cycle (d.package.object_id (), chain, db);
+ }
+
+ chain.pop_back ();
}
int
@@ -581,6 +791,26 @@ main (int argc, char* argv[])
load_prerequisites (r, db);
}
+
+ session s;
+ using query = query<package>;
+
+ // Resolve internal packages dependencies.
+ //
+ {
+ auto r (db.query<package> (query::internal_repository.is_not_null ()));
+ for (auto& p: r)
+ resolve_dependencies (p, db);
+ }
+
+ // Ensure there is no package dependency cycles.
+ //
+ {
+ package_ids chain;
+ auto r (db.query<package> (query::internal_repository.is_not_null ()));
+ for (const auto& p: r)
+ detect_dependency_cycle (p.id, chain, db);
+ }
}
t.commit ();
diff --git a/tests/loader/driver.cxx b/tests/loader/driver.cxx
index 74c6966..2222fde 100644
--- a/tests/loader/driver.cxx
+++ b/tests/loader/driver.cxx
@@ -30,7 +30,7 @@ using namespace brep;
static inline bool
operator== (const dependency& a, const dependency& b)
{
- return a.name == b.name && !a.constraint == !b.constraint &&
+ return a.name () == b.name () && !a.constraint == !b.constraint &&
(!a.constraint || (a.constraint->operation == b.constraint->operation &&
a.constraint->version == b.constraint->version));
}
@@ -45,9 +45,22 @@ check_location (shared_ptr<package>& p)
path (p->id.name + "-" + p->version.string () + ".tar.gz");
}
+static bool
+check_external (const package& p)
+{
+ return p.summary.empty () && p.tags.empty () && !p.description &&
+ p.url.empty () && !p.package_url && p.email.empty () && !p.package_email &&
+ p.internal_repository == nullptr && p.other_repositories.size () > 0 &&
+ p.priority == priority () && p.changes.empty () &&
+ p.license_alternatives.empty () && p.dependencies.empty () &&
+ p.requirements.empty ();
+}
+
int
main (int argc, char* argv[])
{
+ using brep::optional; // Ambiguity with butl::optional.
+
if (argc != 7)
{
cerr << "usage: " << argv[0]
@@ -90,7 +103,7 @@ main (int argc, char* argv[])
transaction t (db.begin ());
assert (db.query<repository> ().size () == 5);
- assert (db.query<package> ().size () == 12);
+ assert (db.query<package> ().size () == 14);
shared_ptr<repository> sr (db.load<repository> ("cppget.org/stable"));
shared_ptr<repository> mr (db.load<repository> ("cppget.org/math"));
@@ -129,48 +142,10 @@ main (int argc, char* argv[])
db.load<package> (package_id ("libfoo", version ("1.2.4"))));
assert (check_location (fpv4));
- shared_ptr<package> xpv (
- db.load<package> (package_id ("libstudxml", version ("1.0.0-1"))));
- assert (check_location (xpv));
-
- // Verify libstudxml package version.
- //
- assert (xpv->summary == "Modern C++ XML API");
- assert (xpv->tags == strings ({"c++", "xml", "parser", "serializer",
- "pull", "streaming", "modern"}));
- assert (!xpv->description);
- assert (xpv->url == "http://www.codesynthesis.com/projects/libstudxml/");
- assert (!xpv->package_url);
- assert (xpv->email ==
- email ("studxml-users@codesynthesis.com",
- "Public mailing list, posts by non-members "
- "are allowed but moderated."));
- assert (xpv->package_email &&
- *xpv->package_email == email ("boris@codesynthesis.com",
- "Direct email to the author."));
-
- assert (xpv->internal_repository.load () == sr);
- assert (xpv->external_repositories.empty ());
- assert (xpv->priority == priority::low);
- assert (xpv->changes.empty ());
-
- assert (xpv->license_alternatives.size () == 1);
- assert (xpv->license_alternatives[0].size () == 1);
- assert (xpv->license_alternatives[0][0] == "MIT");
-
- assert (xpv->dependencies.size () == 2);
- assert (xpv->dependencies[0].size () == 1);
- assert (xpv->dependencies[0][0] ==
- (dependency {
- "libexpat",
- brep::optional<dependency_constraint> (
- dependency_constraint{
- comparison::ge, version ("2.0.0")})}));
-
- assert (xpv->dependencies[1].size () == 1);
- assert (xpv->dependencies[1][0] == (dependency {"libgenx", nullopt}));
-
- assert (xpv->requirements.empty ());
+ assert (sr->complements.empty ());
+ assert (sr->prerequisites.size () == 2);
+ assert (sr->prerequisites[0].load () == cr);
+ assert (sr->prerequisites[1].load () == mr);
// Verify libfoo package versions.
//
@@ -185,8 +160,10 @@ main (int argc, char* argv[])
assert (!fpv1->package_email);
assert (fpv1->internal_repository.load () == sr);
- assert (fpv1->external_repositories.size () == 1);
- assert (fpv1->external_repositories[0].load () == cr);
+ assert (fpv1->other_repositories.size () == 2);
+ assert (fpv1->other_repositories[0].load () == mr);
+ assert (fpv1->other_repositories[1].load () == cr);
+
assert (fpv1->priority == priority::low);
assert (fpv1->changes.empty ());
@@ -208,7 +185,7 @@ main (int argc, char* argv[])
assert (!fpv2->package_email);
assert (fpv2->internal_repository.load () == sr);
- assert (fpv2->external_repositories.empty ());
+ assert (fpv2->other_repositories.empty ());
assert (fpv2->priority == priority::low);
assert (fpv2->changes.empty ());
@@ -220,17 +197,24 @@ main (int argc, char* argv[])
assert (fpv2->dependencies[0].size () == 1);
assert (fpv2->dependencies[1].size () == 1);
+ auto dep (
+ [&db](const char* n,
+ const optional<dependency_constraint>& c) -> dependency
+ {
+ return {lazy_shared_ptr<package> (db, package_id (n, version ())), c};
+ });
+
assert (fpv2->dependencies[0][0] ==
- (dependency {
- "libbar",
- brep::optional<dependency_constraint> (
- dependency_constraint{comparison::le, version ("2.4.0")})}));
+ dep (
+ "libbar",
+ optional<dependency_constraint> (
+ dependency_constraint{comparison::le, version ("2.4.0")})));
assert (fpv2->dependencies[1][0] ==
- (dependency {
- "libexp",
- brep::optional<dependency_constraint> (
- dependency_constraint{comparison::eq, version ("1+1.2")})}));
+ dep (
+ "libexp",
+ brep::optional<dependency_constraint> (
+ dependency_constraint{comparison::eq, version ("1+1.2")})));
assert (fpv2->requirements.empty ());
@@ -245,7 +229,7 @@ main (int argc, char* argv[])
assert (!fpv3->package_email);
assert (fpv3->internal_repository.load () == sr);
- assert (fpv3->external_repositories.empty ());
+ assert (fpv3->other_repositories.empty ());
assert (fpv3->priority == priority::low);
assert (fpv3->changes.empty ());
@@ -257,10 +241,10 @@ main (int argc, char* argv[])
assert (fpv3->dependencies.size () == 1);
assert (fpv3->dependencies[0].size () == 1);
assert (fpv3->dependencies[0][0] ==
- (dependency {
- "libmisc",
- brep::optional<dependency_constraint> (
- dependency_constraint{comparison::ge, version ("2.0.0")})}));
+ dep (
+ "libmisc",
+ brep::optional<dependency_constraint> (
+ dependency_constraint{comparison::ge, version ("2.0.0")})));
// libfoo-1.2.4
//
@@ -273,7 +257,7 @@ main (int argc, char* argv[])
assert (!fpv4->package_email);
assert (fpv4->internal_repository.load () == sr);
- assert (fpv4->external_repositories.empty ());
+ assert (fpv4->other_repositories.empty ());
assert (fpv4->priority == priority::low);
assert (fpv4->changes == "some changes 1\nsome changes 2");
@@ -286,10 +270,10 @@ main (int argc, char* argv[])
assert (fpv4->dependencies.size () == 1);
assert (fpv4->dependencies[0].size () == 1);
assert (fpv4->dependencies[0][0] ==
- (dependency {
- "libmisc",
- brep::optional<dependency_constraint> (
- dependency_constraint{comparison::ge, version ("2.0.0")})}));
+ dep (
+ "libmisc",
+ brep::optional<dependency_constraint> (
+ dependency_constraint{comparison::ge, version ("2.0.0")})));
// Verify 'math' repository.
//
@@ -315,6 +299,52 @@ main (int argc, char* argv[])
db.load<package> (package_id ("libfoo", version ("1.2.4-1"))));
assert (check_location (fpv5));
+ shared_ptr<package> xpv (
+ db.load<package> (package_id ("libstudxml", version ("1.0.0-1"))));
+ assert (check_location (xpv));
+
+ assert (mr->complements.empty ());
+ assert (mr->prerequisites.size () == 1);
+ assert (mr->prerequisites[0].load () == cr);
+
+ // Verify libstudxml package version.
+ //
+ assert (xpv->summary == "Modern C++ XML API");
+ assert (xpv->tags == strings ({"c++", "xml", "parser", "serializer",
+ "pull", "streaming", "modern"}));
+ assert (!xpv->description);
+ assert (xpv->url == "http://www.codesynthesis.com/projects/libstudxml/");
+ assert (!xpv->package_url);
+ assert (xpv->email ==
+ email ("studxml-users@codesynthesis.com",
+ "Public mailing list, posts by non-members "
+ "are allowed but moderated."));
+ assert (xpv->package_email &&
+ *xpv->package_email == email ("boris@codesynthesis.com",
+ "Direct email to the author."));
+
+ assert (xpv->internal_repository.load () == mr);
+ assert (xpv->other_repositories.empty ());
+ assert (xpv->priority == priority::low);
+ assert (xpv->changes.empty ());
+
+ assert (xpv->license_alternatives.size () == 1);
+ assert (xpv->license_alternatives[0].size () == 1);
+ assert (xpv->license_alternatives[0][0] == "MIT");
+
+ assert (xpv->dependencies.size () == 2);
+ assert (xpv->dependencies[0].size () == 1);
+ assert (xpv->dependencies[0][0] ==
+ dep (
+ "libexpat",
+ optional<dependency_constraint> (
+ dependency_constraint{comparison::ge, version ("2.0.0")})));
+
+ assert (xpv->dependencies[1].size () == 1);
+ assert (xpv->dependencies[1][0] == dep ("libgenx", nullopt));
+
+ assert (xpv->requirements.empty ());
+
// Verify libfoo package versions.
//
// libfoo-1.2.4-1
@@ -335,8 +365,8 @@ main (int argc, char* argv[])
*fpv5->package_email == "pack@example.com");
assert (fpv5->internal_repository.load () == mr);
- assert (fpv5->external_repositories.size () == 1);
- assert (fpv5->external_repositories[0].load () == cr);
+ assert (fpv5->other_repositories.size () == 1);
+ assert (fpv5->other_repositories[0].load () == cr);
assert (fpv5->priority == priority::high);
assert (fpv5->priority.comment ==
@@ -362,28 +392,36 @@ main (int argc, char* argv[])
assert (fpv5->license_alternatives[1].size () == 1);
assert (fpv5->license_alternatives[1][0] == "BSD");
- assert (fpv5->dependencies.size () == 2);
+ assert (fpv5->dependencies.size () == 3);
assert (fpv5->dependencies[0].size () == 2);
assert (fpv5->dependencies[0].comment ==
"Crashes with 1.1.0-2.3.0.");
assert (fpv5->dependencies[0][0] ==
- (dependency {
- "libmisc",
- brep::optional<dependency_constraint> (
- dependency_constraint{comparison::lt, version ("1.1")})}));
+ dep (
+ "libmisc",
+ brep::optional<dependency_constraint> (
+ dependency_constraint{comparison::lt, version ("1.1")})));
assert (fpv5->dependencies[0][1] ==
- (dependency {
- "libmisc",
- brep::optional<dependency_constraint> (
- dependency_constraint{comparison::gt, version ("2.3.0")})}));
+ dep (
+ "libmisc",
+ brep::optional<dependency_constraint> (
+ dependency_constraint{comparison::gt, version ("2.3.0")})));
+
+ assert (fpv5->dependencies[1].size () == 1);
+ assert (fpv5->dependencies[1].comment.empty ());
- assert (fpv5->dependencies[1].size () == 2);
- assert (fpv5->dependencies[1].comment == "The newer the better.");
+ assert (fpv5->dependencies[1][0] ==
+ dep ("libexp",
+ brep::optional<dependency_constraint> (
+ dependency_constraint{comparison::ge, version ("1.0")})));
- assert (fpv5->dependencies[1][0] == (dependency {"libstudxml", nullopt}));
- assert (fpv5->dependencies[1][1] == (dependency {"libexpat", nullopt}));
+ assert (fpv5->dependencies[2].size () == 2);
+ assert (fpv5->dependencies[2].comment == "The newer the better.");
+
+ assert (fpv5->dependencies[2][0] == dep ("libstudxml", nullopt));
+ assert (fpv5->dependencies[2][1] == dep ("libexpat", nullopt));
requirements& fpvr5 (fpv5->requirements);
assert (fpvr5.size () == 4);
@@ -419,7 +457,7 @@ main (int argc, char* argv[])
assert (!epv->package_email);
assert (epv->internal_repository.load () == mr);
- assert (epv->external_repositories.empty ());
+ assert (epv->other_repositories.empty ());
assert (epv->priority == priority (priority::low));
assert (epv->changes.empty ());
@@ -429,7 +467,7 @@ main (int argc, char* argv[])
assert (epv->dependencies.size () == 1);
assert (epv->dependencies[0].size () == 1);
- assert (epv->dependencies[0][0] == (dependency {"libmisc", nullopt}));
+ assert (epv->dependencies[0][0] == dep ("libmisc", nullopt));
assert (epv->requirements.empty ());
@@ -461,72 +499,31 @@ main (int argc, char* argv[])
db.load<package> (package_id ("libfoo", version ("1.2.4-2"))));
assert (check_location (fpv6));
+ assert (cr->prerequisites.empty ());
+ assert (cr->complements.size () == 1);
+ assert (cr->complements[0].load () == tr);
+
// Verify libbar package version.
//
// libbar-2.3.5
//
- assert (bpv->summary.empty ());
- assert (bpv->tags.empty ());
- assert (!bpv->description);
- assert (bpv->url.empty ());
- assert (!bpv->package_url);
- assert (bpv->email.empty ());
- assert (!bpv->package_email);
-
- assert (bpv->internal_repository == nullptr);
- assert (bpv->external_repositories.size () == 1);
- assert (bpv->external_repositories[0].load () == cr);
-
- assert (bpv->priority == priority ());
- assert (bpv->changes.empty ());
-
- assert (bpv->license_alternatives.empty ());
- assert (bpv->dependencies.empty ());
- assert (bpv->requirements.empty ());
+ assert (check_external (*bpv));
+ assert (bpv->other_repositories.size () == 1);
+ assert (bpv->other_repositories[0].load () == cr);
// Verify libfoo package versions.
//
// libfoo-0.1
//
- assert (fpv0->summary.empty ());
- assert (fpv0->tags.empty ());
- assert (!fpv0->description);
- assert (fpv0->url.empty ());
- assert (!fpv0->package_url);
- assert (fpv0->email.empty ());
- assert (!fpv0->package_email);
-
- assert (fpv0->internal_repository == nullptr);
- assert (fpv0->external_repositories.size () == 1);
- assert (fpv0->external_repositories[0].load () == cr);
- assert (fpv0->priority == priority::low);
- assert (fpv0->changes.empty ());
-
- assert (fpv0->license_alternatives.empty ());
-
- assert (fpv0->dependencies.empty ());
- assert (fpv0->requirements.empty ());
+ assert (check_external (*fpv0));
+ assert (fpv0->other_repositories.size () == 1);
+ assert (fpv0->other_repositories[0].load () == cr);
// libfoo-1.2.4-2
//
- assert (fpv6->summary.empty ());
- assert (fpv6->tags.empty ());
- assert (!fpv6->description);
- assert (fpv6->url.empty ());
- assert (!fpv6->package_url);
- assert (fpv6->email.empty ());
- assert (!fpv6->package_email);
-
- assert (fpv6->internal_repository == nullptr);
- assert (fpv6->external_repositories.size () == 1);
- assert (fpv6->external_repositories[0].load () == cr);
- assert (fpv6->priority == priority::low);
- assert (fpv6->changes.empty ());
-
- assert (fpv6->license_alternatives.empty ());
-
- assert (fpv6->dependencies.empty ());
- assert (fpv6->requirements.empty ());
+ assert (check_external (*fpv6));
+ assert (fpv6->other_repositories.size () == 1);
+ assert (fpv6->other_repositories[0].load () == cr);
// Verify 'testing' repository.
//
@@ -544,59 +541,76 @@ main (int argc, char* argv[])
file_mtime (dir_path (tr->local_path) / path ("repositories")));
assert (!tr->internal);
- shared_ptr<package> mpv (
- db.load<package> (package_id ("libmisc", version ("1.1"))));
- assert (check_location (mpv));
+ shared_ptr<package> mpv0 (
+ db.load<package> (package_id ("libmisc", version ("2.4.0"))));
+ assert (check_location (mpv0));
- shared_ptr<package> tpv (
- db.load<package> (package_id ("libexpat", version ("5.1"))));
- assert (check_location (tpv));
+ assert (tr->prerequisites.empty ());
+ assert (tr->complements.size () == 1);
+ assert (tr->complements[0].load () == gr);
// Verify libmisc package version.
//
- // libmisc-1.1
+ // libmisc-2.4.0
+ //
+ assert (check_external (*mpv0));
+ assert (mpv0->other_repositories.size () == 1);
+ assert (mpv0->other_repositories[0].load () == tr);
+
+ // Verify 'staging' repository.
//
- assert (mpv->summary.empty ());
- assert (mpv->tags.empty ());
- assert (!mpv->description);
- assert (mpv->url.empty ());
- assert (!mpv->package_url);
- assert (mpv->email.empty ());
- assert (!mpv->package_email);
+ assert (gr->location.canonical_name () == "cppget.org/staging");
+ assert (gr->location.string () ==
+ "http://pkg.cppget.org/external/1/staging");
+ assert (gr->display_name.empty ());
- assert (mpv->internal_repository == nullptr);
- assert (mpv->external_repositories.size () == 1);
- assert (mpv->external_repositories[0].load () == tr);
+ dir_path grp (cp.directory () / dir_path ("external/1/staging"));
+ assert (gr->local_path == grp.normalize ());
- assert (mpv->priority == priority ());
- assert (mpv->changes.empty ());
+ assert (gr->packages_timestamp ==
+ file_mtime (dir_path (gr->local_path) / path ("packages")));
+ assert (gr->repositories_timestamp ==
+ file_mtime (dir_path (gr->local_path) / path ("repositories")));
+ assert (!gr->internal);
- assert (mpv->license_alternatives.empty ());
- assert (mpv->dependencies.empty ());
- assert (mpv->requirements.empty ());
+ shared_ptr<package> tpv (
+ db.load<package> (package_id ("libexpat", version ("5.1"))));
+ assert (check_location (tpv));
+
+ shared_ptr<package> gpv (
+ db.load<package> (package_id ("libgenx", version ("1.0"))));
+ assert (check_location (gpv));
+
+ shared_ptr<package> mpv1 (
+ db.load<package> (package_id ("libmisc", version ("1.0"))));
+ assert (check_location (mpv1));
+
+ assert (gr->prerequisites.empty ());
+ assert (gr->complements.empty ());
// Verify libexpat package version.
//
// libexpat-5.1
//
- assert (tpv->summary.empty ());
- assert (tpv->tags.empty ());
- assert (!tpv->description);
- assert (tpv->url.empty ());
- assert (!tpv->package_url);
- assert (tpv->email.empty ());
- assert (!tpv->package_email);
-
- assert (tpv->internal_repository == nullptr);
- assert (tpv->external_repositories.size () == 1);
- assert (tpv->external_repositories[0].load () == gr);
-
- assert (tpv->priority == priority ());
- assert (tpv->changes.empty ());
-
- assert (tpv->license_alternatives.empty ());
- assert (tpv->dependencies.empty ());
- assert (tpv->requirements.empty ());
+ assert (check_external (*tpv));
+ assert (tpv->other_repositories.size () == 1);
+ assert (tpv->other_repositories[0].load () == gr);
+
+ // Verify libgenx package version.
+ //
+ // libgenx-1.0
+ //
+ assert (check_external (*gpv));
+ assert (gpv->other_repositories.size () == 1);
+ assert (gpv->other_repositories[0].load () == gr);
+
+ // Verify libmisc package version.
+ //
+ // libmisc-1.0
+ //
+ assert (check_external (*mpv1));
+ assert (mpv1->other_repositories.size () == 1);
+ assert (mpv1->other_repositories[0].load () == gr);
// Change package summary, update the object persistent state, rerun
// loader and ensure the model were not rebuilt.
diff --git a/tests/loader/external/1/staging/packages b/tests/loader/external/1/staging/packages
index 86c20c1..e7b22b0 100644
--- a/tests/loader/external/1/staging/packages
+++ b/tests/loader/external/1/staging/packages
@@ -6,3 +6,20 @@ license: MIT
url: http://www.example.com/expat/
email: expat-users@example.com
location: libexpat-5.1.tar.gz
+:
+name: libgenx
+version: 1.0
+summary: The Genx Library
+license: MIT
+url: http://www.example.com/genx/
+email: genx-users@example.com
+location: libgenx-1.0.tar.gz
+:
+name: libmisc
+version: 1.0
+summary: The Misc Library
+license: MIT
+url: http://www.example.com/misc/
+email: misc-users@example.com
+depends: libexpat >= 5.0
+location: libmisc-1.0.tar.gz
diff --git a/tests/loader/external/1/testing/packages b/tests/loader/external/1/testing/packages
index ac5ab95..bdebece 100644
--- a/tests/loader/external/1/testing/packages
+++ b/tests/loader/external/1/testing/packages
@@ -1,9 +1,9 @@
: 1
name: libmisc
-version: 1.1
-summary: The Expat Library
+version: 2.4.0
+summary: The Misc Library
license: MIT
url: http://www.example.com/misc/
email: misc-users@example.com
depends: libexpat >= 5.0
-location: libmisc-1.1.tar.gz
+location: libmisc-2.4.0.tar.gz
diff --git a/tests/loader/internal/1/math/packages b/tests/loader/internal/1/math/packages
index d55a9e3..4d34c13 100644
--- a/tests/loader/internal/1/math/packages
+++ b/tests/loader/internal/1/math/packages
@@ -1,4 +1,19 @@
: 1
+name: libstudxml
+version: 1.0.0-1
+summary: Modern C++ XML API
+license: MIT
+tags: c++, xml, parser, serializer, pull, streaming, modern
+description-file: README
+changes-file: NEWS
+url: http://www.codesynthesis.com/projects/libstudxml/
+email: studxml-users@codesynthesis.com; Public mailing list, posts by\
+ non-members are allowed but moderated.
+package-email: boris@codesynthesis.com; Direct email to the author.
+depends: libexpat >= 2.0.0
+depends: libgenx
+location: libstudxml-1.0.0-1.tar.gz
+:
name: libexp
version: 1+1.2
summary: The exponent
@@ -31,6 +46,7 @@ email: foo-users@example.com; Public mailing list. Read FAQ before posting.
package-url: http://www.example.com/foo/pack; Package details.
package-email: pack@example.com; Current packager.
depends: libmisc < 1.1 | libmisc > 2.3.0; Crashes with 1.1.0-2.3.0.
+depends: libexp >= 1.0
depends: ? libstudxml | libexpat; The newer the better.
requires: linux | windows | macosx; Symbian support is coming.
requires: c++11
diff --git a/tests/loader/internal/1/stable/packages b/tests/loader/internal/1/stable/packages
index 8d1e2fd..756a562 100644
--- a/tests/loader/internal/1/stable/packages
+++ b/tests/loader/internal/1/stable/packages
@@ -9,21 +9,6 @@ email: foo-users@example.com
depends: libmisc >= 2.0.0
location: libfoo-1.2.3-4.tar.gz
:
-name: libstudxml
-version: 1.0.0-1
-summary: Modern C++ XML API
-license: MIT
-tags: c++, xml, parser, serializer, pull, streaming, modern
-description-file: README
-changes-file: NEWS
-url: http://www.codesynthesis.com/projects/libstudxml/
-email: studxml-users@codesynthesis.com; Public mailing list, posts by\
- non-members are allowed but moderated.
-package-email: boris@codesynthesis.com; Direct email to the author.
-depends: libexpat >= 2.0.0
-depends: libgenx
-location: libstudxml-1.0.0-1.tar.gz
-:
name: libfoo
version: 1.2.2
summary: The Foo library
diff --git a/web/module b/web/module
index 25c4bf2..1774884 100644
--- a/web/module
+++ b/web/module
@@ -58,8 +58,7 @@ namespace web
sequence_error (std::string d): std::runtime_error (std::move (d)) {}
};
- template <typename T>
- using optional = butl::optional<T>;
+ using butl::optional;
struct name_value
{
@@ -74,7 +73,7 @@ namespace web
};
using name_values = std::vector<name_value>;
- using path = butl::path;
+ using butl::path;
class request
{