1 |
This makes postinst failures behave more like "real" failures in |
2 |
terms of output and the final emerge return code. However, in other |
3 |
respects, these packages will be treated as successful installations. |
4 |
This means that they will not cause emerge to immediately exit, and |
5 |
they will not trigger recalculation of dependencies when --keep-going |
6 |
is enabled. |
7 |
|
8 |
X-Gentoo-Bug: 547778 |
9 |
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=547778 |
10 |
--- |
11 |
pym/_emerge/EbuildMerge.py | 3 ++- |
12 |
pym/_emerge/PackageMerge.py | 9 +++++++-- |
13 |
pym/_emerge/Scheduler.py | 20 +++++++++++++++++--- |
14 |
pym/portage/const.py | 2 ++ |
15 |
pym/portage/dbapi/_MergeProcess.py | 9 ++++++++- |
16 |
pym/portage/dbapi/vartree.py | 6 ++++++ |
17 |
6 files changed, 42 insertions(+), 7 deletions(-) |
18 |
|
19 |
diff --git a/pym/_emerge/EbuildMerge.py b/pym/_emerge/EbuildMerge.py |
20 |
index df0778c..07d9134 100644 |
21 |
--- a/pym/_emerge/EbuildMerge.py |
22 |
+++ b/pym/_emerge/EbuildMerge.py |
23 |
@@ -8,7 +8,7 @@ from portage.dbapi._MergeProcess import MergeProcess |
24 |
class EbuildMerge(CompositeTask): |
25 |
|
26 |
__slots__ = ("exit_hook", "find_blockers", "logger", "ldpath_mtimes", |
27 |
- "pkg", "pkg_count", "pkg_path", "pretend", |
28 |
+ "pkg", "pkg_count", "pkg_path", "postinst_failure", "pretend", |
29 |
"settings", "tree", "world_atom") |
30 |
|
31 |
def _start(self): |
32 |
@@ -39,6 +39,7 @@ class EbuildMerge(CompositeTask): |
33 |
self.wait() |
34 |
return |
35 |
|
36 |
+ self.postinst_failure = merge_task.postinst_failure |
37 |
pkg = self.pkg |
38 |
self.world_atom(pkg) |
39 |
pkg_count = self.pkg_count |
40 |
diff --git a/pym/_emerge/PackageMerge.py b/pym/_emerge/PackageMerge.py |
41 |
index fa2102f..1e7b58b 100644 |
42 |
--- a/pym/_emerge/PackageMerge.py |
43 |
+++ b/pym/_emerge/PackageMerge.py |
44 |
@@ -5,7 +5,7 @@ from _emerge.CompositeTask import CompositeTask |
45 |
from portage.dep import _repo_separator |
46 |
from portage.output import colorize |
47 |
class PackageMerge(CompositeTask): |
48 |
- __slots__ = ("merge",) |
49 |
+ __slots__ = ("merge", "postinst_failure") |
50 |
|
51 |
def _start(self): |
52 |
|
53 |
@@ -41,4 +41,9 @@ class PackageMerge(CompositeTask): |
54 |
self.merge.statusMessage(msg) |
55 |
|
56 |
task = self.merge.create_install_task() |
57 |
- self._start_task(task, self._default_final_exit) |
58 |
+ self._start_task(task, self._install_exit) |
59 |
+ |
60 |
+ def _install_exit(self, task): |
61 |
+ self.postinst_failure = getattr(task, 'postinst_failure', None) |
62 |
+ self._final_exit(task) |
63 |
+ self.wait() |
64 |
diff --git a/pym/_emerge/Scheduler.py b/pym/_emerge/Scheduler.py |
65 |
index 6b39e3b..13abc92 100644 |
66 |
--- a/pym/_emerge/Scheduler.py |
67 |
+++ b/pym/_emerge/Scheduler.py |
68 |
@@ -115,7 +115,8 @@ class Scheduler(PollScheduler): |
69 |
emergelog(self.xterm_titles, *pargs, **kwargs) |
70 |
|
71 |
class _failed_pkg(SlotObject): |
72 |
- __slots__ = ("build_dir", "build_log", "pkg", "returncode") |
73 |
+ __slots__ = ("build_dir", "build_log", "pkg", |
74 |
+ "postinst_failure", "returncode") |
75 |
|
76 |
class _ConfigPool(object): |
77 |
"""Interface for a task to temporarily allocate a config |
78 |
@@ -1155,10 +1156,10 @@ class Scheduler(PollScheduler): |
79 |
if len(self._failed_pkgs_all) > 1: |
80 |
msg = "The following %d packages have " % \ |
81 |
len(self._failed_pkgs_all) + \ |
82 |
- "failed to build or install:" |
83 |
+ "failed to build, install, or execute postinst:" |
84 |
else: |
85 |
msg = "The following package has " + \ |
86 |
- "failed to build or install:" |
87 |
+ "failed to build, install, or execute postinst:" |
88 |
|
89 |
printer.eerror("") |
90 |
for line in textwrap.wrap(msg, 72): |
91 |
@@ -1168,6 +1169,8 @@ class Scheduler(PollScheduler): |
92 |
# Use unicode_literals to force unicode format string so |
93 |
# that Package.__unicode__() is called in python2. |
94 |
msg = " %s" % (failed_pkg.pkg,) |
95 |
+ if failed_pkg.postinst_failure: |
96 |
+ msg += " (postinst failed)" |
97 |
log_path = self._locate_failure_log(failed_pkg) |
98 |
if log_path is not None: |
99 |
msg += ", Log file:" |
100 |
@@ -1289,6 +1292,17 @@ class Scheduler(PollScheduler): |
101 |
self._status_display.failed = len(self._failed_pkgs) |
102 |
return |
103 |
|
104 |
+ if merge.postinst_failure: |
105 |
+ # Append directly to _failed_pkgs_all for non-critical errors. |
106 |
+ self._failed_pkgs_all.append(self._failed_pkg( |
107 |
+ build_dir=merge.merge.settings.get("PORTAGE_BUILDDIR"), |
108 |
+ build_log=merge.merge.settings.get("PORTAGE_LOG_FILE"), |
109 |
+ pkg=pkg, |
110 |
+ postinst_failure=True, |
111 |
+ returncode=merge.returncode)) |
112 |
+ self._failed_pkg_msg(self._failed_pkgs_all[-1], |
113 |
+ "execute postinst for", "for") |
114 |
+ |
115 |
self._task_complete(pkg) |
116 |
pkg_to_replace = merge.merge.pkg_to_replace |
117 |
if pkg_to_replace is not None: |
118 |
diff --git a/pym/portage/const.py b/pym/portage/const.py |
119 |
index c7ecda2..6c1201d 100644 |
120 |
--- a/pym/portage/const.py |
121 |
+++ b/pym/portage/const.py |
122 |
@@ -277,6 +277,8 @@ TIMESTAMP_FORMAT = "%a, %d %b %Y %H:%M:%S +0000" # to be used with time.gmtime() |
123 |
# Top-level names of Python packages installed by Portage. |
124 |
PORTAGE_PYM_PACKAGES = ("_emerge", "portage", "repoman") |
125 |
|
126 |
+RETURNCODE_POSTINST_FAILURE = 5 |
127 |
+ |
128 |
# =========================================================================== |
129 |
# END OF CONSTANTS -- END OF CONSTANTS -- END OF CONSTANTS -- END OF CONSTANT |
130 |
# =========================================================================== |
131 |
diff --git a/pym/portage/dbapi/_MergeProcess.py b/pym/portage/dbapi/_MergeProcess.py |
132 |
index 956dbb9..35591af 100644 |
133 |
--- a/pym/portage/dbapi/_MergeProcess.py |
134 |
+++ b/pym/portage/dbapi/_MergeProcess.py |
135 |
@@ -23,7 +23,8 @@ class MergeProcess(ForkProcess): |
136 |
|
137 |
__slots__ = ('mycat', 'mypkg', 'settings', 'treetype', |
138 |
'vartree', 'blockers', 'pkgloc', 'infloc', 'myebuild', |
139 |
- 'mydbapi', 'prev_mtimes', 'unmerge', '_elog_reader_fd', '_elog_reg_id', |
140 |
+ 'mydbapi', 'postinst_failure', 'prev_mtimes', 'unmerge', |
141 |
+ '_elog_reader_fd', '_elog_reg_id', |
142 |
'_buf', '_elog_keys', '_locked_vdb') |
143 |
|
144 |
def _start(self): |
145 |
@@ -250,6 +251,12 @@ class MergeProcess(ForkProcess): |
146 |
# in order to avoid a race condition. |
147 |
os._exit(1) |
148 |
|
149 |
+ def _set_returncode(self, wait_retval): |
150 |
+ ForkProcess._set_returncode(self, wait_retval) |
151 |
+ if self.returncode == portage.const.RETURNCODE_POSTINST_FAILURE: |
152 |
+ self.postinst_failure = True |
153 |
+ self.returncode = os.EX_OK |
154 |
+ |
155 |
def _unregister(self): |
156 |
""" |
157 |
Unregister from the scheduler and close open files. |
158 |
diff --git a/pym/portage/dbapi/vartree.py b/pym/portage/dbapi/vartree.py |
159 |
index fca84d1..a2fb325 100644 |
160 |
--- a/pym/portage/dbapi/vartree.py |
161 |
+++ b/pym/portage/dbapi/vartree.py |
162 |
@@ -1577,6 +1577,7 @@ class dblink(object): |
163 |
self._hash_key = (self._eroot, self.mycpv) |
164 |
self._protect_obj = None |
165 |
self._pipe = pipe |
166 |
+ self._postinst_failure = False |
167 |
|
168 |
# When necessary, this attribute is modified for |
169 |
# compliance with RESTRICT=preserve-libs. |
170 |
@@ -4376,6 +4377,7 @@ class dblink(object): |
171 |
if a != os.EX_OK: |
172 |
# It's stupid to bail out here, so keep going regardless of |
173 |
# phase return code. |
174 |
+ self._postinst_failure = True |
175 |
self._elog("eerror", "postinst", [ |
176 |
_("FAILED postinst: %s") % (a,), |
177 |
]) |
178 |
@@ -5042,6 +5044,10 @@ class dblink(object): |
179 |
self.vartree.dbapi._bump_mtime(self.mycpv) |
180 |
if not parallel_install: |
181 |
self.unlockdb() |
182 |
+ |
183 |
+ if retval == os.EX_OK and self._postinst_failure: |
184 |
+ retval = portage.const.RETURNCODE_POSTINST_FAILURE |
185 |
+ |
186 |
return retval |
187 |
|
188 |
def getstring(self,name): |
189 |
-- |
190 |
2.3.5 |