From b83a9bbdb0407c198e615e61491e1f8492ae5dc9 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 5 Oct 2015 08:45:27 +0200 Subject: Add repository location to package, minor cleanups --- bpkg/build.cxx | 2 +- bpkg/package | 26 ++++++++++++++++++++++++-- bpkg/package.cxx | 49 +++++++++++++++++++++++++++++++++++-------------- bpkg/pkg-fetch.cxx | 13 +++++++++++-- bpkg/pkg-unpack.cxx | 4 +++- 5 files changed, 74 insertions(+), 20 deletions(-) diff --git a/bpkg/build.cxx b/bpkg/build.cxx index 361cd9a..e9377ec 100644 --- a/bpkg/build.cxx +++ b/bpkg/build.cxx @@ -149,7 +149,7 @@ namespace bpkg // explicitly added to the configuration and their complements, // recursively. // - ap = filter_one (root, db.query (q)); + ap = filter_one (root, db.query (q)).first; } // Load the package that may have already been selected and diff --git a/bpkg/package b/bpkg/package index 6bd68cc..67a80a8 100644 --- a/bpkg/package +++ b/bpkg/package @@ -10,6 +10,7 @@ #include #include // uint16 #include +#include // pair #include #include @@ -146,7 +147,7 @@ namespace bpkg complements_type complements; prerequisites_type prerequisites; - // Used to detect recursive fecthing. Will probably be replaced + // Used to detect recursive fetching. Will probably be replaced // by the 'repositories' file timestamp or hashsum later. // #pragma db transient @@ -237,6 +238,16 @@ namespace bpkg // List of repositories to which this package version belongs (yes, // in our world, it can be in multiple, unrelated repositories). // + // Note that if the repository is the special root repository (its + // location is empty), then this is a transient (or "fake") object + // for an existing package archive or package directory. In this + // case the location is the path to the archive/directory and to + // determine which one it is, use file/dir_exists(). While on the + // topic of fake available_package objects, when one is created for + // a selected package (see make_available()), this list is left empty + // with the thinking being that since the package is already in at + // least fetched state, we shouldn't be needing its location. + // std::vector locations; //@@ Map? // Package manifest data. @@ -298,7 +309,7 @@ namespace bpkg std::vector> filter (const shared_ptr&, odb::result&&); - shared_ptr + std::pair, shared_ptr> filter_one (const shared_ptr&, odb::result&&); // state @@ -338,6 +349,17 @@ namespace bpkg version_type version; state_type state; + // Repository from which this package came. Note that it is not + // a pointer to the repository object because it could be wiped + // out (e.g., as a result of rep-fetch). We call such packages + // "orphans". While we can get a list of orphan's prerequisites + // (by loading its manifest), we wouldn't know which repository + // to use as a base to resolve them. As a result, an orphan that + // is not already configured (and thus has all its prerequisites + // resolved) is not very useful and can only be purged. + // + repository_location repository; + // Path to the archive of this package, if any. If not absolute, // then it is relative to the configuration directory. The purge // flag indicates whether the archive should be removed when the diff --git a/bpkg/package.cxx b/bpkg/package.cxx index 02cb49d..e764c3f 100644 --- a/bpkg/package.cxx +++ b/bpkg/package.cxx @@ -40,35 +40,54 @@ namespace bpkg // available_package // - // Check if the package is available from the specified repository or - // one of its complements, recursively. Return the first repository - // that contains the package or NULL if none are. + // Check if the package is available from the specified repository, + // its prerequisite repositories, or one of their complements, + // recursively. Return the first repository that contains the + // package or NULL if none are. // static shared_ptr find (const shared_ptr& r, - const shared_ptr& ap) + const shared_ptr& ap, + bool prereq = true) { + const auto& ps (r->prerequisites); const auto& cs (r->complements); for (const package_location& pl: ap->locations) { + const lazy_shared_ptr& lr (pl.repository); + // First check the repository itself. // - if (pl.repository.object_id () == r->name) + if (lr.object_id () == r->name) return r; - // Then check all the complements without loading them. + // Then check all the complements and prerequisites without + // loading them. // - if (cs.find (pl.repository) != cs.end ()) - return pl.repository.load (); + if (cs.find (lr) != cs.end () || (prereq && ps.find (lr) != ps.end ())) + return lr.load (); - // Finally, load the complements and check them recursively. + // Finally, load the complements and prerequisites and check them + // recursively. // for (const lazy_shared_ptr& cr: cs) { - if (shared_ptr r = find (cr.load (), ap)) + // Should we consider prerequisites of our complements as our + // prerequisites? I'd say not. + // + if (shared_ptr r = find (cr.load (), ap, false)) return r; } + + if (prereq) + { + for (const lazy_weak_ptr& pr: ps) + { + if (shared_ptr r = find (pr.load (), ap, false)) + return r; + } + } } return nullptr; @@ -88,16 +107,18 @@ namespace bpkg return aps; } - shared_ptr + pair, shared_ptr> filter_one (const shared_ptr& r, result&& apr) { + using result = pair, shared_ptr>; + for (shared_ptr ap: pointer_result (apr)) { - if (find (r, ap) != nullptr) - return ap; + if (shared_ptr pr = find (r, ap)) + return result (move (ap), move (pr)); } - return nullptr; + return result (); } // state diff --git a/bpkg/pkg-fetch.cxx b/bpkg/pkg-fetch.cxx index ca2bada..b1e5253 100644 --- a/bpkg/pkg-fetch.cxx +++ b/bpkg/pkg-fetch.cxx @@ -37,6 +37,7 @@ namespace bpkg path a; auto_rm arm; bool purge; + repository_location rl; if (o.existing ()) { @@ -50,6 +51,11 @@ namespace bpkg fail << "archive file '" << a << "' does not exist"; purge = o.purge (); + + // Use the special root repository as the repository of this + // package. + // + rl = repository_location (); } else { @@ -79,7 +85,8 @@ namespace bpkg if (p == nullptr) fail << "package " << n << " " << v << " is not available"; - // Pick a repository. Prefer local ones over the remote. + // Pick a repository. Preferring local ones over the remote seems + // like a sensible thing to do. // const package_location* pl (&p->locations.front ()); @@ -96,7 +103,8 @@ namespace bpkg text << "fetching " << pl->location.leaf () << " " << "from " << pl->repository->name; - a = fetch_archive (o, pl->repository->location, pl->location, c); + rl = pl->repository->location; + a = fetch_archive (o, rl, pl->location, c); arm = auto_rm (a); purge = true; } @@ -132,6 +140,7 @@ namespace bpkg move (m.name), move (m.version), state::fetched, + move (rl), move (a), purge, nullopt, // No source directory yet. diff --git a/bpkg/pkg-unpack.cxx b/bpkg/pkg-unpack.cxx index 5fc5f0b..b6decca 100644 --- a/bpkg/pkg-unpack.cxx +++ b/bpkg/pkg-unpack.cxx @@ -57,12 +57,14 @@ namespace bpkg if (ad.sub (ac)) ad = ad.leaf (ac); - // Add the package to the configuration. + // Add the package to the configuration. Use the special root + // repository as the repository of this package. // shared_ptr p (new package { move (m.name), move (m.version), state::unpacked, + repository_location (), nullopt, // No archive false, // Don't purge archive. move (ad), -- cgit v1.1