aboutsummaryrefslogtreecommitdiff
path: root/bpkg/drop.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'bpkg/drop.cxx')
-rw-r--r--bpkg/drop.cxx99
1 files changed, 98 insertions, 1 deletions
diff --git a/bpkg/drop.cxx b/bpkg/drop.cxx
index ac3919e..e2fd455 100644
--- a/bpkg/drop.cxx
+++ b/bpkg/drop.cxx
@@ -4,6 +4,7 @@
#include <bpkg/drop>
+#include <map>
#include <iostream> // cout
#include <butl/utility> // reverse_iterate()
@@ -27,7 +28,41 @@ using namespace butl;
namespace bpkg
{
- void
+ using package_map = map<string, shared_ptr<selected_package>>;
+
+ static void
+ collect_dependent (database& db,
+ package_map& m,
+ const shared_ptr<selected_package>& p,
+ bool w)
+ {
+ using query = query<package_dependent>;
+
+ bool found (false);
+
+ for (auto& pd: db.query<package_dependent> (query::name == p->name))
+ {
+ string& dn (pd.name);
+
+ if (m.find (dn) == m.end ())
+ {
+ shared_ptr<selected_package> dp (db.load<selected_package> (dn));
+ m.emplace (move (dn), dp);
+
+ collect_dependent (db, m, dp, w);
+
+ if (w)
+ warn << "dependent package " << dp->name << " to be dropped as well";
+
+ found = true;
+ }
+ }
+
+ if (w && found)
+ info << "because dropping " << p->name;
+ }
+
+ int
drop (const drop_options& o, cli::scanner& args)
{
tracer trace ("drop");
@@ -47,6 +82,68 @@ namespace bpkg
// any of these objects, they will modify the cached instance, which
// means our list will always "see" their updated state.
//
+ // @@ Revise.
+ //
session s;
+
+ // Assemble the list of packages we will need to drop. Comparing pointers
+ // is valid because of the session above.
+ //
+ package_map pkgs;
+ vector<string> names;
+ {
+ transaction t (db.begin ());
+
+ // The first step is to load all the packages specified by the user.
+ //
+ while (args.more ())
+ {
+ string n (args.next ());
+ level4 ([&]{trace << "package " << n;});
+
+ shared_ptr<selected_package> p (db.find<selected_package> (n));
+
+ if (p == nullptr)
+ fail << "package " << n << " does not exist in configuration " << c;
+
+ if (p->state == package_state::broken)
+ fail << "unable to drop broken package " << n <<
+ info << "use 'pkg-purge --force' to remove";
+
+ if (pkgs.emplace (n, move (p)).second)
+ names.push_back (move (n));
+ }
+
+ // The next step is to see if there are any dependents that are not
+ // already on the list. We will have to drop those as well.
+ //
+ for (const string& n: names)
+ {
+ const shared_ptr<selected_package>& p (pkgs[n]);
+
+ // Unconfigured package cannot have any dependents.
+ //
+ if (p->state != package_state::configured)
+ continue;
+
+ collect_dependent (db, pkgs, p, !o.drop_dependent ());
+ }
+
+ // If we've found dependents, ask the user to confirm.
+ //
+ if (!o.drop_dependent () && names.size () != pkgs.size ())
+ {
+ if (o.yes ())
+ fail << "refusing to drop dependent packages with just --yes" <<
+ info << "specify --drop-dependent to confirm";
+
+ if (!yn_prompt ("drop dependent packages? [y/N]", 'n'))
+ return 1;
+ }
+
+ t.commit ();
+ }
+
+ return 0;
}
}