1 |
Currently module functions return a message to emaint after invocation. |
2 |
Emaint prints this message then exits normally (with a success return |
3 |
code) even if the module encountered an error. This patch aims to |
4 |
change this by having each module public function return a tuple of |
5 |
(returncode, message). Emaint will inspect the return code and will |
6 |
exit unsuccessfully if necessary. |
7 |
--- |
8 |
pym/portage/emaint/main.py | 11 +++++++++-- |
9 |
pym/portage/emaint/modules/binhost/binhost.py | 6 ++++-- |
10 |
pym/portage/emaint/modules/config/config.py | 8 ++++++-- |
11 |
pym/portage/emaint/modules/logs/logs.py | 9 +++++---- |
12 |
pym/portage/emaint/modules/merges/merges.py | 18 +++++++++++------- |
13 |
pym/portage/emaint/modules/move/move.py | 9 +++++++-- |
14 |
pym/portage/emaint/modules/resume/resume.py | 4 +++- |
15 |
pym/portage/emaint/modules/sync/sync.py | 19 +++++++++++++------ |
16 |
pym/portage/emaint/modules/world/world.py | 8 ++++++-- |
17 |
9 files changed, 64 insertions(+), 28 deletions(-) |
18 |
|
19 |
diff --git a/pym/portage/emaint/main.py b/pym/portage/emaint/main.py |
20 |
index 65e3545..ef4383a 100644 |
21 |
--- a/pym/portage/emaint/main.py |
22 |
+++ b/pym/portage/emaint/main.py |
23 |
@@ -115,6 +115,7 @@ class TaskHandler(object): |
24 |
"""Runs the module tasks""" |
25 |
if tasks is None or func is None: |
26 |
return |
27 |
+ returncode = os.EX_OK |
28 |
for task in tasks: |
29 |
inst = task() |
30 |
show_progress = self.show_progress_bar and self.isatty |
31 |
@@ -135,14 +136,20 @@ class TaskHandler(object): |
32 |
# them for other tasks if there is more to do. |
33 |
'options': options.copy() |
34 |
} |
35 |
- result = getattr(inst, func)(**kwargs) |
36 |
+ rcode, msgs = getattr(inst, func)(**kwargs) |
37 |
if show_progress: |
38 |
# make sure the final progress is displayed |
39 |
self.progress_bar.display() |
40 |
print() |
41 |
self.progress_bar.stop() |
42 |
if self.callback: |
43 |
- self.callback(result) |
44 |
+ self.callback(msgs) |
45 |
+ # Keep the last error code when using the 'all' command. |
46 |
+ if rcode != os.EX_OK: |
47 |
+ returncode = rcode |
48 |
+ |
49 |
+ if returncode != os.EX_OK: |
50 |
+ sys.exit(returncode) |
51 |
|
52 |
|
53 |
def print_results(results): |
54 |
diff --git a/pym/portage/emaint/modules/binhost/binhost.py |
55 |
b/pym/portage/emaint/modules/binhost/binhost.py |
56 |
index cf1213e..8cf3da6 100644 |
57 |
--- a/pym/portage/emaint/modules/binhost/binhost.py |
58 |
+++ b/pym/portage/emaint/modules/binhost/binhost.py |
59 |
@@ -86,7 +86,9 @@ class BinhostHandler(object): |
60 |
stale = set(metadata).difference(cpv_all) |
61 |
for cpv in stale: |
62 |
errors.append("'%s' is not in the repository" % cpv) |
63 |
- return errors |
64 |
+ if errors: |
65 |
+ return (1, errors) |
66 |
+ return (os.EX_OK, None) |
67 |
|
68 |
def fix(self, **kwargs): |
69 |
onProgress = kwargs.get('onProgress', None) |
70 |
@@ -177,4 +179,4 @@ class BinhostHandler(object): |
71 |
if maxval == 0: |
72 |
maxval = 1 |
73 |
onProgress(maxval, maxval) |
74 |
- return None |
75 |
+ return (os.EX_OK, None) |
76 |
diff --git a/pym/portage/emaint/modules/config/config.py |
77 |
b/pym/portage/emaint/modules/config/config.py |
78 |
index dad024b..a4a58d9 100644 |
79 |
--- a/pym/portage/emaint/modules/config/config.py |
80 |
+++ b/pym/portage/emaint/modules/config/config.py |
81 |
@@ -36,7 +36,10 @@ class CleanConfig(object): |
82 |
if onProgress: |
83 |
onProgress(maxval, i+1) |
84 |
i += 1 |
85 |
- return self._format_output(messages) |
86 |
+ msgs = self._format_output(messages) |
87 |
+ if msgs: |
88 |
+ return (1, msgs) |
89 |
+ return (os.EX_OK, None) |
90 |
|
91 |
def fix(self, **kwargs): |
92 |
onProgress = kwargs.get('onProgress', None) |
93 |
@@ -65,7 +68,8 @@ class CleanConfig(object): |
94 |
i += 1 |
95 |
if modified: |
96 |
writedict(configs, self.target) |
97 |
- return self._format_output(messages, True) |
98 |
+ msgs = self._format_output(messages, True) |
99 |
+ return (os.EX_OK, msgs) |
100 |
|
101 |
def _format_output(self, messages=[], cleaned=False): |
102 |
output = [] |
103 |
diff --git a/pym/portage/emaint/modules/logs/logs.py |
104 |
b/pym/portage/emaint/modules/logs/logs.py |
105 |
index fe65cf5..8c638d7 100644 |
106 |
--- a/pym/portage/emaint/modules/logs/logs.py |
107 |
+++ b/pym/portage/emaint/modules/logs/logs.py |
108 |
@@ -40,7 +40,6 @@ class CleanLogs(object): |
109 |
'NUM': int: number of days |
110 |
'pretend': boolean |
111 |
""" |
112 |
- messages = [] |
113 |
num_of_days = None |
114 |
pretend = False |
115 |
if kwargs: |
116 |
@@ -70,10 +69,12 @@ class CleanLogs(object): |
117 |
clean_cmd.remove("-delete") |
118 |
|
119 |
if not clean_cmd: |
120 |
- return [] |
121 |
+ return (os.EX_OK, None) |
122 |
rval = self._clean_logs(clean_cmd, settings) |
123 |
- messages += self._convert_errors(rval) |
124 |
- return messages |
125 |
+ errors = self._convert_errors(rval) |
126 |
+ if errors: |
127 |
+ return (rval, errors) |
128 |
+ return (os.EX_OK, None) |
129 |
|
130 |
|
131 |
@staticmethod |
132 |
diff --git a/pym/portage/emaint/modules/merges/merges.py |
133 |
b/pym/portage/emaint/modules/merges/merges.py |
134 |
index 8f677c2..9a87d87 100644 |
135 |
--- a/pym/portage/emaint/modules/merges/merges.py |
136 |
+++ b/pym/portage/emaint/modules/merges/merges.py |
137 |
@@ -239,7 +239,9 @@ class MergesHandler(object): |
138 |
for pkg, mtime in failed_pkgs.items(): |
139 |
mtime_str = time.ctime(int(mtime)) |
140 |
errors.append("'%s' failed to merge on '%s'" % (pkg, mtime_str)) |
141 |
- return errors |
142 |
+ if errors: |
143 |
+ return (1, errors) |
144 |
+ return (os.EX_OK, None) |
145 |
|
146 |
|
147 |
def fix(self, **kwargs): |
148 |
@@ -247,13 +249,13 @@ class MergesHandler(object): |
149 |
module_output = kwargs.get('module_output', None) |
150 |
failed_pkgs = self._failed_pkgs() |
151 |
if not failed_pkgs: |
152 |
- return ['No failed merges found.'] |
153 |
+ return (os.EX_OK, ['No failed merges found.']) |
154 |
|
155 |
pkg_invalid_entries = set() |
156 |
pkg_atoms = set() |
157 |
self._get_pkg_atoms(failed_pkgs, pkg_atoms, pkg_invalid_entries) |
158 |
if pkg_invalid_entries: |
159 |
- return pkg_invalid_entries |
160 |
+ return (1, pkg_invalid_entries) |
161 |
|
162 |
try: |
163 |
self._tracking_file.save(failed_pkgs) |
164 |
@@ -261,7 +263,7 @@ class MergesHandler(object): |
165 |
errors = ['Unable to save failed merges to tracking file: %s\n' |
166 |
% str(ex)] |
167 |
errors.append(', '.join(sorted(failed_pkgs))) |
168 |
- return errors |
169 |
+ return (1, errors) |
170 |
self._remove_failed_dirs(failed_pkgs) |
171 |
results = self._emerge_pkg_atoms(module_output, pkg_atoms) |
172 |
# list any new failed merges |
173 |
@@ -276,12 +278,14 @@ class MergesHandler(object): |
174 |
if not vardb.cpv_exists(pkg_name): |
175 |
still_failed_pkgs[pkg] = mtime |
176 |
self._tracking_file.save(still_failed_pkgs) |
177 |
- return results |
178 |
+ if still_failed_pkgs: |
179 |
+ return (1, results) |
180 |
+ return (os.EX_OK, results) |
181 |
|
182 |
|
183 |
def purge(self, **kwargs): |
184 |
"""Attempt to remove previously saved tracking file.""" |
185 |
if not self._tracking_file.exists(): |
186 |
- return ['Tracking file not found.'] |
187 |
+ return (os.EX_OK, ['Tracking file not found.']) |
188 |
self._tracking_file.purge() |
189 |
- return ['Removed tracking file.'] |
190 |
+ return (os.EX_OK, ['Removed tracking file.']) |
191 |
diff --git a/pym/portage/emaint/modules/move/move.py |
192 |
b/pym/portage/emaint/modules/move/move.py |
193 |
index 41ca167..1a566c3 100644 |
194 |
--- a/pym/portage/emaint/modules/move/move.py |
195 |
+++ b/pym/portage/emaint/modules/move/move.py |
196 |
@@ -123,7 +123,10 @@ class MoveHandler(object): |
197 |
errors.append("'%s' has outdated metadata" % cpv) |
198 |
if onProgress: |
199 |
onProgress(maxval, i+1) |
200 |
- return errors |
201 |
+ |
202 |
+ if errors: |
203 |
+ return (1, errors) |
204 |
+ return (os.EX_OK, None) |
205 |
|
206 |
def fix(self, **kwargs): |
207 |
onProgress = kwargs.get('onProgress', None) |
208 |
@@ -156,7 +159,9 @@ class MoveHandler(object): |
209 |
# Searching for updates in all the metadata is relatively slow, so this |
210 |
# is where the progress bar comes out of indeterminate mode. |
211 |
self._tree.dbapi.update_ents(allupdates, onProgress=onProgress) |
212 |
- return errors |
213 |
+ if errors: |
214 |
+ return(1, errors) |
215 |
+ return (os.EX_OK, None) |
216 |
|
217 |
class MoveInstalled(MoveHandler): |
218 |
|
219 |
diff --git a/pym/portage/emaint/modules/resume/resume.py |
220 |
b/pym/portage/emaint/modules/resume/resume.py |
221 |
index 1bada52..648e8c1 100644 |
222 |
--- a/pym/portage/emaint/modules/resume/resume.py |
223 |
+++ b/pym/portage/emaint/modules/resume/resume.py |
224 |
@@ -2,6 +2,7 @@ |
225 |
# Distributed under the terms of the GNU General Public License v2 |
226 |
|
227 |
import portage |
228 |
+import os |
229 |
|
230 |
|
231 |
class CleanResume(object): |
232 |
@@ -37,7 +38,7 @@ class CleanResume(object): |
233 |
finally: |
234 |
if onProgress: |
235 |
onProgress(maxval, i+1) |
236 |
- return messages |
237 |
+ return (os.EX_OK, messages) |
238 |
|
239 |
def fix(self, **kwargs): |
240 |
onProgress = kwargs.get('onProgress', None) |
241 |
@@ -56,3 +57,4 @@ class CleanResume(object): |
242 |
onProgress(maxval, i+1) |
243 |
if delete_count: |
244 |
mtimedb.commit() |
245 |
+ return (os.EX_OK, None) |
246 |
diff --git a/pym/portage/emaint/modules/sync/sync.py |
247 |
b/pym/portage/emaint/modules/sync/sync.py |
248 |
index 15d63e2..03a684b 100644 |
249 |
--- a/pym/portage/emaint/modules/sync/sync.py |
250 |
+++ b/pym/portage/emaint/modules/sync/sync.py |
251 |
@@ -127,8 +127,8 @@ class SyncRepos(object): |
252 |
% (bold(", ".join(repos))) + "\n ...returning" |
253 |
] |
254 |
if return_messages: |
255 |
- return msgs |
256 |
- return |
257 |
+ return (1, msgs) |
258 |
+ return (1, None) |
259 |
return self._sync(selected, return_messages, |
260 |
emaint_opts=options) |
261 |
|
262 |
@@ -211,8 +211,8 @@ class SyncRepos(object): |
263 |
msgs.append("Emaint sync, nothing to sync... returning") |
264 |
if return_messages: |
265 |
msgs.extend(self.rmessage([('None', os.EX_OK)], 'sync')) |
266 |
- return msgs |
267 |
- return |
268 |
+ return (os.EX_OK, msgs) |
269 |
+ return (os.EX_OK, None) |
270 |
# Portage needs to ensure a sane umask for the files it creates. |
271 |
os.umask(0o22) |
272 |
|
273 |
@@ -232,6 +232,7 @@ class SyncRepos(object): |
274 |
sync_scheduler.wait() |
275 |
retvals = sync_scheduler.retvals |
276 |
msgs.extend(sync_scheduler.msgs) |
277 |
+ returncode = sync_scheduler.returncode |
278 |
|
279 |
if retvals: |
280 |
msgs.extend(self.rmessage(retvals, 'sync')) |
281 |
@@ -244,6 +245,8 @@ class SyncRepos(object): |
282 |
rcode = sync_manager.perform_post_sync_hook('') |
283 |
if rcode: |
284 |
msgs.extend(self.rmessage([('None', rcode)], 'post-sync')) |
285 |
+ if rcode != os.EX_OK: |
286 |
+ returncode = rcode |
287 |
|
288 |
# Reload the whole config. |
289 |
portage._sync_mode = False |
290 |
@@ -254,8 +257,8 @@ class SyncRepos(object): |
291 |
self.emerge_config.opts) |
292 |
|
293 |
if return_messages: |
294 |
- return msgs |
295 |
- return |
296 |
+ return (returncode, msgs) |
297 |
+ return (returncode, None) |
298 |
|
299 |
|
300 |
def _do_pkg_moves(self): |
301 |
@@ -323,6 +326,7 @@ class SyncScheduler(AsyncScheduler): |
302 |
self._init_graph() |
303 |
self.retvals = [] |
304 |
self.msgs = [] |
305 |
+ self.returncode = os.EX_OK |
306 |
|
307 |
def _init_graph(self): |
308 |
''' |
309 |
@@ -360,6 +364,9 @@ class SyncScheduler(AsyncScheduler): |
310 |
returncode, message, updatecache_flg, hooks_enabled = task.result |
311 |
if message: |
312 |
self.msgs.append(message) |
313 |
+ else: |
314 |
+ # Keep the last unsuccessful sync return code. |
315 |
+ self.returncode = returncode |
316 |
repo = task.kwargs['repo'].name |
317 |
self._running_repos.remove(repo) |
318 |
self.retvals.append((repo, returncode)) |
319 |
diff --git a/pym/portage/emaint/modules/world/world.py |
320 |
b/pym/portage/emaint/modules/world/world.py |
321 |
index 2c9dbff..d8a4e69 100644 |
322 |
--- a/pym/portage/emaint/modules/world/world.py |
323 |
+++ b/pym/portage/emaint/modules/world/world.py |
324 |
@@ -65,7 +65,9 @@ class WorldHandler(object): |
325 |
errors += ["'%s' is not installed" % x for x in self.not_installed] |
326 |
else: |
327 |
errors.append(self.world_file + " could not be opened for reading") |
328 |
- return errors |
329 |
+ if errors: |
330 |
+ return (1, errors) |
331 |
+ return (os.EX_OK, None) |
332 |
|
333 |
def fix(self, **kwargs): |
334 |
onProgress = kwargs.get('onProgress', None) |
335 |
@@ -83,7 +85,9 @@ class WorldHandler(object): |
336 |
except portage.exception.PortageException: |
337 |
errors.append("%s could not be opened for writing" % \ |
338 |
self.world_file) |
339 |
- return errors |
340 |
+ if errors: |
341 |
+ return (1, errors) |
342 |
+ return (os.EX_OK, None) |
343 |
finally: |
344 |
world_set.unlock() |
345 |
|
346 |
-- |
347 |
2.10.2 |