1 |
commit: b8c3f38ec5eec077e69451f1f3126999065ea132 |
2 |
Author: Sheng Yu <syu.os <AT> protonmail <DOT> com> |
3 |
AuthorDate: Sun Sep 25 04:29:55 2022 +0000 |
4 |
Commit: Sam James <sam <AT> gentoo <DOT> org> |
5 |
CommitDate: Wed Sep 28 23:56:08 2022 +0000 |
6 |
URL: https://gitweb.gentoo.org/proj/portage.git/commit/?id=b8c3f38e |
7 |
|
8 |
Add more error handling for binpkgs |
9 |
|
10 |
And catch process Exception spawned by portage itself. |
11 |
e.g. bad decompress command. |
12 |
|
13 |
Bug: https://bugs.gentoo.org/871570 |
14 |
Signed-off-by: Sheng Yu <syu.os <AT> protonmail.com> |
15 |
Closes: https://github.com/gentoo/portage/pull/910 |
16 |
Signed-off-by: Sam James <sam <AT> gentoo.org> |
17 |
|
18 |
bin/gpkg-helper.py | 12 +++++++++--- |
19 |
bin/quickpkg | 30 ++++++++++++++++++------------ |
20 |
lib/_emerge/Binpkg.py | 34 ++++++++++++++++++++-------------- |
21 |
lib/portage/gpkg.py | 9 +++++++-- |
22 |
4 files changed, 54 insertions(+), 31 deletions(-) |
23 |
|
24 |
diff --git a/bin/gpkg-helper.py b/bin/gpkg-helper.py |
25 |
index 4752c84ee..4481f4b93 100755 |
26 |
--- a/bin/gpkg-helper.py |
27 |
+++ b/bin/gpkg-helper.py |
28 |
@@ -8,9 +8,11 @@ import portage |
29 |
|
30 |
portage._internal_caller = True |
31 |
from portage import os |
32 |
+from portage.output import EOutput |
33 |
|
34 |
|
35 |
def command_compose(args): |
36 |
+ eout = EOutput() |
37 |
|
38 |
usage = "usage: compose <package_cpv> <binpkg_path> <metadata_dir> <image_dir>\n" |
39 |
|
40 |
@@ -31,9 +33,13 @@ def command_compose(args): |
41 |
sys.stderr.write("Argument 4 is not a directory: '%s'\n" % image_dir) |
42 |
return 1 |
43 |
|
44 |
- gpkg_file = portage.gpkg.gpkg(portage.settings, basename, binpkg_path) |
45 |
- metadata = gpkg_file._generate_metadata_from_dir(metadata_dir) |
46 |
- gpkg_file.compress(image_dir, metadata) |
47 |
+ try: |
48 |
+ gpkg_file = portage.gpkg.gpkg(portage.settings, basename, binpkg_path) |
49 |
+ metadata = gpkg_file._generate_metadata_from_dir(metadata_dir) |
50 |
+ gpkg_file.compress(image_dir, metadata) |
51 |
+ except portage.exception.CompressorOperationFailed: |
52 |
+ eout.eerror("Compressor Operation Failed") |
53 |
+ exit(1) |
54 |
return os.EX_OK |
55 |
|
56 |
|
57 |
|
58 |
diff --git a/bin/quickpkg b/bin/quickpkg |
59 |
index eef5f912f..67eee697a 100755 |
60 |
--- a/bin/quickpkg |
61 |
+++ b/bin/quickpkg |
62 |
@@ -27,6 +27,7 @@ from portage.dbapi.dep_expand import dep_expand |
63 |
from portage.dep import Atom, use_reduce |
64 |
from portage.exception import ( |
65 |
AmbiguousPackageName, |
66 |
+ CompressorOperationFailed, |
67 |
InvalidAtom, |
68 |
InvalidData, |
69 |
InvalidBinaryPackageFormat, |
70 |
@@ -203,24 +204,29 @@ def quickpkg_atom(options, infos, arg, eout): |
71 |
) |
72 |
else: |
73 |
raise InvalidBinaryPackageFormat(binpkg_format) |
74 |
+ except CompressorOperationFailed as e: |
75 |
+ eout.eerror(f"Compressor operation failed") |
76 |
+ os.remove(binpkg_tmpfile) |
77 |
+ binpkg_tmpfile = None |
78 |
finally: |
79 |
if have_lock: |
80 |
dblnk.unlockdb() |
81 |
- pkg_info = bintree.inject(cpv, current_pkg_path=binpkg_tmpfile) |
82 |
- # The pkg_info value ensures that the following getname call |
83 |
- # returns the correct path when FEATURES=binpkg-multi-instance |
84 |
- # is enabled, but fallback to cpv in case the inject call |
85 |
- # returned None due to some kind of failure. |
86 |
- binpkg_path = bintree.getname(pkg_info or cpv) |
87 |
- try: |
88 |
- s = os.stat(binpkg_path) |
89 |
- except OSError: |
90 |
- s = None |
91 |
+ if binpkg_tmpfile is not None: |
92 |
+ pkg_info = bintree.inject(cpv, current_pkg_path=binpkg_tmpfile) |
93 |
+ # The pkg_info value ensures that the following getname call |
94 |
+ # returns the correct path when FEATURES=binpkg-multi-instance |
95 |
+ # is enabled, but fallback to cpv in case the inject call |
96 |
+ # returned None due to some kind of failure. |
97 |
+ binpkg_path = bintree.getname(pkg_info or cpv) |
98 |
+ try: |
99 |
+ s = os.stat(binpkg_path) |
100 |
+ except OSError: |
101 |
+ s = None |
102 |
|
103 |
- if s is None or pkg_info is None: |
104 |
+ if binpkg_tmpfile is None or s is None or pkg_info is None: |
105 |
# Sanity check, shouldn't happen normally. |
106 |
eout.eend(1) |
107 |
- eout.eerror("Failed to create package: '%s'" % binpkg_path) |
108 |
+ eout.eerror(f"Failed to create package: '{cpv}'") |
109 |
retval |= 1 |
110 |
else: |
111 |
eout.eend(0) |
112 |
|
113 |
diff --git a/lib/_emerge/Binpkg.py b/lib/_emerge/Binpkg.py |
114 |
index 7ce0da15f..6c1c0666a 100644 |
115 |
--- a/lib/_emerge/Binpkg.py |
116 |
+++ b/lib/_emerge/Binpkg.py |
117 |
@@ -12,7 +12,6 @@ from _emerge.EbuildMerge import EbuildMerge |
118 |
from _emerge.EbuildBuildDir import EbuildBuildDir |
119 |
from _emerge.SpawnProcess import SpawnProcess |
120 |
from portage.eapi import eapi_exports_replace_vars |
121 |
-from portage.exception import PortageException |
122 |
from portage.output import colorize |
123 |
from portage.util import ensure_dirs |
124 |
from portage.util._async.AsyncTaskFuture import AsyncTaskFuture |
125 |
@@ -393,7 +392,17 @@ class Binpkg(CompositeTask): |
126 |
|
127 |
def _unpack_metadata_exit(self, unpack_metadata): |
128 |
if self._default_exit(unpack_metadata) != os.EX_OK: |
129 |
- unpack_metadata.future.result() |
130 |
+ try: |
131 |
+ unpack_metadata.future.result() |
132 |
+ except Exception as e: |
133 |
+ self._writemsg_level( |
134 |
+ colorize( |
135 |
+ "BAD", |
136 |
+ f"!!! Error Extracting '{self._pkg_path}', {e}\n", |
137 |
+ ), |
138 |
+ noiselevel=-1, |
139 |
+ level=logging.ERROR, |
140 |
+ ) |
141 |
self._async_unlock_builddir(returncode=self.returncode) |
142 |
return |
143 |
|
144 |
@@ -427,18 +436,15 @@ class Binpkg(CompositeTask): |
145 |
if self._default_exit(unpack_contents) != os.EX_OK: |
146 |
try: |
147 |
unpack_contents.future.result() |
148 |
- err = "" |
149 |
- except PortageException as e: |
150 |
- err = e |
151 |
- |
152 |
- self._writemsg_level( |
153 |
- colorize( |
154 |
- "BAD", |
155 |
- f"!!! Error Extracting '{self._pkg_path}', {err}\n", |
156 |
- ), |
157 |
- noiselevel=-1, |
158 |
- level=logging.ERROR, |
159 |
- ) |
160 |
+ except Exception as e: |
161 |
+ self._writemsg_level( |
162 |
+ colorize( |
163 |
+ "BAD", |
164 |
+ f"!!! Error Extracting '{self._pkg_path}', {e}\n", |
165 |
+ ), |
166 |
+ noiselevel=-1, |
167 |
+ level=logging.ERROR, |
168 |
+ ) |
169 |
self._async_unlock_builddir(returncode=self.returncode) |
170 |
return |
171 |
|
172 |
|
173 |
diff --git a/lib/portage/gpkg.py b/lib/portage/gpkg.py |
174 |
index c0a80208f..ff2195854 100644 |
175 |
--- a/lib/portage/gpkg.py |
176 |
+++ b/lib/portage/gpkg.py |
177 |
@@ -214,7 +214,11 @@ class tar_stream_writer: |
178 |
|
179 |
if self.proc: |
180 |
# Write to external program |
181 |
- self.proc.stdin.write(data) |
182 |
+ try: |
183 |
+ self.proc.stdin.write(data) |
184 |
+ except BrokenPipeError: |
185 |
+ self.error = True |
186 |
+ raise CompressorOperationFailed("PIPE broken") |
187 |
else: |
188 |
# Write to container |
189 |
self.container.fileobj.write(data) |
190 |
@@ -232,7 +236,8 @@ class tar_stream_writer: |
191 |
if self.proc is not None: |
192 |
self.proc.stdin.close() |
193 |
if self.proc.wait() != os.EX_OK: |
194 |
- raise CompressorOperationFailed("compression failed") |
195 |
+ if not self.error: |
196 |
+ raise CompressorOperationFailed("compression failed") |
197 |
if self.read_thread.is_alive(): |
198 |
self.read_thread.join() |