1 |
Author: zmedico |
2 |
Date: 2009-02-26 04:26:07 +0000 (Thu, 26 Feb 2009) |
3 |
New Revision: 12713 |
4 |
|
5 |
Modified: |
6 |
main/trunk/pym/_emerge/__init__.py |
7 |
Log: |
8 |
Bug #259954 - Do not spawn parallel build when the system is in a fragile |
9 |
state due to a system package having an unsatisfied runtime dependency |
10 |
(such as sys-libs/pam having an unsatisfied PDEPEND on sys-auth/pambase). |
11 |
|
12 |
|
13 |
Modified: main/trunk/pym/_emerge/__init__.py |
14 |
=================================================================== |
15 |
--- main/trunk/pym/_emerge/__init__.py 2009-02-26 04:03:10 UTC (rev 12712) |
16 |
+++ main/trunk/pym/_emerge/__init__.py 2009-02-26 04:26:07 UTC (rev 12713) |
17 |
@@ -1819,8 +1819,8 @@ |
18 |
""" |
19 |
Start an asynchronous task and then return as soon as possible. |
20 |
""" |
21 |
+ self._start_hook() |
22 |
self._start() |
23 |
- self._start_hook() |
24 |
|
25 |
def _start(self): |
26 |
raise NotImplementedError(self) |
27 |
@@ -10020,6 +10020,13 @@ |
28 |
# when no other packages are building. |
29 |
self._deep_system_deps = set() |
30 |
|
31 |
+ # Holds packages to merge which will satisfy currently unsatisfied |
32 |
+ # deep runtime dependencies of system packages. If this is not empty |
33 |
+ # then no parallel builds will be spawned until it is empty. This |
34 |
+ # minimizes the possibility that a build will fail due to the system |
35 |
+ # being in a fragile state. For example, see bug #259954. |
36 |
+ self._unsatisfied_system_deps = set() |
37 |
+ |
38 |
self._status_display = JobStatusDisplay() |
39 |
self._max_load = myopts.get("--load-average") |
40 |
max_jobs = myopts.get("--jobs") |
41 |
@@ -10768,6 +10775,59 @@ |
42 |
elif isinstance(pkg, Blocker): |
43 |
pass |
44 |
|
45 |
+ def _system_merge_started(self, merge): |
46 |
+ """ |
47 |
+ Add any unsatisfied runtime deps to self._unsatisfied_system_deps. |
48 |
+ """ |
49 |
+ graph = self._digraph |
50 |
+ if graph is None: |
51 |
+ return |
52 |
+ pkg = merge.merge.pkg |
53 |
+ completed_tasks = self._completed_tasks |
54 |
+ unsatisfied = self._unsatisfied_system_deps |
55 |
+ |
56 |
+ def ignore_non_runtime(priority): |
57 |
+ """ |
58 |
+ Ignore non-runtime priorities |
59 |
+ """ |
60 |
+ if isinstance(priority, DepPriority) and \ |
61 |
+ (priority.runtime or priority.runtime_post): |
62 |
+ return False |
63 |
+ return True |
64 |
+ |
65 |
+ def ignore_satisfied_runtime(priority): |
66 |
+ """ |
67 |
+ Ignore non-runtime and satisfied runtime priorities. |
68 |
+ """ |
69 |
+ if isinstance(priority, DepPriority) and \ |
70 |
+ not priority.satisfied and \ |
71 |
+ (priority.runtime or priority.runtime_post): |
72 |
+ return False |
73 |
+ return True |
74 |
+ |
75 |
+ traversed = set() |
76 |
+ dep_stack = [pkg] |
77 |
+ while dep_stack: |
78 |
+ node = dep_stack.pop() |
79 |
+ if node in traversed: |
80 |
+ continue |
81 |
+ traversed.add(node) |
82 |
+ |
83 |
+ unsatisfied_runtime = set(graph.child_nodes(node, |
84 |
+ ignore_priority=ignore_satisfied_runtime)) |
85 |
+ for child in graph.child_nodes(node, |
86 |
+ ignore_priority=ignore_non_runtime): |
87 |
+ if not isinstance(child, Package) or \ |
88 |
+ child.operation == 'uninstall': |
89 |
+ continue |
90 |
+ if child is pkg: |
91 |
+ continue |
92 |
+ dep_stack.append(child) |
93 |
+ if child.operation == 'merge' and \ |
94 |
+ child not in completed_tasks and \ |
95 |
+ child in unsatisfied_runtime: |
96 |
+ unsatisfied.add(child) |
97 |
+ |
98 |
def _merge_wait_exit_handler(self, task): |
99 |
self._merge_wait_scheduled.remove(task) |
100 |
self._merge_exit(task) |
101 |
@@ -10829,6 +10889,7 @@ |
102 |
# Since dependencies on system packages are frequently |
103 |
# unspecified, merge them only when no builds are executing. |
104 |
self._merge_wait_queue.append(merge) |
105 |
+ merge.addStartListener(self._system_merge_started) |
106 |
else: |
107 |
merge.addExitListener(self._merge_exit) |
108 |
self._task_queues.merge.add(merge) |
109 |
@@ -10855,6 +10916,7 @@ |
110 |
|
111 |
def _task_complete(self, pkg): |
112 |
self._completed_tasks.add(pkg) |
113 |
+ self._unsatisfied_system_deps.discard(pkg) |
114 |
self._choose_pkg_return_early = False |
115 |
|
116 |
def _merge(self): |
117 |
@@ -10882,6 +10944,7 @@ |
118 |
del self._pkg_queue[:] |
119 |
self._completed_tasks.clear() |
120 |
self._deep_system_deps.clear() |
121 |
+ self._unsatisfied_system_deps.clear() |
122 |
self._choose_pkg_return_early = False |
123 |
self._status_display.reset() |
124 |
self._digraph = None |
125 |
@@ -11076,6 +11139,7 @@ |
126 |
|
127 |
if self._choose_pkg_return_early or \ |
128 |
self._merge_wait_scheduled or \ |
129 |
+ (self._jobs and self._unsatisfied_system_deps) or \ |
130 |
not self._can_add_job() or \ |
131 |
self._job_delay(): |
132 |
return bool(state_change) |