aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2010-03-10 10:24:20 +0000
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2010-03-10 10:24:20 +0000
commit59a47623de1a67d2d5c96e5159165cc516ff73c5 (patch)
tree6ad85932e219ba82a3827f83bc4a3fb56b012568
parent81633f02d9b43b010d82bb28759c49f3a7c0a601 (diff)
parenta1f50b15a22d07b7c56246a9c5173eb625560ab1 (diff)
downloadpaludis-59a47623de1a67d2d5c96e5159165cc516ff73c5.tar.gz
paludis-59a47623de1a67d2d5c96e5159165cc516ff73c5.tar.xz
Merge branch 'dependent-tracking'
-rw-r--r--paludis/resolver/constraint.cc7
-rw-r--r--paludis/resolver/decider.cc253
-rw-r--r--paludis/resolver/decider.hh23
-rw-r--r--paludis/resolver/orderer.cc9
-rw-r--r--paludis/resolver/reason-fwd.hh3
-rw-r--r--paludis/resolver/reason.cc44
-rw-r--r--paludis/resolver/reason.hh17
-rw-r--r--paludis/resolver/resolver_functions.hh21
-rw-r--r--paludis/resolver/resolver_test.cc59
-rw-r--r--paludis/resolver/resolver_test.hh17
-rw-r--r--src/clients/cave/cmd_display_resolution.cc5
-rw-r--r--src/clients/cave/cmd_resolve_cmdline.cc22
-rw-r--r--src/clients/cave/cmd_resolve_cmdline.hh7
-rw-r--r--src/clients/cave/cmd_resolve_dump.cc5
-rw-r--r--src/clients/cave/resolve_common.cc115
15 files changed, 595 insertions, 12 deletions
diff --git a/paludis/resolver/constraint.cc b/paludis/resolver/constraint.cc
index 79124f4..b89435a 100644
--- a/paludis/resolver/constraint.cc
+++ b/paludis/resolver/constraint.cc
@@ -1,7 +1,7 @@
/* vim: set sw=4 sts=4 et foldmethod=syntax : */
/*
- * Copyright (c) 2009 Ciaran McCreesh
+ * Copyright (c) 2009, 2010 Ciaran McCreesh
*
* This file is part of the Paludis package manager. Paludis is free software;
* you can redistribute it and/or modify it under the terms of the GNU General
@@ -168,6 +168,11 @@ namespace
{
return make_null_shared_ptr();
}
+
+ const std::tr1::shared_ptr<const PackageID> visit(const DependentReason &) const
+ {
+ return make_null_shared_ptr();
+ }
};
}
diff --git a/paludis/resolver/decider.cc b/paludis/resolver/decider.cc
index dd6b4f7..5074247 100644
--- a/paludis/resolver/decider.cc
+++ b/paludis/resolver/decider.cc
@@ -36,7 +36,9 @@
#include <paludis/util/make_named_values.hh>
#include <paludis/util/make_shared_ptr.hh>
#include <paludis/util/wrapped_forward_iterator.hh>
+#include <paludis/util/wrapped_output_iterator.hh>
#include <paludis/util/enum_iterator.hh>
+#include <paludis/util/indirect_iterator-impl.hh>
#include <paludis/environment.hh>
#include <paludis/notifier_callback.hh>
#include <paludis/repository.hh>
@@ -51,9 +53,11 @@
#include <paludis/slot_requirement.hh>
#include <paludis/choice.hh>
#include <paludis/action.hh>
+#include <paludis/elike_slot_requirement.hh>
#include <paludis/util/private_implementation_pattern-impl.hh>
+#include <algorithm>
#include <map>
#include <set>
@@ -135,6 +139,232 @@ Decider::_resolve_decide_with_dependencies()
}
}
+bool
+Decider::_resolve_dependents()
+{
+ Context context("When finding dependents:");
+
+ bool changed(false);
+ const std::pair<
+ std::tr1::shared_ptr<const PackageIDSequence>,
+ std::tr1::shared_ptr<const PackageIDSequence> > changing(_collect_changing());
+
+ if (changing.first->empty())
+ return false;
+
+ const std::tr1::shared_ptr<const PackageIDSequence> staying(_collect_staying(changing.first));
+
+ for (PackageIDSequence::ConstIterator s(staying->begin()), s_end(staying->end()) ;
+ s != s_end ; ++s)
+ {
+ _imp->env->trigger_notifier_callback(NotifierCallbackResolverStepEvent());
+
+ if (_allowed_to_break(*s))
+ continue;
+
+ const std::tr1::shared_ptr<const PackageIDSequence> dependent_upon(_dependent_upon(
+ *s, changing.first, changing.second));
+ if (dependent_upon->empty())
+ continue;
+
+ if (_remove_if_dependent(*s))
+ {
+ Resolvent resolvent(*s, dt_install_to_slash);
+
+ /* we've changed things if we've not already done anything for this resolvent */
+ if (_imp->resolutions_by_resolvent.end() == _imp->resolutions_by_resolvent.find(resolvent))
+ changed = true;
+
+ const std::tr1::shared_ptr<Resolution> resolution(_resolution_for_resolvent(resolvent, true));
+ const std::tr1::shared_ptr<const ConstraintSequence> constraints(_make_constraints_for_dependent(
+ resolvent, resolution, *s, dependent_upon));
+ for (ConstraintSequence::ConstIterator c(constraints->begin()), c_end(constraints->end()) ;
+ c != c_end ; ++c)
+ _apply_resolution_constraint(resolvent, resolution, *c);
+ }
+ else
+ {
+ throw InternalError(PALUDIS_HERE, "unsafe " + stringify(**s));
+ }
+ }
+
+ return changed;
+}
+
+const std::tr1::shared_ptr<ConstraintSequence>
+Decider::_make_constraints_for_dependent(
+ const Resolvent & resolvent,
+ const std::tr1::shared_ptr<const Resolution> & resolution,
+ const std::tr1::shared_ptr<const PackageID> & id,
+ const std::tr1::shared_ptr<const PackageIDSequence> & r) const
+{
+ return _imp->fns.get_constraints_for_dependent_fn()(resolvent, resolution, id, r);
+}
+
+namespace
+{
+ struct DependentChecker
+ {
+ const Environment * const env;
+ const std::tr1::shared_ptr<const PackageIDSequence> going_away;
+ const std::tr1::shared_ptr<const PackageIDSequence> newly_available;
+ const std::tr1::shared_ptr<PackageIDSequence> result;
+
+ DependentChecker(
+ const Environment * const e,
+ const std::tr1::shared_ptr<const PackageIDSequence> & g,
+ const std::tr1::shared_ptr<const PackageIDSequence> & n) :
+ env(e),
+ going_away(g),
+ newly_available(n),
+ result(new PackageIDSequence)
+ {
+ }
+
+ void visit(const DependencySpecTree::NodeType<NamedSetDepSpec>::Type & s)
+ {
+ const std::tr1::shared_ptr<const SetSpecTree> set(env->set(s.spec()->name()));
+ set->root()->accept(*this);
+ }
+
+ void visit(const DependencySpecTree::NodeType<PackageDepSpec>::Type & s)
+ {
+ for (PackageIDSequence::ConstIterator g(going_away->begin()), g_end(going_away->end()) ;
+ g != g_end ; ++g)
+ {
+ if (! match_package(*env, *s.spec(), **g, MatchPackageOptions()))
+ continue;
+
+ if (indirect_iterator(newly_available->end()) == std::find_if(
+ indirect_iterator(newly_available->begin()), indirect_iterator(newly_available->end()),
+ std::tr1::bind(&match_package, std::tr1::cref(*env), std::tr1::cref(*s.spec()),
+ std::tr1::placeholders::_1, MatchPackageOptions())))
+ result->push_back(*g);
+ }
+ }
+
+ void visit(const DependencySpecTree::NodeType<BlockDepSpec>::Type &)
+ {
+ }
+
+ void visit(const DependencySpecTree::NodeType<ConditionalDepSpec>::Type & s)
+ {
+ if (s.spec()->condition_met())
+ std::for_each(indirect_iterator(s.begin()), indirect_iterator(s.end()),
+ accept_visitor(*this));
+ }
+
+ void visit(const DependencySpecTree::NodeType<AnyDepSpec>::Type & s)
+ {
+ std::for_each(indirect_iterator(s.begin()), indirect_iterator(s.end()),
+ accept_visitor(*this));
+ }
+
+ void visit(const DependencySpecTree::NodeType<AllDepSpec>::Type & s)
+ {
+ std::for_each(indirect_iterator(s.begin()), indirect_iterator(s.end()),
+ accept_visitor(*this));
+ }
+
+ void visit(const DependencySpecTree::NodeType<DependenciesLabelsDepSpec>::Type &)
+ {
+ }
+ };
+}
+
+const std::tr1::shared_ptr<const PackageIDSequence>
+Decider::_dependent_upon(
+ const std::tr1::shared_ptr<const PackageID> & id,
+ const std::tr1::shared_ptr<const PackageIDSequence> & going_away,
+ const std::tr1::shared_ptr<const PackageIDSequence> & staying) const
+{
+ DependentChecker c(_imp->env, going_away, staying);
+ if (id->dependencies_key())
+ id->dependencies_key()->value()->root()->accept(c);
+ else
+ {
+ if (id->build_dependencies_key())
+ id->build_dependencies_key()->value()->root()->accept(c);
+ if (id->run_dependencies_key())
+ id->run_dependencies_key()->value()->root()->accept(c);
+ if (id->post_dependencies_key())
+ id->post_dependencies_key()->value()->root()->accept(c);
+ if (id->suggested_dependencies_key())
+ id->suggested_dependencies_key()->value()->root()->accept(c);
+ }
+
+ return c.result;
+}
+
+namespace
+{
+ struct ChangingCollector
+ {
+ std::tr1::shared_ptr<PackageIDSequence> going_away;
+ std::tr1::shared_ptr<PackageIDSequence> newly_available;
+
+ ChangingCollector() :
+ going_away(new PackageIDSequence),
+ newly_available(new PackageIDSequence)
+ {
+ }
+
+ void visit(const NothingNoChangeDecision &)
+ {
+ }
+
+ void visit(const ExistingNoChangeDecision &)
+ {
+ }
+
+ void visit(const RemoveDecision & d)
+ {
+ std::copy(d.ids()->begin(), d.ids()->end(), going_away->back_inserter());
+ }
+
+ void visit(const ChangesToMakeDecision &)
+ {
+ /* todo */
+ }
+
+ void visit(const UnableToMakeDecision &)
+ {
+ }
+ };
+}
+
+const std::pair<
+ std::tr1::shared_ptr<const PackageIDSequence>,
+ std::tr1::shared_ptr<const PackageIDSequence> >
+Decider::_collect_changing() const
+{
+ ChangingCollector c;
+
+ for (ResolutionsByResolventMap::const_iterator i(_imp->resolutions_by_resolvent.begin()),
+ i_end(_imp->resolutions_by_resolvent.end()) ;
+ i != i_end ; ++i)
+ if (i->second->decision())
+ i->second->decision()->accept(c);
+
+ return std::make_pair(c.going_away, c.newly_available);
+}
+
+const std::tr1::shared_ptr<const PackageIDSequence>
+Decider::_collect_staying(const std::tr1::shared_ptr<const PackageIDSequence> & going_away) const
+{
+ const std::tr1::shared_ptr<const PackageIDSequence> existing((*_imp->env)[selection::AllVersionsUnsorted(
+ generator::All() | filter::InstalledAtRoot(FSEntry("/")))]);
+
+ const std::tr1::shared_ptr<PackageIDSequence> result(new PackageIDSequence);
+ for (PackageIDSequence::ConstIterator x(existing->begin()), x_end(existing->end()) ;
+ x != x_end ; ++x)
+ if (indirect_iterator(going_away->end()) == std::find(indirect_iterator(going_away->begin()),
+ indirect_iterator(going_away->end()), **x))
+ result->push_back(*x);
+
+ return result;
+}
+
void
Decider::_resolve_destinations()
{
@@ -1357,6 +1587,18 @@ Decider::_allowed_to_remove(const std::tr1::shared_ptr<const PackageID> & id) co
return id->supports_action(SupportsActionTest<UninstallAction>()) && _imp->fns.allowed_to_remove_fn()(id);
}
+bool
+Decider::_allowed_to_break(const std::tr1::shared_ptr<const PackageID> & id) const
+{
+ return _imp->fns.allowed_to_break_fn()(id);
+}
+
+bool
+Decider::_remove_if_dependent(const std::tr1::shared_ptr<const PackageID> & id) const
+{
+ return _imp->fns.remove_if_dependent_fn()(id);
+}
+
const std::tr1::shared_ptr<const PackageIDSequence>
Decider::_installed_ids(const Resolvent & resolvent) const
{
@@ -1516,8 +1758,15 @@ Decider::add_target_with_reason(const PackageOrBlockDepSpec & spec, const std::t
void
Decider::resolve()
{
- _imp->env->trigger_notifier_callback(NotifierCallbackResolverStageEvent("Deciding"));
- _resolve_decide_with_dependencies();
+ while (true)
+ {
+ _imp->env->trigger_notifier_callback(NotifierCallbackResolverStageEvent("Deciding"));
+ _resolve_decide_with_dependencies();
+ _imp->env->trigger_notifier_callback(NotifierCallbackResolverStageEvent("Finding Dependents"));
+ if (! _resolve_dependents())
+ break;
+ }
+
_imp->env->trigger_notifier_callback(NotifierCallbackResolverStageEvent("Finding Destinations"));
_resolve_destinations();
}
diff --git a/paludis/resolver/decider.hh b/paludis/resolver/decider.hh
index 872b293..3a17b65 100644
--- a/paludis/resolver/decider.hh
+++ b/paludis/resolver/decider.hh
@@ -85,6 +85,12 @@ namespace paludis
const Resolvent & resolvent, const BlockDepSpec & dep,
const std::tr1::shared_ptr<const Reason> & reason) const;
+ const std::tr1::shared_ptr<ConstraintSequence> _make_constraints_for_dependent(
+ const Resolvent &,
+ const std::tr1::shared_ptr<const Resolution> & resolution,
+ const std::tr1::shared_ptr<const PackageID> &,
+ const std::tr1::shared_ptr<const PackageIDSequence> &) const;
+
void _apply_resolution_constraint(const Resolvent &,
const std::tr1::shared_ptr<Resolution> &,
const std::tr1::shared_ptr<const Constraint> &);
@@ -123,6 +129,7 @@ namespace paludis
const ChangesToMakeDecision &) const;
void _resolve_decide_with_dependencies();
+ bool _resolve_dependents() PALUDIS_ATTRIBUTE((warn_unused_result));
void _resolve_destinations();
const std::tr1::shared_ptr<Destination> _make_destination_for(
@@ -190,6 +197,22 @@ namespace paludis
bool _allowed_to_remove(const std::tr1::shared_ptr<const PackageID> &) const PALUDIS_ATTRIBUTE((warn_unused_result));
+ bool _allowed_to_break(const std::tr1::shared_ptr<const PackageID> &) const PALUDIS_ATTRIBUTE((warn_unused_result));
+
+ bool _remove_if_dependent(const std::tr1::shared_ptr<const PackageID> &) const PALUDIS_ATTRIBUTE((warn_unused_result));
+
+ const std::pair<
+ std::tr1::shared_ptr<const PackageIDSequence>,
+ std::tr1::shared_ptr<const PackageIDSequence> > _collect_changing() const PALUDIS_ATTRIBUTE((warn_unused_result));
+
+ const std::tr1::shared_ptr<const PackageIDSequence> _collect_staying(
+ const std::tr1::shared_ptr<const PackageIDSequence> &) const PALUDIS_ATTRIBUTE((warn_unused_result));
+
+ const std::tr1::shared_ptr<const PackageIDSequence> _dependent_upon(
+ const std::tr1::shared_ptr<const PackageID> &,
+ const std::tr1::shared_ptr<const PackageIDSequence> &,
+ const std::tr1::shared_ptr<const PackageIDSequence> &) const PALUDIS_ATTRIBUTE((warn_unused_result));
+
public:
Decider(const Environment * const,
const ResolverFunctions &,
diff --git a/paludis/resolver/orderer.cc b/paludis/resolver/orderer.cc
index daeb486..999b85e 100644
--- a/paludis/resolver/orderer.cc
+++ b/paludis/resolver/orderer.cc
@@ -482,6 +482,10 @@ namespace
}
}
}
+
+ void visit(const DependentReason &) const
+ {
+ }
};
struct DepArrowHandler
@@ -720,6 +724,11 @@ namespace
struct AlreadyMetDep
{
+ bool visit(const DependentReason &) const
+ {
+ return false;
+ }
+
bool visit(const PresetReason &) const
{
return false;
diff --git a/paludis/resolver/reason-fwd.hh b/paludis/resolver/reason-fwd.hh
index 14d0ae2..4fa50d7 100644
--- a/paludis/resolver/reason-fwd.hh
+++ b/paludis/resolver/reason-fwd.hh
@@ -1,7 +1,7 @@
/* vim: set sw=4 sts=4 et foldmethod=syntax : */
/*
- * Copyright (c) 2009 Ciaran McCreesh
+ * Copyright (c) 2009, 2010 Ciaran McCreesh
*
* This file is part of the Paludis package manager. Paludis is free software;
* you can redistribute it and/or modify it under the terms of the GNU General
@@ -31,6 +31,7 @@ namespace paludis
struct TargetReason;
struct PresetReason;
struct SetReason;
+ struct DependentReason;
}
}
diff --git a/paludis/resolver/reason.cc b/paludis/resolver/reason.cc
index 6191782..7499979 100644
--- a/paludis/resolver/reason.cc
+++ b/paludis/resolver/reason.cc
@@ -109,6 +109,43 @@ DependencyReason::serialise(Serialiser & s) const
namespace paludis
{
template <>
+ struct Implementation<DependentReason>
+ {
+ const std::tr1::shared_ptr<const PackageID> id_being_removed;
+
+ Implementation(const std::tr1::shared_ptr<const PackageID> & i) :
+ id_being_removed(i)
+ {
+ }
+ };
+}
+
+DependentReason::DependentReason(const std::tr1::shared_ptr<const PackageID> & i) :
+ PrivateImplementationPattern<DependentReason>(new Implementation<DependentReason>(i))
+{
+}
+
+DependentReason::~DependentReason()
+{
+}
+
+const std::tr1::shared_ptr<const PackageID>
+DependentReason::id_being_removed() const
+{
+ return _imp->id_being_removed;
+}
+
+void
+DependentReason::serialise(Serialiser & s) const
+{
+ s.object("DependencyReason")
+ .member(SerialiserFlags<serialise::might_be_null>(), "id_being_removed", id_being_removed())
+ ;
+}
+
+namespace paludis
+{
+ template <>
struct Implementation<PresetReason>
{
const std::string explanation;
@@ -233,11 +270,18 @@ Reason::deserialise(Deserialisation & d)
v.member<bool>("already_met"))
);
}
+ else if (d.class_name() == "DependentReason")
+ {
+ Deserialisator v(d, "DependentReason");
+ const std::tr1::shared_ptr<const PackageID> id_being_removed(v.member<std::tr1::shared_ptr<const PackageID> >("id_being_removed"));
+ return make_shared_ptr(new DependentReason(id_being_removed));
+ }
else
throw InternalError(PALUDIS_HERE, "unknown class '" + stringify(d.class_name()) + "'");
}
template class PrivateImplementationPattern<DependencyReason>;
+template class PrivateImplementationPattern<DependentReason>;
template class PrivateImplementationPattern<SetReason>;
template class PrivateImplementationPattern<PresetReason>;
diff --git a/paludis/resolver/reason.hh b/paludis/resolver/reason.hh
index a48e84e..8144e76 100644
--- a/paludis/resolver/reason.hh
+++ b/paludis/resolver/reason.hh
@@ -37,7 +37,7 @@ namespace paludis
{
class Reason :
public virtual DeclareAbstractAcceptMethods<Reason, MakeTypeList<
- TargetReason, DependencyReason, PresetReason, SetReason>::Type>
+ TargetReason, DependencyReason, DependentReason, PresetReason, SetReason>::Type>
{
public:
virtual ~Reason() = 0;
@@ -78,6 +78,20 @@ namespace paludis
virtual void serialise(Serialiser &) const;
};
+ class DependentReason :
+ private PrivateImplementationPattern<DependentReason>,
+ public Reason,
+ public ImplementAcceptMethods<Reason, DependentReason>
+ {
+ public:
+ DependentReason(const std::tr1::shared_ptr<const PackageID> & id);
+ ~DependentReason();
+
+ const std::tr1::shared_ptr<const PackageID> id_being_removed() const;
+
+ virtual void serialise(Serialiser &) const;
+ };
+
class PresetReason :
private PrivateImplementationPattern<PresetReason>,
public Reason,
@@ -114,6 +128,7 @@ namespace paludis
#ifdef PALUDIS_HAVE_EXTERN_TEMPLATE
extern template class PrivateImplementationPattern<resolver::DependencyReason>;
+ extern template class PrivateImplementationPattern<resolver::DependentReason>;
extern template class PrivateImplementationPattern<resolver::SetReason>;
#endif
diff --git a/paludis/resolver/resolver_functions.hh b/paludis/resolver/resolver_functions.hh
index e0028c3..8c6f525 100644
--- a/paludis/resolver/resolver_functions.hh
+++ b/paludis/resolver/resolver_functions.hh
@@ -40,16 +40,19 @@ namespace paludis
{
namespace n
{
+ struct allowed_to_break_fn;
struct allowed_to_remove_fn;
struct care_about_dep_fn;
struct confirm_fn;
struct find_repository_for_fn;
+ struct get_constraints_for_dependent_fn;
struct get_destination_types_for_fn;
struct get_initial_constraints_for_fn;
struct get_resolvents_for_fn;
struct get_use_existing_fn;
struct make_destination_filtered_generator_fn;
struct prefer_or_avoid_fn;
+ struct remove_if_dependent_fn;
struct take_dependency_fn;
}
@@ -57,6 +60,10 @@ namespace paludis
{
typedef std::tr1::function<bool (
const std::tr1::shared_ptr<const PackageID> &
+ )> AllowedToBreakFunction;
+
+ typedef std::tr1::function<bool (
+ const std::tr1::shared_ptr<const PackageID> &
)> AllowedToRemoveFunction;
typedef std::tr1::function<bool (
@@ -77,6 +84,13 @@ namespace paludis
const ChangesToMakeDecision &
)> FindRepositoryForFunction;
+ typedef std::tr1::function<std::tr1::shared_ptr<ConstraintSequence> (
+ const Resolvent &,
+ const std::tr1::shared_ptr<const Resolution> &,
+ const std::tr1::shared_ptr<const PackageID> &,
+ const std::tr1::shared_ptr<const PackageIDSequence> &
+ )> GetConstraintsForDependentFunction;
+
typedef std::tr1::function<DestinationTypes (
const PackageDepSpec &,
const std::tr1::shared_ptr<const PackageID> &,
@@ -109,6 +123,10 @@ namespace paludis
)> PreferOrAvoidFunction;
typedef std::tr1::function<bool (
+ const std::tr1::shared_ptr<const PackageID> &
+ )> RemoveIfDependentFunction;
+
+ typedef std::tr1::function<bool (
const Resolvent &,
const SanitisedDependency &,
const std::tr1::shared_ptr<const Reason> &
@@ -116,10 +134,12 @@ namespace paludis
struct ResolverFunctions
{
+ NamedValue<n::allowed_to_break_fn, AllowedToBreakFunction> allowed_to_break_fn;
NamedValue<n::allowed_to_remove_fn, AllowedToRemoveFunction> allowed_to_remove_fn;
NamedValue<n::care_about_dep_fn, CareAboutDepFunction> care_about_dep_fn;
NamedValue<n::confirm_fn, ConfirmFunction> confirm_fn;
NamedValue<n::find_repository_for_fn, FindRepositoryForFunction> find_repository_for_fn;
+ NamedValue<n::get_constraints_for_dependent_fn, GetConstraintsForDependentFunction> get_constraints_for_dependent_fn;
NamedValue<n::get_destination_types_for_fn, GetDestinationTypesForFunction> get_destination_types_for_fn;
NamedValue<n::get_initial_constraints_for_fn, GetInitialConstraintsFunction> get_initial_constraints_for_fn;
NamedValue<n::get_resolvents_for_fn, GetResolventsForFunction> get_resolvents_for_fn;
@@ -127,6 +147,7 @@ namespace paludis
NamedValue<n::make_destination_filtered_generator_fn,
MakeDestinationFilteredGeneratorFunction> make_destination_filtered_generator_fn;
NamedValue<n::prefer_or_avoid_fn, PreferOrAvoidFunction> prefer_or_avoid_fn;
+ NamedValue<n::remove_if_dependent_fn, RemoveIfDependentFunction> remove_if_dependent_fn;
NamedValue<n::take_dependency_fn, TakeDependencyFunction> take_dependency_fn;
};
}
diff --git a/paludis/resolver/resolver_test.cc b/paludis/resolver/resolver_test.cc
index d82eb95..010678d 100644
--- a/paludis/resolver/resolver_test.cc
+++ b/paludis/resolver/resolver_test.cc
@@ -31,6 +31,7 @@
#include <paludis/resolver/job.hh>
#include <paludis/resolver/jobs.hh>
#include <paludis/resolver/job_id.hh>
+#include <paludis/resolver/reason.hh>
#include <paludis/util/map.hh>
#include <paludis/util/make_shared_ptr.hh>
#include <paludis/util/sequence.hh>
@@ -46,6 +47,7 @@
#include <paludis/filter.hh>
#include <paludis/filtered_generator.hh>
#include <paludis/generator.hh>
+#include <paludis/elike_slot_requirement.hh>
#include <paludis/util/wrapped_forward_iterator-impl.hh>
#include <paludis/util/indirect_iterator-impl.hh>
@@ -246,6 +248,14 @@ paludis::resolver::resolver_test::find_repository_for_fn(
}
bool
+paludis::resolver::resolver_test::allowed_to_break_fn(
+ const std::tr1::shared_ptr<const QualifiedPackageNameSet> & s,
+ const std::tr1::shared_ptr<const PackageID> & i)
+{
+ return s->end() != s->find(i->name());
+}
+
+bool
paludis::resolver::resolver_test::allowed_to_remove_fn(
const std::tr1::shared_ptr<const QualifiedPackageNameSet> & s,
const std::tr1::shared_ptr<const PackageID> & i)
@@ -253,6 +263,14 @@ paludis::resolver::resolver_test::allowed_to_remove_fn(
return s->end() != s->find(i->name());
}
+bool
+paludis::resolver::resolver_test::remove_if_dependent_fn(
+ const std::tr1::shared_ptr<const QualifiedPackageNameSet> & s,
+ const std::tr1::shared_ptr<const PackageID> & i)
+{
+ return s->end() != s->find(i->name());
+}
+
Tribool
paludis::resolver::resolver_test::prefer_or_avoid_fn(
const std::tr1::shared_ptr<const Map<QualifiedPackageName, bool> > & s,
@@ -274,10 +292,46 @@ paludis::resolver::resolver_test::confirm_fn(
return true;
}
+const std::tr1::shared_ptr<ConstraintSequence>
+paludis::resolver::resolver_test::get_constraints_for_dependent_fn(
+ const Resolvent &,
+ const std::tr1::shared_ptr<const Resolution> &,
+ const std::tr1::shared_ptr<const PackageID> & id,
+ const std::tr1::shared_ptr<const PackageIDSequence> & ids)
+{
+ const std::tr1::shared_ptr<ConstraintSequence> result(new ConstraintSequence);
+
+ PartiallyMadePackageDepSpec partial_spec((PartiallyMadePackageDepSpecOptions()));
+ partial_spec.package(id->name());
+ if (id->slot_key())
+ partial_spec.slot_requirement(make_shared_ptr(new ELikeSlotExactRequirement(
+ id->slot_key()->value(), false)));
+ PackageDepSpec spec(partial_spec);
+
+ for (PackageIDSequence::ConstIterator i(ids->begin()), i_end(ids->end()) ;
+ i != i_end ; ++i)
+ {
+ const std::tr1::shared_ptr<DependentReason> reason(new DependentReason(*i));
+
+ result->push_back(make_shared_ptr(new Constraint(make_named_values<Constraint>(
+ value_for<n::destination_type>(dt_install_to_slash),
+ value_for<n::nothing_is_fine_too>(true),
+ value_for<n::reason>(reason),
+ value_for<n::spec>(BlockDepSpec("!" + stringify(spec), spec, false)),
+ value_for<n::untaken>(false),
+ value_for<n::use_existing>(ue_if_possible)
+ ))));
+ }
+
+ return result;
+}
+
ResolverTestCase::ResolverTestCase(const std::string & t, const std::string & s, const std::string & e,
const std::string & l) :
TestCase(s),
+ allowed_to_break_names(new QualifiedPackageNameSet),
allowed_to_remove_names(new QualifiedPackageNameSet),
+ remove_if_dependent_names(new QualifiedPackageNameSet),
prefer_or_avoid_names(new Map<QualifiedPackageName, bool>)
{
std::tr1::shared_ptr<Map<std::string, std::string> > keys(new Map<std::string, std::string>);
@@ -324,6 +378,8 @@ ResolverFunctions
ResolverTestCase::get_resolver_functions(InitialConstraints & initial_constraints)
{
return make_named_values<ResolverFunctions>(
+ value_for<n::allowed_to_break_fn>(std::tr1::bind(&allowed_to_break_fn,
+ allowed_to_break_names, std::tr1::placeholders::_1)),
value_for<n::allowed_to_remove_fn>(std::tr1::bind(&allowed_to_remove_fn,
allowed_to_remove_names, std::tr1::placeholders::_1)),
value_for<n::care_about_dep_fn>(&care_about_dep_fn),
@@ -331,6 +387,7 @@ ResolverTestCase::get_resolver_functions(InitialConstraints & initial_constraint
value_for<n::find_repository_for_fn>(std::tr1::bind(&find_repository_for_fn,
&env, std::tr1::placeholders::_1, std::tr1::placeholders::_2,
std::tr1::placeholders::_3)),
+ value_for<n::get_constraints_for_dependent_fn>(&get_constraints_for_dependent_fn),
value_for<n::get_destination_types_for_fn>(&get_destination_types_for_fn),
value_for<n::get_initial_constraints_for_fn>(
std::tr1::bind(&initial_constraints_for_fn, std::tr1::ref(initial_constraints),
@@ -340,6 +397,8 @@ ResolverTestCase::get_resolver_functions(InitialConstraints & initial_constraint
value_for<n::make_destination_filtered_generator_fn>(&make_destination_filtered_generator_fn),
value_for<n::prefer_or_avoid_fn>(std::tr1::bind(&prefer_or_avoid_fn,
prefer_or_avoid_names, std::tr1::placeholders::_1)),
+ value_for<n::remove_if_dependent_fn>(std::tr1::bind(&remove_if_dependent_fn,
+ remove_if_dependent_names, std::tr1::placeholders::_1)),
value_for<n::take_dependency_fn>(&take_dependency_fn)
);
}
diff --git a/paludis/resolver/resolver_test.hh b/paludis/resolver/resolver_test.hh
index 7e19693..65acbc3 100644
--- a/paludis/resolver/resolver_test.hh
+++ b/paludis/resolver/resolver_test.hh
@@ -63,6 +63,13 @@ namespace paludis
const InitialConstraints & initial_constraints,
const Resolvent & resolvent);
+ const std::tr1::shared_ptr<ConstraintSequence>
+ get_constraints_for_dependent_fn(
+ const Resolvent &,
+ const std::tr1::shared_ptr<const Resolution> &,
+ const std::tr1::shared_ptr<const PackageID> & id,
+ const std::tr1::shared_ptr<const PackageIDSequence> & ids);
+
std::tr1::shared_ptr<Resolvents> get_resolvents_for_fn(const PackageDepSpec & spec,
const std::tr1::shared_ptr<const SlotName> &,
const std::tr1::shared_ptr<const Reason> &);
@@ -91,10 +98,18 @@ namespace paludis
const std::tr1::shared_ptr<const PackageID> &,
const std::tr1::shared_ptr<const Reason> &);
+ bool allowed_to_break_fn(
+ const std::tr1::shared_ptr<const QualifiedPackageNameSet> &,
+ const std::tr1::shared_ptr<const PackageID> &);
+
bool allowed_to_remove_fn(
const std::tr1::shared_ptr<const QualifiedPackageNameSet> &,
const std::tr1::shared_ptr<const PackageID> &);
+ bool remove_if_dependent_fn(
+ const std::tr1::shared_ptr<const QualifiedPackageNameSet> &,
+ const std::tr1::shared_ptr<const PackageID> &);
+
Tribool prefer_or_avoid_fn(
const std::tr1::shared_ptr<const Map<QualifiedPackageName, bool> > &,
const QualifiedPackageName &);
@@ -109,7 +124,9 @@ namespace paludis
TestEnvironment env;
std::tr1::shared_ptr<Repository> repo, inst_repo;
std::tr1::shared_ptr<FakeInstalledRepository> fake_inst_repo;
+ std::tr1::shared_ptr<QualifiedPackageNameSet> allowed_to_break_names;
std::tr1::shared_ptr<QualifiedPackageNameSet> allowed_to_remove_names;
+ std::tr1::shared_ptr<QualifiedPackageNameSet> remove_if_dependent_names;
std::tr1::shared_ptr<Map<QualifiedPackageName, bool> > prefer_or_avoid_names;
ResolverTestCase(const std::string & group, const std::string & test_name, const std::string & eapi,
diff --git a/src/clients/cave/cmd_display_resolution.cc b/src/clients/cave/cmd_display_resolution.cc
index f486433..615af9f 100644
--- a/src/clients/cave/cmd_display_resolution.cc
+++ b/src/clients/cave/cmd_display_resolution.cc
@@ -195,6 +195,11 @@ namespace
}
}
+ std::pair<std::string, bool> visit(const DependentReason & r) const
+ {
+ return std::make_pair("dependent upon " + stringify(*r.id_being_removed()), true);
+ }
+
std::pair<std::string, bool> visit(const TargetReason &) const
{
return std::make_pair("target", true);
diff --git a/src/clients/cave/cmd_resolve_cmdline.cc b/src/clients/cave/cmd_resolve_cmdline.cc
index af0e31d..b95cc3e 100644
--- a/src/clients/cave/cmd_resolve_cmdline.cc
+++ b/src/clients/cave/cmd_resolve_cmdline.cc
@@ -66,14 +66,30 @@ ResolveCommandLineResolutionOptions::ResolveCommandLineResolutionOptions(args::A
a_permit_any_version(&g_resolution_options, "permit-any-version", 'a', "Permit installs of versions matching the supplied "
"specification even if those versions are worse than the best visible version in the slot. Use '*/*' "
"to allow all worse versions to be installed."),
-// a_permit_unsafe_uninstall(&g_resolution_options, "permit-unsafe-uninstall", 'u',
-// "Permit uninstalls matching the given specification even if the uninstall isn't known to be safe. Use "
-// "'*/*' to allow all unsafe uninstalls. Note that this does not imply --permit-uninstall."),
// a_purge(&g_resolution_options, "purge", 'P',
// "Purge packages matching the given specification, if they will no longer be used after "
// "a resolution. Use '*/*' to accept all purges, but note that by doing so you are putting "
// "a great deal of trust in package authors to get dependencies right."),
+ g_dependent_options(this, "Dependent Options", "Dependent options. A package is dependent if it "
+ "requires (or looks like it might require) a package which is being removed. By default, "
+ "dependent packages are treated as errors. These options specify a different behaviour."),
+ a_uninstalls_may_break(&g_resolution_options, "uninstalls-may-break", 'u',
+ "Permit uninstalls that might break packages matching the specified specification. May be "
+ "specified multiple times. Use '*/*' to allow all packages to be broken."),
+ a_remove_if_dependent(&g_resolution_options, "remove-if-dependent", 'r',
+ "Remove dependent packages that might be broken by other changes if those packages match "
+ "the specified specification. May be specified multiple times. Use '*/*' to remove all "
+ "dependent packages that might be broken, recursively. Does not imply --permit-uninstall, "
+ "which must also be specified."),
+ a_less_restrictive_remove_blockers(&g_resolution_options, "less-restrictive-remove-blockers", 'l',
+ "Use less restrictive blockers for packages matching the supplied specification if that "
+ "package is to be removed by --remove-if-dependent. May be specified multiple times. "
+ "Normally removing dependents is done by a pseudo-block in the form '!cat/pkg:slot'. If "
+ "matched by this option, the block will instead only block the installed dependent "
+ "package, so if reinstalling or upgrading the package will make it no longer be dependent "
+ "then this will be done instead."),
+
g_keep_options(this, "Reinstall Options", "Control whether installed packages are kept."),
a_keep_targets(&g_keep_options, "keep-targets", 'K',
"Select whether to keep target packages",
diff --git a/src/clients/cave/cmd_resolve_cmdline.hh b/src/clients/cave/cmd_resolve_cmdline.hh
index d0fd84e..de465a8 100644
--- a/src/clients/cave/cmd_resolve_cmdline.hh
+++ b/src/clients/cave/cmd_resolve_cmdline.hh
@@ -46,14 +46,17 @@ namespace paludis
args::StringSetArg a_permit_uninstall;
args::StringSetArg a_permit_downgrade;
args::StringSetArg a_permit_any_version;
-// args::StringSetArg a_permit_unsafe_uninstall;
// args::StringSetArg a_purge;
+ args::ArgsGroup g_dependent_options;
+ args::StringSetArg a_uninstalls_may_break;
+ args::StringSetArg a_remove_if_dependent;
+ args::StringSetArg a_less_restrictive_remove_blockers;
+
args::ArgsGroup g_keep_options;
args::EnumArg a_keep_targets;
args::EnumArg a_keep;
args::EnumArg a_reinstall_scm;
-// args::SwitchArg a_reinstall_for_removals;
args::StringSetArg a_with;
args::StringSetArg a_without;
diff --git a/src/clients/cave/cmd_resolve_dump.cc b/src/clients/cave/cmd_resolve_dump.cc
index 40f8fa3..caf5a80 100644
--- a/src/clients/cave/cmd_resolve_dump.cc
+++ b/src/clients/cave/cmd_resolve_dump.cc
@@ -156,6 +156,11 @@ namespace
str = "Set(" + stringify(r.set_name()) + " " + f.str + ")";
}
+ void visit(const DependentReason & r)
+ {
+ str = "Dependent(" + stringify(*r.id_being_removed()) + ")";
+ }
+
void visit(const DependencyReason & r)
{
std::stringstream s;
diff --git a/src/clients/cave/resolve_common.cc b/src/clients/cave/resolve_common.cc
index 3a7bac4..69c3423 100644
--- a/src/clients/cave/resolve_common.cc
+++ b/src/clients/cave/resolve_common.cc
@@ -38,6 +38,7 @@
#include <paludis/util/thread.hh>
#include <paludis/util/timestamp.hh>
#include <paludis/util/map.hh>
+#include <paludis/util/make_shared_copy.hh>
#include <paludis/args/do_help.hh>
#include <paludis/args/escape.hh>
#include <paludis/resolver/resolver.hh>
@@ -66,6 +67,7 @@
#include <paludis/serialise-impl.hh>
#include <paludis/selection_cache.hh>
#include <paludis/package_dep_spec_properties.hh>
+#include <paludis/elike_slot_requirement.hh>
#include <algorithm>
#include <iostream>
@@ -338,6 +340,11 @@ namespace
return common_target();
}
+ DestinationTypes visit(const DependentReason &) const
+ {
+ return common_target();
+ }
+
DestinationTypes visit(const DependencyReason & reason) const
{
DestinationTypes result;
@@ -510,6 +517,11 @@ namespace
return use_existing_from_cmdline(resolution_options.a_keep_targets, from_set);
}
+ UseExisting visit(const DependentReason &) const
+ {
+ return ue_if_possible;
+ }
+
UseExisting visit(const PresetReason &) const
{
return ue_if_possible;
@@ -695,6 +707,11 @@ namespace
return false;
}
+ bool visit(const DependentReason &) const
+ {
+ return false;
+ }
+
bool visit(const PresetReason &) const
{
return false;
@@ -1031,7 +1048,7 @@ namespace
throw InternalError(PALUDIS_HERE, "unhandled dt");
}
- bool allowed_to_remove_fn(
+ bool match_any(
const Environment * const env,
const PackageDepSpecList & list,
const std::tr1::shared_ptr<const PackageID> & i)
@@ -1044,6 +1061,30 @@ namespace
return false;
}
+ bool allowed_to_break_fn(
+ const Environment * const env,
+ const PackageDepSpecList & list,
+ const std::tr1::shared_ptr<const PackageID> & i)
+ {
+ return match_any(env, list, i);
+ }
+
+ bool allowed_to_remove_fn(
+ const Environment * const env,
+ const PackageDepSpecList & list,
+ const std::tr1::shared_ptr<const PackageID> & i)
+ {
+ return match_any(env, list, i);
+ }
+
+ bool remove_if_dependent_fn(
+ const Environment * const env,
+ const PackageDepSpecList & list,
+ const std::tr1::shared_ptr<const PackageID> & i)
+ {
+ return match_any(env, list, i);
+ }
+
bool prefer_or_avoid_one(const Environment * const env, const QualifiedPackageName & q, const std::string & s)
{
Context context("When working out whether we favour or avoid '" + stringify(q) + "' due to '" + s + "':");
@@ -1167,6 +1208,47 @@ namespace
));
}
+ const std::tr1::shared_ptr<ConstraintSequence> get_constraints_for_dependent_fn(
+ const Environment * const env,
+ const PackageDepSpecList & list,
+ const Resolvent &,
+ const std::tr1::shared_ptr<const Resolution> &,
+ const std::tr1::shared_ptr<const PackageID> & id,
+ const std::tr1::shared_ptr<const PackageIDSequence> & ids)
+ {
+ const std::tr1::shared_ptr<ConstraintSequence> result(new ConstraintSequence);
+
+ std::tr1::shared_ptr<PackageDepSpec> spec;
+ if (match_any(env, list, id))
+ spec = make_shared_copy(id->uniquely_identifying_spec());
+ else
+ {
+ PartiallyMadePackageDepSpec partial_spec((PartiallyMadePackageDepSpecOptions()));
+ partial_spec.package(id->name());
+ if (id->slot_key())
+ partial_spec.slot_requirement(make_shared_ptr(new ELikeSlotExactRequirement(
+ id->slot_key()->value(), false)));
+ spec = make_shared_ptr(new PackageDepSpec(partial_spec));
+ }
+
+ for (PackageIDSequence::ConstIterator i(ids->begin()), i_end(ids->end()) ;
+ i != i_end ; ++i)
+ {
+ const std::tr1::shared_ptr<DependentReason> reason(new DependentReason(*i));
+
+ result->push_back(make_shared_ptr(new Constraint(make_named_values<Constraint>(
+ value_for<n::destination_type>(dt_install_to_slash),
+ value_for<n::nothing_is_fine_too>(true),
+ value_for<n::reason>(reason),
+ value_for<n::spec>(BlockDepSpec("!" + stringify(*spec), *spec, false)),
+ value_for<n::untaken>(false),
+ value_for<n::use_existing>(ue_if_possible)
+ ))));
+ }
+
+ return result;
+ }
+
void ser_thread_func(StringListStream & ser_stream, const ResolverLists & resolution_lists)
{
Serialiser ser(ser_stream);
@@ -1397,7 +1479,7 @@ paludis::cave::resolve_common(
int retcode(0);
InitialConstraints initial_constraints;
- PackageDepSpecList allowed_to_remove_specs;
+ PackageDepSpecList allowed_to_remove_specs, allowed_to_break_specs, remove_if_dependent_specs, less_restrictive_remove_blockers_specs;
for (args::StringSetArg::ConstIterator i(resolution_options.a_permit_uninstall.begin_args()),
i_end(resolution_options.a_permit_uninstall.end_args()) ;
@@ -1405,6 +1487,24 @@ paludis::cave::resolve_common(
allowed_to_remove_specs.push_back(parse_user_package_dep_spec(*i, env.get(),
UserPackageDepSpecOptions() + updso_allow_wildcards));
+ for (args::StringSetArg::ConstIterator i(resolution_options.a_uninstalls_may_break.begin_args()),
+ i_end(resolution_options.a_uninstalls_may_break.end_args()) ;
+ i != i_end ; ++i)
+ allowed_to_break_specs.push_back(parse_user_package_dep_spec(*i, env.get(),
+ UserPackageDepSpecOptions() + updso_allow_wildcards));
+
+ for (args::StringSetArg::ConstIterator i(resolution_options.a_remove_if_dependent.begin_args()),
+ i_end(resolution_options.a_remove_if_dependent.end_args()) ;
+ i != i_end ; ++i)
+ remove_if_dependent_specs.push_back(parse_user_package_dep_spec(*i, env.get(),
+ UserPackageDepSpecOptions() + updso_allow_wildcards));
+
+ for (args::StringSetArg::ConstIterator i(resolution_options.a_less_restrictive_remove_blockers.begin_args()),
+ i_end(resolution_options.a_less_restrictive_remove_blockers.end_args()) ;
+ i != i_end ; ++i)
+ less_restrictive_remove_blockers_specs.push_back(parse_user_package_dep_spec(*i, env.get(),
+ UserPackageDepSpecOptions() + updso_allow_wildcards));
+
for (args::StringSetArg::ConstIterator i(resolution_options.a_preset.begin_args()),
i_end(resolution_options.a_preset.end_args()) ;
i != i_end ; ++i)
@@ -1435,6 +1535,10 @@ paludis::cave::resolve_common(
}
ResolverFunctions resolver_functions(make_named_values<ResolverFunctions>(
+ value_for<n::allowed_to_break_fn>(std::tr1::bind(&allowed_to_break_fn,
+ env.get(),
+ std::tr1::cref(allowed_to_break_specs),
+ std::tr1::placeholders::_1)),
value_for<n::allowed_to_remove_fn>(std::tr1::bind(&allowed_to_remove_fn,
env.get(),
std::tr1::cref(allowed_to_remove_specs),
@@ -1448,6 +1552,9 @@ paludis::cave::resolve_common(
value_for<n::find_repository_for_fn>(std::tr1::bind(&find_repository_for_fn,
env.get(), std::tr1::cref(resolution_options), std::tr1::placeholders::_1, std::tr1::placeholders::_2,
std::tr1::placeholders::_3)),
+ value_for<n::get_constraints_for_dependent_fn>(std::tr1::bind(&get_constraints_for_dependent_fn,
+ env.get(), std::tr1::cref(less_restrictive_remove_blockers_specs), std::tr1::placeholders::_1,
+ std::tr1::placeholders::_2, std::tr1::placeholders::_3, std::tr1::placeholders::_4)),
value_for<n::get_destination_types_for_fn>(std::tr1::bind(&get_destination_types_for_fn,
env.get(), std::tr1::cref(resolution_options), std::tr1::placeholders::_1, std::tr1::placeholders::_2,
std::tr1::placeholders::_3)),
@@ -1464,6 +1571,10 @@ paludis::cave::resolve_common(
value_for<n::prefer_or_avoid_fn>(std::tr1::bind(&prefer_or_avoid_fn,
env.get(), std::tr1::cref(resolution_options),
std::tr1::placeholders::_1)),
+ value_for<n::remove_if_dependent_fn>(std::tr1::bind(&remove_if_dependent_fn,
+ env.get(),
+ std::tr1::cref(remove_if_dependent_specs),
+ std::tr1::placeholders::_1)),
value_for<n::take_dependency_fn>(std::tr1::bind(&take_dependency_fn, env.get(),
std::tr1::cref(resolution_options), std::tr1::placeholders::_1, std::tr1::placeholders::_2, std::tr1::placeholders::_3))