diff options
Diffstat (limited to 'bpkg/pkg-status.cxx')
-rw-r--r-- | bpkg/pkg-status.cxx | 124 |
1 files changed, 106 insertions, 18 deletions
diff --git a/bpkg/pkg-status.cxx b/bpkg/pkg-status.cxx index c75019e..dbd2bd0 100644 --- a/bpkg/pkg-status.cxx +++ b/bpkg/pkg-status.cxx @@ -4,7 +4,8 @@ #include <bpkg/pkg-status> -#include <iostream> // cout +#include <iostream> // cout +#include <functional> // function #include <bpkg/types> #include <bpkg/package> @@ -39,39 +40,126 @@ namespace bpkg database db (open (c, trace)); transaction t (db.begin ()); + session s; - using query = odb::query<package>; - query q (query::name == n); + level4 ([&]{trace << "package " << n << "; version " << v;}); - if (!v.empty ()) + // First search in the packages that already exist in this configuration. + // + shared_ptr<package> p; { - q = q && (query::version.epoch == v.epoch () && - query::version.revision == v.revision () && - query::version.canonical_upstream == v.canonical_upstream ()); - } + using query = query<package>; + query q (query::name == n); - shared_ptr<package> p (db.query_one<package> (q)); - t.commit (); + if (!v.empty ()) + q = q && query::version == v; + + p = db.query_one<package> (q); + } - if (p == nullptr) + // Now look for available packages. If the user specified the version + // explicitly and we found the corresponding existing package, then + // no need to look for it in available packages. + // + vector<shared_ptr<available_package>> aps; + if (p == nullptr || v.empty ()) { - // @@ TODO: This is where we search the packages available in - // the repositories and if found, print its status as 'available' - // plus a list of versions. + using query = query<available_package>; + + query q (query::id.name == n); + + // If we found an existing package, then only look for versions + // greater than what already exists. // - cout << "unknown"; + if (p != nullptr) + q = q && query::id.version > p->version; + else if (!v.empty ()) + // + // Otherwise, if the user specified the version, then only look for + // that specific version. + // + q = q && query::id.version == v; + + q += order_by_version_desc (query::id.version); + + // Only consider packages that are in repositories that were + // explicitly added to the configuration and their complements, + // transitively. While we could maybe come up with a (barely + // comprehensible) view/query to achieve this, doing it on the + // "client side" is definitely more straightforward. + // + shared_ptr<repository> root (db.load<repository> ("")); + + for (shared_ptr<available_package> ap: + pointer_result (db.query<available_package> (q))) + { + function<bool (const shared_ptr<repository>&)> find = + [&ap, &find](const shared_ptr<repository>& r) -> bool + { + const auto& cs (r->complements); + + for (const package_location& pl: ap->locations) + { + // First check all the complements without loading them. + // + if (cs.find (pl.repository) != cs.end ()) + return true; + + // If not found, then load the complements and check them + // recursively. + // + for (lazy_shared_ptr<repository> cr: cs) + { + if (find (cr.load ())) + return true; + } + } + + return false; + }; + + level4 ([&]{trace << "available " << ap->version;}); + + if (find (root)) + aps.push_back (ap); + } } - else + + t.commit (); + + bool found (false); + + if (p != nullptr) { cout << p->state; - // Also print the version of the package unless the user - // specified it. + // Also print the version of the package unless the user specified it. // if (v.empty ()) cout << " " << p->version; + + found = true; } + if (!aps.empty ()) + { + cout << (found ? "; " : "") << "available"; + + // If the user specified the version, then there will be only one + // entry. + // + if (v.empty ()) + { + for (shared_ptr<available_package> ap: aps) + cout << ' ' << ap->version; + } + + found = true; + } + + if (!found) + cout << "unknown"; + cout << endl; } } |