Gentoo Archives: gentoo-portage-dev

From: Alexandru Elisei <alexandru.elisei@×××××.com>
To: gentoo-portage-dev@l.g.o
Subject: [gentoo-portage-dev] Re: [PATCH V3] emaint: exit with non-zero status code when module fails (bug 567478)
Date: Wed, 18 Jan 2017 17:16:00
Message-Id: CAB-4s4kRPQN_9vAJK0aA0=noU6SrwDw-Li+k=Xup=9TEh=p60A@mail.gmail.com
In Reply to: [gentoo-portage-dev] [PATCH] emaint: exit with non-zero status code when module fails (bug 567478) by Alexandru Elisei
1 Module functions currently 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), where returncode is boolean True if the function
6 was successful or False otherwise. Emaint will inspect the return codes
7 and exit unsuccessfully if necessary.
8
9 The variable PORT_LOGDIR was added to the test environment to prevent
10 CleanLogs.clean() from failing when the variable isn't set or not a
11 directory.
12 ---
13 pym/portage/emaint/main.py | 12 +++++++++---
14 pym/portage/emaint/modules/binhost/binhost.py | 6 ++++--
15 pym/portage/emaint/modules/config/config.py | 6 ++++--
16 pym/portage/emaint/modules/logs/logs.py | 9 +++++----
17 pym/portage/emaint/modules/merges/merges.py | 18 +++++++++++-------
18 pym/portage/emaint/modules/move/move.py | 9 +++++++--
19 pym/portage/emaint/modules/resume/resume.py | 3 ++-
20 pym/portage/emaint/modules/sync/sync.py | 20 +++++++++++++-------
21 pym/portage/emaint/modules/world/world.py | 8 ++++++--
22 pym/portage/tests/emerge/test_simple.py | 1 +
23 10 files changed, 62 insertions(+), 30 deletions(-)
24
25 diff --git a/pym/portage/emaint/main.py b/pym/portage/emaint/main.py
26 index 65e3545..f448d6b 100644
27 --- a/pym/portage/emaint/main.py
28 +++ b/pym/portage/emaint/main.py
29 @@ -115,6 +115,7 @@ class TaskHandler(object):
30 """Runs the module tasks"""
31 if tasks is None or func is None:
32 return
33 + returncodes = []
34 for task in tasks:
35 inst = task()
36 show_progress = self.show_progress_bar and self.isatty
37 @@ -135,14 +136,17 @@ class TaskHandler(object):
38 # them for other tasks if there is more to do.
39 'options': options.copy()
40 }
41 - result = getattr(inst, func)(**kwargs)
42 + returncode, msgs = getattr(inst, func)(**kwargs)
43 + returncodes.append(returncode)
44 if show_progress:
45 # make sure the final progress is displayed
46 self.progress_bar.display()
47 print()
48 self.progress_bar.stop()
49 if self.callback:
50 - self.callback(result)
51 + self.callback(msgs)
52 +
53 + return returncodes
54
55
56 def print_results(results):
57 @@ -237,4 +241,6 @@ def emaint_main(myargv):
58 task_opts = options.__dict__
59 task_opts['return-messages'] = True
60 taskmaster = TaskHandler(callback=print_results, module_output=sys.stdout)
61 - taskmaster.run_tasks(tasks, func, status, options=task_opts)
62 + returncodes = taskmaster.run_tasks(tasks, func, status, options=task_opts)
63 +
64 + sys.exit(False in returncodes)
65 diff --git a/pym/portage/emaint/modules/binhost/binhost.py
66 b/pym/portage/emaint/modules/binhost/binhost.py
67 index cf1213e..527b02f 100644
68 --- a/pym/portage/emaint/modules/binhost/binhost.py
69 +++ b/pym/portage/emaint/modules/binhost/binhost.py
70 @@ -86,7 +86,9 @@ class BinhostHandler(object):
71 stale = set(metadata).difference(cpv_all)
72 for cpv in stale:
73 errors.append("'%s' is not in the repository" % cpv)
74 - return errors
75 + if errors:
76 + return (False, errors)
77 + return (True, None)
78
79 def fix(self, **kwargs):
80 onProgress = kwargs.get('onProgress', None)
81 @@ -177,4 +179,4 @@ class BinhostHandler(object):
82 if maxval == 0:
83 maxval = 1
84 onProgress(maxval, maxval)
85 - return None
86 + return (True, None)
87 diff --git a/pym/portage/emaint/modules/config/config.py
88 b/pym/portage/emaint/modules/config/config.py
89 index dad024b..a05a3c2 100644
90 --- a/pym/portage/emaint/modules/config/config.py
91 +++ b/pym/portage/emaint/modules/config/config.py
92 @@ -36,7 +36,8 @@ class CleanConfig(object):
93 if onProgress:
94 onProgress(maxval, i+1)
95 i += 1
96 - return self._format_output(messages)
97 + msgs = self._format_output(messages)
98 + return (True, msgs)
99
100 def fix(self, **kwargs):
101 onProgress = kwargs.get('onProgress', None)
102 @@ -65,7 +66,8 @@ class CleanConfig(object):
103 i += 1
104 if modified:
105 writedict(configs, self.target)
106 - return self._format_output(messages, True)
107 + msgs = self._format_output(messages, True)
108 + return (True, msgs)
109
110 def _format_output(self, messages=[], cleaned=False):
111 output = []
112 diff --git a/pym/portage/emaint/modules/logs/logs.py
113 b/pym/portage/emaint/modules/logs/logs.py
114 index fe65cf5..028084a 100644
115 --- a/pym/portage/emaint/modules/logs/logs.py
116 +++ b/pym/portage/emaint/modules/logs/logs.py
117 @@ -40,7 +40,6 @@ class CleanLogs(object):
118 'NUM': int: number of days
119 'pretend': boolean
120 """
121 - messages = []
122 num_of_days = None
123 pretend = False
124 if kwargs:
125 @@ -70,10 +69,12 @@ class CleanLogs(object):
126 clean_cmd.remove("-delete")
127
128 if not clean_cmd:
129 - return []
130 + return (True, None)
131 rval = self._clean_logs(clean_cmd, settings)
132 - messages += self._convert_errors(rval)
133 - return messages
134 + errors = self._convert_errors(rval)
135 + if errors:
136 + return (False, errors)
137 + return (True, None)
138
139
140 @staticmethod
141 diff --git a/pym/portage/emaint/modules/merges/merges.py
142 b/pym/portage/emaint/modules/merges/merges.py
143 index 8f677c2..416a725 100644
144 --- a/pym/portage/emaint/modules/merges/merges.py
145 +++ b/pym/portage/emaint/modules/merges/merges.py
146 @@ -239,7 +239,9 @@ class MergesHandler(object):
147 for pkg, mtime in failed_pkgs.items():
148 mtime_str = time.ctime(int(mtime))
149 errors.append("'%s' failed to merge on '%s'" % (pkg, mtime_str))
150 - return errors
151 + if errors:
152 + return (False, errors)
153 + return (True, None)
154
155
156 def fix(self, **kwargs):
157 @@ -247,13 +249,13 @@ class MergesHandler(object):
158 module_output = kwargs.get('module_output', None)
159 failed_pkgs = self._failed_pkgs()
160 if not failed_pkgs:
161 - return ['No failed merges found.']
162 + return (True, ['No failed merges found.'])
163
164 pkg_invalid_entries = set()
165 pkg_atoms = set()
166 self._get_pkg_atoms(failed_pkgs, pkg_atoms, pkg_invalid_entries)
167 if pkg_invalid_entries:
168 - return pkg_invalid_entries
169 + return (False, pkg_invalid_entries)
170
171 try:
172 self._tracking_file.save(failed_pkgs)
173 @@ -261,7 +263,7 @@ class MergesHandler(object):
174 errors = ['Unable to save failed merges to tracking file: %s\n'
175 % str(ex)]
176 errors.append(', '.join(sorted(failed_pkgs)))
177 - return errors
178 + return (False, errors)
179 self._remove_failed_dirs(failed_pkgs)
180 results = self._emerge_pkg_atoms(module_output, pkg_atoms)
181 # list any new failed merges
182 @@ -276,12 +278,14 @@ class MergesHandler(object):
183 if not vardb.cpv_exists(pkg_name):
184 still_failed_pkgs[pkg] = mtime
185 self._tracking_file.save(still_failed_pkgs)
186 - return results
187 + if still_failed_pkgs:
188 + return (False, results)
189 + return (True, results)
190
191
192 def purge(self, **kwargs):
193 """Attempt to remove previously saved tracking file."""
194 if not self._tracking_file.exists():
195 - return ['Tracking file not found.']
196 + return (True, ['Tracking file not found.'])
197 self._tracking_file.purge()
198 - return ['Removed tracking file.']
199 + return (True, ['Removed tracking file.'])
200 diff --git a/pym/portage/emaint/modules/move/move.py
201 b/pym/portage/emaint/modules/move/move.py
202 index 41ca167..1c2636d 100644
203 --- a/pym/portage/emaint/modules/move/move.py
204 +++ b/pym/portage/emaint/modules/move/move.py
205 @@ -123,7 +123,10 @@ class MoveHandler(object):
206 errors.append("'%s' has outdated metadata" % cpv)
207 if onProgress:
208 onProgress(maxval, i+1)
209 - return errors
210 +
211 + if errors:
212 + return (False, errors)
213 + return (True, None)
214
215 def fix(self, **kwargs):
216 onProgress = kwargs.get('onProgress', None)
217 @@ -156,7 +159,9 @@ class MoveHandler(object):
218 # Searching for updates in all the metadata is relatively slow, so this
219 # is where the progress bar comes out of indeterminate mode.
220 self._tree.dbapi.update_ents(allupdates, onProgress=onProgress)
221 - return errors
222 + if errors:
223 + return (False, errors)
224 + return (True, None)
225
226 class MoveInstalled(MoveHandler):
227
228 diff --git a/pym/portage/emaint/modules/resume/resume.py
229 b/pym/portage/emaint/modules/resume/resume.py
230 index 1bada52..0d65d41 100644
231 --- a/pym/portage/emaint/modules/resume/resume.py
232 +++ b/pym/portage/emaint/modules/resume/resume.py
233 @@ -37,7 +37,7 @@ class CleanResume(object):
234 finally:
235 if onProgress:
236 onProgress(maxval, i+1)
237 - return messages
238 + return (True, messages)
239
240 def fix(self, **kwargs):
241 onProgress = kwargs.get('onProgress', None)
242 @@ -56,3 +56,4 @@ class CleanResume(object):
243 onProgress(maxval, i+1)
244 if delete_count:
245 mtimedb.commit()
246 + return (True, None)
247 diff --git a/pym/portage/emaint/modules/sync/sync.py
248 b/pym/portage/emaint/modules/sync/sync.py
249 index 15d63e2..d867699 100644
250 --- a/pym/portage/emaint/modules/sync/sync.py
251 +++ b/pym/portage/emaint/modules/sync/sync.py
252 @@ -127,8 +127,8 @@ class SyncRepos(object):
253 % (bold(", ".join(repos))) + "\n ...returning"
254 ]
255 if return_messages:
256 - return msgs
257 - return
258 + return (False, msgs)
259 + return (False, None)
260 return self._sync(selected, return_messages,
261 emaint_opts=options)
262
263 @@ -211,8 +211,8 @@ class SyncRepos(object):
264 msgs.append("Emaint sync, nothing to sync... returning")
265 if return_messages:
266 msgs.extend(self.rmessage([('None', os.EX_OK)], 'sync'))
267 - return msgs
268 - return
269 + return (True, msgs)
270 + return (True, None)
271 # Portage needs to ensure a sane umask for the files it creates.
272 os.umask(0o22)
273
274 @@ -232,9 +232,14 @@ class SyncRepos(object):
275 sync_scheduler.wait()
276 retvals = sync_scheduler.retvals
277 msgs.extend(sync_scheduler.msgs)
278 + returncode = True
279
280 if retvals:
281 msgs.extend(self.rmessage(retvals, 'sync'))
282 + for repo, returncode in retvals:
283 + if returncode != os.EX_OK:
284 + returncode = False
285 + break
286 else:
287 msgs.extend(self.rmessage([('None', os.EX_OK)], 'sync'))
288
289 @@ -244,6 +249,8 @@ class SyncRepos(object):
290 rcode = sync_manager.perform_post_sync_hook('')
291 if rcode:
292 msgs.extend(self.rmessage([('None', rcode)], 'post-sync'))
293 + if rcode != os.EX_OK:
294 + returncode = False
295
296 # Reload the whole config.
297 portage._sync_mode = False
298 @@ -254,8 +261,8 @@ class SyncRepos(object):
299 self.emerge_config.opts)
300
301 if return_messages:
302 - return msgs
303 - return
304 + return (returncode, msgs)
305 + return (returncode, None)
306
307
308 def _do_pkg_moves(self):
309 @@ -355,7 +362,6 @@ class SyncScheduler(AsyncScheduler):
310 # that hooks will be called in a backward-compatible manner
311 # even if all sync tasks have failed.
312 hooks_enabled = True
313 - returncode = task.returncode
314 if task.returncode == os.EX_OK:
315 returncode, message, updatecache_flg, hooks_enabled = task.result
316 if message:
317 diff --git a/pym/portage/emaint/modules/world/world.py
318 b/pym/portage/emaint/modules/world/world.py
319 index 2c9dbff..ebc3adc 100644
320 --- a/pym/portage/emaint/modules/world/world.py
321 +++ b/pym/portage/emaint/modules/world/world.py
322 @@ -65,7 +65,9 @@ class WorldHandler(object):
323 errors += ["'%s' is not installed" % x for x in self.not_installed]
324 else:
325 errors.append(self.world_file + " could not be opened for reading")
326 - return errors
327 + if errors:
328 + return (False, errors)
329 + return (True, None)
330
331 def fix(self, **kwargs):
332 onProgress = kwargs.get('onProgress', None)
333 @@ -83,7 +85,9 @@ class WorldHandler(object):
334 except portage.exception.PortageException:
335 errors.append("%s could not be opened for writing" % \
336 self.world_file)
337 - return errors
338 + if errors:
339 + return (False, errors)
340 + return (True, None)
341 finally:
342 world_set.unlock()
343
344 diff --git a/pym/portage/tests/emerge/test_simple.py
345 b/pym/portage/tests/emerge/test_simple.py
346 index b1a2af5..5930f6c 100644
347 --- a/pym/portage/tests/emerge/test_simple.py
348 +++ b/pym/portage/tests/emerge/test_simple.py
349 @@ -382,6 +382,7 @@ pkg_preinst() {
350 "PORTAGE_PYTHON" : portage_python,
351 "PORTAGE_REPOSITORIES" : settings.repositories.config_string(),
352 "PORTAGE_TMPDIR" : portage_tmpdir,
353 + "PORT_LOGDIR" : portage_tmpdir,
354 "PYTHONDONTWRITEBYTECODE" : os.environ.get("PYTHONDONTWRITEBYTECODE", ""),
355 "PYTHONPATH" : pythonpath,
356 "__PORTAGE_TEST_PATH_OVERRIDE" : fake_bin,
357 --
358 2.10.2
359
360 On 1/17/17, Alexandru Elisei <alexandru.elisei@×××××.com> wrote:
361 > Currently module functions return a message to emaint after invocation.
362 > Emaint prints this message then exits normally (with a success return
363 > code) even if the module encountered an error. This patch aims to
364 > change this by having each module public function return a tuple of
365 > (returncode, message). Emaint will inspect the return code and will
366 > exit unsuccessfully if necessary.
367 > ---
368 > pym/portage/emaint/main.py | 11 +++++++++--
369 > pym/portage/emaint/modules/binhost/binhost.py | 6 ++++--
370 > pym/portage/emaint/modules/config/config.py | 8 ++++++--
371 > pym/portage/emaint/modules/logs/logs.py | 9 +++++----
372 > pym/portage/emaint/modules/merges/merges.py | 18 +++++++++++-------
373 > pym/portage/emaint/modules/move/move.py | 9 +++++++--
374 > pym/portage/emaint/modules/resume/resume.py | 4 +++-
375 > pym/portage/emaint/modules/sync/sync.py | 19 +++++++++++++------
376 > pym/portage/emaint/modules/world/world.py | 8 ++++++--
377 > 9 files changed, 64 insertions(+), 28 deletions(-)
378 >
379 > diff --git a/pym/portage/emaint/main.py b/pym/portage/emaint/main.py
380 > index 65e3545..ef4383a 100644
381 > --- a/pym/portage/emaint/main.py
382 > +++ b/pym/portage/emaint/main.py
383 > @@ -115,6 +115,7 @@ class TaskHandler(object):
384 > """Runs the module tasks"""
385 > if tasks is None or func is None:
386 > return
387 > + returncode = os.EX_OK
388 > for task in tasks:
389 > inst = task()
390 > show_progress = self.show_progress_bar and self.isatty
391 > @@ -135,14 +136,20 @@ class TaskHandler(object):
392 > # them for other tasks if there is more to do.
393 > 'options': options.copy()
394 > }
395 > - result = getattr(inst, func)(**kwargs)
396 > + rcode, msgs = getattr(inst, func)(**kwargs)
397 > if show_progress:
398 > # make sure the final progress is displayed
399 > self.progress_bar.display()
400 > print()
401 > self.progress_bar.stop()
402 > if self.callback:
403 > - self.callback(result)
404 > + self.callback(msgs)
405 > + # Keep the last error code when using the 'all' command.
406 > + if rcode != os.EX_OK:
407 > + returncode = rcode
408 > +
409 > + if returncode != os.EX_OK:
410 > + sys.exit(returncode)
411 >
412 >
413 > def print_results(results):
414 > diff --git a/pym/portage/emaint/modules/binhost/binhost.py
415 > b/pym/portage/emaint/modules/binhost/binhost.py
416 > index cf1213e..8cf3da6 100644
417 > --- a/pym/portage/emaint/modules/binhost/binhost.py
418 > +++ b/pym/portage/emaint/modules/binhost/binhost.py
419 > @@ -86,7 +86,9 @@ class BinhostHandler(object):
420 > stale = set(metadata).difference(cpv_all)
421 > for cpv in stale:
422 > errors.append("'%s' is not in the repository" % cpv)
423 > - return errors
424 > + if errors:
425 > + return (1, errors)
426 > + return (os.EX_OK, None)
427 >
428 > def fix(self, **kwargs):
429 > onProgress = kwargs.get('onProgress', None)
430 > @@ -177,4 +179,4 @@ class BinhostHandler(object):
431 > if maxval == 0:
432 > maxval = 1
433 > onProgress(maxval, maxval)
434 > - return None
435 > + return (os.EX_OK, None)
436 > diff --git a/pym/portage/emaint/modules/config/config.py
437 > b/pym/portage/emaint/modules/config/config.py
438 > index dad024b..a4a58d9 100644
439 > --- a/pym/portage/emaint/modules/config/config.py
440 > +++ b/pym/portage/emaint/modules/config/config.py
441 > @@ -36,7 +36,10 @@ class CleanConfig(object):
442 > if onProgress:
443 > onProgress(maxval, i+1)
444 > i += 1
445 > - return self._format_output(messages)
446 > + msgs = self._format_output(messages)
447 > + if msgs:
448 > + return (1, msgs)
449 > + return (os.EX_OK, None)
450 >
451 > def fix(self, **kwargs):
452 > onProgress = kwargs.get('onProgress', None)
453 > @@ -65,7 +68,8 @@ class CleanConfig(object):
454 > i += 1
455 > if modified:
456 > writedict(configs, self.target)
457 > - return self._format_output(messages, True)
458 > + msgs = self._format_output(messages, True)
459 > + return (os.EX_OK, msgs)
460 >
461 > def _format_output(self, messages=[], cleaned=False):
462 > output = []
463 > diff --git a/pym/portage/emaint/modules/logs/logs.py
464 > b/pym/portage/emaint/modules/logs/logs.py
465 > index fe65cf5..8c638d7 100644
466 > --- a/pym/portage/emaint/modules/logs/logs.py
467 > +++ b/pym/portage/emaint/modules/logs/logs.py
468 > @@ -40,7 +40,6 @@ class CleanLogs(object):
469 > 'NUM': int: number of days
470 > 'pretend': boolean
471 > """
472 > - messages = []
473 > num_of_days = None
474 > pretend = False
475 > if kwargs:
476 > @@ -70,10 +69,12 @@ class CleanLogs(object):
477 > clean_cmd.remove("-delete")
478 >
479 > if not clean_cmd:
480 > - return []
481 > + return (os.EX_OK, None)
482 > rval = self._clean_logs(clean_cmd, settings)
483 > - messages += self._convert_errors(rval)
484 > - return messages
485 > + errors = self._convert_errors(rval)
486 > + if errors:
487 > + return (rval, errors)
488 > + return (os.EX_OK, None)
489 >
490 >
491 > @staticmethod
492 > diff --git a/pym/portage/emaint/modules/merges/merges.py
493 > b/pym/portage/emaint/modules/merges/merges.py
494 > index 8f677c2..9a87d87 100644
495 > --- a/pym/portage/emaint/modules/merges/merges.py
496 > +++ b/pym/portage/emaint/modules/merges/merges.py
497 > @@ -239,7 +239,9 @@ class MergesHandler(object):
498 > for pkg, mtime in failed_pkgs.items():
499 > mtime_str = time.ctime(int(mtime))
500 > errors.append("'%s' failed to merge on '%s'" % (pkg, mtime_str))
501 > - return errors
502 > + if errors:
503 > + return (1, errors)
504 > + return (os.EX_OK, None)
505 >
506 >
507 > def fix(self, **kwargs):
508 > @@ -247,13 +249,13 @@ class MergesHandler(object):
509 > module_output = kwargs.get('module_output', None)
510 > failed_pkgs = self._failed_pkgs()
511 > if not failed_pkgs:
512 > - return ['No failed merges found.']
513 > + return (os.EX_OK, ['No failed merges found.'])
514 >
515 > pkg_invalid_entries = set()
516 > pkg_atoms = set()
517 > self._get_pkg_atoms(failed_pkgs, pkg_atoms, pkg_invalid_entries)
518 > if pkg_invalid_entries:
519 > - return pkg_invalid_entries
520 > + return (1, pkg_invalid_entries)
521 >
522 > try:
523 > self._tracking_file.save(failed_pkgs)
524 > @@ -261,7 +263,7 @@ class MergesHandler(object):
525 > errors = ['Unable to save failed merges to tracking file: %s\n'
526 > % str(ex)]
527 > errors.append(', '.join(sorted(failed_pkgs)))
528 > - return errors
529 > + return (1, errors)
530 > self._remove_failed_dirs(failed_pkgs)
531 > results = self._emerge_pkg_atoms(module_output, pkg_atoms)
532 > # list any new failed merges
533 > @@ -276,12 +278,14 @@ class MergesHandler(object):
534 > if not vardb.cpv_exists(pkg_name):
535 > still_failed_pkgs[pkg] = mtime
536 > self._tracking_file.save(still_failed_pkgs)
537 > - return results
538 > + if still_failed_pkgs:
539 > + return (1, results)
540 > + return (os.EX_OK, results)
541 >
542 >
543 > def purge(self, **kwargs):
544 > """Attempt to remove previously saved tracking file."""
545 > if not self._tracking_file.exists():
546 > - return ['Tracking file not found.']
547 > + return (os.EX_OK, ['Tracking file not found.'])
548 > self._tracking_file.purge()
549 > - return ['Removed tracking file.']
550 > + return (os.EX_OK, ['Removed tracking file.'])
551 > diff --git a/pym/portage/emaint/modules/move/move.py
552 > b/pym/portage/emaint/modules/move/move.py
553 > index 41ca167..1a566c3 100644
554 > --- a/pym/portage/emaint/modules/move/move.py
555 > +++ b/pym/portage/emaint/modules/move/move.py
556 > @@ -123,7 +123,10 @@ class MoveHandler(object):
557 > errors.append("'%s' has outdated metadata" % cpv)
558 > if onProgress:
559 > onProgress(maxval, i+1)
560 > - return errors
561 > +
562 > + if errors:
563 > + return (1, errors)
564 > + return (os.EX_OK, None)
565 >
566 > def fix(self, **kwargs):
567 > onProgress = kwargs.get('onProgress', None)
568 > @@ -156,7 +159,9 @@ class MoveHandler(object):
569 > # Searching for updates in all the metadata is relatively slow, so this
570 > # is where the progress bar comes out of indeterminate mode.
571 > self._tree.dbapi.update_ents(allupdates, onProgress=onProgress)
572 > - return errors
573 > + if errors:
574 > + return(1, errors)
575 > + return (os.EX_OK, None)
576 >
577 > class MoveInstalled(MoveHandler):
578 >
579 > diff --git a/pym/portage/emaint/modules/resume/resume.py
580 > b/pym/portage/emaint/modules/resume/resume.py
581 > index 1bada52..648e8c1 100644
582 > --- a/pym/portage/emaint/modules/resume/resume.py
583 > +++ b/pym/portage/emaint/modules/resume/resume.py
584 > @@ -2,6 +2,7 @@
585 > # Distributed under the terms of the GNU General Public License v2
586 >
587 > import portage
588 > +import os
589 >
590 >
591 > class CleanResume(object):
592 > @@ -37,7 +38,7 @@ class CleanResume(object):
593 > finally:
594 > if onProgress:
595 > onProgress(maxval, i+1)
596 > - return messages
597 > + return (os.EX_OK, messages)
598 >
599 > def fix(self, **kwargs):
600 > onProgress = kwargs.get('onProgress', None)
601 > @@ -56,3 +57,4 @@ class CleanResume(object):
602 > onProgress(maxval, i+1)
603 > if delete_count:
604 > mtimedb.commit()
605 > + return (os.EX_OK, None)
606 > diff --git a/pym/portage/emaint/modules/sync/sync.py
607 > b/pym/portage/emaint/modules/sync/sync.py
608 > index 15d63e2..03a684b 100644
609 > --- a/pym/portage/emaint/modules/sync/sync.py
610 > +++ b/pym/portage/emaint/modules/sync/sync.py
611 > @@ -127,8 +127,8 @@ class SyncRepos(object):
612 > % (bold(", ".join(repos))) + "\n ...returning"
613 > ]
614 > if return_messages:
615 > - return msgs
616 > - return
617 > + return (1, msgs)
618 > + return (1, None)
619 > return self._sync(selected, return_messages,
620 > emaint_opts=options)
621 >
622 > @@ -211,8 +211,8 @@ class SyncRepos(object):
623 > msgs.append("Emaint sync, nothing to sync... returning")
624 > if return_messages:
625 > msgs.extend(self.rmessage([('None', os.EX_OK)], 'sync'))
626 > - return msgs
627 > - return
628 > + return (os.EX_OK, msgs)
629 > + return (os.EX_OK, None)
630 > # Portage needs to ensure a sane umask for the files it creates.
631 > os.umask(0o22)
632 >
633 > @@ -232,6 +232,7 @@ class SyncRepos(object):
634 > sync_scheduler.wait()
635 > retvals = sync_scheduler.retvals
636 > msgs.extend(sync_scheduler.msgs)
637 > + returncode = sync_scheduler.returncode
638 >
639 > if retvals:
640 > msgs.extend(self.rmessage(retvals, 'sync'))
641 > @@ -244,6 +245,8 @@ class SyncRepos(object):
642 > rcode = sync_manager.perform_post_sync_hook('')
643 > if rcode:
644 > msgs.extend(self.rmessage([('None', rcode)], 'post-sync'))
645 > + if rcode != os.EX_OK:
646 > + returncode = rcode
647 >
648 > # Reload the whole config.
649 > portage._sync_mode = False
650 > @@ -254,8 +257,8 @@ class SyncRepos(object):
651 > self.emerge_config.opts)
652 >
653 > if return_messages:
654 > - return msgs
655 > - return
656 > + return (returncode, msgs)
657 > + return (returncode, None)
658 >
659 >
660 > def _do_pkg_moves(self):
661 > @@ -323,6 +326,7 @@ class SyncScheduler(AsyncScheduler):
662 > self._init_graph()
663 > self.retvals = []
664 > self.msgs = []
665 > + self.returncode = os.EX_OK
666 >
667 > def _init_graph(self):
668 > '''
669 > @@ -360,6 +364,9 @@ class SyncScheduler(AsyncScheduler):
670 > returncode, message, updatecache_flg, hooks_enabled = task.result
671 > if message:
672 > self.msgs.append(message)
673 > + else:
674 > + # Keep the last unsuccessful sync return code.
675 > + self.returncode = returncode
676 > repo = task.kwargs['repo'].name
677 > self._running_repos.remove(repo)
678 > self.retvals.append((repo, returncode))
679 > diff --git a/pym/portage/emaint/modules/world/world.py
680 > b/pym/portage/emaint/modules/world/world.py
681 > index 2c9dbff..d8a4e69 100644
682 > --- a/pym/portage/emaint/modules/world/world.py
683 > +++ b/pym/portage/emaint/modules/world/world.py
684 > @@ -65,7 +65,9 @@ class WorldHandler(object):
685 > errors += ["'%s' is not installed" % x for x in self.not_installed]
686 > else:
687 > errors.append(self.world_file + " could not be opened for reading")
688 > - return errors
689 > + if errors:
690 > + return (1, errors)
691 > + return (os.EX_OK, None)
692 >
693 > def fix(self, **kwargs):
694 > onProgress = kwargs.get('onProgress', None)
695 > @@ -83,7 +85,9 @@ class WorldHandler(object):
696 > except portage.exception.PortageException:
697 > errors.append("%s could not be opened for writing" % \
698 > self.world_file)
699 > - return errors
700 > + if errors:
701 > + return (1, errors)
702 > + return (os.EX_OK, None)
703 > finally:
704 > world_set.unlock()
705 >
706 > --
707 > 2.10.2
708 >

Replies