aboutsummaryrefslogtreecommitdiff
path: root/bpkg/pkg-status.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'bpkg/pkg-status.cxx')
-rw-r--r--bpkg/pkg-status.cxx124
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;
}
}