aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2009-11-23 18:03:36 +0000
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2009-11-23 18:03:36 +0000
commit99903f001a205491afa6cd2238f968cebf643059 (patch)
treecc7cd14d53618d6256e7e0ac45b2a5c21e3f1c4b
parenta7cc219d30b452bb3c76cbd4186fa0fd38f83c4f (diff)
downloadpaludis-99903f001a205491afa6cd2238f968cebf643059.tar.gz
paludis-99903f001a205491afa6cd2238f968cebf643059.tar.xz
Usable gets its own job
-rw-r--r--paludis/resolver/job-fwd.hh1
-rw-r--r--paludis/resolver/job.cc60
-rw-r--r--paludis/resolver/job.hh22
-rw-r--r--paludis/resolver/jobs.cc88
-rw-r--r--paludis/resolver/jobs.hh8
-rw-r--r--paludis/resolver/orderer.cc149
-rw-r--r--paludis/resolver/resolver_TEST_cycles.cc38
-rwxr-xr-xpaludis/resolver/resolver_TEST_cycles_setup.sh70
-rw-r--r--paludis/resolver/resolver_test.cc5
-rw-r--r--src/clients/cave/cmd_display_resolution.cc6
-rw-r--r--src/clients/cave/cmd_execute_resolution.cc9
11 files changed, 416 insertions, 40 deletions
diff --git a/paludis/resolver/job-fwd.hh b/paludis/resolver/job-fwd.hh
index 3e19e0c..74f4b6e 100644
--- a/paludis/resolver/job-fwd.hh
+++ b/paludis/resolver/job-fwd.hh
@@ -30,6 +30,7 @@ namespace paludis
struct PretendJob;
struct FetchJob;
struct NoChangeJob;
+ struct UsableJob;
struct SyncPointJob;
struct UntakenInstallJob;
}
diff --git a/paludis/resolver/job.cc b/paludis/resolver/job.cc
index 1126075..6dbe120 100644
--- a/paludis/resolver/job.cc
+++ b/paludis/resolver/job.cc
@@ -47,6 +47,19 @@ namespace paludis
};
template <>
+ struct Implementation<UsableJob>
+ {
+ const std::tr1::shared_ptr<const Resolution> resolution;
+ const std::tr1::shared_ptr<ArrowSequence> arrows;
+
+ Implementation(const std::tr1::shared_ptr<const Resolution> & r) :
+ resolution(r),
+ arrows(new ArrowSequence)
+ {
+ }
+ };
+
+ template <>
struct Implementation<PretendJob>
{
const std::tr1::shared_ptr<const Resolution> resolution;
@@ -150,6 +163,14 @@ Job::deserialise(Deserialisation & d)
));
do_arrows(result, v);
}
+ else if (d.class_name() == "UsableJob")
+ {
+ Deserialisator v(d, "UsableJob");
+ result.reset(new UsableJob(
+ v.member<std::tr1::shared_ptr<Resolution> >("resolution")
+ ));
+ do_arrows(result, v);
+ }
else if (d.class_name() == "SimpleInstallJob")
{
Deserialisator v(d, "SimpleInstallJob");
@@ -237,6 +258,44 @@ NoChangeJob::serialise(Serialiser & s) const
;
}
+UsableJob::UsableJob(const std::tr1::shared_ptr<const Resolution> & r) :
+ PrivateImplementationPattern<UsableJob>(new Implementation<UsableJob>(r))
+{
+}
+
+UsableJob::~UsableJob()
+{
+}
+
+const std::tr1::shared_ptr<const Resolution>
+UsableJob::resolution() const
+{
+ return _imp->resolution;
+}
+
+const std::tr1::shared_ptr<ArrowSequence>
+UsableJob::arrows() const
+{
+ return _imp->arrows;
+}
+
+const JobID
+UsableJob::id() const
+{
+ return make_named_values<JobID>(
+ value_for<n::string_id>("o:" + stringify(resolution()->resolvent()))
+ );
+}
+
+void
+UsableJob::serialise(Serialiser & s) const
+{
+ s.object("UsableJob")
+ .member(SerialiserFlags<serialise::might_be_null, serialise::container>(), "arrows", arrows())
+ .member(SerialiserFlags<serialise::might_be_null>(), "resolution", resolution())
+ ;
+}
+
PretendJob::PretendJob(const std::tr1::shared_ptr<const Resolution> & r,
const std::tr1::shared_ptr<const ChangesToMakeDecision> & d) :
PrivateImplementationPattern<PretendJob>(new Implementation<PretendJob>(r, d))
@@ -452,6 +511,7 @@ SyncPointJob::serialise(Serialiser & s) const
}
template class PrivateImplementationPattern<resolver::NoChangeJob>;
+template class PrivateImplementationPattern<resolver::UsableJob>;
template class PrivateImplementationPattern<resolver::PretendJob>;
template class PrivateImplementationPattern<resolver::FetchJob>;
template class PrivateImplementationPattern<resolver::SimpleInstallJob>;
diff --git a/paludis/resolver/job.hh b/paludis/resolver/job.hh
index 0c29846..c1c8bf3 100644
--- a/paludis/resolver/job.hh
+++ b/paludis/resolver/job.hh
@@ -39,7 +39,7 @@ namespace paludis
{
class PALUDIS_VISIBLE Job :
public virtual DeclareAbstractAcceptMethods<Job, MakeTypeList<
- NoChangeJob, SimpleInstallJob, PretendJob, FetchJob, UntakenInstallJob, SyncPointJob>::Type>
+ NoChangeJob, UsableJob, SimpleInstallJob, PretendJob, FetchJob, UntakenInstallJob, SyncPointJob>::Type>
{
public:
virtual ~Job() = 0;
@@ -75,6 +75,25 @@ namespace paludis
virtual void serialise(Serialiser &) const;
};
+ class PALUDIS_VISIBLE UsableJob :
+ public Job,
+ public ImplementAcceptMethods<Job, UsableJob>,
+ private PrivateImplementationPattern<UsableJob>
+ {
+ public:
+ UsableJob(const std::tr1::shared_ptr<const Resolution> &);
+ ~UsableJob();
+
+ virtual const JobID id() const PALUDIS_ATTRIBUTE((warn_unused_result));
+
+ virtual const std::tr1::shared_ptr<ArrowSequence> arrows()
+ const PALUDIS_ATTRIBUTE((warn_unused_result));
+
+ const std::tr1::shared_ptr<const Resolution> resolution() const PALUDIS_ATTRIBUTE((warn_unused_result));
+
+ virtual void serialise(Serialiser &) const;
+ };
+
class PALUDIS_VISIBLE PretendJob :
public Job,
public ImplementAcceptMethods<Job, PretendJob>,
@@ -182,6 +201,7 @@ namespace paludis
#ifdef PALUDIS_HAVE_EXTERN_TEMPLATE
extern template class PrivateImplementationPattern<resolver::NoChangeJob>;
+ extern template class PrivateImplementationPattern<resolver::UsableJob>;
extern template class PrivateImplementationPattern<resolver::PretendJob>;
extern template class PrivateImplementationPattern<resolver::FetchJob>;
extern template class PrivateImplementationPattern<resolver::SimpleInstallJob>;
diff --git a/paludis/resolver/jobs.cc b/paludis/resolver/jobs.cc
index 2f31c78..53ef32c 100644
--- a/paludis/resolver/jobs.cc
+++ b/paludis/resolver/jobs.cc
@@ -72,6 +72,11 @@ namespace
jobs_list_by_resolvent_index.insert(std::make_pair(j.resolution()->resolvent(), i));
}
+ void visit(const UsableJob & j)
+ {
+ jobs_list_by_resolvent_index.insert(std::make_pair(j.resolution()->resolvent(), i));
+ }
+
void visit(const SimpleInstallJob & j)
{
jobs_list_by_resolvent_index.insert(std::make_pair(j.resolution()->resolvent(), i));
@@ -108,7 +113,7 @@ Jobs::add(const std::tr1::shared_ptr<Job> & j)
namespace
{
- struct BuildJobChecker
+ struct InstalledJobChecker
{
bool visit(const PretendJob &) const
{
@@ -135,22 +140,95 @@ namespace
return true;
}
+ bool visit(const UsableJob &) const
+ {
+ return false;
+ }
+
bool visit(const SimpleInstallJob &) const
{
return true;
}
};
+
+ struct UsableJobChecker
+ {
+ bool visit(const PretendJob &) const
+ {
+ return false;
+ }
+
+ bool visit(const SyncPointJob &) const
+ {
+ return false;
+ }
+
+ bool visit(const FetchJob &) const
+ {
+ return false;
+ }
+
+ bool visit(const UntakenInstallJob &) const
+ {
+ return true;
+ }
+
+ bool visit(const NoChangeJob &) const
+ {
+ return true;
+ }
+
+ bool visit(const UsableJob &) const
+ {
+ return true;
+ }
+
+ bool visit(const SimpleInstallJob &) const
+ {
+ return false;
+ }
+ };
+}
+
+const JobID
+Jobs::find_id_for_installed(const Resolvent & r) const
+{
+ std::pair<JobsListByResolventIndex::const_iterator, JobsListByResolventIndex::const_iterator> candidates(
+ _imp->jobs_list_by_resolvent_index.equal_range(r));
+
+ for ( ; candidates.first != candidates.second ; ++candidates.first)
+ {
+ if ((*candidates.first->second)->accept_returning<bool>(InstalledJobChecker()))
+ return (*candidates.first->second)->id();
+ }
+
+ throw InternalError(PALUDIS_HERE, "no build job for " + stringify(r));
+}
+
+bool
+Jobs::have_job_for_installed(const Resolvent & r) const
+{
+ std::pair<JobsListByResolventIndex::const_iterator, JobsListByResolventIndex::const_iterator> candidates(
+ _imp->jobs_list_by_resolvent_index.equal_range(r));
+
+ for ( ; candidates.first != candidates.second ; ++candidates.first)
+ {
+ if ((*candidates.first->second)->accept_returning<bool>(InstalledJobChecker()))
+ return true;
+ }
+
+ return false;
}
const JobID
-Jobs::find_id_for_building(const Resolvent & r) const
+Jobs::find_id_for_usable(const Resolvent & r) const
{
std::pair<JobsListByResolventIndex::const_iterator, JobsListByResolventIndex::const_iterator> candidates(
_imp->jobs_list_by_resolvent_index.equal_range(r));
for ( ; candidates.first != candidates.second ; ++candidates.first)
{
- if ((*candidates.first->second)->accept_returning<bool>(BuildJobChecker()))
+ if ((*candidates.first->second)->accept_returning<bool>(UsableJobChecker()))
return (*candidates.first->second)->id();
}
@@ -158,14 +236,14 @@ Jobs::find_id_for_building(const Resolvent & r) const
}
bool
-Jobs::have_job_for_building(const Resolvent & r) const
+Jobs::have_job_for_usable(const Resolvent & r) const
{
std::pair<JobsListByResolventIndex::const_iterator, JobsListByResolventIndex::const_iterator> candidates(
_imp->jobs_list_by_resolvent_index.equal_range(r));
for ( ; candidates.first != candidates.second ; ++candidates.first)
{
- if ((*candidates.first->second)->accept_returning<bool>(BuildJobChecker()))
+ if ((*candidates.first->second)->accept_returning<bool>(UsableJobChecker()))
return true;
}
diff --git a/paludis/resolver/jobs.hh b/paludis/resolver/jobs.hh
index 6010d82..d49a349 100644
--- a/paludis/resolver/jobs.hh
+++ b/paludis/resolver/jobs.hh
@@ -42,9 +42,13 @@ namespace paludis
void add(const std::tr1::shared_ptr<Job> &);
- bool have_job_for_building(const Resolvent &) const PALUDIS_ATTRIBUTE((warn_unused_result));
+ bool have_job_for_installed(const Resolvent &) const PALUDIS_ATTRIBUTE((warn_unused_result));
- const JobID find_id_for_building(const Resolvent &) const PALUDIS_ATTRIBUTE((warn_unused_result));
+ const JobID find_id_for_installed(const Resolvent &) const PALUDIS_ATTRIBUTE((warn_unused_result));
+
+ bool have_job_for_usable(const Resolvent &) const PALUDIS_ATTRIBUTE((warn_unused_result));
+
+ const JobID find_id_for_usable(const Resolvent &) const PALUDIS_ATTRIBUTE((warn_unused_result));
const std::tr1::shared_ptr<Job> fetch(
const JobID &) PALUDIS_ATTRIBUTE((warn_unused_result));
diff --git a/paludis/resolver/orderer.cc b/paludis/resolver/orderer.cc
index a06b3e6..84193f0 100644
--- a/paludis/resolver/orderer.cc
+++ b/paludis/resolver/orderer.cc
@@ -200,6 +200,10 @@ namespace
lists->jobs()->add(install_job);
lists->unordered_job_ids()->push_back(install_job->id());
+ const std::tr1::shared_ptr<UsableJob> usable_job(new UsableJob(resolution));
+ lists->jobs()->add(usable_job);
+ lists->unordered_job_ids()->push_back(usable_job->id());
+
/* we can't do any fetches or installs until all pretends have passed */
fetch_job->arrows()->push_back(make_named_values<Arrow>(
value_for<n::comes_after>(common_jobs.done_pretends()->id()),
@@ -217,9 +221,11 @@ namespace
value_for<n::maybe_reason>(make_null_shared_ptr())
));
- /* we haven't done all our installs until we've done our install */
+ /* we haven't done all our installs until we're usable
+ * (arguably this should just be install rather than usable,
+ * but the stronger requirement doesn't seem to hurt */
common_jobs.done_installs()->arrows()->push_back(make_named_values<Arrow>(
- value_for<n::comes_after>(install_job->id()),
+ value_for<n::comes_after>(usable_job->id()),
value_for<n::maybe_reason>(make_null_shared_ptr())
));
@@ -228,6 +234,12 @@ namespace
value_for<n::comes_after>(fetch_job->id()),
value_for<n::maybe_reason>(make_null_shared_ptr())
));
+
+ /* we aren't usable until we've been installed */
+ usable_job->arrows()->push_back(make_named_values<Arrow>(
+ value_for<n::comes_after>(install_job->id()),
+ value_for<n::maybe_reason>(make_null_shared_ptr())
+ ));
}
else
{
@@ -344,15 +356,18 @@ namespace
struct DepArrowsAdder
{
const std::tr1::shared_ptr<Jobs> jobs;
- const JobID we_are_usable_identifier;
+ const JobID our_identifier;
+ const bool is_usable;
const std::tr1::shared_ptr<const Reason> reason;
DepArrowsAdder(
const std::tr1::shared_ptr<Jobs> & j,
const JobID & i,
+ const bool u,
const std::tr1::shared_ptr<const Reason> & r) :
jobs(j),
- we_are_usable_identifier(i),
+ our_identifier(i),
+ is_usable(u),
reason(r)
{
}
@@ -372,20 +387,10 @@ namespace
void visit(const DependencyReason & r) const
{
- Context context("When adding arrows for job '" + stringify(we_are_usable_identifier.string_id())
+ Context context("When adding arrows for job '" + stringify(our_identifier.string_id())
+ "' with reason '" + stringify(r.sanitised_dependency().spec())
+ "' from '" + stringify(r.from_resolvent()) + "':");
- /* we might not be changing anything (e.g. for a blocker), or we
- * might be a dependency that got cancelled out later when
- * something was changed from a decision to an error. */
- if (! jobs->have_job_for_building(r.from_resolvent()))
- {
- Log::get_instance()->message("resolver.orderer.job.no_job_for_building", ll_warning, lc_context)
- << "No job for building '" << r.from_resolvent() << "'. Verify manually that this is sane for now.";
- return;
- }
-
if (r.sanitised_dependency().spec().if_block())
{
/* only strong blockers impose arrows. todo: maybe weak
@@ -393,11 +398,21 @@ namespace
* that make matters worse with silly Gentoo KDE blockers? */
if (r.sanitised_dependency().spec().if_block()->strong())
{
+ /* we might not be changing anything (e.g. for a blocker), or we
+ * might be a dependency that got cancelled out later when
+ * something was changed from a decision to an error. */
+ if (! jobs->have_job_for_installed(r.from_resolvent()))
+ {
+ Log::get_instance()->message("resolver.orderer.job.no_job_for_installed", ll_warning, lc_context)
+ << "No job for building '" << r.from_resolvent() << "'. Verify manually that this is sane for now.";
+ return;
+ }
+
/* todo: this should probably only cause an arrow if the
* blocker is currently met */
- jobs->fetch(jobs->find_id_for_building(r.from_resolvent()))->arrows()->push_back(
+ jobs->fetch(jobs->find_id_for_installed(r.from_resolvent()))->arrows()->push_back(
make_named_values<Arrow>(
- value_for<n::comes_after>(we_are_usable_identifier),
+ value_for<n::comes_after>(our_identifier),
value_for<n::maybe_reason>(reason)
));
}
@@ -412,11 +427,37 @@ namespace
if (v.build || v.run)
{
- jobs->fetch(jobs->find_id_for_building(r.from_resolvent()))->arrows()->push_back(
- make_named_values<Arrow>(
- value_for<n::comes_after>(we_are_usable_identifier),
- value_for<n::maybe_reason>(reason)
- ));
+ /* we might not be changing anything (e.g. for a blocker), or we
+ * might be a dependency that got cancelled out later when
+ * something was changed from a decision to an error. */
+ if (! jobs->have_job_for_usable(r.from_resolvent()))
+ {
+ Log::get_instance()->message("resolver.orderer.job.no_job_for_usable", ll_warning, lc_context)
+ << "No job for building '" << r.from_resolvent() << "'. Verify manually that this is sane for now.";
+ return;
+ }
+
+ if (v.build)
+ {
+ /* build: we must be usable before the other package is built */
+ if (is_usable)
+ jobs->fetch(jobs->find_id_for_installed(r.from_resolvent()))->arrows()->push_back(
+ make_named_values<Arrow>(
+ value_for<n::comes_after>(our_identifier),
+ value_for<n::maybe_reason>(reason)
+ ));
+ }
+
+ if (v.run)
+ {
+ /* run: we must be usable before the other package is usable */
+ if (is_usable)
+ jobs->fetch(jobs->find_id_for_usable(r.from_resolvent()))->arrows()->push_back(
+ make_named_values<Arrow>(
+ value_for<n::comes_after>(our_identifier),
+ value_for<n::maybe_reason>(reason)
+ ));
+ }
}
}
}
@@ -425,33 +466,38 @@ namespace
struct DepArrowHandler
{
const std::tr1::shared_ptr<Jobs> jobs;
- const JobID we_are_usable_identifier;
+ const JobID our_identifier;
DepArrowHandler(
const std::tr1::shared_ptr<Jobs> & j,
const JobID & i) :
jobs(j),
- we_are_usable_identifier(i)
+ our_identifier(i)
{
}
- void add_dep_arrows(const std::tr1::shared_ptr<const Resolution> & r)
+ void add_dep_arrows(const bool u, const std::tr1::shared_ptr<const Resolution> & r)
{
for (Constraints::ConstIterator c(r->constraints()->begin()), c_end(r->constraints()->end()) ;
c != c_end ; ++c)
if ((*c)->reason())
- (*c)->reason()->accept(DepArrowsAdder(jobs, we_are_usable_identifier, (*c)->reason()));
+ (*c)->reason()->accept(DepArrowsAdder(jobs, our_identifier, u, (*c)->reason()));
}
void visit(const SimpleInstallJob & c)
{
- add_dep_arrows(c.resolution());
+ add_dep_arrows(false, c.resolution());
}
void visit(const NoChangeJob & c)
{
/* a dep b dep c, b not changing. we still want c before a. */
- add_dep_arrows(c.resolution());
+ add_dep_arrows(true, c.resolution());
+ }
+
+ void visit(const UsableJob & c)
+ {
+ add_dep_arrows(true, c.resolution());
}
void visit(const FetchJob &)
@@ -581,6 +627,44 @@ namespace
return already_met(r.sanitised_dependency().spec());
}
};
+
+ struct Pass2Ignorable
+ {
+ bool visit(const NoChangeJob &) const
+ {
+ return true;
+ }
+
+ bool visit(const UsableJob &) const
+ {
+ return true;
+ }
+
+ bool visit(const PretendJob &) const
+ {
+ return false;
+ }
+
+ bool visit(const SyncPointJob &) const
+ {
+ return false;
+ }
+
+ bool visit(const FetchJob &) const
+ {
+ return false;
+ }
+
+ bool visit(const UntakenInstallJob &) const
+ {
+ return false;
+ }
+
+ bool visit(const SimpleInstallJob &) const
+ {
+ return false;
+ }
+ };
}
bool
@@ -596,11 +680,12 @@ Orderer::_can_order(const JobID & i, const int pass) const
if ((! skippable) && (pass >= 2))
{
- /* if our job is a NoChangeJob, and we're supposed to come
- * after a NoChangeJob, ignore the arrow. */
+ /* if our job is a NoChangeJob or a UsableJob, and we're
+ * supposed to come after a NoChangeJob or a UsableJob, ignore
+ * the arrow. */
const std::tr1::shared_ptr<const Job> other_job(_imp->lists->jobs()->fetch(a->comes_after()));
- if (simple_visitor_cast<const NoChangeJob>(*job) &&
- simple_visitor_cast<const NoChangeJob>(*other_job))
+ if (job->accept_returning<bool>(Pass2Ignorable()) &&
+ other_job->accept_returning<bool>(Pass2Ignorable()))
skippable = true;
}
diff --git a/paludis/resolver/resolver_TEST_cycles.cc b/paludis/resolver/resolver_TEST_cycles.cc
index 5636ccc..ced07c8 100644
--- a/paludis/resolver/resolver_TEST_cycles.cc
+++ b/paludis/resolver/resolver_TEST_cycles.cc
@@ -138,5 +138,43 @@ namespace test_cases
}
}
} test_existing_usable;
+
+ struct TestMutualRunDeps : ResolverCyclesTestCase
+ {
+ TestMutualRunDeps() : ResolverCyclesTestCase("mutual-run-deps") { }
+
+ void run()
+ {
+ std::tr1::shared_ptr<const ResolverLists> resolutions(get_resolutions("mutual-run-deps/target"));
+
+ {
+ TestMessageSuffix s("errors");
+ check_resolution_list(resolutions->jobs(), resolutions->error_resolutions(), ResolutionListChecks()
+ .finished()
+ );
+ }
+
+ {
+ TestMessageSuffix s("ordered");
+ check_resolution_list(resolutions->jobs(), resolutions->ordered_job_ids(), ResolutionListChecks()
+ .qpn(QualifiedPackageName("mutual-run-deps/dep-a"))
+ .qpn(QualifiedPackageName("mutual-run-deps/dep-b"))
+ .qpn(QualifiedPackageName("mutual-run-deps/dep-c"))
+ .qpn(QualifiedPackageName("mutual-run-deps/target"))
+ .finished()
+ );
+ }
+ }
+ } test_mutual_run_deps;
+
+ struct TestMutualBuildDeps : ResolverCyclesTestCase
+ {
+ TestMutualBuildDeps() : ResolverCyclesTestCase("mutual-build-deps") { }
+
+ void run()
+ {
+ TEST_CHECK_THROWS(get_resolutions("mutual-build-deps/target"), Exception);
+ }
+ } test_mutual_build_deps;
}
diff --git a/paludis/resolver/resolver_TEST_cycles_setup.sh b/paludis/resolver/resolver_TEST_cycles_setup.sh
index 2c04ab1..762cad0 100755
--- a/paludis/resolver/resolver_TEST_cycles_setup.sh
+++ b/paludis/resolver/resolver_TEST_cycles_setup.sh
@@ -60,5 +60,75 @@ SLOT="0"
DEPENDENCIES="existing-usable/target"
END
+# mutual-run-deps
+echo 'mutual-run-deps' >> metadata/categories.conf
+
+mkdir -p 'packages/mutual-run-deps/target'
+cat <<END > packages/mutual-run-deps/target/target-1.exheres-0
+SUMMARY="target"
+PLATFORMS="test"
+SLOT="0"
+DEPENDENCIES="mutual-run-deps/dep-a"
+END
+
+mkdir -p 'packages/mutual-run-deps/dep-a'
+cat <<END > packages/mutual-run-deps/dep-a/dep-a-1.exheres-0
+SUMMARY="target"
+PLATFORMS="test"
+SLOT="0"
+DEPENDENCIES="run: mutual-run-deps/dep-b mutual-run-deps/dep-c"
+END
+
+mkdir -p 'packages/mutual-run-deps/dep-b'
+cat <<END > packages/mutual-run-deps/dep-b/dep-b-1.exheres-0
+SUMMARY="target"
+PLATFORMS="test"
+SLOT="0"
+DEPENDENCIES="run: mutual-run-deps/dep-a"
+END
+
+mkdir -p 'packages/mutual-run-deps/dep-c'
+cat <<END > packages/mutual-run-deps/dep-c/dep-c-1.exheres-0
+SUMMARY="target"
+PLATFORMS="test"
+SLOT="0"
+DEPENDENCIES="run: mutual-run-deps/dep-b"
+END
+
+# mutual-build-deps
+echo 'mutual-build-deps' >> metadata/categories.conf
+
+mkdir -p 'packages/mutual-build-deps/target'
+cat <<END > packages/mutual-build-deps/target/target-1.exheres-0
+SUMMARY="target"
+PLATFORMS="test"
+SLOT="0"
+DEPENDENCIES="mutual-build-deps/dep-a"
+END
+
+mkdir -p 'packages/mutual-build-deps/dep-a'
+cat <<END > packages/mutual-build-deps/dep-a/dep-a-1.exheres-0
+SUMMARY="target"
+PLATFORMS="test"
+SLOT="0"
+DEPENDENCIES="build: mutual-build-deps/dep-b mutual-build-deps/dep-c"
+END
+
+mkdir -p 'packages/mutual-build-deps/dep-b'
+cat <<END > packages/mutual-build-deps/dep-b/dep-b-1.exheres-0
+SUMMARY="target"
+PLATFORMS="test"
+SLOT="0"
+DEPENDENCIES="build: mutual-build-deps/dep-a"
+END
+
+mkdir -p 'packages/mutual-build-deps/dep-c'
+cat <<END > packages/mutual-build-deps/dep-c/dep-c-1.exheres-0
+SUMMARY="target"
+PLATFORMS="test"
+SLOT="0"
+DEPENDENCIES="build: mutual-build-deps/dep-b"
+END
+
cd ..
diff --git a/paludis/resolver/resolver_test.cc b/paludis/resolver/resolver_test.cc
index 0e2893e..2e904b7 100644
--- a/paludis/resolver/resolver_test.cc
+++ b/paludis/resolver/resolver_test.cc
@@ -509,6 +509,11 @@ namespace
return make_null_shared_ptr();
}
+ std::tr1::shared_ptr<const Resolution> visit(const UsableJob &) const
+ {
+ return make_null_shared_ptr();
+ }
+
std::tr1::shared_ptr<const Resolution> visit(const FetchJob &) const
{
return make_null_shared_ptr();
diff --git a/src/clients/cave/cmd_display_resolution.cc b/src/clients/cave/cmd_display_resolution.cc
index c6bffa4..623fb16 100644
--- a/src/clients/cave/cmd_display_resolution.cc
+++ b/src/clients/cave/cmd_display_resolution.cc
@@ -386,6 +386,12 @@ namespace
}
const std::tr1::shared_ptr<const Resolution> visit(
+ const UsableJob &) const
+ {
+ return make_null_shared_ptr();
+ }
+
+ const std::tr1::shared_ptr<const Resolution> visit(
const PretendJob &) const
{
return make_null_shared_ptr();
diff --git a/src/clients/cave/cmd_execute_resolution.cc b/src/clients/cave/cmd_execute_resolution.cc
index a25df94..709a2d0 100644
--- a/src/clients/cave/cmd_execute_resolution.cc
+++ b/src/clients/cave/cmd_execute_resolution.cc
@@ -304,6 +304,10 @@ namespace
{
}
+ void visit(const UsableJob &)
+ {
+ }
+
void visit(const SyncPointJob &)
{
}
@@ -441,6 +445,11 @@ namespace
{
return true;
}
+
+ bool visit(const UsableJob &)
+ {
+ return true;
+ }
};
int execute_resolution(