From f5adc6c0ee7965abcad4cc73d0f36d1ed3cba3cc Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 29 Sep 2015 11:29:50 +0200 Subject: Complete pkg-status, rework object model --- bpkg/pkg-status.cxx | 124 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 106 insertions(+), 18 deletions(-) (limited to 'bpkg/pkg-status.cxx') 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 -#include // cout +#include // cout +#include // function #include #include @@ -39,39 +40,126 @@ namespace bpkg database db (open (c, trace)); transaction t (db.begin ()); + session s; - using query = odb::query; - 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 p; { - q = q && (query::version.epoch == v.epoch () && - query::version.revision == v.revision () && - query::version.canonical_upstream == v.canonical_upstream ()); - } + using query = query; + query q (query::name == n); - shared_ptr p (db.query_one (q)); - t.commit (); + if (!v.empty ()) + q = q && query::version == v; + + p = db.query_one (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> 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; + + 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 root (db.load ("")); + + for (shared_ptr ap: + pointer_result (db.query (q))) + { + function&)> find = + [&ap, &find](const shared_ptr& 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 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 ap: aps) + cout << ' ' << ap->version; + } + + found = true; + } + + if (!found) + cout << "unknown"; + cout << endl; } } -- cgit v1.1