diff options
-rw-r--r-- | etc/brep-module.conf | 3 | ||||
-rw-r--r-- | libbrep/build-extra.sql | 3 | ||||
-rw-r--r-- | libbrep/common.hxx | 30 | ||||
-rw-r--r-- | libbrep/package.cxx | 12 | ||||
-rw-r--r-- | libbrep/package.hxx | 17 | ||||
-rw-r--r-- | libbrep/package.xml | 28 | ||||
-rw-r--r-- | load/load.cli | 22 | ||||
-rw-r--r-- | load/load.cxx | 240 | ||||
-rw-r--r-- | mod/mod-package-version-details.cxx | 87 | ||||
-rw-r--r-- | mod/page.cxx | 46 | ||||
-rw-r--r-- | tests/load/driver.cxx | 1705 | ||||
-rw-r--r-- | tests/load/git-cache/packages.manifest | 14 | ||||
-rw-r--r-- | tests/load/git-cache/repositories.manifest | 7 | ||||
-rw-r--r-- | tests/load/git-loadtab | 1 |
14 files changed, 1256 insertions, 959 deletions
diff --git a/etc/brep-module.conf b/etc/brep-module.conf index 2dc738e..ca02227 100644 --- a/etc/brep-module.conf +++ b/etc/brep-module.conf @@ -23,6 +23,7 @@ menu Packages= # menu Builds=?builds # menu Submit=?submit +# menu CI=?ci menu About=?about @@ -262,7 +263,7 @@ menu About=?about # not exit in the alloted time, then it is killed and its termination is # treated as abnormal. # -# submit-handler-timeout 60 +# submit-handler-timeout # The directory to save CI request data to. If unspecified, the package CI diff --git a/libbrep/build-extra.sql b/libbrep/build-extra.sql index 96e355c..e0aa92a 100644 --- a/libbrep/build-extra.sql +++ b/libbrep/build-extra.sql @@ -14,7 +14,8 @@ DROP FOREIGN TABLE IF EXISTS build_repository; -- CREATE FOREIGN TABLE build_repository ( name TEXT NOT NULL, - location TEXT NOT NULL, + location_url TEXT NOT NULL, + location_type TEXT NOT NULL, certificate_fingerprint TEXT NULL) SERVER package_server OPTIONS (table_name 'repository'); diff --git a/libbrep/common.hxx b/libbrep/common.hxx index 5b172ec..0163ca0 100644 --- a/libbrep/common.hxx +++ b/libbrep/common.hxx @@ -218,21 +218,39 @@ namespace brep // repository_type // using bpkg::repository_type; + using bpkg::to_repository_type; + + #pragma db map type(repository_type) as(string) \ + to(to_string (?)) \ + from(brep::to_repository_type (?)) // repository_url // using bpkg::repository_url; + #pragma db map type(repository_url) as(string) \ + to((?).string ()) \ + from((?).empty () ? brep::repository_url () : brep::repository_url (?)) + // repository_location // using bpkg::repository_location; - #pragma db map type(repository_location) as(string) \ - to((?).url ().string ()) \ - from(brep::repository_location ((?).empty () \ - ? bpkg::repository_url () \ - : brep::repository_url (?), \ - brep::repository_type::pkg)) + #pragma db value + struct _repository_location + { + repository_url url; + repository_type type; + }; + + // Note that the type() call fails for an empty repository location. + // + #pragma db map type(repository_location) as(_repository_location) \ + to(brep::_repository_location {(?).url (), \ + (?).empty () \ + ? brep::repository_type::pkg \ + : (?).type ()}) \ + from(brep::repository_location (std::move ((?).url), (?).type)) // Version comparison operators. // diff --git a/libbrep/package.cxx b/libbrep/package.cxx index 5b729c8..6d4550d 100644 --- a/libbrep/package.cxx +++ b/libbrep/package.cxx @@ -15,16 +15,10 @@ namespace brep { // dependency // - package_name dependency:: - name () const - { - return package.object_id ().name; - } - ostream& operator<< (ostream& o, const dependency& d) { - o << d.name (); + o << d.name; if (d.constraint) o << ' ' << *d.constraint; @@ -35,7 +29,7 @@ namespace brep bool operator== (const dependency& x, const dependency& y) { - return x.name () == y.name () && x.constraint == y.constraint; + return x.name == y.name && x.constraint == y.constraint; } bool @@ -67,6 +61,7 @@ namespace brep requirements_type rq, build_constraints_type bc, optional<path> lc, + optional<string> fr, optional<string> sh, shared_ptr<repository_type> rp) : id (move (nm), vr), @@ -93,6 +88,7 @@ namespace brep : build_constraints_type ()), internal_repository (move (rp)), location (move (lc)), + fragment (move (fr)), sha256sum (move (sh)) { assert (internal_repository->internal); diff --git a/libbrep/package.hxx b/libbrep/package.hxx index e7a8338..3d281b0 100644 --- a/libbrep/package.hxx +++ b/libbrep/package.hxx @@ -120,17 +120,16 @@ namespace brep { using package_type = brep::package; - lazy_shared_ptr<package_type> package; + package_name name; optional<dependency_constraint> constraint; - // Prerequisite package name. + // Resolved dependency package. NULL if the repository load was shallow + // and so the package dependencies are not resolved. // - package_name - name () const; + lazy_shared_ptr<package_type> package; // Database mapping. // - #pragma db member(package) column("") not_null #pragma db member(constraint) column("") }; @@ -212,7 +211,7 @@ namespace brep // uint16_t priority; - optional<string> url; + optional<string> interface_url; // Present only for internal repositories. // @@ -318,6 +317,7 @@ namespace brep requirements_type, build_constraints_type, optional<path> location, + optional<string> fragment, optional<string> sha256sum, shared_ptr<repository_type>); @@ -370,6 +370,11 @@ namespace brep // optional<path> location; + // Present only for packages that come from the supporting fragmentation + // internal repository (normally version control-based). + // + optional<string> fragment; + // Present only for internal packages. // optional<string> sha256sum; diff --git a/libbrep/package.xml b/libbrep/package.xml index 47ff071..55baae9 100644 --- a/libbrep/package.xml +++ b/libbrep/package.xml @@ -2,15 +2,17 @@ <model version="7"> <table name="repository" kind="object"> <column name="name" type="TEXT" null="false"/> - <column name="location" type="TEXT" null="false"/> + <column name="location_url" type="TEXT" null="false"/> + <column name="location_type" type="TEXT" null="false"/> <column name="display_name" type="TEXT" null="false"/> <column name="priority" type="INTEGER" null="false"/> - <column name="url" type="TEXT" null="true"/> + <column name="interface_url" type="TEXT" null="true"/> <column name="email" type="TEXT" null="true"/> <column name="email_comment" type="TEXT" null="true"/> <column name="summary" type="TEXT" null="true"/> <column name="description" type="TEXT" null="true"/> - <column name="cache_location" type="TEXT" null="false"/> + <column name="cache_location_url" type="TEXT" null="false"/> + <column name="cache_location_type" type="TEXT" null="false"/> <column name="certificate_fingerprint" type="TEXT" null="true"/> <column name="certificate_name" type="TEXT" null="true"/> <column name="certificate_organization" type="TEXT" null="true"/> @@ -99,6 +101,7 @@ <column name="build_email_comment" type="TEXT" null="true"/> <column name="internal_repository" type="TEXT" null="true"/> <column name="location" type="TEXT" null="true"/> + <column name="fragment" type="TEXT" null="true"/> <column name="sha256sum" type="TEXT" null="true"/> <column name="search_index" type="tsvector" null="true"/> <primary-key> @@ -259,10 +262,6 @@ <column name="dependency_index" type="BIGINT" null="false"/> <column name="index" type="BIGINT" null="false"/> <column name="dep_name" type="CITEXT" null="false"/> - <column name="dep_version_epoch" type="INTEGER" null="false"/> - <column name="dep_version_canonical_upstream" type="TEXT" null="false"/> - <column name="dep_version_canonical_release" type="TEXT" null="false" options="COLLATE "C""/> - <column name="dep_version_revision" type="INTEGER" null="false"/> <column name="dep_min_version_epoch" type="INTEGER" null="true"/> <column name="dep_min_version_canonical_upstream" type="TEXT" null="true"/> <column name="dep_min_version_canonical_release" type="TEXT" null="true"/> @@ -277,6 +276,11 @@ <column name="dep_max_version_release" type="TEXT" null="true"/> <column name="dep_min_open" type="BOOLEAN" null="true"/> <column name="dep_max_open" type="BOOLEAN" null="true"/> + <column name="dep_package_name" type="CITEXT" null="true"/> + <column name="dep_package_version_epoch" type="INTEGER" null="true"/> + <column name="dep_package_version_canonical_upstream" type="TEXT" null="true"/> + <column name="dep_package_version_canonical_release" type="TEXT" null="true" options="COLLATE "C""/> + <column name="dep_package_version_revision" type="INTEGER" null="true"/> <foreign-key name="object_id_fk" on-delete="CASCADE"> <column name="name"/> <column name="version_epoch"/> @@ -299,11 +303,11 @@ <column name="version_revision"/> </index> <foreign-key name="dep_package_fk" deferrable="DEFERRED"> - <column name="dep_name"/> - <column name="dep_version_epoch"/> - <column name="dep_version_canonical_upstream"/> - <column name="dep_version_canonical_release"/> - <column name="dep_version_revision"/> + <column name="dep_package_name"/> + <column name="dep_package_version_epoch"/> + <column name="dep_package_version_canonical_upstream"/> + <column name="dep_package_version_canonical_release"/> + <column name="dep_package_version_revision"/> <references table="package"> <column name="name"/> <column name="version_epoch"/> diff --git a/load/load.cli b/load/load.cli index 6db6048..bbe54ff 100644 --- a/load/load.cli +++ b/load/load.cli @@ -10,7 +10,7 @@ include <libbrep/types.hxx>; "\section=1" "\name=brep-load" -"\summary=load build2 repositories into brep package database" +"\summary=load repositories into brep package database" { "<options> <loadtab>", @@ -23,10 +23,10 @@ include <libbrep/types.hxx>; \h|DESCRIPTION| - \cb{brep-load} reads the list of repositories from the specified - <loadtab> configuration file, fetches their manifest files, and loads the - repository and package information into the \cb{package} database, suitable - for consumption by the \cb{brep} web module. + \cb{brep-load} reads the list of repositories from the specified <loadtab> + configuration file, fetches their manifest files, and loads the repository + and package information into the \cb{package} database, suitable for + consumption by the \cb{brep} web module. Note that \cb{brep-load} expects the \cb{package} database schema to have already been created using \l{brep-migrate(1)}. @@ -40,6 +40,18 @@ class options { "\h|OPTIONS|" + bool --force + { + "Reload package information regardless of the repository manifest file + timestamps." + }; + + bool --shallow + { + "Don't load package information from prerequisite or complement + repositories." + }; + std::string --db-user|-u { "<user>", diff --git a/load/load.cxx b/load/load.cxx index 1875f2a..01d77c2 100644 --- a/load/load.cxx +++ b/load/load.cxx @@ -68,12 +68,34 @@ struct internal_repository using internal_repositories = vector<internal_repository>; - // Parse loadtab file. - // - // loadtab consists of lines in the following format: - // - // <remote-repository-location> <display-name> cache:<local-repository-location> [fingerprint:<fingerprint>] - // +// Parse loadtab file. +// +// loadtab consists of lines in the following format: +// +// <remote-repository-location> <display-name> cache:<local-repository-location> [fingerprint:<fingerprint>] +// +// Note that if the remote repository location is a pkg repository, then the +// repository cache should be its local copy. Otherwise, the cache directory +// is expected to contain just repositories.manifest and packages.manifest +// files as dumped by bpkg-rep-info, for example: +// +// $ bpkg rep-info --manifest +// --repositories-file repositories.manifest +// --packages-file packages.manifest +// <remote-repository-location> +// +// Specifically, the packages.manifest is not a pkg package manifest list. It +// contains a raw list of package manifests that may contain values forbidden +// for the pkg package manifest list (description-file, changes-file) and may +// omit the required ones (sha256sum). +// +// @@ Latter, we may also want to support loading bpkg repositories using +// manifest files produced by bpkg-rep-info command. This, in particular, +// will allow handling CI requests for bpkg repositories. +// +// The current thinking is that the CI handler will be able to "suggest" +// this using (the planned) cache:file+dir:// form. +// static internal_repositories load_repositories (path p) { @@ -116,8 +138,10 @@ load_repositories (path p) try { - r.location = repository_location (repository_url (tl[i].value), - repository_type::pkg); + repository_url u (tl[i].value); + + r.location = repository_location (u, + guess_type (u, false /* local */)); } catch (const invalid_argument& e) { @@ -164,9 +188,15 @@ load_repositories (path p) if (cache_path.relative ()) cache_path = p.directory () / cache_path; + // A non-pkg repository cache is not a real repository (see + // above). We create the location of the dir type for such a cache + // to distinguish it when it comes to the manifest files parsing. + // r.cache_location = repository_location ( repository_url (cache_path.string ()), - repository_type::pkg); + r.location.type () == repository_type::pkg + ? r.location.type () + : repository_type::dir); // Created from the absolute path repository location can not be // other than absolute. @@ -318,8 +348,10 @@ load_packages (const shared_ptr<repository>& rp, database& db) // assert (!rp->cache_location.empty ()); - pkg_package_manifests pkm; - path p (rp->cache_location.path () / packages); + vector<package_manifest> pms; + const repository_location& cl (rp->cache_location); + + path p (cl.path () / packages); try { @@ -327,7 +359,25 @@ load_packages (const shared_ptr<repository>& rp, database& db) rp->packages_timestamp = file_mtime (p); manifest_parser mp (ifs, p.string ()); - pkm = pkg_package_manifests (mp); + + // If the repository cache directory is not a pkg repository, then the + // packages.manifest file it contains is a raw list of the package + // manifests that we need to parse manually (see above). + // + if (cl.type () != repository_type::pkg) + { + // We put no restrictions on the manifest values present since it's not + // critical for displaying and building if the packages omit some + // manifest values (see libbpkg/manifest.hxx for details). + // + for (manifest_name_value nv (mp.next ()); !nv.empty (); nv = mp.next ()) + pms.emplace_back (mp, + move (nv), + false /* ignore_unknown */, + package_manifest_flags::none); + } + else + pms = pkg_package_manifests (mp); } catch (const io_error& e) { @@ -335,15 +385,15 @@ load_packages (const shared_ptr<repository>& rp, database& db) throw failed (); } - for (auto& pm: pkm) + for (auto& pm: pms) { shared_ptr<package> p ( db.find<package> (package_id (pm.name, pm.version))); // sha256sum should always be present if the package manifest comes from - // the packages.manifest file. + // the packages.manifest file belonging to the pkg repository. // - assert (pm.sha256sum); + assert (pm.sha256sum || cl.type () != repository_type::pkg); if (p == nullptr) { @@ -354,23 +404,34 @@ load_packages (const shared_ptr<repository>& rp, database& db) optional<string> dsc; if (pm.description) { - assert (!pm.description->file); - dsc = move (pm.description->text); + // The description value should not be of the file type if the + // package manifest comes from the pkg repository. + // + assert (!pm.description->file || cl.type () != repository_type::pkg); + + if (!pm.description->file) + dsc = move (pm.description->text); } string chn; for (auto& c: pm.changes) { - assert (!c.file); + // The changes value should not be of the file type if the package + // manifest comes from the pkg repository. + // + assert (!c.file || cl.type () != repository_type::pkg); - if (chn.empty ()) - chn = move (c.text); - else + if (!c.file) { - if (chn.back () != '\n') - chn += '\n'; // Always have a blank line as a separator. + if (chn.empty ()) + chn = move (c.text); + else + { + if (chn.back () != '\n') + chn += '\n'; // Always have a blank line as a separator. - chn += "\n" + c.text; + chn += "\n" + c.text; + } } } @@ -392,14 +453,12 @@ load_packages (const shared_ptr<repository>& rp, database& db) ds.emplace_back (pda.conditional, pda.buildtime, 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. + // The package member will be assigned during dependency + // resolution procedure. // - ds.back ().push_back ({ - lazy_shared_ptr<package> ( - db, package_id (move (pd.name), version ())), - move (pd.constraint)}); + ds.back ().push_back ({move (pd.name), + move (pd.constraint), + nullptr /* package */}); } // Cache before the package name is moved. @@ -427,6 +486,7 @@ load_packages (const shared_ptr<repository>& rp, database& db) move (pm.requirements), move (pm.build_constraints), move (pm.location), + move (pm.fragment), move (pm.sha256sum), rp); } @@ -444,13 +504,24 @@ load_packages (const shared_ptr<repository>& rp, database& db) // assert (!rp->internal || p->internal ()); - if (rp->internal && pm.sha256sum != p->sha256sum) - cerr << "warning: sha256sum mismatch for package " << p->id.name - << " " << p->version << endl - << " info: " << p->internal_repository.load ()->location - << " has " << *p->sha256sum << endl - << " info: " << rp->location << " has " << *pm.sha256sum - << endl; + // Note that the sha256sum manifest value can only be present if the + // package comes from the pkg repository. + // + if (rp->internal && pm.sha256sum) + { + // Save the package sha256sum if it is not present yet, match + // otherwise. + // + if (!p->sha256sum) + p->sha256sum = move (pm.sha256sum); + else if (*pm.sha256sum != *p->sha256sum) + cerr << "warning: sha256sum mismatch for package " << p->id.name + << " " << p->version << endl + << " info: " << p->internal_repository.load ()->location + << " has " << *p->sha256sum << endl + << " info: " << rp->location << " has " << *pm.sha256sum + << endl; + } p->other_repositories.push_back (rp); db.update (p); @@ -460,13 +531,15 @@ load_packages (const shared_ptr<repository>& rp, database& db) db.persist (rp); // Save the repository state. } -// Load the repository manifest values, prerequsite repositories, and their -// complements state from the repositories.manifest file. Update the repository -// persistent state to save changed members. Should be called once per -// persisted internal repository. +// Load the repository manifest values from the repositories.manifest file. +// Unless this is a shallow load, also load prerequsite repositories and +// their complements state. Update the repository persistent state to save +// changed members. Should be called once per persisted internal repository. // static void -load_repositories (const shared_ptr<repository>& rp, database& db) +load_repositories (const shared_ptr<repository>& rp, + database& db, + bool shallow) { // repositories_timestamp other than timestamp_nonexistent signals that // repository prerequisites are already loaded. @@ -508,11 +581,11 @@ load_repositories (const shared_ptr<repository>& rp, database& db) if (rm.effective_role () == repository_role::base) { - assert (rp->location.remote () && !rp->url); + assert (rp->location.remote () && !rp->interface_url); // Update the base repository with manifest values. // - rp->url = rm.effective_url (rp->location); + rp->interface_url = rm.effective_url (rp->location); // @@ Should we throw if url is not available for external repository ? // Can, basically, repository be available on the web but have no web @@ -521,11 +594,11 @@ load_repositories (const shared_ptr<repository>& rp, database& db) // Yes, there can be no web interface. So we should just not form // links to packages from such repos. // - if (rp->url) + if (rp->interface_url) { // Normalize web interface url adding trailing '/' if not present. // - auto& u (*rp->url); + auto& u (*rp->interface_url); assert (!u.empty ()); if (u.back () != '/') u += '/'; @@ -561,8 +634,12 @@ load_repositories (const shared_ptr<repository>& rp, database& db) continue; } - // Load prerequisite or complement repository. + // Load prerequisite or complement repository unless this is a shallow + // load. // + if (shallow) + continue; + assert (!rm.location.empty ()); repository_location rl; @@ -581,8 +658,7 @@ load_repositories (const shared_ptr<repository>& rp, database& db) { // Absolute path location make no sense for the web interface. // - if (rm.location.type () != repository_type::pkg || - rm.location.absolute ()) + if (rm.location.absolute ()) bad_location (); // Convert the relative repository location to remote one, leave remote @@ -639,7 +715,7 @@ load_repositories (const shared_ptr<repository>& rp, database& db) } load_packages (pr, db); - load_repositories (pr, db); + load_repositories (pr, db, false /* shallow */); } db.update (rp); @@ -680,7 +756,7 @@ find (const lazy_shared_ptr<repository>& r, return false; } -// Resolve package dependencies. Ensure that the best matching dependency +// Resolve package dependencies. Make sure 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. @@ -701,10 +777,10 @@ resolve_dependencies (package& p, database& db) { // Dependency should not be resolved yet. // - assert (d.package.object_id ().version.empty ()); + assert (d.package == nullptr); using query = query<package>; - query q (query::id.name == d.name ()); + query q (query::id.name == d.name); const auto& vm (query::id.version); if (d.constraint) @@ -755,7 +831,7 @@ resolve_dependencies (package& p, database& db) } } - if (d.package.object_id ().version.empty ()) + if (d.package == nullptr) { cerr << "error: can't resolve dependency " << d << " of the package " << p.id.name << " " << p.version << endl @@ -778,16 +854,17 @@ resolve_dependencies (package& p, database& db) using package_ids = vector<package_id>; -// Ensure the package dependency chain do not contain the package id. Throw -// failed 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. +// Make sure the package dependency chain doesn't contain the package id. +// Throw failed 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) +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. @@ -1042,7 +1119,7 @@ try // internal_repositories irs (load_repositories (path (argv[1]))); - if (changed (irs, db)) + if (ops.force () || changed (irs, db)) { // Rebuild repositories persistent state from scratch. // @@ -1055,11 +1132,13 @@ try uint16_t priority (1); for (const auto& ir: irs) { - optional<certificate> cert ( - certificate_info ( + optional<certificate> cert; + + if (ir.location.type () == repository_type::pkg) + cert = certificate_info ( ops, !ir.cache_location.empty () ? ir.cache_location : ir.location, - ir.fingerprint)); + ir.fingerprint); shared_ptr<repository> r ( make_shared<repository> (ir.location, @@ -1080,24 +1159,27 @@ try shared_ptr<repository> r ( db.load<repository> (ir.location.canonical_name ())); - load_repositories (r, db); + load_repositories (r, db, ops.shallow ()); } - session s; - using query = query<package>; - - // Resolve internal packages dependencies. + // Resolve internal packages dependencies unless this is a shallow load. // - for (auto& p: - db.query<package> (query::internal_repository.is_not_null ())) - resolve_dependencies (p, db); + if (!ops.shallow ()) + { + session s; + using query = query<package>; - // Ensure there is no package dependency cycles. - // - package_ids chain; - for (const auto& p: - db.query<package> (query::internal_repository.is_not_null ())) - detect_dependency_cycle (p.id, chain, db); + for (auto& p: + db.query<package> (query::internal_repository.is_not_null ())) + resolve_dependencies (p, db); + + // Make sure there is no package dependency cycles. + // + package_ids chain; + for (const auto& p: + db.query<package> (query::internal_repository.is_not_null ())) + detect_dependency_cycle (p.id, chain, db); + } } t.commit (); diff --git a/mod/mod-package-version-details.cxx b/mod/mod-package-version-details.cxx index 0e3b3f7..d2d96d2 100644 --- a/mod/mod-package-version-details.cxx +++ b/mod/mod-package-version-details.cxx @@ -184,8 +184,6 @@ handle (request& rq, response& rs) : P_DESCRIPTION (*d, options_->package_description (), url (!full, id))); - assert (pkg->location && pkg->sha256sum); - const repository_location& rl (pkg->internal_repository.load ()->location); s << TABLE(CLASS="proplist", ID="version") @@ -198,10 +196,22 @@ handle (request& rq, response& rs) << TR_PRIORITY (pkg->priority) << TR_LICENSES (pkg->license_alternatives) << TR_REPOSITORY (rl.canonical_name (), root) - << TR_LOCATION (rl) - << TR_DOWNLOAD (rl.string () + "/" + pkg->location->string ()) - << TR_SHA256SUM (*pkg->sha256sum) - << ~TBODY + << TR_LOCATION (rl); + + if (rl.type () == repository_type::pkg) + { + assert (pkg->location); + + s << TR_DOWNLOAD (rl.string () + "/" + pkg->location->string ()); + } + + if (pkg->fragment) + s << TR_VALUE ("fragment", *pkg->fragment); + + if (pkg->sha256sum) + s << TR_SHA256SUM (*pkg->sha256sum); + + s << ~TBODY << ~TABLE << TABLE(CLASS="proplist", ID="package") @@ -267,38 +277,49 @@ handle (request& rq, response& rs) if (&d != &da[0]) s << " | "; - shared_ptr<package> p (d.package.load ()); - assert (p->internal () || !p->other_repositories.empty ()); - - shared_ptr<repository> r ( - p->internal () - ? p->internal_repository.load () - : p->other_repositories[0].load ()); - const auto& dcon (d.constraint); - const package_name& dname (p->id.name); - string ename (mime_url_encode (dname.string (), false)); - - if (r->url) - { - string u (*r->url + ename); - s << A(HREF=u) << dname << ~A; + const package_name& dname (d.name); - if (dcon) - s << ' ' << A(HREF=u + "/" + p->version.string ()) << *dcon << ~A; - } - else if (p->internal ()) + // Try to display the dependency as a link if it is resolved. + // Otherwise display it as a plain text. + // + if (d.package != nullptr) { - dir_path u (root / dir_path (ename)); - s << A(HREF=u) << dname << ~A; - - if (dcon) - s << ' ' << A(HREF=u / path (p->version.string ())) << *dcon << ~A; + shared_ptr<package> p (d.package.load ()); + assert (p->internal () || !p->other_repositories.empty ()); + + shared_ptr<repository> r ( + p->internal () + ? p->internal_repository.load () + : p->other_repositories[0].load ()); + + string ename (mime_url_encode (dname.string (), false)); + + if (r->interface_url) + { + string u (*r->interface_url + ename); + s << A(HREF=u) << dname << ~A; + + if (dcon) + s << ' ' + << A(HREF=u + "/" + p->version.string ()) << *dcon << ~A; + } + else if (p->internal ()) + { + dir_path u (root / dir_path (ename)); + s << A(HREF=u) << dname << ~A; + + 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; } else - // Display the dependency as a plain text if no repository URL - // available. - // s << d; } diff --git a/mod/page.cxx b/mod/page.cxx index 3a6e989..46b5e71 100644 --- a/mod/page.cxx +++ b/mod/page.cxx @@ -401,7 +401,7 @@ namespace brep // set<package_name> names; for (const auto& da: d) - names.emplace (da.name ()); + names.emplace (da.name); bool mult (names.size () > 1); @@ -411,7 +411,7 @@ namespace brep bool first (true); for (const auto& da: d) { - package_name n (da.name ()); + const package_name& n (da.name); if (names.find (n) != names.end ()) { names.erase (n); @@ -421,24 +421,32 @@ namespace brep else s << " | "; - shared_ptr<package> p (da.package.load ()); - assert (p->internal () || !p->other_repositories.empty ()); - - shared_ptr<repository> r ( - p->internal () - ? p->internal_repository.load () - : p->other_repositories[0].load ()); - - auto en (mime_url_encode (n.string (), false)); - - if (r->url) - s << A(HREF=*r->url + en) << n << ~A; - else if (p->internal ()) - s << A(HREF=root_ / path (en)) << n << ~A; + // Try to display the dependency as a link if it is resolved. + // Otherwise display it as plain text. + // + if (da.package != nullptr) + { + shared_ptr<package> p (da.package.load ()); + assert (p->internal () || !p->other_repositories.empty ()); + + shared_ptr<repository> r ( + p->internal () + ? p->internal_repository.load () + : p->other_repositories[0].load ()); + + auto en (mime_url_encode (n.string (), false)); + + if (r->interface_url) + s << A(HREF=*r->interface_url + en) << n << ~A; + else if (p->internal ()) + s << A(HREF=root_ / path (en)) << n << ~A; + else + // Display the dependency as plain text if no repository URL + // available. + // + s << n; + } else - // Display the dependency as a plain text if no repository URL - // available. - // s << n; } } diff --git a/tests/load/driver.cxx b/tests/load/driver.cxx index 8e7c86e..b387b9b 100644 --- a/tests/load/driver.cxx +++ b/tests/load/driver.cxx @@ -60,29 +60,53 @@ namespace bpkg } } +static void +test_pkg_repos (const cstrings& loader_args, + const dir_path& loadtab_dir, + odb::pgsql::database&); + +static void +test_git_repos (const cstrings& loader_args, + const dir_path& loadtab_dir, + odb::pgsql::database&); + int main (int argc, char* argv[]) { auto print_usage = [argv]() { - cerr << "usage: " << argv[0] - << " <loader_path> [loader_options] <loadtab_file>" << endl; + cerr << "usage: " << argv[0] << " (pkg|git) " + << "<loader-path> [loader-options] <loadtab-dir>" << endl; }; - if (argc < 3) + if (argc < 4) { print_usage (); return 1; } + int i (1); + repository_type rt; + + try + { + rt = to_repository_type (argv[i++]); + } + catch (const invalid_argument&) + { + print_usage (); + return 1; + } + + // Parse the database options. + // string user; string password; string name ("brep_package"); string host; unsigned int port (0); - int i (2); - for (; i < argc - 1; ++i) + for (++i; i < argc - 1; ++i) { string n (argv[i]); if (n == "--db-user" || n == "-u") @@ -103,32 +127,24 @@ main (int argc, char* argv[]) return 1; } - try - { - path cp (argv[argc - 1]); + dir_path loadtab_dir (argv[i]); - // Make configuration file path absolute to use it's directory as base for - // internal repositories relative local paths. - // - if (cp.relative ()) - cp.complete (); - - // Update the packages.manifest file timestamp to enforce the loader to - // update the persistent state. - // - path p (cp.directory () / dir_path ("1/stable") / packages); - char const* args[] = {"touch", p.string ().c_str (), nullptr}; - assert (process (args).wait ()); - - timestamp srt (file_mtime (p)); + // Make configuration file directory absolute to use it as base for internal + // repositories relative local paths. + // + if (loadtab_dir.relative ()) + loadtab_dir.complete (); - // Run the loader. - // - char const** ld_args (const_cast<char const**> (argv + 1)); - assert (process (ld_args).wait ()); + // Extract the loader args that are common for all tests (database options, + // etc). Note that they don't contain the loadtab path and the trailing + // NULL. + // + cstrings loader_args; + for (int i (2); i != argc - 1; ++i) + loader_args.push_back (argv[i]); - // Check persistent objects validity. - // + try + { odb::pgsql::database db ( user, password, @@ -137,773 +153,868 @@ main (int argc, char* argv[]) port, "options='-c default_transaction_isolation=serializable'"); + switch (rt) { - session s; - transaction t (db.begin ()); - - assert (db.query<repository> ().size () == 7); - assert (db.query<package> ().size () == 18); - - shared_ptr<repository> sr ( - db.load<repository> ("pkg:dev.cppget.org/stable")); - - shared_ptr<repository> mr ( - db.load<repository> ("pkg:dev.cppget.org/math")); - - shared_ptr<repository> cr ( - db.load<repository> ("pkg:dev.cppget.org/misc")); - - shared_ptr<repository> tr ( - db.load<repository> ("pkg:dev.cppget.org/testing")); - - shared_ptr<repository> gr ( - db.load<repository> ("pkg:dev.cppget.org/staging")); - - // Verify 'stable' repository. - // - assert (sr->location.canonical_name () == "pkg:dev.cppget.org/stable"); - assert (sr->location.string () == - "http://dev.cppget.org/1/stable"); - assert (sr->display_name == "stable"); - assert (sr->priority == 1); - assert (!sr->url); - assert (sr->email && *sr->email == "repoman@dev.cppget.org" && - sr->email->comment == "public mailing list"); - assert (sr->summary && - *sr->summary == "General C++ package stable repository"); - assert (sr->description && *sr->description == - "This is the awesome C++ package repository full of exciting " - "stuff."); - - dir_path srp (cp.directory () / dir_path ("1/stable")); - assert (sr->cache_location.path () == srp.normalize ()); - - assert (sr->packages_timestamp == srt); - assert (sr->repositories_timestamp == - file_mtime (sr->cache_location.path () / repositories)); - - assert (sr->internal); - 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. - // - // libfoo-+0-X.Y - // - shared_ptr<package> fpvxy ( - db.load<package> ( - package_id (package_name ("libfoo"), version ("+0-X.Y")))); - - assert (fpvxy->project == package_name ("libfoo")); - assert (fpvxy->summary == "The Foo Library"); - assert (fpvxy->tags.empty ()); - assert (!fpvxy->description); - assert (!fpvxy->url); - assert (!fpvxy->package_url); - assert (!fpvxy->email); - assert (!fpvxy->package_email); - - assert (fpvxy->internal_repository.load () == mr); - assert (fpvxy->other_repositories.empty ()); - - assert (fpvxy->priority == priority::low); - assert (fpvxy->changes.empty ()); - - assert (fpvxy->license_alternatives.size () == 1); - assert (fpvxy->license_alternatives[0].size () == 1); - assert (fpvxy->license_alternatives[0][0] == "MIT"); - - assert (fpvxy->dependencies.empty ()); - assert (fpvxy->requirements.empty ()); - - assert (check_location (fpvxy)); - - assert (fpvxy->sha256sum && *fpvxy->sha256sum == - "c994fd49f051ab7fb25f3a4e68ca878e484c5d3c2cb132b37d41224b0621b618"); - - // libfoo-1.0 - // - shared_ptr<package> fpv1 ( - db.load<package> ( - package_id (package_name ("libfoo"), version ("1.0")))); - - assert (fpv1->summary == "The Foo Library"); - assert (fpv1->tags.empty ()); - assert (!fpv1->description); - assert (!fpv1->url); - assert (!fpv1->package_url); - assert (!fpv1->email); - assert (!fpv1->package_email); - - assert (fpv1->internal_repository.load () == sr); - 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 ()); - - assert (fpv1->license_alternatives.size () == 1); - assert (fpv1->license_alternatives[0].size () == 1); - assert (fpv1->license_alternatives[0][0] == "MIT"); - - assert (fpv1->dependencies.empty ()); - assert (fpv1->requirements.empty ()); - - assert (check_location (fpv1)); - - assert (fpv1->sha256sum && *fpv1->sha256sum == - "0df6d45a3514c6101609bdcfefe7659b5754e505c6cf6b4107141d8217bb981d"); - - // libfoo-1.2.2 - // - shared_ptr<package> fpv2 ( - db.load<package> ( - package_id (package_name ("libfoo"), version ("1.2.2")))); - - assert (fpv2->summary == "The Foo library"); - assert (fpv2->tags == strings ({"c++", "foo"})); - assert (!fpv2->description); - assert (fpv2->url && *fpv2->url == "http://www.example.com/foo/"); - assert (!fpv2->package_url); - assert (fpv2->email && *fpv2->email == "foo-users@example.com"); - assert (!fpv2->package_email); - - assert (fpv2->internal_repository.load () == sr); - assert (fpv2->other_repositories.empty ()); - assert (fpv2->priority == priority::low); - assert (fpv2->changes.empty ()); - - assert (fpv2->license_alternatives.size () == 1); - assert (fpv2->license_alternatives[0].size () == 1); - assert (fpv2->license_alternatives[0][0] == "MIT"); - - assert (fpv2->dependencies.size () == 2); - assert (fpv2->dependencies[0].size () == 1); - assert (fpv2->dependencies[1].size () == 1); - - auto dep = [&db] ( - const char* n, const optional<dependency_constraint>& c) -> dependency + case repository_type::pkg: + { + test_pkg_repos (loader_args, loadtab_dir, db); + break; + } + case repository_type::git: { - return {lazy_shared_ptr<package> ( - db, package_id (package_name (n), version ())), c}; - }; - - assert (fpv2->dependencies[0][0] == - dep ( - "libbar", - optional<dependency_constraint> ( - dependency_constraint ( - nullopt, true, version ("2.4.0"), false)))); - - assert (fpv2->dependencies[1][0] == - dep ( - "libexp", - optional<dependency_constraint> ( - dependency_constraint ( - version ("+2-1.2"), false, version ("+2-1.2"), false)))); - - assert (check_location (fpv2)); - - assert (fpv2->sha256sum && *fpv2->sha256sum == - "088068ea3d69542a153f829cf836013374763148fba0a43d8047974f58b5efd7"); - - // libfoo-1.2.2-alpha.1 - // - shared_ptr<package> fpv2a ( - db.load<package> ( - package_id (package_name ("libfoo"), version ("1.2.2-alpha.1")))); - - assert (fpv2a->summary == "The Foo library"); - assert (fpv2a->tags == strings ({"c++", "foo"})); - assert (!fpv2a->description); - assert (fpv2a->url && *fpv2a->url == "http://www.example.com/foo/"); - assert (!fpv2a->package_url); - assert (fpv2a->email && *fpv2a->email == "foo-users@example.com"); - assert (!fpv2a->package_email); - - assert (fpv2a->internal_repository.load () == sr); - assert (fpv2a->other_repositories.empty ()); - assert (fpv2a->priority == priority::low); - assert (fpv2a->changes.empty ()); - - assert (fpv2a->license_alternatives.size () == 1); - assert (fpv2a->license_alternatives[0].size () == 1); - assert (fpv2a->license_alternatives[0][0] == "MIT"); - - assert (fpv2a->dependencies.size () == 3); - assert (fpv2a->dependencies[0].size () == 2); - assert (fpv2a->dependencies[1].size () == 1); - assert (fpv2a->dependencies[2].size () == 2); - - assert (fpv2a->dependencies[0][0] == - dep ( - "libmisc", - optional<dependency_constraint> ( - dependency_constraint ( - version ("0.1"), false, version ("2.0.0-"), true)))); - - assert (fpv2a->dependencies[0][1] == - dep ( - "libmisc", - optional<dependency_constraint> ( - dependency_constraint ( - version ("2.0"), false, version ("5.0"), false)))); - - assert (fpv2a->dependencies[1][0] == - dep ( - "libgenx", - optional<dependency_constraint> ( - dependency_constraint ( - version ("0.2"), true, version ("3.0"), true)))); - - assert (fpv2a->dependencies[2][0] == - dep ( - "libexpat", - optional<dependency_constraint> ( - dependency_constraint ( - nullopt, true, version ("5.2"), true)))); - - assert (fpv2a->dependencies[2][1] == - dep ( - "libexpat", - optional<dependency_constraint> ( - dependency_constraint ( - version ("1"), true, version ("5.1"), false)))); - - assert (fpv2a->requirements.empty ()); - - assert (check_location (fpv2a)); - - assert (fpv2a->sha256sum && *fpv2a->sha256sum == - "34fc224087bfd9212de4acfbbf5275513ebc57678b5f029546918a62c57d15cb"); - - // libfoo-1.2.3-4 - // - shared_ptr<package> fpv3 ( - db.load<package> ( - package_id (package_name ("libfoo"), version ("1.2.3+4")))); - - assert (fpv3->summary == "The Foo library"); - assert (fpv3->tags == strings ({"c++", "foo"})); - assert (!fpv3->description); - assert (fpv3->url && *fpv3->url == "http://www.example.com/foo/"); - assert (!fpv3->package_url); - assert (fpv3->email && *fpv3->email == "foo-users@example.com"); - assert (!fpv3->package_email); - - assert (fpv3->internal_repository.load () == sr); - assert (fpv3->other_repositories.empty ()); - assert (fpv3->priority == priority::low); - - assert (fpv3->changes.empty ()); - - assert (fpv3->license_alternatives.size () == 1); - assert (fpv3->license_alternatives[0].size () == 1); - assert (fpv3->license_alternatives[0][0] == "MIT"); - - assert (fpv3->dependencies.size () == 1); - assert (fpv3->dependencies[0].size () == 1); - assert (fpv3->dependencies[0][0] == - dep ( - "libmisc", - optional<dependency_constraint> ( - dependency_constraint ( - version ("2.0.0"), false, nullopt, true)))); - - assert (check_location (fpv3)); - - assert (fpv3->sha256sum && *fpv3->sha256sum == - "204fb25edf2404e9e88e1bef8b2a444281a807d9087093147a2cc80a1ffba79a"); - - // libfoo-1.2.4 - // - shared_ptr<package> fpv4 ( - db.load<package> ( - package_id (package_name ("libfoo"), version ("1.2.4")))); - - assert (fpv4->summary == "The Foo Library"); - assert (fpv4->tags == strings ({"c++", "foo"})); - assert (*fpv4->description == "Very good foo library."); - assert (fpv4->url && *fpv4->url == "http://www.example.com/foo/"); - assert (!fpv4->package_url); - assert (fpv4->email && *fpv4->email == "foo-users@example.com"); - assert (!fpv4->package_email); - - assert (fpv4->internal_repository.load () == sr); - assert (fpv4->other_repositories.empty ()); - assert (fpv4->priority == priority::low); - assert (fpv4->changes == "some changes 1\n\nsome changes 2"); - - assert (fpv4->license_alternatives.size () == 1); - assert (fpv4->license_alternatives[0].comment == - "Permissive free software license."); - assert (fpv4->license_alternatives[0].size () == 1); - assert (fpv4->license_alternatives[0][0] == "MIT"); - - assert (fpv4->dependencies.size () == 1); - assert (fpv4->dependencies[0].size () == 1); - assert (fpv4->dependencies[0][0] == - dep ( - "libmisc", - optional<dependency_constraint> ( - dependency_constraint ( - version ("2.0.0"), false, nullopt, true)))); - - assert (check_location (fpv4)); - - assert (fpv4->sha256sum && *fpv4->sha256sum == - "aa1606323bfc59b70de642629dc5d8318cc5348e3646f90ed89406d975db1e1d"); - - // Verify 'math' repository. - // - assert (mr->location.canonical_name () == "pkg:dev.cppget.org/math"); - assert (mr->location.string () == - "http://dev.cppget.org/1/math"); - assert (mr->display_name == "math"); - assert (mr->priority == 2); - assert (!mr->url); - assert (mr->email && *mr->email == "repoman@dev.cppget.org"); - assert (mr->summary && *mr->summary == "Math C++ package repository"); - assert (mr->description && *mr->description == - "This is the awesome C++ package repository full of remarkable " - "algorithms and\nAPIs."); - - dir_path mrp (cp.directory () / dir_path ("1/math")); - assert (mr->cache_location.path () == mrp.normalize ()); - - assert (mr->packages_timestamp == - file_mtime (mr->cache_location.path () / packages)); - - assert (mr->repositories_timestamp == - file_mtime (mr->cache_location.path () / repositories)); - - assert (mr->internal); - - assert (mr->complements.empty ()); - assert (mr->prerequisites.size () == 1); - assert (mr->prerequisites[0].load () == cr); - - // Verify libstudxml package version. - // - shared_ptr<package> xpv ( - db.load<package> ( - package_id (package_name ("libstudxml"), version ("1.0.0+1")))); - - assert (xpv->summary == "Modern C++ XML API"); - assert (xpv->tags == strings ({"c++", "xml", "parser", "serializer", - "pull", "streaming", "modern"})); - assert (!xpv->description); - assert (xpv->url && - *xpv->url == "http://www.codesynthesis.com/projects/libstudxml/"); - assert (!xpv->package_url); - assert (xpv->email && *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 ( - version ("2.0.0"), false, nullopt, true)))); - - assert (xpv->dependencies[1].size () == 1); - assert (xpv->dependencies[1][0] == dep ("libgenx", nullopt)); - - assert (xpv->requirements.empty ()); - - assert (check_location (xpv)); - - assert (xpv->sha256sum && *xpv->sha256sum == - "cfa4b1f89f8e903d48eff1e1d14628c32aa4d126d09b0b056d2cd80f8dc78580"); - - // Verify libfoo package versions. - // - // libfoo-1.2.4-1 - // - shared_ptr<package> fpv5 ( - db.load<package> ( - package_id (package_name ("libfoo"), version ("1.2.4+1")))); - - assert (fpv5->summary == "The Foo Math Library"); - assert (fpv5->tags == strings ({"c++", "foo", "math"})); - assert (*fpv5->description == - "A modern C++ library with easy to use linear algebra and lot " - "of optimization\ntools.\n\nThere are over 100 functions in " - "total with an extensive test suite. The API is\nsimilar to " - "MATLAB.\n\nUseful for conversion of research code into " - "production environments."); - - assert (fpv5->url && *fpv5->url == "http://www.example.com/foo/"); - - assert (fpv5->doc_url && *fpv5->doc_url == - "http://www.example.org/projects/libfoo/man.xhtml" && - fpv5->doc_url->comment == "Documentation page."); - - assert (fpv5->src_url && *fpv5->src_url == - "http://scm.example.com/?p=odb/libodb.git;a=tree" && - fpv5->src_url->comment == "Source tree url."); - - assert (fpv5->package_url && - *fpv5->package_url == "http://www.example.com/foo/pack"); - assert (fpv5->email && *fpv5->email == "foo-users@example.com"); - assert (fpv5->package_email && - *fpv5->package_email == "pack@example.com"); - - assert (fpv5->internal_repository.load () == mr); - assert (fpv5->other_repositories.size () == 1); - assert (fpv5->other_repositories[0].load () == cr); - - assert (fpv5->priority == priority::high); - assert (fpv5->priority.comment == - "Critical bug fixes, performance improvement."); - - const char ch[] = R"DLM(1.2.4+1 + test_git_repos (loader_args, loadtab_dir, db); + break; + } + default: + { + print_usage (); + return 1; + } + } + } + // Fully qualified to avoid ambiguity with odb exception. + // + catch (const std::exception& e) + { + cerr << e << endl; + return 1; + } + + return 0; +} + +static inline dependency +dep (const char* n, optional<dependency_constraint> c) +{ + return dependency {package_name (n), move (c), nullptr}; +} + +static void +test_git_repos (const cstrings& loader_args, + const dir_path& loadtab_dir, + odb::pgsql::database& db) +{ + path loadtab (loadtab_dir / "git-loadtab"); + + cstrings args (loader_args); + args.push_back ("--force"); + args.push_back ("--shallow"); + args.push_back (loadtab.string ().c_str ()); + args.push_back (nullptr); + + { + // Run the loader. + // + assert (process (args.data ()).wait ()); + + // Check persistent objects. + // + session s; + transaction t (db.begin ()); + + assert (db.query<repository> ().size () == 1); + assert (db.query<package> ().size () == 1); + + // Verify 'foo' repository. + // + shared_ptr<repository> r ( + db.load<repository> ("git:example.com/foo#master")); + + assert (r->location.string () == "https://git.example.com/foo.git#master"); + assert (r->summary && *r->summary == "foo project repository"); + + // Verify libfoo package version. + // + // libfoo-1.0 + // + shared_ptr<package> p ( + db.load<package> ( + package_id (package_name ("libfoo"), version ("1.0")))); + + assert (p->fragment && + *p->fragment == "0f50af28d1cfb0c22f5b88e2bf674ab732e058d9"); + + assert (p->dependencies.size () == 1); + assert (p->dependencies[0].size () == 1); + + assert (p->dependencies[0][0] == + dep ("libmisc", + dependency_constraint ( + version ("1.0"), false, version ("1.0"), false))); + + t.commit (); + } +} + +static void +test_pkg_repos (const cstrings& loader_args, + const dir_path& loadtab_dir, + odb::pgsql::database& db) +{ + path p (loadtab_dir / dir_path ("1/stable") / packages); + timestamp srt (file_mtime (p)); + + path loadtab (loadtab_dir / "loadtab"); + + // Load the repositories and check persistent objects validity. + // + { + cstrings args (loader_args); + args.push_back ("--force"); + args.push_back (loadtab.string ().c_str ()); + args.push_back (nullptr); + + // Run the loader. + // + assert (process (args.data ()).wait ()); + + // Check persistent objects. + // + session s; + transaction t (db.begin ()); + + assert (db.query<repository> ().size () == 7); + assert (db.query<package> ().size () == 18); + + shared_ptr<repository> sr ( + db.load<repository> ("pkg:dev.cppget.org/stable")); + + shared_ptr<repository> mr ( + db.load<repository> ("pkg:dev.cppget.org/math")); + + shared_ptr<repository> cr ( + db.load<repository> ("pkg:dev.cppget.org/misc")); + + shared_ptr<repository> tr ( + db.load<repository> ("pkg:dev.cppget.org/testing")); + + shared_ptr<repository> gr ( + db.load<repository> ("pkg:dev.cppget.org/staging")); + + // Verify 'stable' repository. + // + assert (sr->location.canonical_name () == "pkg:dev.cppget.org/stable"); + assert (sr->location.string () == + "http://dev.cppget.org/1/stable"); + assert (sr->display_name == "stable"); + assert (sr->priority == 1); + assert (!sr->interface_url); + assert (sr->email && *sr->email == "repoman@dev.cppget.org" && + sr->email->comment == "public mailing list"); + assert (sr->summary && + *sr->summary == "General C++ package stable repository"); + assert (sr->description && *sr->description == + "This is the awesome C++ package repository full of exciting " + "stuff."); + + dir_path srp (loadtab.directory () / dir_path ("1/stable")); + assert (sr->cache_location.path () == srp.normalize ()); + + assert (sr->packages_timestamp == srt); + assert (sr->repositories_timestamp == + file_mtime (sr->cache_location.path () / repositories)); + + assert (sr->internal); + 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. + // + // libfoo-+0-X.Y + // + shared_ptr<package> fpvxy ( + db.load<package> ( + package_id (package_name ("libfoo"), version ("+0-X.Y")))); + + assert (fpvxy->project == package_name ("libfoo")); + assert (fpvxy->summary == "The Foo Library"); + assert (fpvxy->tags.empty ()); + assert (!fpvxy->description); + assert (!fpvxy->url); + assert (!fpvxy->package_url); + assert (!fpvxy->email); + assert (!fpvxy->package_email); + + assert (fpvxy->internal_repository.load () == mr); + assert (fpvxy->other_repositories.empty ()); + + assert (fpvxy->priority == priority::low); + assert (fpvxy->changes.empty ()); + + assert (fpvxy->license_alternatives.size () == 1); + assert (fpvxy->license_alternatives[0].size () == 1); + assert (fpvxy->license_alternatives[0][0] == "MIT"); + + assert (fpvxy->dependencies.empty ()); + assert (fpvxy->requirements.empty ()); + + assert (check_location (fpvxy)); + + assert (fpvxy->sha256sum && *fpvxy->sha256sum == + "c994fd49f051ab7fb25f3a4e68ca878e484c5d3c2cb132b37d41224b0621b618"); + + // libfoo-1.0 + // + shared_ptr<package> fpv1 ( + db.load<package> ( + package_id (package_name ("libfoo"), version ("1.0")))); + + assert (fpv1->summary == "The Foo Library"); + assert (fpv1->tags.empty ()); + assert (!fpv1->description); + assert (!fpv1->url); + assert (!fpv1->package_url); + assert (!fpv1->email); + assert (!fpv1->package_email); + + assert (fpv1->internal_repository.load () == sr); + 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 ()); + + assert (fpv1->license_alternatives.size () == 1); + assert (fpv1->license_alternatives[0].size () == 1); + assert (fpv1->license_alternatives[0][0] == "MIT"); + + assert (fpv1->dependencies.empty ()); + assert (fpv1->requirements.empty ()); + + assert (check_location (fpv1)); + + assert (fpv1->sha256sum && *fpv1->sha256sum == + "0df6d45a3514c6101609bdcfefe7659b5754e505c6cf6b4107141d8217bb981d"); + + // libfoo-1.2.2 + // + shared_ptr<package> fpv2 ( + db.load<package> ( + package_id (package_name ("libfoo"), version ("1.2.2")))); + + assert (fpv2->summary == "The Foo library"); + assert (fpv2->tags == strings ({"c++", "foo"})); + assert (!fpv2->description); + assert (fpv2->url && *fpv2->url == "http://www.example.com/foo/"); + assert (!fpv2->package_url); + assert (fpv2->email && *fpv2->email == "foo-users@example.com"); + assert (!fpv2->package_email); + + assert (fpv2->internal_repository.load () == sr); + assert (fpv2->other_repositories.empty ()); + assert (fpv2->priority == priority::low); + assert (fpv2->changes.empty ()); + + assert (fpv2->license_alternatives.size () == 1); + assert (fpv2->license_alternatives[0].size () == 1); + assert (fpv2->license_alternatives[0][0] == "MIT"); + + assert (fpv2->dependencies.size () == 2); + assert (fpv2->dependencies[0].size () == 1); + assert (fpv2->dependencies[1].size () == 1); + + assert (fpv2->dependencies[0][0] == + dep ("libbar", + dependency_constraint ( + nullopt, true, version ("2.4.0"), false))); + + assert (fpv2->dependencies[1][0] == + dep ("libexp", + dependency_constraint ( + version ("+2-1.2"), false, version ("+2-1.2"), false))); + + assert (check_location (fpv2)); + + assert (fpv2->sha256sum && *fpv2->sha256sum == + "088068ea3d69542a153f829cf836013374763148fba0a43d8047974f58b5efd7"); + + // libfoo-1.2.2-alpha.1 + // + shared_ptr<package> fpv2a ( + db.load<package> ( + package_id (package_name ("libfoo"), version ("1.2.2-alpha.1")))); + + assert (fpv2a->summary == "The Foo library"); + assert (fpv2a->tags == strings ({"c++", "foo"})); + assert (!fpv2a->description); + assert (fpv2a->url && *fpv2a->url == "http://www.example.com/foo/"); + assert (!fpv2a->package_url); + assert (fpv2a->email && *fpv2a->email == "foo-users@example.com"); + assert (!fpv2a->package_email); + + assert (fpv2a->internal_repository.load () == sr); + assert (fpv2a->other_repositories.empty ()); + assert (fpv2a->priority == priority::low); + assert (fpv2a->changes.empty ()); + + assert (fpv2a->license_alternatives.size () == 1); + assert (fpv2a->license_alternatives[0].size () == 1); + assert (fpv2a->license_alternatives[0][0] == "MIT"); + + assert (fpv2a->dependencies.size () == 3); + assert (fpv2a->dependencies[0].size () == 2); + assert (fpv2a->dependencies[1].size () == 1); + assert (fpv2a->dependencies[2].size () == 2); + + assert (fpv2a->dependencies[0][0] == + dep ("libmisc", + dependency_constraint ( + version ("0.1"), false, version ("2.0.0-"), true))); + + assert (fpv2a->dependencies[0][1] == + dep ("libmisc", + dependency_constraint ( + version ("2.0"), false, version ("5.0"), false))); + + assert (fpv2a->dependencies[1][0] == + dep ("libgenx", + dependency_constraint ( + version ("0.2"), true, version ("3.0"), true))); + + assert (fpv2a->dependencies[2][0] == + dep ("libexpat", + dependency_constraint ( + nullopt, true, version ("5.2"), true))); + + assert (fpv2a->dependencies[2][1] == + dep ("libexpat", + dependency_constraint ( + version ("1"), true, version ("5.1"), false))); + + assert (fpv2a->requirements.empty ()); + + assert (check_location (fpv2a)); + + assert (fpv2a->sha256sum && *fpv2a->sha256sum == + "34fc224087bfd9212de4acfbbf5275513ebc57678b5f029546918a62c57d15cb"); + + // libfoo-1.2.3-4 + // + shared_ptr<package> fpv3 ( + db.load<package> ( + package_id (package_name ("libfoo"), version ("1.2.3+4")))); + + assert (fpv3->summary == "The Foo library"); + assert (fpv3->tags == strings ({"c++", "foo"})); + assert (!fpv3->description); + assert (fpv3->url && *fpv3->url == "http://www.example.com/foo/"); + assert (!fpv3->package_url); + assert (fpv3->email && *fpv3->email == "foo-users@example.com"); + assert (!fpv3->package_email); + + assert (fpv3->internal_repository.load () == sr); + assert (fpv3->other_repositories.empty ()); + assert (fpv3->priority == priority::low); + + assert (fpv3->changes.empty ()); + + assert (fpv3->license_alternatives.size () == 1); + assert (fpv3->license_alternatives[0].size () == 1); + assert (fpv3->license_alternatives[0][0] == "MIT"); + + assert (fpv3->dependencies.size () == 1); + assert (fpv3->dependencies[0].size () == 1); + assert (fpv3->dependencies[0][0] == + dep ("libmisc", + dependency_constraint ( + version ("2.0.0"), false, nullopt, true))); + + assert (check_location (fpv3)); + + assert (fpv3->sha256sum && *fpv3->sha256sum == + "204fb25edf2404e9e88e1bef8b2a444281a807d9087093147a2cc80a1ffba79a"); + + // libfoo-1.2.4 + // + shared_ptr<package> fpv4 ( + db.load<package> ( + package_id (package_name ("libfoo"), version ("1.2.4")))); + + assert (fpv4->summary == "The Foo Library"); + assert (fpv4->tags == strings ({"c++", "foo"})); + assert (*fpv4->description == "Very good foo library."); + assert (fpv4->url && *fpv4->url == "http://www.example.com/foo/"); + assert (!fpv4->package_url); + assert (fpv4->email && *fpv4->email == "foo-users@example.com"); + assert (!fpv4->package_email); + + assert (fpv4->internal_repository.load () == sr); + assert (fpv4->other_repositories.empty ()); + assert (fpv4->priority == priority::low); + assert (fpv4->changes == "some changes 1\n\nsome changes 2"); + + assert (fpv4->license_alternatives.size () == 1); + assert (fpv4->license_alternatives[0].comment == + "Permissive free software license."); + assert (fpv4->license_alternatives[0].size () == 1); + assert (fpv4->license_alternatives[0][0] == "MIT"); + + assert (fpv4->dependencies.size () == 1); + assert (fpv4->dependencies[0].size () == 1); + assert (fpv4->dependencies[0][0] == + dep ("libmisc", + dependency_constraint ( + version ("2.0.0"), false, nullopt, true))); + + assert (check_location (fpv4)); + + assert (fpv4->sha256sum && *fpv4->sha256sum == + "aa1606323bfc59b70de642629dc5d8318cc5348e3646f90ed89406d975db1e1d"); + + // Verify 'math' repository. + // + assert (mr->location.canonical_name () == "pkg:dev.cppget.org/math"); + assert (mr->location.string () == + "http://dev.cppget.org/1/math"); + assert (mr->display_name == "math"); + assert (mr->priority == 2); + assert (!mr->interface_url); + assert (mr->email && *mr->email == "repoman@dev.cppget.org"); + assert (mr->summary && *mr->summary == "Math C++ package repository"); + assert (mr->description && *mr->description == + "This is the awesome C++ package repository full of remarkable " + "algorithms and\nAPIs."); + + dir_path mrp (loadtab.directory () / dir_path ("1/math")); + assert (mr->cache_location.path () == mrp.normalize ()); + + assert (mr->packages_timestamp == + file_mtime (mr->cache_location.path () / packages)); + + assert (mr->repositories_timestamp == + file_mtime (mr->cache_location.path () / repositories)); + + assert (mr->internal); + + assert (mr->complements.empty ()); + assert (mr->prerequisites.size () == 1); + assert (mr->prerequisites[0].load () == cr); + + // Verify libstudxml package version. + // + shared_ptr<package> xpv ( + db.load<package> ( + package_id (package_name ("libstudxml"), version ("1.0.0+1")))); + + assert (xpv->summary == "Modern C++ XML API"); + assert (xpv->tags == strings ({"c++", "xml", "parser", "serializer", + "pull", "streaming", "modern"})); + assert (!xpv->description); + assert (xpv->url && + *xpv->url == "http://www.codesynthesis.com/projects/libstudxml/"); + assert (!xpv->package_url); + assert (xpv->email && *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", + dependency_constraint ( + version ("2.0.0"), false, nullopt, true))); + + assert (xpv->dependencies[1].size () == 1); + assert (xpv->dependencies[1][0] == dep ("libgenx", nullopt)); + + assert (xpv->requirements.empty ()); + + assert (check_location (xpv)); + + assert (xpv->sha256sum && *xpv->sha256sum == + "cfa4b1f89f8e903d48eff1e1d14628c32aa4d126d09b0b056d2cd80f8dc78580"); + + // Verify libfoo package versions. + // + // libfoo-1.2.4-1 + // + shared_ptr<package> fpv5 ( + db.load<package> ( + package_id (package_name ("libfoo"), version ("1.2.4+1")))); + + assert (fpv5->summary == "The Foo Math Library"); + assert (fpv5->tags == strings ({"c++", "foo", "math"})); + assert (*fpv5->description == + "A modern C++ library with easy to use linear algebra and lot " + "of optimization\ntools.\n\nThere are over 100 functions in " + "total with an extensive test suite. The API is\nsimilar to " + "MATLAB.\n\nUseful for conversion of research code into " + "production environments."); + + assert (fpv5->url && *fpv5->url == "http://www.example.com/foo/"); + + assert (fpv5->doc_url && *fpv5->doc_url == + "http://www.example.org/projects/libfoo/man.xhtml" && + fpv5->doc_url->comment == "Documentation page."); + + assert (fpv5->src_url && *fpv5->src_url == + "http://scm.example.com/?p=odb/libodb.git;a=tree" && + fpv5->src_url->comment == "Source tree url."); + + assert (fpv5->package_url && + *fpv5->package_url == "http://www.example.com/foo/pack"); + assert (fpv5->email && *fpv5->email == "foo-users@example.com"); + assert (fpv5->package_email && + *fpv5->package_email == "pack@example.com"); + + assert (fpv5->internal_repository.load () == mr); + assert (fpv5->other_repositories.size () == 1); + assert (fpv5->other_repositories[0].load () == cr); + + assert (fpv5->priority == priority::high); + assert (fpv5->priority.comment == + "Critical bug fixes, performance improvement."); + + const char ch[] = R"DLM(1.2.4+1 * applied patch for critical bug-219 * regenerated documentation 1.2.4 * test suite extended significantly)DLM"; - assert (fpv5->changes == ch); - - assert (fpv5->license_alternatives.size () == 2); - assert (fpv5->license_alternatives[0].comment == - "If using with GNU TLS."); - assert (fpv5->license_alternatives[0].size () == 2); - assert (fpv5->license_alternatives[0][0] == "LGPLv2"); - assert (fpv5->license_alternatives[0][1] == "MIT"); - assert (fpv5->license_alternatives[1].comment == - "If using with OpenSSL."); - assert (fpv5->license_alternatives[1].size () == 1); - assert (fpv5->license_alternatives[1][0] == "BSD"); - - 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] == - dep ( - "libmisc", - optional<dependency_constraint> ( - dependency_constraint ( - nullopt, true, version ("1.1"), true)))); - - assert (fpv5->dependencies[0][1] == - dep ( - "libmisc", - optional<dependency_constraint> ( - dependency_constraint ( - version ("2.3.0"), true, nullopt, true)))); - - assert (fpv5->dependencies[1].size () == 1); - assert (fpv5->dependencies[1].comment.empty ()); - - assert (fpv5->dependencies[1][0] == - dep ("libexp", - optional<dependency_constraint> ( - dependency_constraint ( - version ("1.0"), false, nullopt, true)))); - - 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); - - assert (fpvr5[0] == strings ({"linux", "windows", "macosx"})); - assert (!fpvr5[0].conditional); - assert (fpvr5[0].comment == "Symbian support is coming."); - - assert (fpvr5[1] == strings ({"c++11"})); - assert (!fpvr5[1].conditional); - assert (fpvr5[1].comment.empty ()); - - assert (fpvr5[2].empty ()); - assert (fpvr5[2].conditional); - assert (fpvr5[2].comment == - "libc++ standard library if using Clang on Mac OS X."); - - assert (fpvr5[3] == strings ({"vc++ >= 12.0"})); - assert (fpvr5[3].conditional); - assert (fpvr5[3].comment == "Only if using VC++ on Windows."); - - assert (check_location (fpv5)); - - assert (fpv5->sha256sum && *fpv5->sha256sum == - "c5e593d8efdc34a258f8c0b8cc352dc7193ea4a1d666bcf8d48708c7dd82d0d6"); - - // Verify libexp package version. - // - // libexp-+2-1.2 - // - shared_ptr<package> epv ( - db.load<package> ( - package_id (package_name ("libexp"), version ("+2-1.2+1")))); - - assert (epv->project == "mathLab"); - assert (epv->summary == "The exponent"); - assert (epv->tags == strings ({"mathlab", "c++", "exponent"})); - assert (epv->description && *epv->description == - "The exponent math function."); - assert (epv->url && *epv->url == "http://www.exp.com"); - assert (!epv->package_url); - assert (epv->email && *epv->email == email ("users@exp.com")); - assert (!epv->package_email); - assert (epv->build_email && *epv->build_email == "builds@exp.com"); - - assert (epv->internal_repository.load () == mr); - assert (epv->other_repositories.empty ()); - assert (epv->priority == priority (priority::low)); - assert (epv->changes.empty ()); - - assert (epv->license_alternatives.size () == 1); - assert (epv->license_alternatives[0].size () == 1); - assert (epv->license_alternatives[0][0] == "MIT"); - - assert (epv->dependencies.size () == 2); - assert (epv->dependencies[0].size () == 1); - assert (epv->dependencies[0][0] == dep ("libmisc", nullopt)); - - assert (epv->dependencies[1].size () == 1); - assert (epv->dependencies[1][0] == - dep ("libpq", - optional<dependency_constraint> ( - dependency_constraint ( - version ("9.0.0"), false, nullopt, true)))); - - assert (epv->requirements.empty ()); - - db.load (*epv, epv->build_section); - - assert ( - epv->build_constraints == - build_constraints ({ + assert (fpv5->changes == ch); + + assert (fpv5->license_alternatives.size () == 2); + assert (fpv5->license_alternatives[0].comment == + "If using with GNU TLS."); + assert (fpv5->license_alternatives[0].size () == 2); + assert (fpv5->license_alternatives[0][0] == "LGPLv2"); + assert (fpv5->license_alternatives[0][1] == "MIT"); + assert (fpv5->license_alternatives[1].comment == + "If using with OpenSSL."); + assert (fpv5->license_alternatives[1].size () == 1); + assert (fpv5->license_alternatives[1][0] == "BSD"); + + 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] == + dep ("libmisc", + dependency_constraint ( + nullopt, true, version ("1.1"), true))); + + assert (fpv5->dependencies[0][1] == + dep ("libmisc", + dependency_constraint ( + version ("2.3.0"), true, nullopt, true))); + + assert (fpv5->dependencies[1].size () == 1); + assert (fpv5->dependencies[1].comment.empty ()); + + assert (fpv5->dependencies[1][0] == + dep ("libexp", + dependency_constraint ( + version ("1.0"), false, nullopt, true))); + + 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); + + assert (fpvr5[0] == strings ({"linux", "windows", "macosx"})); + assert (!fpvr5[0].conditional); + assert (fpvr5[0].comment == "Symbian support is coming."); + + assert (fpvr5[1] == strings ({"c++11"})); + assert (!fpvr5[1].conditional); + assert (fpvr5[1].comment.empty ()); + + assert (fpvr5[2].empty ()); + assert (fpvr5[2].conditional); + assert (fpvr5[2].comment == + "libc++ standard library if using Clang on Mac OS X."); + + assert (fpvr5[3] == strings ({"vc++ >= 12.0"})); + assert (fpvr5[3].conditional); + assert (fpvr5[3].comment == "Only if using VC++ on Windows."); + + assert (check_location (fpv5)); + + assert (fpv5->sha256sum && *fpv5->sha256sum == + "c5e593d8efdc34a258f8c0b8cc352dc7193ea4a1d666bcf8d48708c7dd82d0d6"); + + // Verify libexp package version. + // + // libexp-+2-1.2 + // + shared_ptr<package> epv ( + db.load<package> ( + package_id (package_name ("libexp"), version ("+2-1.2+1")))); + + assert (epv->project == "mathLab"); + assert (epv->summary == "The exponent"); + assert (epv->tags == strings ({"mathlab", "c++", "exponent"})); + assert (epv->description && *epv->description == + "The exponent math function."); + assert (epv->url && *epv->url == "http://www.exp.com"); + assert (!epv->package_url); + assert (epv->email && *epv->email == email ("users@exp.com")); + assert (!epv->package_email); + assert (epv->build_email && *epv->build_email == "builds@exp.com"); + + assert (epv->internal_repository.load () == mr); + assert (epv->other_repositories.empty ()); + assert (epv->priority == priority (priority::low)); + assert (epv->changes.empty ()); + + assert (epv->license_alternatives.size () == 1); + assert (epv->license_alternatives[0].size () == 1); + assert (epv->license_alternatives[0][0] == "MIT"); + + assert (epv->dependencies.size () == 2); + assert (epv->dependencies[0].size () == 1); + assert (epv->dependencies[0][0] == dep ("libmisc", nullopt)); + + assert (epv->dependencies[1].size () == 1); + assert (epv->dependencies[1][0] == + dep ("libpq", + dependency_constraint ( + version ("9.0.0"), false, nullopt, true))); + + assert (epv->requirements.empty ()); + + db.load (*epv, epv->build_section); + + assert ( + epv->build_constraints == + build_constraints ({ build_constraint (true, "*", nullopt, "Only supported on Linux."), - build_constraint (false, "linux*", nullopt, "")})); - - assert (check_location (epv)); - assert (epv->sha256sum && *epv->sha256sum == - "bc68940a1b3b7e345cbceac35d308b4e04b304f49ff2087340949f2879709967"); - - // Verify libpq package version. - // - // libpq-0 - // - shared_ptr<package> qpv ( - db.load<package> (package_id (package_name ("libpq"), version ("0")))); - - assert (qpv->summary == "PostgreSQL C API client library"); - - // Verify 'misc' repository. - // - assert (cr->location.canonical_name () == "pkg:dev.cppget.org/misc"); - assert (cr->location.string () == - "http://dev.cppget.org/1/misc"); - assert (cr->display_name.empty ()); - assert (cr->priority == 0); - assert (cr->url && *cr->url == "http://misc.cppget.org/"); - assert (!cr->email); - assert (!cr->summary); - assert (!cr->description); - - dir_path crp (cp.directory () / dir_path ("1/misc")); - assert (cr->cache_location.path () == crp.normalize ()); - - assert (cr->packages_timestamp == - file_mtime (cr->cache_location.path () / packages)); - - assert (cr->repositories_timestamp == - file_mtime (cr->cache_location.path () / repositories)); - - assert (!cr->internal); - assert (cr->prerequisites.empty ()); - assert (cr->complements.size () == 1); - assert (cr->complements[0].load () == tr); - - // Verify libbar package version. - // - // libbar-2.4.0+3 - // - shared_ptr<package> bpv ( - db.load<package> ( - package_id (package_name ("libbar"), version ("2.4.0+3")))); - - assert (check_external (*bpv)); - assert (bpv->other_repositories.size () == 1); - assert (bpv->other_repositories[0].load () == cr); - assert (check_location (bpv)); - - // Verify libfoo package versions. - // - // libfoo-0.1 - // - shared_ptr<package> fpv0 ( - db.load<package> ( - package_id (package_name ("libfoo"), version ("0.1")))); - - assert (check_external (*fpv0)); - assert (fpv0->other_repositories.size () == 1); - assert (fpv0->other_repositories[0].load () == cr); - assert (check_location (fpv0)); - - // libfoo-1.2.4-2 - // - shared_ptr<package> fpv6 ( - db.load<package> ( - package_id (package_name ("libfoo"), version ("1.2.4+2")))); - - assert (check_external (*fpv6)); - assert (fpv6->other_repositories.size () == 1); - assert (fpv6->other_repositories[0].load () == cr); - assert (check_location (fpv6)); - - // Verify 'testing' repository. - // - assert (tr->location.canonical_name () == "pkg:dev.cppget.org/testing"); - assert (tr->location.string () == - "http://dev.cppget.org/1/testing"); - assert (tr->display_name.empty ()); - assert (tr->priority == 0); - assert (tr->url && *tr->url == "http://test.cppget.org/hello/"); - assert (!tr->email); - assert (!tr->summary); - assert (!tr->description); - - dir_path trp (cp.directory () / dir_path ("1/testing")); - assert (tr->cache_location.path () == trp.normalize ()); - - assert (tr->packages_timestamp == - file_mtime (tr->cache_location.path () / packages)); - - assert (tr->repositories_timestamp == - file_mtime (tr->cache_location.path () / repositories)); - - assert (!tr->internal); - assert (tr->prerequisites.empty ()); - assert (tr->complements.size () == 1); - assert (tr->complements[0].load () == gr); - - // Verify libmisc package version. - // - // libmisc-2.4.0 - // - shared_ptr<package> mpv0 ( - db.load<package> ( - package_id (package_name ("libmisc"), version ("2.4.0")))); - - assert (check_external (*mpv0)); - assert (mpv0->other_repositories.size () == 1); - assert (mpv0->other_repositories[0].load () == tr); - assert (check_location (mpv0)); - - // libmisc-2.3.0+1 - // - shared_ptr<package> mpv1 ( - db.load<package> ( - package_id (package_name ("libmisc"), version ("2.3.0+1")))); - - assert (check_external (*mpv1)); - assert (mpv1->other_repositories.size () == 1); - assert (mpv1->other_repositories[0].load () == tr); - assert (check_location (mpv1)); - - // Verify 'staging' repository. - // - assert (gr->location.canonical_name () == "pkg:dev.cppget.org/staging"); - assert (gr->location.string () == - "http://dev.cppget.org/1/staging"); - assert (gr->display_name.empty ()); - assert (gr->priority == 0); - assert (gr->url && *gr->url == "http://dev.cppget.org/"); - assert (!gr->email); - assert (!gr->summary); - assert (!gr->description); - - dir_path grp (cp.directory () / dir_path ("1/staging")); - assert (gr->cache_location.path () == grp.normalize ()); - - assert (gr->packages_timestamp == - file_mtime (gr->cache_location.path () / packages)); - - assert (gr->repositories_timestamp == - file_mtime (gr->cache_location.path () / repositories)); - - assert (!gr->internal); - assert (gr->prerequisites.empty ()); - assert (gr->complements.empty ()); - - // Verify libexpat package version. - // - // libexpat-5.1 - // - shared_ptr<package> tpv ( - db.load<package> ( - package_id (package_name ("libexpat"), version ("5.1")))); - - assert (check_external (*tpv)); - assert (tpv->other_repositories.size () == 1); - assert (tpv->other_repositories[0].load () == gr); - assert (check_location (tpv)); - - // Verify libgenx package version. - // - // libgenx-1.0 - // - shared_ptr<package> gpv ( - db.load<package> ( - package_id (package_name ("libgenx"), version ("1.0")))); - - assert (check_external (*gpv)); - assert (gpv->other_repositories.size () == 1); - assert (gpv->other_repositories[0].load () == gr); - assert (check_location (gpv)); - - // Verify libmisc package version. - // - // libmisc-1.0 - // - shared_ptr<package> mpv2 ( - db.load<package> ( - package_id (package_name ("libmisc"), version ("1.0")))); - - assert (check_external (*mpv2)); - assert (mpv2->other_repositories.size () == 1); - assert (mpv2->other_repositories[0].load () == gr); - assert (check_location (mpv2)); - - // Change package summary, update the object persistent state, rerun - // loader and ensure the model were not rebuilt. - // - bpv->summary = "test"; - db.update (bpv); - - t.commit (); - } + build_constraint (false, "linux*", nullopt, "")})); + + assert (check_location (epv)); + assert (epv->sha256sum && *epv->sha256sum == + "bc68940a1b3b7e345cbceac35d308b4e04b304f49ff2087340949f2879709967"); + + // Verify libpq package version. + // + // libpq-0 + // + shared_ptr<package> qpv ( + db.load<package> (package_id (package_name ("libpq"), version ("0")))); + + assert (qpv->summary == "PostgreSQL C API client library"); + + // Verify 'misc' repository. + // + assert (cr->location.canonical_name () == "pkg:dev.cppget.org/misc"); + assert (cr->location.string () == + "http://dev.cppget.org/1/misc"); + assert (cr->display_name.empty ()); + assert (cr->priority == 0); + assert (cr->interface_url && + *cr->interface_url == "http://misc.cppget.org/"); + assert (!cr->email); + assert (!cr->summary); + assert (!cr->description); + + dir_path crp (loadtab.directory () / dir_path ("1/misc")); + assert (cr->cache_location.path () == crp.normalize ()); + + assert (cr->packages_timestamp == + file_mtime (cr->cache_location.path () / packages)); + + assert (cr->repositories_timestamp == + file_mtime (cr->cache_location.path () / repositories)); + + assert (!cr->internal); + assert (cr->prerequisites.empty ()); + assert (cr->complements.size () == 1); + assert (cr->complements[0].load () == tr); + + // Verify libbar package version. + // + // libbar-2.4.0+3 + // + shared_ptr<package> bpv ( + db.load<package> ( + package_id (package_name ("libbar"), version ("2.4.0+3")))); + + assert (check_external (*bpv)); + assert (bpv->other_repositories.size () == 1); + assert (bpv->other_repositories[0].load () == cr); + assert (check_location (bpv)); + + // Verify libfoo package versions. + // + // libfoo-0.1 + // + shared_ptr<package> fpv0 ( + db.load<package> ( + package_id (package_name ("libfoo"), version ("0.1")))); + + assert (check_external (*fpv0)); + assert (fpv0->other_repositories.size () == 1); + assert (fpv0->other_repositories[0].load () == cr); + assert (check_location (fpv0)); + + // libfoo-1.2.4-2 + // + shared_ptr<package> fpv6 ( + db.load<package> ( + package_id (package_name ("libfoo"), version ("1.2.4+2")))); + + assert (check_external (*fpv6)); + assert (fpv6->other_repositories.size () == 1); + assert (fpv6->other_repositories[0].load () == cr); + assert (check_location (fpv6)); + + // Verify 'testing' repository. + // + assert (tr->location.canonical_name () == "pkg:dev.cppget.org/testing"); + assert (tr->location.string () == + "http://dev.cppget.org/1/testing"); + assert (tr->display_name.empty ()); + assert (tr->priority == 0); + assert (tr->interface_url && + *tr->interface_url == "http://test.cppget.org/hello/"); + assert (!tr->email); + assert (!tr->summary); + assert (!tr->description); + + dir_path trp (loadtab.directory () / dir_path ("1/testing")); + assert (tr->cache_location.path () == trp.normalize ()); + + assert (tr->packages_timestamp == + file_mtime (tr->cache_location.path () / packages)); + + assert (tr->repositories_timestamp == + file_mtime (tr->cache_location.path () / repositories)); + + assert (!tr->internal); + assert (tr->prerequisites.empty ()); + assert (tr->complements.size () == 1); + assert (tr->complements[0].load () == gr); + + // Verify libmisc package version. + // + // libmisc-2.4.0 + // + shared_ptr<package> mpv0 ( + db.load<package> ( + package_id (package_name ("libmisc"), version ("2.4.0")))); + + assert (check_external (*mpv0)); + assert (mpv0->other_repositories.size () == 1); + assert (mpv0->other_repositories[0].load () == tr); + assert (check_location (mpv0)); + + // libmisc-2.3.0+1 + // + shared_ptr<package> mpv1 ( + db.load<package> ( + package_id (package_name ("libmisc"), version ("2.3.0+1")))); + + assert (check_external (*mpv1)); + assert (mpv1->other_repositories.size () == 1); + assert (mpv1->other_repositories[0].load () == tr); + assert (check_location (mpv1)); + + // Verify 'staging' repository. + // + assert (gr->location.canonical_name () == "pkg:dev.cppget.org/staging"); + assert (gr->location.string () == + "http://dev.cppget.org/1/staging"); + assert (gr->display_name.empty ()); + assert (gr->priority == 0); + assert (gr->interface_url && + *gr->interface_url == "http://dev.cppget.org/"); + assert (!gr->email); + assert (!gr->summary); + assert (!gr->description); + + dir_path grp (loadtab.directory () / dir_path ("1/staging")); + assert (gr->cache_location.path () == grp.normalize ()); + + assert (gr->packages_timestamp == + file_mtime (gr->cache_location.path () / packages)); + + assert (gr->repositories_timestamp == + file_mtime (gr->cache_location.path () / repositories)); + + assert (!gr->internal); + assert (gr->prerequisites.empty ()); + assert (gr->complements.empty ()); + + // Verify libexpat package version. + // + // libexpat-5.1 + // + shared_ptr<package> tpv ( + db.load<package> ( + package_id (package_name ("libexpat"), version ("5.1")))); + + assert (check_external (*tpv)); + assert (tpv->other_repositories.size () == 1); + assert (tpv->other_repositories[0].load () == gr); + assert (check_location (tpv)); + + // Verify libgenx package version. + // + // libgenx-1.0 + // + shared_ptr<package> gpv ( + db.load<package> ( + package_id (package_name ("libgenx"), version ("1.0")))); + + assert (check_external (*gpv)); + assert (gpv->other_repositories.size () == 1); + assert (gpv->other_repositories[0].load () == gr); + assert (check_location (gpv)); + + // Verify libmisc package version. + // + // libmisc-1.0 + // + shared_ptr<package> mpv2 ( + db.load<package> ( + package_id (package_name ("libmisc"), version ("1.0")))); + + assert (check_external (*mpv2)); + assert (mpv2->other_repositories.size () == 1); + assert (mpv2->other_repositories[0].load () == gr); + assert (check_location (mpv2)); + + // Change package summary, update the object persistent state, rerun + // the loader and make sure the model were not rebuilt. + // + bpv->summary = "test"; + db.update (bpv); + + t.commit (); + } + + // Rerun the loader without --force and make sure the model were not + // rebuilt. + // + { + cstrings args (loader_args); + args.push_back (loadtab.string ().c_str ()); + args.push_back (nullptr); + + assert (process (args.data ()).wait ()); - assert (process (ld_args).wait ()); transaction t (db.begin ()); shared_ptr<package> bpv ( @@ -914,11 +1025,27 @@ main (int argc, char* argv[]) t.commit (); } - // Fully qualified to avoid ambiguity with odb exception. + + // Restore the original setup. // - catch (const std::exception& e) { - cerr << e << endl; - return 1; + cstrings args (loader_args); + args.push_back ("--force"); + args.push_back (loadtab.string ().c_str ()); + args.push_back (nullptr); + + assert (process (args.data ()).wait ()); + + transaction t (db.begin ()); + + shared_ptr<package> bpv ( + db.find<package> ( + package_id (package_name ("libbar"), version ("2.4.0+3")))); + + // External package summary is not saved. + // + assert (bpv->summary.empty ()); + + t.commit (); } } diff --git a/tests/load/git-cache/packages.manifest b/tests/load/git-cache/packages.manifest new file mode 100644 index 0000000..1cec922 --- /dev/null +++ b/tests/load/git-cache/packages.manifest @@ -0,0 +1,14 @@ +: 1 +name: libfoo +version: 1.0 +project: foo +summary: The Foo Library +license: MIT +tags: c++, foo +description-file: README +changes-file: NEWS +url: http://www.example.com/foo/ +email: foo-users@example.com +depends: libmisc == 1.0 +location: libfoo +fragment: 0f50af28d1cfb0c22f5b88e2bf674ab732e058d9 diff --git a/tests/load/git-cache/repositories.manifest b/tests/load/git-cache/repositories.manifest new file mode 100644 index 0000000..f8f5696 --- /dev/null +++ b/tests/load/git-cache/repositories.manifest @@ -0,0 +1,7 @@ +: 1 +location: ../libmisc.git##HEAD +type: git +role: prerequisite +fragment: 0f50af28d1cfb0c22f5b88e2bf674ab732e058d9 +: +summary: foo project repository diff --git a/tests/load/git-loadtab b/tests/load/git-loadtab new file mode 100644 index 0000000..eb8f88b --- /dev/null +++ b/tests/load/git-loadtab @@ -0,0 +1 @@ +https://git.example.com/foo.git#master foo cache:git-cache |