summaryrefslogtreecommitdiffstats
path: root/pym/_emerge/__init__.py
diff options
context:
space:
mode:
authorZac Medico <zmedico@gentoo.org>2009-03-11 06:20:51 +0000
committerZac Medico <zmedico@gentoo.org>2009-03-11 06:20:51 +0000
commitf87cd4108155f90eadedb029a1036f7232ef6f5d (patch)
tree2e9ac8ea32fbc10e1c51b9ee392ec6635638b8b6 /pym/_emerge/__init__.py
parent6222e3e41f5b7e5f8cb60b36bfcfa10d169cd1c1 (diff)
downloadportage-f87cd4108155f90eadedb029a1036f7232ef6f5d.tar.gz
portage-f87cd4108155f90eadedb029a1036f7232ef6f5d.tar.bz2
portage-f87cd4108155f90eadedb029a1036f7232ef6f5d.zip
Bug #259954 - Do not spawn parallel build when the system is in a fragile
state due to a system package having an unsatisfied runtime dependency (such as sys-libs/pam having an unsatisfied PDEPEND on sys-auth/pambase). (trunk r12713) svn path=/main/branches/2.1.6/; revision=12968
Diffstat (limited to 'pym/_emerge/__init__.py')
-rw-r--r--pym/_emerge/__init__.py66
1 files changed, 65 insertions, 1 deletions
diff --git a/pym/_emerge/__init__.py b/pym/_emerge/__init__.py
index df34400d2..04df62a5d 100644
--- a/pym/_emerge/__init__.py
+++ b/pym/_emerge/__init__.py
@@ -1800,8 +1800,8 @@ class AsynchronousTask(SlotObject):
"""
Start an asynchronous task and then return as soon as possible.
"""
- self._start()
self._start_hook()
+ self._start()
def _start(self):
raise NotImplementedError(self)
@@ -10004,6 +10004,13 @@ class Scheduler(PollScheduler):
# when no other packages are building.
self._deep_system_deps = set()
+ # Holds packages to merge which will satisfy currently unsatisfied
+ # deep runtime dependencies of system packages. If this is not empty
+ # then no parallel builds will be spawned until it is empty. This
+ # minimizes the possibility that a build will fail due to the system
+ # being in a fragile state. For example, see bug #259954.
+ self._unsatisfied_system_deps = set()
+
self._status_display = JobStatusDisplay()
self._max_load = myopts.get("--load-average")
max_jobs = myopts.get("--jobs")
@@ -10752,6 +10759,59 @@ class Scheduler(PollScheduler):
elif isinstance(pkg, Blocker):
pass
+ def _system_merge_started(self, merge):
+ """
+ Add any unsatisfied runtime deps to self._unsatisfied_system_deps.
+ """
+ graph = self._digraph
+ if graph is None:
+ return
+ pkg = merge.merge.pkg
+ completed_tasks = self._completed_tasks
+ unsatisfied = self._unsatisfied_system_deps
+
+ def ignore_non_runtime(priority):
+ """
+ Ignore non-runtime priorities
+ """
+ if isinstance(priority, DepPriority) and \
+ (priority.runtime or priority.runtime_post):
+ return False
+ return True
+
+ def ignore_satisfied_runtime(priority):
+ """
+ Ignore non-runtime and satisfied runtime priorities.
+ """
+ if isinstance(priority, DepPriority) and \
+ not priority.satisfied and \
+ (priority.runtime or priority.runtime_post):
+ return False
+ return True
+
+ traversed = set()
+ dep_stack = [pkg]
+ while dep_stack:
+ node = dep_stack.pop()
+ if node in traversed:
+ continue
+ traversed.add(node)
+
+ unsatisfied_runtime = set(graph.child_nodes(node,
+ ignore_priority=ignore_satisfied_runtime))
+ for child in graph.child_nodes(node,
+ ignore_priority=ignore_non_runtime):
+ if not isinstance(child, Package) or \
+ child.operation == 'uninstall':
+ continue
+ if child is pkg:
+ continue
+ dep_stack.append(child)
+ if child.operation == 'merge' and \
+ child not in completed_tasks and \
+ child in unsatisfied_runtime:
+ unsatisfied.add(child)
+
def _merge_wait_exit_handler(self, task):
self._merge_wait_scheduled.remove(task)
self._merge_exit(task)
@@ -10813,6 +10873,7 @@ class Scheduler(PollScheduler):
# Since dependencies on system packages are frequently
# unspecified, merge them only when no builds are executing.
self._merge_wait_queue.append(merge)
+ merge.addStartListener(self._system_merge_started)
else:
merge.addExitListener(self._merge_exit)
self._task_queues.merge.add(merge)
@@ -10839,6 +10900,7 @@ class Scheduler(PollScheduler):
def _task_complete(self, pkg):
self._completed_tasks.add(pkg)
+ self._unsatisfied_system_deps.discard(pkg)
self._choose_pkg_return_early = False
def _merge(self):
@@ -10866,6 +10928,7 @@ class Scheduler(PollScheduler):
del self._pkg_queue[:]
self._completed_tasks.clear()
self._deep_system_deps.clear()
+ self._unsatisfied_system_deps.clear()
self._choose_pkg_return_early = False
self._status_display.reset()
self._digraph = None
@@ -11060,6 +11123,7 @@ class Scheduler(PollScheduler):
if self._choose_pkg_return_early or \
self._merge_wait_scheduled or \
+ (self._jobs and self._unsatisfied_system_deps) or \
not self._can_add_job() or \
self._job_delay():
return bool(state_change)