aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2007-07-05 20:21:17 +0000
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2007-07-05 20:21:17 +0000
commitd7861625881a6ed1490b9b434c373565404fc1c8 (patch)
treeed4bfe748e8f79484f3455fa4e361355de90691c
parenta3ca6e94cb25fd915beff6092578dabacf1b4c47 (diff)
downloadpaludis-d7861625881a6ed1490b9b434c373565404fc1c8.tar.gz
paludis-d7861625881a6ed1490b9b434c373565404fc1c8.tar.xz
r3784@snowflake: ciaranm | 2007-07-05 21:15:58 +0100
Require --permit-unsafe-uninstalls for unsafe uninstalls
-rw-r--r--bash-completion/paludis1
-rw-r--r--paludis/dep_list/Makefile.am16
-rw-r--r--paludis/dep_list/uninstall_list.cc92
-rw-r--r--paludis/dep_list/uninstall_list.hh14
-rw-r--r--paludis/dep_list/uninstall_list.se20
-rw-r--r--paludis/dep_list/uninstall_list.sr5
-rw-r--r--paludis/dep_list/uninstall_list_TEST.cc18
-rw-r--r--paludis/tasks/report_task.cc2
-rw-r--r--paludis/tasks/uninstall_task.cc64
-rw-r--r--paludis/tasks/uninstall_task.hh30
-rw-r--r--src/clients/paludis/command_line.cc2
-rw-r--r--src/clients/paludis/command_line.hh3
-rw-r--r--src/clients/paludis/uninstall.cc55
-rw-r--r--zsh-completion/_paludis1
14 files changed, 249 insertions, 74 deletions
diff --git a/bash-completion/paludis b/bash-completion/paludis
index 2a5d0e6..9e42bdb 100644
--- a/bash-completion/paludis
+++ b/bash-completion/paludis
@@ -110,6 +110,7 @@ _paludis() {
--show-reasons \
--show-use-descriptions \
--with-unused-dependencies \
+ --permit-unsafe-uninstalls \
--with-dependencies \
--all-versions \
${deplist_opts}"
diff --git a/paludis/dep_list/Makefile.am b/paludis/dep_list/Makefile.am
index b2ee270..b490511 100644
--- a/paludis/dep_list/Makefile.am
+++ b/paludis/dep_list/Makefile.am
@@ -2,7 +2,9 @@ CLEANFILES = *~ gmon.out *.gcov *.gcno *.gcda
DISTCLEANFILES = \
dep_list-sr.hh dep_list-sr.cc \
uninstall_list-sr.hh uninstall_list-sr.cc \
- options-se.hh options-se.cc
+ options-se.hh options-se.cc \
+ uninstall_list-se.hh uninstall_list-se.cc
+
BUILT_SOURCES = $(DISTCLEANFILES)
MAINTAINERCLEANFILES = Makefile.in
@@ -26,7 +28,8 @@ paludis_dep_list_include_HEADERS = \
dep_list-fwd.hh \
uninstall_list-sr.hh \
range_rewriter.hh \
- options-se.hh
+ options-se.hh \
+ uninstall_list-se.hh
libpaludisdeplist_la_SOURCES = \
options.cc options.hh \
@@ -54,7 +57,8 @@ EXTRA_DIST = \
range_rewriter_TEST.cc \
dep_list.sr dep_list-sr.hh dep_list-sr.cc \
uninstall_list.sr uninstall_list-sr.hh uninstall_list-sr.cc \
- options.se options-se.hh options-se.cc
+ options.se options-se.hh options-se.cc \
+ uninstall_list.se uninstall_list-se.hh uninstall_list-se.cc
TESTS = \
dep_list_TEST \
@@ -133,6 +137,12 @@ uninstall_list-sr.hh : uninstall_list.sr $(top_srcdir)/misc/make_sr.bash
uninstall_list-sr.cc : uninstall_list.sr $(top_srcdir)/misc/make_sr.bash
if ! $(top_srcdir)/misc/make_sr.bash --source $(srcdir)/uninstall_list.sr > $@ ; then rm -f $@ ; exit 1 ; fi
+uninstall_list-se.hh : uninstall_list.se $(top_srcdir)/misc/make_se.bash
+ if ! $(top_srcdir)/misc/make_se.bash --header $(srcdir)/uninstall_list.se > $@ ; then rm -f $@ ; exit 1 ; fi
+
+uninstall_list-se.cc : uninstall_list.se $(top_srcdir)/misc/make_se.bash
+ if ! $(top_srcdir)/misc/make_se.bash --source $(srcdir)/uninstall_list.se > $@ ; then rm -f $@ ; exit 1 ; fi
+
options-se.hh : options.se $(top_srcdir)/misc/make_se.bash
if ! $(top_srcdir)/misc/make_se.bash --header $(srcdir)/options.se > $@ ; then rm -f $@ ; exit 1 ; fi
diff --git a/paludis/dep_list/uninstall_list.cc b/paludis/dep_list/uninstall_list.cc
index d52f644..8208a4a 100644
--- a/paludis/dep_list/uninstall_list.cc
+++ b/paludis/dep_list/uninstall_list.cc
@@ -17,11 +17,7 @@
* Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "uninstall_list.hh"
-
-using namespace paludis;
-
-#include <paludis/dep_list/uninstall_list-sr.cc>
+#include <paludis/dep_list/uninstall_list.hh>
#include <paludis/dep_list/condition_tracker.hh>
#include <paludis/environment.hh>
#include <paludis/util/join.hh>
@@ -31,6 +27,7 @@ using namespace paludis;
#include <paludis/util/set.hh>
#include <paludis/util/set-impl.hh>
#include <paludis/util/private_implementation_pattern-impl.hh>
+#include <paludis/util/make_shared_ptr.hh>
#include <paludis/hashed_containers.hh>
#include <paludis/match_package.hh>
#include <paludis/package_database.hh>
@@ -43,6 +40,11 @@ using namespace paludis;
#include <list>
#include <algorithm>
+using namespace paludis;
+
+#include <paludis/dep_list/uninstall_list-se.cc>
+#include <paludis/dep_list/uninstall_list-sr.cc>
+
typedef MakeHashedMap<tr1::shared_ptr<const PackageID>, tr1::shared_ptr<const DepListEntryTags> >::Type DepCollectorCache;
template class Set<tr1::shared_ptr<DepTag> >;
@@ -97,6 +99,13 @@ UninstallList::~UninstallList()
void
UninstallList::add(const tr1::shared_ptr<const PackageID> & e, tr1::shared_ptr<DepTag> t)
{
+ real_add(e, t, false);
+}
+
+void
+UninstallList::real_add(const tr1::shared_ptr<const PackageID> & e, tr1::shared_ptr<DepTag> t,
+ const bool error)
+{
std::list<UninstallListEntry>::iterator i;
if (_imp->uninstall_list.end() != ((i = std::find_if(_imp->uninstall_list.begin(),
_imp->uninstall_list.end(), MatchUninstallListEntry(e)))))
@@ -109,10 +118,17 @@ UninstallList::add(const tr1::shared_ptr<const PackageID> & e, tr1::shared_ptr<D
Context context("When adding '" + stringify(*e) + "' to the uninstall list:");
- add_package(e, t);
+ if ((! error) || (! e->virtual_for_key()))
+ add_package(e, t, error ? ulk_required : (e->virtual_for_key() ? ulk_virtual : ulk_package));
- if (_imp->options.with_dependencies)
- add_dependencies(*e);
+ if (! error)
+ {
+ /* don't recurse errors, it gets horrid */
+ if (_imp->options.with_dependencies_included)
+ add_dependencies(*e, false);
+ else if (_imp->options.with_dependencies_as_errors)
+ add_dependencies(*e, true);
+ }
move_package_to_end(e);
@@ -147,7 +163,7 @@ UninstallList::add_unused()
PackageIDSetComparator());
for (PackageIDSet::Iterator i(unused->begin()), i_end(unused->end()) ; i != i_end ; ++i)
- add_package(*i, tr1::shared_ptr<DepTag>());
+ add_package(*i, tr1::shared_ptr<DepTag>(), (*i)->virtual_for_key() ? ulk_virtual : ulk_package);
}
UninstallList::Iterator
@@ -164,19 +180,23 @@ UninstallList::end() const
UninstallListOptions::UninstallListOptions() :
with_unused_dependencies(false),
- with_dependencies(false)
+ with_dependencies_included(false),
+ with_dependencies_as_errors(false)
{
}
void
-UninstallList::add_package(const tr1::shared_ptr<const PackageID> & e, tr1::shared_ptr<DepTag> t)
+UninstallList::add_package(const tr1::shared_ptr<const PackageID> & e, tr1::shared_ptr<DepTag> t,
+ const UninstallListEntryKind k)
{
Context context("When adding package '" + stringify(*e) + "' to the uninstall list:");
std::list<UninstallListEntry>::iterator i(_imp->uninstall_list.insert(
- _imp->uninstall_list.end(), UninstallListEntry(
- e, e->virtual_for_key(), tr1::shared_ptr<Set<tr1::shared_ptr<DepTag> > >(
- new Set<tr1::shared_ptr<DepTag> >))));
+ _imp->uninstall_list.end(), UninstallListEntry(UninstallListEntry::create()
+ .package_id(e)
+ .tags(make_shared_ptr(new Set<tr1::shared_ptr<DepTag> >))
+ .kind(k))));
+
if (t)
i->tags->insert(t);
}
@@ -334,11 +354,13 @@ UninstallList::add_unused_dependencies()
{
added = false;
- /* find packages that're depped upon by anything in our uninstall list */
+ /* find packages that're depped upon by anything in our uninstall list, excluding error
+ * packages */
tr1::shared_ptr<PackageIDSet> uninstall_list_targets(new PackageIDSet);
for (std::list<UninstallListEntry>::const_iterator i(_imp->uninstall_list.begin()),
i_end(_imp->uninstall_list.end()) ; i != i_end ; ++i)
- uninstall_list_targets->insert(i->package_id);
+ if (i->kind == ulk_package || i->kind == ulk_virtual)
+ uninstall_list_targets->insert(i->package_id);
tr1::shared_ptr<const PackageIDSet> depped_upon_list(collect_depped_upon(uninstall_list_targets));
@@ -375,14 +397,14 @@ UninstallList::add_unused_dependencies()
_imp->uninstall_list.end(), MatchUninstallListEntry(*i)))
continue;
- add_package(*i, tr1::shared_ptr<DepTag>());
+ add_package(*i, tr1::shared_ptr<DepTag>(), (*i)->virtual_for_key() ? ulk_virtual : ulk_package);
added = true;
}
}
}
void
-UninstallList::add_dependencies(const PackageID & e)
+UninstallList::add_dependencies(const PackageID & e, const bool error)
{
Context context("When adding things that depend upon '" + stringify(e) + "':");
@@ -422,8 +444,8 @@ UninstallList::add_dependencies(const PackageID & e)
"' because it depends upon '" << e << "'";
logged = true;
}
- add(*i, tr1::shared_ptr<DependencyDepTag>(
- new DependencyDepTag(tag->package_id(), *tag->dependency(), tag->conditions())));
+ real_add(*i, tr1::shared_ptr<DependencyDepTag>(
+ new DependencyDepTag(tag->package_id(), *tag->dependency(), tag->conditions())), error);
}
}
@@ -447,3 +469,33 @@ UninstallList::collect_world() const
return result;
}
+namespace
+{
+ struct IsError
+ {
+ bool operator() (const UninstallListEntry & e) const
+ {
+ switch (e.kind)
+ {
+ case ulk_virtual:
+ case ulk_package:
+ return false;
+
+ case ulk_required:
+ return true;
+
+ case last_ulk:
+ ;
+ }
+
+ throw InternalError(PALUDIS_HERE, "Bad e.kind");
+ }
+ };
+}
+
+bool
+UninstallList::has_errors() const
+{
+ return end() != std::find_if(begin(), end(), IsError());
+}
+
diff --git a/paludis/dep_list/uninstall_list.hh b/paludis/dep_list/uninstall_list.hh
index 8012b6e..c5457d2 100644
--- a/paludis/dep_list/uninstall_list.hh
+++ b/paludis/dep_list/uninstall_list.hh
@@ -30,6 +30,8 @@
namespace paludis
{
+
+#include <paludis/dep_list/uninstall_list-se.hh>
#include <paludis/dep_list/uninstall_list-sr.hh>
class Environment;
@@ -45,10 +47,13 @@ namespace paludis
public InstantiationPolicy<UninstallList, instantiation_method::NonCopyableTag>
{
private:
- void add_package(const tr1::shared_ptr<const PackageID> &, tr1::shared_ptr<DepTag>);
+ void add_package(const tr1::shared_ptr<const PackageID> &, tr1::shared_ptr<DepTag>,
+ const UninstallListEntryKind k);
+ void real_add(const tr1::shared_ptr<const PackageID> &,
+ tr1::shared_ptr<DepTag>, const bool);
void move_package_to_end(const tr1::shared_ptr<const PackageID> &);
void add_unused_dependencies();
- void add_dependencies(const PackageID &);
+ void add_dependencies(const PackageID &, const bool);
tr1::shared_ptr<const PackageIDSet> collect_depped_upon(
const tr1::shared_ptr<const PackageIDSet> targets) const;
@@ -82,6 +87,11 @@ namespace paludis
*/
void add_unused();
+ /**
+ * Whether we have any errors.
+ */
+ bool has_errors() const;
+
///\name Iterate over our items to remove
///\{
diff --git a/paludis/dep_list/uninstall_list.se b/paludis/dep_list/uninstall_list.se
new file mode 100644
index 0000000..b201c6e
--- /dev/null
+++ b/paludis/dep_list/uninstall_list.se
@@ -0,0 +1,20 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et ft=sh :
+
+make_enum_UninstallListEntryKind()
+{
+ prefix ulk
+
+ key ulk_package "A package to be uninstalled"
+ key ulk_required "A package that is still required"
+ key ulk_virtual "A virtual"
+
+ doxygen_comment <<"END"
+ /**
+ * Kind of an UninstallListEntry.
+ *
+ * \ingroup grpuninstalllist
+ */
+END
+}
+
diff --git a/paludis/dep_list/uninstall_list.sr b/paludis/dep_list/uninstall_list.sr
index 83924cb..1b20a8f 100644
--- a/paludis/dep_list/uninstall_list.sr
+++ b/paludis/dep_list/uninstall_list.sr
@@ -6,7 +6,8 @@ make_class_UninstallListOptions()
visible
key with_unused_dependencies bool
- key with_dependencies bool
+ key with_dependencies_included bool
+ key with_dependencies_as_errors bool
extra_constructors <<END
UninstallListOptions();
@@ -30,8 +31,8 @@ make_class_UninstallListEntry()
visible
key package_id "tr1::shared_ptr<const PackageID>"
- key skip_uninstall bool
key tags "tr1::shared_ptr<Set<tr1::shared_ptr<DepTag> > >"
+ key kind UninstallListEntryKind
allow_named_args
diff --git a/paludis/dep_list/uninstall_list_TEST.cc b/paludis/dep_list/uninstall_list_TEST.cc
index 4773583..2436240 100644
--- a/paludis/dep_list/uninstall_list_TEST.cc
+++ b/paludis/dep_list/uninstall_list_TEST.cc
@@ -219,7 +219,8 @@ namespace test_cases
{
return UninstallListOptions::create()
.with_unused_dependencies(true)
- .with_dependencies(false);
+ .with_dependencies_included(false)
+ .with_dependencies_as_errors(false);
}
} uninstall_list_with_unused_deps_test;
@@ -251,7 +252,8 @@ namespace test_cases
{
return UninstallListOptions::create()
.with_unused_dependencies(true)
- .with_dependencies(false);
+ .with_dependencies_included(false)
+ .with_dependencies_as_errors(false);
}
} uninstall_list_with_unused_deps_recursive_test;
@@ -283,7 +285,8 @@ namespace test_cases
{
return UninstallListOptions::create()
.with_unused_dependencies(true)
- .with_dependencies(false);
+ .with_dependencies_included(false)
+ .with_dependencies_as_errors(false);
}
} uninstall_list_with_unused_deps_with_used_test;
@@ -319,7 +322,8 @@ namespace test_cases
{
return UninstallListOptions::create()
.with_unused_dependencies(true)
- .with_dependencies(false);
+ .with_dependencies_as_errors(false)
+ .with_dependencies_included(false);
}
} uninstall_list_with_unused_deps_with_cross_used_test;
@@ -358,7 +362,8 @@ namespace test_cases
{
return UninstallListOptions::create()
.with_unused_dependencies(true)
- .with_dependencies(false);
+ .with_dependencies_included(false)
+ .with_dependencies_as_errors(false);
}
} uninstall_list_with_unused_deps_world_test;
@@ -399,7 +404,8 @@ namespace test_cases
{
return UninstallListOptions::create()
.with_unused_dependencies(true)
- .with_dependencies(false);
+ .with_dependencies_included(false)
+ .with_dependencies_as_errors(false);
}
} uninstall_list_with_unused_deps_world_target_test;
}
diff --git a/paludis/tasks/report_task.cc b/paludis/tasks/report_task.cc
index c8713df..4942111 100644
--- a/paludis/tasks/report_task.cc
+++ b/paludis/tasks/report_task.cc
@@ -153,7 +153,7 @@ ReportTask::execute()
std::set<tr1::shared_ptr<const PackageID>, PackageIDSetComparator> unused;
for (UninstallList::Iterator i(unused_list.begin()), i_end(unused_list.end());
i != i_end ; ++i)
- if (! i->skip_uninstall)
+ if (i->kind != ulk_virtual)
unused.insert(i->package_id);
for (PackageDatabase::RepositoryIterator r(e->package_database()->begin_repositories()),
diff --git a/paludis/tasks/uninstall_task.cc b/paludis/tasks/uninstall_task.cc
index 1cf45da..8ca01bc 100644
--- a/paludis/tasks/uninstall_task.cc
+++ b/paludis/tasks/uninstall_task.cc
@@ -25,6 +25,7 @@
#include <paludis/util/visitor-impl.hh>
#include <paludis/util/private_implementation_pattern-impl.hh>
#include <paludis/util/stringify.hh>
+#include <paludis/util/tr1_functional.hh>
#include <paludis/util/sequence.hh>
#include <paludis/query.hh>
#include <paludis/package_database.hh>
@@ -36,9 +37,41 @@
#include <map>
#include <set>
#include <list>
+#include <algorithm>
+#include <functional>
using namespace paludis;
+AmbiguousUnmergeTargetError::AmbiguousUnmergeTargetError(const std::string & t,
+ const tr1::shared_ptr<const PackageIDSequence> m) throw () :
+ Exception("Ambiguous unmerge target '" + t + "'"),
+ _t(t),
+ _p(m)
+{
+}
+
+AmbiguousUnmergeTargetError::~AmbiguousUnmergeTargetError() throw ()
+{
+}
+
+AmbiguousUnmergeTargetError::Iterator
+AmbiguousUnmergeTargetError::begin() const
+{
+ return Iterator(_p->begin());
+}
+
+AmbiguousUnmergeTargetError::Iterator
+AmbiguousUnmergeTargetError::end() const
+{
+ return Iterator(_p->end());
+}
+
+std::string
+AmbiguousUnmergeTargetError::target() const
+{
+ return _t;
+}
+
namespace paludis
{
template<>
@@ -56,6 +89,7 @@ namespace paludis
bool with_unused_dependencies;
bool with_dependencies;
bool unused;
+ bool check_safety;
bool had_set_targets;
bool had_package_targets;
@@ -69,6 +103,7 @@ namespace paludis
with_unused_dependencies(false),
with_dependencies(false),
unused(false),
+ check_safety(false),
had_set_targets(false),
had_package_targets(false)
{
@@ -104,6 +139,12 @@ UninstallTask::set_preserve_world(const bool v)
}
void
+UninstallTask::set_check_safety(const bool v)
+{
+ _imp->check_safety = v;
+}
+
+void
UninstallTask::add_target(const std::string & target)
{
Context context("When adding uninstall target '" + target + "':");
@@ -186,13 +227,16 @@ UninstallTask::add_unused()
void
UninstallTask::execute()
{
+ using namespace tr1::placeholders;
+
Context context("When executing uninstall task:");
on_build_unmergelist_pre();
UninstallList list(_imp->env, UninstallListOptions::create()
- .with_dependencies(_imp->with_dependencies)
- .with_unused_dependencies(_imp->with_unused_dependencies));
+ .with_unused_dependencies(_imp->with_unused_dependencies)
+ .with_dependencies_included(_imp->with_dependencies)
+ .with_dependencies_as_errors(_imp->check_safety));
if (_imp->unused)
list.add_unused();
@@ -242,6 +286,12 @@ UninstallTask::execute()
if (_imp->pretend)
return;
+ if (list.has_errors())
+ {
+ on_not_continuing_due_to_errors();
+ return;
+ }
+
if (_imp->preserve_world)
on_preserve_world();
else
@@ -253,7 +303,7 @@ UninstallTask::execute()
std::map<QualifiedPackageName, std::set<VersionSpec> > being_removed;
for (UninstallList::Iterator i(list.begin()), i_end(list.end()) ; i != i_end ; ++i)
- if (! i->skip_uninstall)
+ if (i->kind != ulk_virtual)
being_removed[i->package_id->name()].insert(i->package_id->version());
for (std::map<QualifiedPackageName, std::set<VersionSpec> >::const_iterator
@@ -293,12 +343,12 @@ UninstallTask::execute()
int x(0), y(0);
for (UninstallList::Iterator i(list.begin()), i_end(list.end()) ; i != i_end ; ++i)
- if (! i->skip_uninstall)
+ if (i->kind != ulk_virtual)
++y;
for (UninstallList::Iterator i(list.begin()), i_end(list.end()) ; i != i_end ; ++i)
{
- if (i->skip_uninstall)
+ if (i->kind == ulk_virtual)
continue;
++x;
@@ -338,10 +388,6 @@ UninstallTask::execute()
throw PackageUninstallActionError("Uninstall aborted by hook");
}
-AmbiguousUnmergeTargetError::~AmbiguousUnmergeTargetError() throw ()
-{
-}
-
void
UninstallTask::set_with_unused_dependencies(const bool value)
{
diff --git a/paludis/tasks/uninstall_task.hh b/paludis/tasks/uninstall_task.hh
index a5abbb1..0a97975 100644
--- a/paludis/tasks/uninstall_task.hh
+++ b/paludis/tasks/uninstall_task.hh
@@ -24,7 +24,6 @@
#include <paludis/package_id.hh>
#include <paludis/util/instantiation_policy.hh>
#include <paludis/util/private_implementation_pattern.hh>
-#include <paludis/util/sequence.hh>
#include <libwrapiter/libwrapiter_forward_iterator.hh>
namespace paludis
@@ -49,12 +48,7 @@ namespace paludis
///\{
AmbiguousUnmergeTargetError(const std::string & our_target,
- const tr1::shared_ptr<const PackageIDSequence> matches) throw () :
- Exception("Ambiguous unmerge target '" + our_target + "'"),
- _t(our_target),
- _p(matches)
- {
- }
+ const tr1::shared_ptr<const PackageIDSequence> matches) throw ();
~AmbiguousUnmergeTargetError() throw ();
@@ -63,27 +57,16 @@ namespace paludis
///\name Iterate over our entries
///\{
- typedef PackageIDSequence::Iterator Iterator;
-
- Iterator begin() const
- {
- return _p->begin();
- }
-
- Iterator end() const
- {
- return _p->end();
- }
+ typedef libwrapiter::ForwardIterator<AmbiguousUnmergeTargetError, const tr1::shared_ptr<const PackageID> > Iterator;
+ Iterator begin() const;
+ Iterator end() const;
///\}
/**
* What was our target?
*/
- const std::string & target() const
- {
- return _t;
- }
+ std::string target() const;
};
/**
@@ -121,6 +104,7 @@ namespace paludis
void set_all_versions(const bool value);
void set_with_unused_dependencies(const bool value);
void set_with_dependencies(const bool value);
+ void set_check_safety(const bool value);
///\}
@@ -147,6 +131,8 @@ namespace paludis
virtual void on_uninstall_post(const UninstallListEntry &) = 0;
virtual void on_uninstall_all_post() = 0;
+ virtual void on_not_continuing_due_to_errors() = 0;
+
virtual void on_update_world_pre() = 0;
virtual void on_update_world(const PackageDepSpec &) = 0;
virtual void on_update_world(const SetName &) = 0;
diff --git a/src/clients/paludis/command_line.cc b/src/clients/paludis/command_line.cc
index 8a1da58..38637a1 100644
--- a/src/clients/paludis/command_line.cc
+++ b/src/clients/paludis/command_line.cc
@@ -110,6 +110,8 @@ CommandLine::CommandLine() :
"Also uninstall packages that depend upon the target"),
a_all_versions(&uninstall_args, "all-versions", '\0',
"Uninstall all versions of a package"),
+ a_permit_unsafe_uninstalls(&uninstall_args, "permit-unsafe-uninstalls", '\0',
+ "Allow depended-upon packages to uninstalled"),
dl_args(this, "DepList behaviour",
"Modify dependency list generation behaviour. Use with caution."),
diff --git a/src/clients/paludis/command_line.hh b/src/clients/paludis/command_line.hh
index e1b9c82..d1abc4c 100644
--- a/src/clients/paludis/command_line.hh
+++ b/src/clients/paludis/command_line.hh
@@ -231,6 +231,9 @@ class CommandLine :
/// --all-versions
paludis::args::SwitchArg a_all_versions;
+ /// --permit-unsafe-uninstalls
+ paludis::args::SwitchArg a_permit_unsafe_uninstalls;
+
///\}
/// \name DepList behaviour arguments
diff --git a/src/clients/paludis/uninstall.cc b/src/clients/paludis/uninstall.cc
index e59672e..5c16226 100644
--- a/src/clients/paludis/uninstall.cc
+++ b/src/clients/paludis/uninstall.cc
@@ -45,13 +45,14 @@ namespace
public UninstallTask
{
private:
- int _count, _current_count;
+ int _count, _current_count, _error_count;
public:
OurUninstallTask(tr1::shared_ptr<Environment> e) :
UninstallTask(e.get()),
_count(0),
- _current_count(0)
+ _current_count(0),
+ _error_count(0)
{
}
@@ -73,21 +74,49 @@ namespace
virtual void on_display_unmerge_list_post()
{
- cout << endl << endl <<
- "Total: " << _count << (_count == 1 ? " package" : " packages") << endl;
+ cout << endl << endl;
+
+ cout << "Total: " << _count << (_count == 1 ? " package" : " packages");
+
+ if (_error_count)
+ {
+ cout << " and " << colour(cl_error, stringify(_error_count) + " errors") << endl;
+ cout << "Use either --" << CommandLine::get_instance()->a_with_dependencies.long_name()
+ << " or --" << CommandLine::get_instance()->a_permit_unsafe_uninstalls.long_name() << endl;
+ }
+ else
+ cout << endl;
}
virtual void on_display_unmerge_list_entry(const UninstallListEntry & d)
{
- if (d.skip_uninstall)
+ if (d.kind == ulk_virtual)
if (CommandLine::get_instance()->a_show_reasons.argument() != "full")
return;
- cout << "* " << colour(d.skip_uninstall ? cl_unimportant : cl_package_name, stringify(*d.package_id));
- ++_count;
+ switch (d.kind)
+ {
+ case ulk_package:
+ cout << "* " << colour(cl_package_name, stringify(*d.package_id));
+ ++_count;
+ break;
+
+ case ulk_virtual:
+ cout << "* " << colour(cl_unimportant, stringify(*d.package_id));
+ break;
+
+ case ulk_required:
+ cout << "* " << colour(cl_error, stringify(*d.package_id));
+ ++_error_count;
+ break;
+
+ case last_ulk:
+ break;
+ }
if ((CommandLine::get_instance()->a_show_reasons.argument() == "summary") ||
- (CommandLine::get_instance()->a_show_reasons.argument() == "full"))
+ (CommandLine::get_instance()->a_show_reasons.argument() == "full") ||
+ ulk_required == d.kind)
{
std::string deps;
unsigned count(0), max_count;
@@ -116,7 +145,9 @@ namespace
deps.append(stringify(count - max_count + 1) + " more, ");
deps.erase(deps.length() - 2);
- cout << " " << colour(d.skip_uninstall ? cl_unimportant : cl_tag,
+ if (d.kind == ulk_required)
+ cout << " requires";
+ cout << " " << colour(d.kind == ulk_virtual ? cl_unimportant : cl_tag,
"<" + deps + ">");
}
}
@@ -146,6 +177,11 @@ namespace
{
}
+ virtual void on_not_continuing_due_to_errors()
+ {
+ cout << endl << colour(cl_error, "Cannot continue with uninstall due to the errors indicated above") << endl << endl;
+ }
+
virtual void on_update_world_pre()
{
cout << endl << colour(cl_heading, "Updating world file") << endl << endl;
@@ -190,6 +226,7 @@ namespace
task.set_preserve_world(CommandLine::get_instance()->a_preserve_world.specified());
task.set_with_unused_dependencies(CommandLine::get_instance()->a_with_unused_dependencies.specified());
task.set_with_dependencies(CommandLine::get_instance()->a_with_dependencies.specified());
+ task.set_check_safety(! CommandLine::get_instance()->a_permit_unsafe_uninstalls.specified());
task.set_all_versions(CommandLine::get_instance()->a_all_versions.specified());
try
diff --git a/zsh-completion/_paludis b/zsh-completion/_paludis
index be3147d..edfeb10 100644
--- a/zsh-completion/_paludis
+++ b/zsh-completion/_paludis
@@ -37,6 +37,7 @@ _paludis() {
)
uninstall_args=(
"--with-unused-dependencies[Also uninstall any dependencies of the target that are no longer used]"
+ "--permit-unsafe-uninstalls[Permit depended-upon packages to be uninstalled]"
"--with-dependencies[Also uninstall packages that depend upon the target]"
"--all-versions[Uninstall all versions of a package]"
)