aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2007-11-05 12:58:38 +0000
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2007-11-05 12:58:38 +0000
commitd52731e02a65fcddf6fcb788a9d6ea21505332a4 (patch)
tree65e7435de2f4d499a95b4895c128fbb342752ffa
parent6086e49a1d56a1d67e7318005a7bfb40366411b0 (diff)
downloadpaludis-d52731e02a65fcddf6fcb788a9d6ea21505332a4.tar.gz
paludis-d52731e02a65fcddf6fcb788a9d6ea21505332a4.tar.xz
--continue-on-failure if-independent. Fixes: ticket:366
-rw-r--r--NEWS2
-rw-r--r--paludis/args/install_args_group.cc13
-rw-r--r--paludis/args/install_args_group.hh2
-rw-r--r--paludis/handled_information-fwd.hh1
-rw-r--r--paludis/handled_information.cc30
-rw-r--r--paludis/handled_information.hh31
-rw-r--r--paludis/install_task.cc237
-rw-r--r--paludis/install_task.hh4
-rw-r--r--paludis/install_task.se2
-rw-r--r--src/clients/paludis/Makefile.am6
-rw-r--r--src/output/console_install_task.cc20
-rw-r--r--src/output/console_install_task.hh3
12 files changed, 342 insertions, 9 deletions
diff --git a/NEWS b/NEWS
index afc08eb..e877bc3 100644
--- a/NEWS
+++ b/NEWS
@@ -14,6 +14,8 @@ trunk/:
* New, much more flexible, faster inquisitio.
+ * paludis --continue-on-failure if-independent implemented.
+
* Bug fixes: --dl-deps-default works again. More
robustness/compilance improvements for reconcilio, including
proper handling of ELF files that use the non-native byte order.
diff --git a/paludis/args/install_args_group.cc b/paludis/args/install_args_group.cc
index 01f8ea6..b55a2a0 100644
--- a/paludis/args/install_args_group.cc
+++ b/paludis/args/install_args_group.cc
@@ -53,11 +53,12 @@ InstallArgsGroup::InstallArgsGroup(ArgsHandler * h, const std::string & our_name
("changed", "Show for new and changed flags")
("all", "Show for all flags"),
"none"),
- a_continue_on_faillure(this, "continue-on-failure", '\0', "Whether to continue after a fetch or install error",
+ a_continue_on_failure(this, "continue-on-failure", '\0', "Whether to continue after a fetch or install error",
args::EnumArg::EnumArgOptions
("if-fetch-only", "If fetching only")
("never", "Never")
("if-satisfied", "If remaining packages' dependencies are satisfied")
+ ("if-independent", "If independent of failed and skipped packages")
("always", "Always (UNSAFE)"),
"if-fetch-only")
{
@@ -114,13 +115,15 @@ InstallArgsGroup::populate_install_task(const Environment *, InstallTask & task)
task.set_debug_mode(a_debug_build.option());
task.set_checks_mode(a_checks.option());
- if (a_continue_on_faillure.argument() == "if-fetch-only")
+ if (a_continue_on_failure.argument() == "if-fetch-only")
task.set_continue_on_failure(itcof_if_fetch_only);
- else if (a_continue_on_faillure.argument() == "never")
+ else if (a_continue_on_failure.argument() == "never")
task.set_continue_on_failure(itcof_never);
- else if (a_continue_on_faillure.argument() == "if-satisfied")
+ else if (a_continue_on_failure.argument() == "if-satisfied")
task.set_continue_on_failure(itcof_if_satisfied);
- else if (a_continue_on_faillure.argument() == "always")
+ else if (a_continue_on_failure.argument() == "if-independent")
+ task.set_continue_on_failure(itcof_if_independent);
+ else if (a_continue_on_failure.argument() == "always")
task.set_continue_on_failure(itcof_always);
else
throw args::DoHelp("bad value for --continue-on-failure");
diff --git a/paludis/args/install_args_group.hh b/paludis/args/install_args_group.hh
index 82effbb..7f6a6f4 100644
--- a/paludis/args/install_args_group.hh
+++ b/paludis/args/install_args_group.hh
@@ -96,7 +96,7 @@ namespace paludis
paludis::args::EnumArg a_show_use_descriptions;
/// --continue-on-failure
- paludis::args::EnumArg a_continue_on_faillure;
+ paludis::args::EnumArg a_continue_on_failure;
/// }
diff --git a/paludis/handled_information-fwd.hh b/paludis/handled_information-fwd.hh
index 751186f..f8ccc3d 100644
--- a/paludis/handled_information-fwd.hh
+++ b/paludis/handled_information-fwd.hh
@@ -31,6 +31,7 @@ namespace paludis
class DepListEntryHandled;
class DepListEntryHandledSuccess;
class DepListEntryHandledSkippedUnsatisfied;
+ class DepListEntryHandledSkippedDependent;
class DepListEntryHandledFailed;
class DepListEntryUnhandled;
class DepListEntryNoHandlingRequired;
diff --git a/paludis/handled_information.cc b/paludis/handled_information.cc
index fd1190e..b3767ba 100644
--- a/paludis/handled_information.cc
+++ b/paludis/handled_information.cc
@@ -57,3 +57,33 @@ DepListEntryHandledSkippedUnsatisfied::spec() const
return _imp->spec;
}
+namespace paludis
+{
+ template <>
+ struct Implementation<DepListEntryHandledSkippedDependent>
+ {
+ const tr1::shared_ptr<const PackageID> id;
+
+ Implementation(const tr1::shared_ptr<const PackageID> & i) :
+ id(i)
+ {
+ }
+ };
+}
+
+DepListEntryHandledSkippedDependent::DepListEntryHandledSkippedDependent(const tr1::shared_ptr<const PackageID> & i) :
+ PrivateImplementationPattern<DepListEntryHandledSkippedDependent>(new Implementation<DepListEntryHandledSkippedDependent>(i))
+{
+}
+
+DepListEntryHandledSkippedDependent::~DepListEntryHandledSkippedDependent()
+{
+}
+
+const tr1::shared_ptr<const PackageID>
+DepListEntryHandledSkippedDependent::id() const
+{
+ return _imp->id;
+}
+
+
diff --git a/paludis/handled_information.hh b/paludis/handled_information.hh
index 2cfd8e0..a55c912 100644
--- a/paludis/handled_information.hh
+++ b/paludis/handled_information.hh
@@ -25,6 +25,7 @@
#include <paludis/util/attributes.hh>
#include <paludis/util/private_implementation_pattern.hh>
#include <paludis/dep_spec-fwd.hh>
+#include <paludis/package_id-fwd.hh>
/** \file
* Declarations for DepListEntryHandled classes, which are used by DepList and
@@ -52,6 +53,7 @@ namespace paludis
DepListEntryHandled,
DepListEntryHandledSuccess,
DepListEntryHandledSkippedUnsatisfied,
+ DepListEntryHandledSkippedDependent,
DepListEntryHandledFailed,
DepListEntryUnhandled,
DepListEntryNoHandlingRequired
@@ -142,6 +144,35 @@ namespace paludis
};
/**
+ * Represents a DepListEntry that was skipped because of a dependency upon a
+ * failed package.
+ *
+ * \ingroup g_dep_list
+ * \since 0.26
+ * \nosubgrouping
+ */
+ class PALUDIS_VISIBLE DepListEntryHandledSkippedDependent :
+ public DepListEntryHandled,
+ public ConstAcceptInterfaceVisitsThis<DepListEntryHandledVisitorTypes, DepListEntryHandledSkippedDependent>,
+ private PrivateImplementationPattern<DepListEntryHandledSkippedDependent>
+ {
+ public:
+ ///\name Basic operations
+ ///\{
+
+ DepListEntryHandledSkippedDependent(const tr1::shared_ptr<const PackageID> &);
+ ~DepListEntryHandledSkippedDependent();
+
+ ///\}
+
+ /**
+ * Upon which PackageID are we dependent? If multiple dependent IDs are
+ * unsatisfied, returns one of them.
+ */
+ const tr1::shared_ptr<const PackageID> id() const PALUDIS_ATTRIBUTE((warn_unused_result));
+ };
+
+ /**
* Represents a DepListEntry that failed.
*
* \ingroup g_dep_list
diff --git a/paludis/install_task.cc b/paludis/install_task.cc
index d9ed094..f58f8b3 100644
--- a/paludis/install_task.cc
+++ b/paludis/install_task.cc
@@ -316,6 +316,13 @@ namespace
task.on_display_failure_summary_skipped_unsatisfied(*entry, s.spec());
}
+ void visit(const DepListEntryHandledSkippedDependent & s)
+ {
+ ++skipped;
+ ++total;
+ task.on_display_failure_summary_skipped_dependent(*entry, s.id());
+ }
+
void visit(const DepListEntryHandledFailed &)
{
++failures;
@@ -360,6 +367,7 @@ InstallTask::_display_failure_summary()
case itcof_always:
case itcof_if_satisfied:
+ case itcof_if_independent:
break;
case itcof_never:
@@ -657,6 +665,17 @@ InstallTask::_main_actions()
continue;
}
+ case itcof_if_independent:
+ {
+ tr1::shared_ptr<const PackageID> d(_dependent(*dep));
+ if (! d)
+ break;
+ dep->handled.reset(new DepListEntryHandledSkippedDependent(d));
+ on_skip_dependent(*dep, d, x, y, s, f);
+ ++s;
+ continue;
+ }
+
case itcof_always:
break;
@@ -1128,6 +1147,219 @@ InstallTask::_unsatisfied(const DepListEntry & e) const
namespace
{
+ struct CheckHandledVisitor :
+ ConstVisitor<DepListEntryHandledVisitorTypes>
+ {
+ bool failure;
+ bool skipped;
+ bool success;
+
+ CheckHandledVisitor() :
+ failure(false),
+ skipped(false),
+ success(false)
+ {
+ }
+
+ void visit(const DepListEntryHandledSkippedUnsatisfied &)
+ {
+ skipped = true;
+ }
+
+ void visit(const DepListEntryHandledSuccess &)
+ {
+ success = true;
+ }
+
+ void visit(const DepListEntryHandledSkippedDependent &)
+ {
+ skipped = true;
+ }
+
+ void visit(const DepListEntryHandledFailed &)
+ {
+ failure = true;
+ }
+
+ void visit(const DepListEntryNoHandlingRequired &)
+ {
+ }
+
+ void visit(const DepListEntryUnhandled &)
+ {
+ }
+ };
+
+ struct CheckIndependentVisitor :
+ ConstVisitor<DependencySpecTree>,
+ ConstVisitor<DependencySpecTree>::VisitConstSequence<CheckIndependentVisitor, AllDepSpec>,
+ ConstVisitor<DependencySpecTree>::VisitConstSequence<CheckIndependentVisitor, AnyDepSpec>
+ {
+ using ConstVisitor<DependencySpecTree>::VisitConstSequence<CheckIndependentVisitor, AllDepSpec>::visit_sequence;
+ using ConstVisitor<DependencySpecTree>::VisitConstSequence<CheckIndependentVisitor, AnyDepSpec>::visit_sequence;
+
+ const Environment * const env;
+ const DepList & dep_list;
+ const tr1::shared_ptr<const PackageID> id;
+ tr1::shared_ptr<PackageIDSet> already_checked;
+
+ tr1::shared_ptr<const PackageID> failure;
+ std::set<SetName> recursing_sets;
+
+ CheckIndependentVisitor(
+ const Environment * const e,
+ const DepList & d,
+ const tr1::shared_ptr<const PackageID> & i,
+ const tr1::shared_ptr<PackageIDSet> & a) :
+ env(e),
+ dep_list(d),
+ id(i),
+ already_checked(a)
+ {
+ }
+
+ void visit_leaf(const BlockDepSpec &)
+ {
+ }
+
+ void visit_leaf(const DependencyLabelsDepSpec &)
+ {
+ }
+
+ void visit_leaf(const PackageDepSpec & a)
+ {
+ if (failure)
+ return;
+
+ for (DepList::ConstIterator d(dep_list.begin()), d_end(dep_list.end()) ;
+ d != d_end ; ++d)
+ {
+ if (! d->handled)
+ continue;
+
+ if (! match_package(*env, a, *d->package_id))
+ continue;
+
+ CheckHandledVisitor v;
+ d->handled->accept(v);
+
+ if (v.failure || v.skipped)
+ failure = d->package_id;
+ else if (v.success)
+ return;
+ }
+
+ /* no match on the dep list, fall back to installed packages. if
+ * there are no matches here it's not a problem because of or-deps. */
+ tr1::shared_ptr<const PackageIDSequence> installed(env->package_database()->query(
+ query::Matches(a) &
+ query::SupportsAction<InstalledAction>(),
+ qo_whatever));
+
+ for (PackageIDSequence::ConstIterator i(installed->begin()), i_end(installed->end()) ;
+ i != i_end ; ++i)
+ {
+ if (already_checked->end() != already_checked->find(*i))
+ continue;
+ already_checked->insert(*i);
+
+ CheckIndependentVisitor v(env, dep_list, *i, already_checked);
+
+ if (dl_deps_pre == dep_list.options()->uninstalled_deps_pre ||
+ dl_deps_pre_or_post == dep_list.options()->uninstalled_deps_pre)
+ if ((*i)->build_dependencies_key())
+ (*i)->build_dependencies_key()->value()->accept(v);
+
+ if (dl_deps_pre == dep_list.options()->uninstalled_deps_runtime ||
+ dl_deps_pre_or_post == dep_list.options()->uninstalled_deps_runtime)
+ if ((*i)->run_dependencies_key())
+ (*i)->run_dependencies_key()->value()->accept(v);
+
+ if (dl_deps_pre == dep_list.options()->uninstalled_deps_post ||
+ dl_deps_pre_or_post == dep_list.options()->uninstalled_deps_post)
+ if ((*i)->post_dependencies_key())
+ (*i)->post_dependencies_key()->value()->accept(v);
+
+ if ((dl_deps_pre == dep_list.options()->uninstalled_deps_suggested ||
+ dl_deps_pre_or_post == dep_list.options()->uninstalled_deps_suggested)
+ && dl_suggested_install == dep_list.options()->suggested)
+ if ((*i)->suggested_dependencies_key())
+ (*i)->suggested_dependencies_key()->value()->accept(v);
+
+ if (v.failure)
+ {
+ failure = v.failure;
+ return;
+ }
+ }
+ }
+
+ void visit_sequence(const UseDepSpec & u,
+ DependencySpecTree::ConstSequenceIterator cur,
+ DependencySpecTree::ConstSequenceIterator end)
+ {
+ if (env->query_use(u.flag(), *id) ^ u.inverse())
+ std::for_each(cur, end, accept_visitor(*this));
+ }
+
+ void visit_leaf(const NamedSetDepSpec & s)
+ {
+ tr1::shared_ptr<const SetSpecTree::ConstItem> set(env->set(s.name()));
+
+ if (! set)
+ {
+ Log::get_instance()->message(ll_warning, lc_context) << "Unknown set '" << s.name() << "'";
+ return;
+ }
+
+ if (! recursing_sets.insert(s.name()).second)
+ {
+ Log::get_instance()->message(ll_warning, lc_context) << "Recursively defined set '" << s.name() << "'";
+ return;
+ }
+
+ set->accept(*this);
+
+ recursing_sets.erase(s.name());
+ }
+ };
+}
+
+tr1::shared_ptr<const PackageID>
+InstallTask::_dependent(const DepListEntry & e) const
+{
+ Context context("When checking whether dependencies for '" + stringify(*e.package_id) + "' are independent of failed packages:");
+
+ tr1::shared_ptr<PackageIDSet> already_checked(new PackageIDSet);
+ CheckIndependentVisitor v(environment(), _imp->dep_list, e.package_id, already_checked);
+ already_checked->insert(e.package_id);
+
+ if (dl_deps_pre == _imp->dep_list.options()->uninstalled_deps_pre ||
+ dl_deps_pre_or_post == _imp->dep_list.options()->uninstalled_deps_pre)
+ if (e.package_id->build_dependencies_key())
+ e.package_id->build_dependencies_key()->value()->accept(v);
+
+ if (dl_deps_pre == _imp->dep_list.options()->uninstalled_deps_runtime ||
+ dl_deps_pre_or_post == _imp->dep_list.options()->uninstalled_deps_runtime)
+ if (e.package_id->run_dependencies_key())
+ e.package_id->run_dependencies_key()->value()->accept(v);
+
+ if (dl_deps_pre == _imp->dep_list.options()->uninstalled_deps_post ||
+ dl_deps_pre_or_post == _imp->dep_list.options()->uninstalled_deps_post)
+ if (e.package_id->post_dependencies_key())
+ e.package_id->post_dependencies_key()->value()->accept(v);
+
+ if ((dl_deps_pre == _imp->dep_list.options()->uninstalled_deps_suggested ||
+ dl_deps_pre_or_post == _imp->dep_list.options()->uninstalled_deps_suggested)
+ && dl_suggested_install == _imp->dep_list.options()->suggested)
+ if (e.package_id->suggested_dependencies_key())
+ e.package_id->suggested_dependencies_key()->value()->accept(v);
+
+ return v.failure;
+}
+
+namespace
+{
struct NotYetInstalledVisitor :
ConstVisitor<DepListEntryHandledVisitorTypes>
{
@@ -1148,6 +1380,11 @@ namespace
result->push_back(id);
}
+ void visit(const DepListEntryHandledSkippedDependent &)
+ {
+ result->push_back(id);
+ }
+
void visit(const DepListEntryHandledFailed &)
{
result->push_back(id);
diff --git a/paludis/install_task.hh b/paludis/install_task.hh
index b5c4f72..2a57513 100644
--- a/paludis/install_task.hh
+++ b/paludis/install_task.hh
@@ -66,6 +66,7 @@ namespace paludis
void _display_failure_summary();
tr1::shared_ptr<const PackageDepSpec> _unsatisfied(const DepListEntry &) const;
+ tr1::shared_ptr<const PackageID> _dependent(const DepListEntry &) const;
protected:
///\name Basic operations
@@ -133,6 +134,7 @@ namespace paludis
virtual void on_display_failure_summary_success(const DepListEntry &) = 0;
virtual void on_display_failure_summary_failure(const DepListEntry &) = 0;
virtual void on_display_failure_summary_skipped_unsatisfied(const DepListEntry &, const PackageDepSpec &) = 0;
+ virtual void on_display_failure_summary_skipped_dependent(const DepListEntry &, const tr1::shared_ptr<const PackageID> &) = 0;
virtual void on_display_failure_summary_totals(const int, const int, const int, const int) = 0;
virtual void on_display_failure_summary_post() = 0;
virtual void on_display_failure_no_summary() = 0;
@@ -152,6 +154,8 @@ namespace paludis
virtual void on_skip_unsatisfied(const DepListEntry &, const PackageDepSpec &,
const int x, const int y, const int s, const int f) = 0;
+ virtual void on_skip_dependent(const DepListEntry &, const tr1::shared_ptr<const PackageID> &,
+ const int x, const int y, const int s, const int f) = 0;
virtual void on_no_clean_needed(const DepListEntry &) = 0;
virtual void on_clean_all_pre(const DepListEntry &,
diff --git a/paludis/install_task.se b/paludis/install_task.se
index 1077013..de8c1a7 100644
--- a/paludis/install_task.se
+++ b/paludis/install_task.se
@@ -8,7 +8,7 @@ make_enum_InstallTaskContinueOnFailure()
key itcof_if_fetch_only "Continue, but only if fetch only"
key itcof_never "Never"
-# key itcof_if_independent "Continue if packages are independent"
+ key itcof_if_independent "Continue if packages are independent"
key itcof_if_satisfied "If dependencies are satisfied"
key itcof_always "Always"
diff --git a/src/clients/paludis/Makefile.am b/src/clients/paludis/Makefile.am
index cb995d3..cd28da8 100644
--- a/src/clients/paludis/Makefile.am
+++ b/src/clients/paludis/Makefile.am
@@ -73,13 +73,15 @@ TESTS_ENVIRONMENT = env \
TESTS = version_TEST help_TEST \
list_repository_formats_TEST list_dep_tag_categories_TEST \
- exception_TEST install_TEST upgrade_TEST args_from_environment_TEST
+ exception_TEST install_TEST upgrade_TEST args_from_environment_TEST \
+ continue_on_failure_TEST
EXTRA_DIST = \
$(man_MANS) \
$(TESTS) \
install_TEST_setup.sh install_TEST_cleanup.sh \
- upgrade_TEST_setup.sh upgrade_TEST_cleanup.sh
+ upgrade_TEST_setup.sh upgrade_TEST_cleanup.sh \
+ continue_on_failure_TEST_setup.sh continue_on_failure_TEST_cleanup.sh
CLEANFILES = *~ gmon.out *.gcov *.gcno *.gcda
DISTCLEANFILES = $(man_MANS) $(noinst_DATA)
diff --git a/src/output/console_install_task.cc b/src/output/console_install_task.cc
index 9920172..36d2f5a 100644
--- a/src/output/console_install_task.cc
+++ b/src/output/console_install_task.cc
@@ -429,6 +429,16 @@ ConsoleInstallTask::on_skip_unsatisfied(const DepListEntry & d, const PackageDep
}
void
+ConsoleInstallTask::on_skip_dependent(const DepListEntry & d, const tr1::shared_ptr<const PackageID> & id,
+ const int x, const int y, const int s, const int f)
+{
+ std::string m("(" + make_x_of_y(x, y, s, f) + ") Skipping " + stringify(*d.package_id) +
+ " (dependent upon '" + stringify(*id) + "')");
+
+ output_heading(m);
+}
+
+void
ConsoleInstallTask::on_install_post(const DepListEntry &, const int, const int,
const int, const int)
{
@@ -1502,6 +1512,16 @@ ConsoleInstallTask::on_display_failure_summary_skipped_unsatisfied(const DepList
}
void
+ConsoleInstallTask::on_display_failure_summary_skipped_dependent(const DepListEntry & e,
+ const tr1::shared_ptr<const PackageID> & id)
+{
+ output_starred_item_no_endl("");
+ output_stream() << colour(cl_package_name, *e.package_id) << ": skipped (dependent upon '"
+ << *id << "')";
+ output_endl();
+}
+
+void
ConsoleInstallTask::on_display_failure_summary_totals(const int total, const int successes,
const int skipped, const int failures)
{
diff --git a/src/output/console_install_task.hh b/src/output/console_install_task.hh
index dd83ef5..16e20cc 100644
--- a/src/output/console_install_task.hh
+++ b/src/output/console_install_task.hh
@@ -156,6 +156,8 @@ namespace paludis
virtual void on_skip_unsatisfied(const DepListEntry &, const PackageDepSpec &,
const int x, const int y, const int s, const int f);
+ virtual void on_skip_dependent(const DepListEntry &, const tr1::shared_ptr<const PackageID> &,
+ const int x, const int y, const int s, const int f);
virtual void on_no_clean_needed(const DepListEntry &);
virtual void on_clean_all_pre(const DepListEntry &,
@@ -192,6 +194,7 @@ namespace paludis
virtual void on_display_failure_summary_success(const DepListEntry &);
virtual void on_display_failure_summary_failure(const DepListEntry &);
virtual void on_display_failure_summary_skipped_unsatisfied(const DepListEntry &, const PackageDepSpec &);
+ virtual void on_display_failure_summary_skipped_dependent(const DepListEntry &, const tr1::shared_ptr<const PackageID> &);
virtual void on_display_failure_summary_totals(const int, const int, const int, const int);
virtual void on_display_failure_summary_post();
virtual void on_display_failure_no_summary();