diff options
Diffstat (limited to 'bpkg/drop.cxx')
-rw-r--r-- | bpkg/drop.cxx | 99 |
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; } } |