From e6f10cabb7fbdba6fd11bcd109dbe765285c762c Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 22 Oct 2015 11:07:03 +0200 Subject: Implement dependents check in drop command Also, add support for commands to return program status. --- bpkg/bpkg.cxx | 10 +++-- bpkg/build | 2 +- bpkg/build.cxx | 8 ++-- bpkg/cfg-create | 2 +- bpkg/cfg-create.cxx | 4 +- bpkg/drop | 2 +- bpkg/drop-options.cli | 11 +++++- bpkg/drop.cxx | 99 +++++++++++++++++++++++++++++++++++++++++++++++++- bpkg/help | 2 +- bpkg/help.cxx | 4 +- bpkg/pkg-clean | 4 +- bpkg/pkg-command | 2 +- bpkg/pkg-command.cxx | 4 +- bpkg/pkg-configure | 2 +- bpkg/pkg-configure.cxx | 4 +- bpkg/pkg-disfigure | 2 +- bpkg/pkg-disfigure.cxx | 4 +- bpkg/pkg-fetch | 2 +- bpkg/pkg-fetch.cxx | 4 +- bpkg/pkg-purge | 2 +- bpkg/pkg-purge.cxx | 4 +- bpkg/pkg-status | 2 +- bpkg/pkg-status.cxx | 3 +- bpkg/pkg-unpack | 2 +- bpkg/pkg-unpack.cxx | 4 +- bpkg/pkg-update | 4 +- bpkg/pkg-verify | 2 +- bpkg/pkg-verify.cxx | 17 +++++++-- bpkg/rep-add | 2 +- bpkg/rep-add.cxx | 4 +- bpkg/rep-create | 2 +- bpkg/rep-create.cxx | 7 +++- bpkg/rep-fetch | 2 +- bpkg/rep-fetch.cxx | 4 +- bpkg/rep-info | 2 +- bpkg/rep-info.cxx | 4 +- 36 files changed, 192 insertions(+), 47 deletions(-) (limited to 'bpkg') diff --git a/bpkg/bpkg.cxx b/bpkg/bpkg.cxx index 61f7425..6246d6f 100644 --- a/bpkg/bpkg.cxx +++ b/bpkg/bpkg.cxx @@ -145,6 +145,7 @@ try // Handle commands. // + int r (1); for (;;) { // help @@ -152,7 +153,7 @@ try if (cmd.help ()) { assert (h); - help (ho, "help", help_options::print_usage); + r = help (ho, "help", help_options::print_usage); break; } @@ -163,7 +164,7 @@ try // if (h) // help (ho, "pkg-verify", pkg_verify_options::print_usage); // else - // pkg_verify (parse (co, args), args); + // r = pkg_verify (parse (co, args), args); // // return 0; // } @@ -174,7 +175,7 @@ try if (h) \ help (ho, SP#CMD, NP##CMD##_options::print_usage); \ else \ - NP##CMD (parse (co, args), args); \ + r = NP##CMD (parse (co, args), args); \ \ break; \ } @@ -219,6 +220,9 @@ try fail << "unhandled command"; } + if (r != 0) + return r; + // Warn if args contain some leftover junk. We already successfully // performed the command so failing would probably be misleading. // diff --git a/bpkg/build b/bpkg/build index cc89599..a5c047d 100644 --- a/bpkg/build +++ b/bpkg/build @@ -10,7 +10,7 @@ namespace bpkg { - void + int build (const build_options&, cli::scanner& args); } diff --git a/bpkg/build.cxx b/bpkg/build.cxx index ec9de3b..1aeb35d 100644 --- a/bpkg/build.cxx +++ b/bpkg/build.cxx @@ -731,7 +731,7 @@ namespace bpkg map_type map_; }; - void + int build (const build_options& o, cli::scanner& args) { tracer trace ("build"); @@ -1029,12 +1029,12 @@ namespace bpkg } if (o.print_only ()) - return; + return 0; // Ask the user if we should continue. // if (!(o.yes () || yn_prompt ("continue? [Y/n]", 'y'))) - return; + return 1; // Ok, we have the green light. The overall action plan is as follows. // @@ -1230,5 +1230,7 @@ namespace bpkg text << "updated " << sp->name << " " << sp->version; } } + + return 0; } } diff --git a/bpkg/cfg-create b/bpkg/cfg-create index ffd3ba5..b6dcc21 100644 --- a/bpkg/cfg-create +++ b/bpkg/cfg-create @@ -10,7 +10,7 @@ namespace bpkg { - void + int cfg_create (const cfg_create_options&, cli::scanner& args); } diff --git a/bpkg/cfg-create.cxx b/bpkg/cfg-create.cxx index bbb624c..c98dd28 100644 --- a/bpkg/cfg-create.cxx +++ b/bpkg/cfg-create.cxx @@ -18,7 +18,7 @@ using namespace butl; namespace bpkg { - void + int cfg_create (const cfg_create_options& o, cli::scanner& args) { tracer trace ("cfg_create"); @@ -130,5 +130,7 @@ namespace bpkg c.complete ().normalize (); text << "created new configuration in " << c; } + + return 0; } } diff --git a/bpkg/drop b/bpkg/drop index 1687c82..0054045 100644 --- a/bpkg/drop +++ b/bpkg/drop @@ -10,7 +10,7 @@ namespace bpkg { - void + int drop (const drop_options&, cli::scanner& args); } diff --git a/bpkg/drop-options.cli b/bpkg/drop-options.cli index 301bc9a..d1a3769 100644 --- a/bpkg/drop-options.cli +++ b/bpkg/drop-options.cli @@ -31,10 +31,17 @@ namespace bpkg bool --yes|-y { "Assume the answer to all prompts is \cb{yes}. Note that this option - does not apply to the dropping of dependents confirmation." + does not apply to the dropping of dependents; use \cb{--drop-dependent} + for that." }; - bool --disfigure-only|-d + bool --drop-dependent + { + "Don't warn about or ask for confirmation of dropping dependent + packages." + }; + + bool --disfigure-only { "Disfigure all the packages but don't purge." }; 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 +#include #include // cout #include // reverse_iterate() @@ -27,7 +28,41 @@ using namespace butl; namespace bpkg { - void + using package_map = map>; + + static void + collect_dependent (database& db, + package_map& m, + const shared_ptr& p, + bool w) + { + using query = query; + + bool found (false); + + for (auto& pd: db.query (query::name == p->name)) + { + string& dn (pd.name); + + if (m.find (dn) == m.end ()) + { + shared_ptr dp (db.load (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 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 p (db.find (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& 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; } } diff --git a/bpkg/help b/bpkg/help index 9c81e7e..8bd5596 100644 --- a/bpkg/help +++ b/bpkg/help @@ -12,7 +12,7 @@ namespace bpkg { - void + int help (const help_options&, const string& topic, void (*usage) (std::ostream&)); diff --git a/bpkg/help.cxx b/bpkg/help.cxx index 66b68aa..f03ad21 100644 --- a/bpkg/help.cxx +++ b/bpkg/help.cxx @@ -51,7 +51,7 @@ namespace bpkg o << ""<< endl; } - void + int help (const help_options&, const string& t, void (*usage) (std::ostream&)) { ostream& o (cout); @@ -77,5 +77,7 @@ namespace bpkg else fail << "unknown bpkg command/help topic '" << t << "'" << info << "run 'bpkg help' for more information"; + + return 0; } } diff --git a/bpkg/pkg-clean b/bpkg/pkg-clean index baed20a..1195cfe 100644 --- a/bpkg/pkg-clean +++ b/bpkg/pkg-clean @@ -11,10 +11,10 @@ namespace bpkg { - inline void + inline int pkg_clean (const pkg_clean_options& o, cli::scanner& args) { - pkg_command ("clean", o, args); + return pkg_command ("clean", o, args); } } diff --git a/bpkg/pkg-command b/bpkg/pkg-command index 360a550..724caa8 100644 --- a/bpkg/pkg-command +++ b/bpkg/pkg-command @@ -13,7 +13,7 @@ namespace bpkg { // Common pkg-{update,clean,test,install,...} implementation. // - void + int pkg_command (const string& cmd, // Without the 'pkg-' prefix. const configuration_options&, cli::scanner& args); diff --git a/bpkg/pkg-command.cxx b/bpkg/pkg-command.cxx index 67ea07a..253ee66 100644 --- a/bpkg/pkg-command.cxx +++ b/bpkg/pkg-command.cxx @@ -39,7 +39,7 @@ namespace bpkg run_b (bspec); } - void + int pkg_command (const string& cmd, const configuration_options& o, cli::scanner& args) @@ -75,5 +75,7 @@ namespace bpkg if (verb) text << cmd << (cmd.back () != 'e' ? "ed " : "d ") << p->name << " " << p->version; + + return 0; } } diff --git a/bpkg/pkg-configure b/bpkg/pkg-configure index b042e60..df2fc40 100644 --- a/bpkg/pkg-configure +++ b/bpkg/pkg-configure @@ -11,7 +11,7 @@ namespace bpkg { - void + int pkg_configure (const pkg_configure_options&, cli::scanner& args); // Configure the package, update its state, and commit the transaction. diff --git a/bpkg/pkg-configure.cxx b/bpkg/pkg-configure.cxx index 9e256ce..f7e1901 100644 --- a/bpkg/pkg-configure.cxx +++ b/bpkg/pkg-configure.cxx @@ -144,7 +144,7 @@ namespace bpkg t.commit (); } - void + int pkg_configure (const pkg_configure_options& o, cli::scanner& args) { tracer trace ("pkg_configure"); @@ -192,5 +192,7 @@ namespace bpkg if (verb) text << "configured " << p->name << " " << p->version; + + return 0; } } diff --git a/bpkg/pkg-disfigure b/bpkg/pkg-disfigure index ef78d05..2833522 100644 --- a/bpkg/pkg-disfigure +++ b/bpkg/pkg-disfigure @@ -11,7 +11,7 @@ namespace bpkg { - void + int pkg_disfigure (const pkg_disfigure_options&, cli::scanner& args); // Disfigure the package, update its state, and commit the diff --git a/bpkg/pkg-disfigure.cxx b/bpkg/pkg-disfigure.cxx index d9e5552..465213b 100644 --- a/bpkg/pkg-disfigure.cxx +++ b/bpkg/pkg-disfigure.cxx @@ -127,7 +127,7 @@ namespace bpkg t.commit (); } - void + int pkg_disfigure (const pkg_disfigure_options& o, cli::scanner& args) { tracer trace ("pkg_disfigure"); @@ -159,5 +159,7 @@ namespace bpkg if (verb) text << "disfigured " << p->name << " " << p->version; + + return 0; } } diff --git a/bpkg/pkg-fetch b/bpkg/pkg-fetch index 7cfd214..d321889 100644 --- a/bpkg/pkg-fetch +++ b/bpkg/pkg-fetch @@ -13,7 +13,7 @@ namespace bpkg { - void + int pkg_fetch (const pkg_fetch_options&, cli::scanner& args); // Fetch the package as an archive file and commit the transaction. diff --git a/bpkg/pkg-fetch.cxx b/bpkg/pkg-fetch.cxx index 9a2e84c..492c4e7 100644 --- a/bpkg/pkg-fetch.cxx +++ b/bpkg/pkg-fetch.cxx @@ -226,7 +226,7 @@ namespace bpkg return p; } - void + int pkg_fetch (const pkg_fetch_options& o, cli::scanner& args) { tracer trace ("pkg_fetch"); @@ -269,5 +269,7 @@ namespace bpkg if (verb) text << "fetched " << p->name << " " << p->version; + + return 0; } } diff --git a/bpkg/pkg-purge b/bpkg/pkg-purge index 0c88e19..399606d 100644 --- a/bpkg/pkg-purge +++ b/bpkg/pkg-purge @@ -11,7 +11,7 @@ namespace bpkg { - void + int pkg_purge (const pkg_purge_options&, cli::scanner& args); // Remove package's filesystem objects (the source directory and, if diff --git a/bpkg/pkg-purge.cxx b/bpkg/pkg-purge.cxx index 47ff05f..b90136a 100644 --- a/bpkg/pkg-purge.cxx +++ b/bpkg/pkg-purge.cxx @@ -66,7 +66,7 @@ namespace bpkg } } - void + int pkg_purge (const pkg_purge_options& o, cli::scanner& args) { tracer trace ("pkg_purge"); @@ -182,5 +182,7 @@ namespace bpkg if (verb) text << (o.keep () ? "keeping archive " : "purged ") << p->name << " " << p->version; + + return 0; } } diff --git a/bpkg/pkg-status b/bpkg/pkg-status index 98bd014..175ea87 100644 --- a/bpkg/pkg-status +++ b/bpkg/pkg-status @@ -10,7 +10,7 @@ namespace bpkg { - void + int pkg_status (const pkg_status_options&, cli::scanner& args); } diff --git a/bpkg/pkg-status.cxx b/bpkg/pkg-status.cxx index 2f0bf7f..c31e834 100644 --- a/bpkg/pkg-status.cxx +++ b/bpkg/pkg-status.cxx @@ -20,7 +20,7 @@ using namespace butl; namespace bpkg { - void + int pkg_status (const pkg_status_options& o, cli::scanner& args) { tracer trace ("pkg_status"); @@ -129,5 +129,6 @@ namespace bpkg cout << "unknown"; cout << endl; + return 0; } } diff --git a/bpkg/pkg-unpack b/bpkg/pkg-unpack index a569efe..1e5339d 100644 --- a/bpkg/pkg-unpack +++ b/bpkg/pkg-unpack @@ -11,7 +11,7 @@ namespace bpkg { - void + int pkg_unpack (const pkg_unpack_options&, cli::scanner& args); // Unpack the package as a source directory and commit the transaction. diff --git a/bpkg/pkg-unpack.cxx b/bpkg/pkg-unpack.cxx index c224350..5af8a10 100644 --- a/bpkg/pkg-unpack.cxx +++ b/bpkg/pkg-unpack.cxx @@ -215,7 +215,7 @@ namespace bpkg return p; } - void + int pkg_unpack (const pkg_unpack_options& o, cli::scanner& args) { tracer trace ("pkg_unpack"); @@ -255,5 +255,7 @@ namespace bpkg if (verb) text << "unpacked " << p->name << " " << p->version; + + return 0; } } diff --git a/bpkg/pkg-update b/bpkg/pkg-update index b34e44a..a266da3 100644 --- a/bpkg/pkg-update +++ b/bpkg/pkg-update @@ -12,10 +12,10 @@ namespace bpkg { - inline void + inline int pkg_update (const pkg_update_options& o, cli::scanner& args) { - pkg_command ("update", o, args); + return pkg_command ("update", o, args); } inline void diff --git a/bpkg/pkg-verify b/bpkg/pkg-verify index e0675c6..8a62b66 100644 --- a/bpkg/pkg-verify +++ b/bpkg/pkg-verify @@ -12,7 +12,7 @@ namespace bpkg { - void + int pkg_verify (const pkg_verify_options&, cli::scanner& args); // Verify archive is a valid package and return its manifest. Throw diff --git a/bpkg/pkg-verify.cxx b/bpkg/pkg-verify.cxx index 969eb22..5e16410 100644 --- a/bpkg/pkg-verify.cxx +++ b/bpkg/pkg-verify.cxx @@ -208,7 +208,7 @@ namespace bpkg } } - void + int pkg_verify (const pkg_verify_options& o, cli::scanner& args) { tracer trace ("pkg_verify"); @@ -227,9 +227,18 @@ namespace bpkg // If we were asked to run silent, don't yap about the reason // why the package is invalid. Just return the error status. // - package_manifest m (pkg_verify (o, a, !o.silent ())); + try + { + package_manifest m (pkg_verify (o, a, !o.silent ())); + + if (verb && !o.silent ()) + text << "valid package " << m.name << " " << m.version; - if (verb && !o.silent ()) - text << "valid package " << m.name << " " << m.version; + return 0; + } + catch (const failed&) + { + return 1; + } } } diff --git a/bpkg/rep-add b/bpkg/rep-add index 3aff082..10d85f4 100644 --- a/bpkg/rep-add +++ b/bpkg/rep-add @@ -10,7 +10,7 @@ namespace bpkg { - void + int rep_add (const rep_add_options&, cli::scanner& args); } diff --git a/bpkg/rep-add.cxx b/bpkg/rep-add.cxx index bed6b86..4348206 100644 --- a/bpkg/rep-add.cxx +++ b/bpkg/rep-add.cxx @@ -19,7 +19,7 @@ using namespace butl; namespace bpkg { - void + int rep_add (const rep_add_options& o, cli::scanner& args) { tracer trace ("rep_add"); @@ -64,5 +64,7 @@ namespace bpkg if (verb) text << "added " << rn; + + return 0; } } diff --git a/bpkg/rep-create b/bpkg/rep-create index 7ce693e..322c76c 100644 --- a/bpkg/rep-create +++ b/bpkg/rep-create @@ -10,7 +10,7 @@ namespace bpkg { - void + int rep_create (const rep_create_options&, cli::scanner& args); } diff --git a/bpkg/rep-create.cxx b/bpkg/rep-create.cxx index 291374e..1f0e420 100644 --- a/bpkg/rep-create.cxx +++ b/bpkg/rep-create.cxx @@ -131,7 +131,7 @@ namespace bpkg throw failed (); } - void + int rep_create (const rep_create_options& o, cli::scanner& args) try { @@ -195,9 +195,12 @@ namespace bpkg d.normalize (); text << pm.size () << " package(s) in " << d; } + + return 0; } catch (const invalid_path& e) { - fail << "invalid path: '" << e.path () << "'"; + error << "invalid path: '" << e.path () << "'"; + throw failed (); } } diff --git a/bpkg/rep-fetch b/bpkg/rep-fetch index 9977571..9175755 100644 --- a/bpkg/rep-fetch +++ b/bpkg/rep-fetch @@ -10,7 +10,7 @@ namespace bpkg { - void + int rep_fetch (const rep_fetch_options&, cli::scanner& args); } diff --git a/bpkg/rep-fetch.cxx b/bpkg/rep-fetch.cxx index 7443f56..f96607f 100644 --- a/bpkg/rep-fetch.cxx +++ b/bpkg/rep-fetch.cxx @@ -175,7 +175,7 @@ namespace bpkg db.update (r); } - void + int rep_fetch (const rep_fetch_options& o, cli::scanner&) { tracer trace ("rep_fetch"); @@ -239,5 +239,7 @@ namespace bpkg if (verb) text << pcount << " package(s) in " << rcount << " repository(s)"; + + return 0; } } diff --git a/bpkg/rep-info b/bpkg/rep-info index 8437a53..ef01369 100644 --- a/bpkg/rep-info +++ b/bpkg/rep-info @@ -10,7 +10,7 @@ namespace bpkg { - void + int rep_info (const rep_info_options&, cli::scanner& args); } diff --git a/bpkg/rep-info.cxx b/bpkg/rep-info.cxx index 8bb3c7d..041d804 100644 --- a/bpkg/rep-info.cxx +++ b/bpkg/rep-info.cxx @@ -21,7 +21,7 @@ using namespace butl; namespace bpkg { - void + int rep_info (const rep_info_options& o, cli::scanner& args) { tracer trace ("rep_info"); @@ -108,5 +108,7 @@ namespace bpkg { fail << "unable to write to STDOUT"; } + + return 0; } } -- cgit v1.1