Module functions currently return a message to emaint after invocation.
Emaint prints this message then exits normally (with a success return
code) even if the module encountered an error. This patch aims to
change this by having each module public function return a tuple of
(returncode, message), where returncode is boolean True if the function
was successful or False otherwise. Emaint will inspect the return codes
and exit unsuccessfully if necessary.
#
# I've modified the patch as per Brian's suggestions:
# - the modules return True on success and False on failure.
# - TaskHandler.run_tasks() returns a list of all the module return
# codes, then emaint_main() exits.
# - the portage/pym/portage/tests/emerge/test_simple.py change wasn't
# present in the first version of the patch because of a subtle bug that
# I introduced: rval was None when the variable PORT_LOGDIR wasn't set,
# it was different from os.EX_OK so TaskHandler.run_tasks() was exiting
# with sys.exit(None), which is zero - success.
---
 pym/portage/emaint/main.py                    | 12 +++++++++---
 pym/portage/emaint/modules/binhost/binhost.py |  6 ++++--
 pym/portage/emaint/modules/config/config.py   |  6 ++++--
 pym/portage/emaint/modules/logs/logs.py       |  9 +++++----
 pym/portage/emaint/modules/merges/merges.py   | 18 +++++++++++-------
 pym/portage/emaint/modules/move/move.py       |  9 +++++++--
 pym/portage/emaint/modules/resume/resume.py   |  4 +++-
 pym/portage/emaint/modules/sync/sync.py       | 20 +++++++++++++-------
 pym/portage/emaint/modules/world/world.py     |  8 ++++++--
 pym/portage/tests/emerge/test_simple.py       |  1 +
 10 files changed, 63 insertions(+), 30 deletions(-)

diff --git a/pym/portage/emaint/main.py b/pym/portage/emaint/main.py
index 65e3545..f448d6b 100644
--- a/pym/portage/emaint/main.py
+++ b/pym/portage/emaint/main.py
@@ -115,6 +115,7 @@ class TaskHandler(object):
                """Runs the module tasks"""
                if tasks is None or func is None:
                        return
+               returncodes = []
                for task in tasks:
                        inst = task()
                        show_progress = self.show_progress_bar and self.isatty
@@ -135,14 +136,17 @@ class TaskHandler(object):
                                # them for other tasks if there is more to do.
                                'options': options.copy()
                                }
-                       result = getattr(inst, func)(**kwargs)
+                       returncode, msgs = getattr(inst, func)(**kwargs)
+                       returncodes.append(returncode)
                        if show_progress:
                                # make sure the final progress is displayed
                                self.progress_bar.display()
                                print()
                                self.progress_bar.stop()
                        if self.callback:
-                               self.callback(result)
+                               self.callback(msgs)
+
+               return returncodes


 def print_results(results):
@@ -237,4 +241,6 @@ def emaint_main(myargv):
        task_opts = options.__dict__
        task_opts['return-messages'] = True
        taskmaster = TaskHandler(callback=print_results, 
module_output=sys.stdout)
-       taskmaster.run_tasks(tasks, func, status, options=task_opts)
+       returncodes = taskmaster.run_tasks(tasks, func, status, 
options=task_opts)
+
+       sys.exit(False in returncodes)
diff --git a/pym/portage/emaint/modules/binhost/binhost.py
b/pym/portage/emaint/modules/binhost/binhost.py
index cf1213e..527b02f 100644
--- a/pym/portage/emaint/modules/binhost/binhost.py
+++ b/pym/portage/emaint/modules/binhost/binhost.py
@@ -86,7 +86,9 @@ class BinhostHandler(object):
                stale = set(metadata).difference(cpv_all)
                for cpv in stale:
                        errors.append("'%s' is not in the repository" % cpv)
-               return errors
+               if errors:
+                       return (False, errors)
+               return (True, None)

        def fix(self,  **kwargs):
                onProgress = kwargs.get('onProgress', None)
@@ -177,4 +179,4 @@ class BinhostHandler(object):
                        if maxval == 0:
                                maxval = 1
                        onProgress(maxval, maxval)
-               return None
+               return (True, None)
diff --git a/pym/portage/emaint/modules/config/config.py
b/pym/portage/emaint/modules/config/config.py
index dad024b..a05a3c2 100644
--- a/pym/portage/emaint/modules/config/config.py
+++ b/pym/portage/emaint/modules/config/config.py
@@ -36,7 +36,8 @@ class CleanConfig(object):
                        if onProgress:
                                onProgress(maxval, i+1)
                                i += 1
-               return self._format_output(messages)
+               msgs = self._format_output(messages)
+               return (True, msgs)

        def fix(self, **kwargs):
                onProgress = kwargs.get('onProgress', None)
@@ -65,7 +66,8 @@ class CleanConfig(object):
                                i += 1
                if modified:
                        writedict(configs, self.target)
-               return self._format_output(messages, True)
+               msgs = self._format_output(messages, True)
+               return (True, msgs)

        def _format_output(self, messages=[], cleaned=False):
                output = []
diff --git a/pym/portage/emaint/modules/logs/logs.py
b/pym/portage/emaint/modules/logs/logs.py
index fe65cf5..028084a 100644
--- a/pym/portage/emaint/modules/logs/logs.py
+++ b/pym/portage/emaint/modules/logs/logs.py
@@ -40,7 +40,6 @@ class CleanLogs(object):
                                'NUM': int: number of days
                                'pretend': boolean
                """
-               messages = []
                num_of_days = None
                pretend = False
                if kwargs:
@@ -70,10 +69,12 @@ class CleanLogs(object):
                                        clean_cmd.remove("-delete")

                if not clean_cmd:
-                       return []
+                       return (True, None)
                rval = self._clean_logs(clean_cmd, settings)
-               messages += self._convert_errors(rval)
-               return messages
+               errors = self._convert_errors(rval)
+               if errors:
+                       return (False, errors)
+               return (True, None)


        @staticmethod
diff --git a/pym/portage/emaint/modules/merges/merges.py
b/pym/portage/emaint/modules/merges/merges.py
index 8f677c2..416a725 100644
--- a/pym/portage/emaint/modules/merges/merges.py
+++ b/pym/portage/emaint/modules/merges/merges.py
@@ -239,7 +239,9 @@ class MergesHandler(object):
                for pkg, mtime in failed_pkgs.items():
                        mtime_str = time.ctime(int(mtime))
                        errors.append("'%s' failed to merge on '%s'" % (pkg, 
mtime_str))
-               return errors
+               if errors:
+                       return (False, errors)
+               return (True, None)


        def fix(self, **kwargs):
@@ -247,13 +249,13 @@ class MergesHandler(object):
                module_output = kwargs.get('module_output', None)
                failed_pkgs = self._failed_pkgs()
                if not failed_pkgs:
-                       return ['No failed merges found.']
+                       return (True, ['No failed merges found.'])

                pkg_invalid_entries = set()
                pkg_atoms = set()
                self._get_pkg_atoms(failed_pkgs, pkg_atoms, pkg_invalid_entries)
                if pkg_invalid_entries:
-                       return pkg_invalid_entries
+                       return (False, pkg_invalid_entries)

                try:
                        self._tracking_file.save(failed_pkgs)
@@ -261,7 +263,7 @@ class MergesHandler(object):
                        errors = ['Unable to save failed merges to tracking 
file: %s\n'
                                % str(ex)]
                        errors.append(', '.join(sorted(failed_pkgs)))
-                       return errors
+                       return (False, errors)
                self._remove_failed_dirs(failed_pkgs)
                results = self._emerge_pkg_atoms(module_output, pkg_atoms)
                # list any new failed merges
@@ -276,12 +278,14 @@ class MergesHandler(object):
                        if not vardb.cpv_exists(pkg_name):
                                still_failed_pkgs[pkg] = mtime
                self._tracking_file.save(still_failed_pkgs)
-               return results
+               if still_failed_pkgs:
+                       return (False, results)
+               return (True, results)


        def purge(self, **kwargs):
                """Attempt to remove previously saved tracking file."""
                if not self._tracking_file.exists():
-                       return ['Tracking file not found.']
+                       return (True, ['Tracking file not found.'])
                self._tracking_file.purge()
-               return ['Removed tracking file.']
+               return (True, ['Removed tracking file.'])
diff --git a/pym/portage/emaint/modules/move/move.py
b/pym/portage/emaint/modules/move/move.py
index 41ca167..1c2636d 100644
--- a/pym/portage/emaint/modules/move/move.py
+++ b/pym/portage/emaint/modules/move/move.py
@@ -123,7 +123,10 @@ class MoveHandler(object):
                                errors.append("'%s' has outdated metadata" % 
cpv)
                        if onProgress:
                                onProgress(maxval, i+1)
-               return errors
+
+               if errors:
+                       return (False, errors)
+               return (True, None)

        def fix(self,  **kwargs):
                onProgress = kwargs.get('onProgress', None)
@@ -156,7 +159,9 @@ class MoveHandler(object):
                # Searching for updates in all the metadata is relatively slow, 
so this
                # is where the progress bar comes out of indeterminate mode.
                self._tree.dbapi.update_ents(allupdates, onProgress=onProgress)
-               return errors
+               if errors:
+                       return (False, errors)
+               return (True, None)

 class MoveInstalled(MoveHandler):

diff --git a/pym/portage/emaint/modules/resume/resume.py
b/pym/portage/emaint/modules/resume/resume.py
index 1bada52..1d14275 100644
--- a/pym/portage/emaint/modules/resume/resume.py
+++ b/pym/portage/emaint/modules/resume/resume.py
@@ -2,6 +2,7 @@
 # Distributed under the terms of the GNU General Public License v2

 import portage
+import os


 class CleanResume(object):
@@ -37,7 +38,7 @@ class CleanResume(object):
                        finally:
                                if onProgress:
                                        onProgress(maxval, i+1)
-               return messages
+               return (True, messages)

        def fix(self,  **kwargs):
                onProgress = kwargs.get('onProgress', None)
@@ -56,3 +57,4 @@ class CleanResume(object):
                                        onProgress(maxval, i+1)
                if delete_count:
                        mtimedb.commit()
+               return (True, None)
diff --git a/pym/portage/emaint/modules/sync/sync.py
b/pym/portage/emaint/modules/sync/sync.py
index 15d63e2..d867699 100644
--- a/pym/portage/emaint/modules/sync/sync.py
+++ b/pym/portage/emaint/modules/sync/sync.py
@@ -127,8 +127,8 @@ class SyncRepos(object):
                                % (bold(", ".join(repos))) + "\n   ...returning"
                                ]
                        if return_messages:
-                               return msgs
-                       return
+                               return (False, msgs)
+                       return (False, None)
                return self._sync(selected, return_messages,
                        emaint_opts=options)

@@ -211,8 +211,8 @@ class SyncRepos(object):
                        msgs.append("Emaint sync, nothing to sync... returning")
                        if return_messages:
                                msgs.extend(self.rmessage([('None', os.EX_OK)], 
'sync'))
-                               return msgs
-                       return
+                               return (True, msgs)
+                       return (True, None)
                # Portage needs to ensure a sane umask for the files it creates.
                os.umask(0o22)

@@ -232,9 +232,14 @@ class SyncRepos(object):
                sync_scheduler.wait()
                retvals = sync_scheduler.retvals
                msgs.extend(sync_scheduler.msgs)
+               returncode = True

                if retvals:
                        msgs.extend(self.rmessage(retvals, 'sync'))
+                       for repo, returncode in retvals:
+                               if returncode != os.EX_OK:
+                                       returncode = False
+                                       break
                else:
                        msgs.extend(self.rmessage([('None', os.EX_OK)], 'sync'))

@@ -244,6 +249,8 @@ class SyncRepos(object):
                        rcode = sync_manager.perform_post_sync_hook('')
                        if rcode:
                                msgs.extend(self.rmessage([('None', rcode)], 
'post-sync'))
+                               if rcode != os.EX_OK:
+                                       returncode = False

                # Reload the whole config.
                portage._sync_mode = False
@@ -254,8 +261,8 @@ class SyncRepos(object):
                        self.emerge_config.opts)

                if return_messages:
-                       return msgs
-               return
+                       return (returncode, msgs)
+               return (returncode, None)


        def _do_pkg_moves(self):
@@ -355,7 +362,6 @@ class SyncScheduler(AsyncScheduler):
                # that hooks will be called in a backward-compatible manner
                # even if all sync tasks have failed.
                hooks_enabled = True
-               returncode = task.returncode
                if task.returncode == os.EX_OK:
                        returncode, message, updatecache_flg, hooks_enabled = 
task.result
                        if message:
diff --git a/pym/portage/emaint/modules/world/world.py
b/pym/portage/emaint/modules/world/world.py
index 2c9dbff..ebc3adc 100644
--- a/pym/portage/emaint/modules/world/world.py
+++ b/pym/portage/emaint/modules/world/world.py
@@ -65,7 +65,9 @@ class WorldHandler(object):
                        errors += ["'%s' is not installed" % x for x in 
self.not_installed]
                else:
                        errors.append(self.world_file + " could not be opened 
for reading")
-               return errors
+               if errors:
+                       return (False, errors)
+               return (True, None)

        def fix(self, **kwargs):
                onProgress = kwargs.get('onProgress', None)
@@ -83,7 +85,9 @@ class WorldHandler(object):
                                except portage.exception.PortageException:
                                        errors.append("%s could not be opened 
for writing" % \
                                                self.world_file)
-                       return errors
+                       if errors:
+                               return (False, errors)
+                       return (True, None)
                finally:
                        world_set.unlock()

diff --git a/pym/portage/tests/emerge/test_simple.py
b/pym/portage/tests/emerge/test_simple.py
index b1a2af5..5930f6c 100644
--- a/pym/portage/tests/emerge/test_simple.py
+++ b/pym/portage/tests/emerge/test_simple.py
@@ -382,6 +382,7 @@ pkg_preinst() {
                        "PORTAGE_PYTHON" : portage_python,
                        "PORTAGE_REPOSITORIES" : 
settings.repositories.config_string(),
                        "PORTAGE_TMPDIR" : portage_tmpdir,
+                       "PORT_LOGDIR" : portage_tmpdir,
                        "PYTHONDONTWRITEBYTECODE" : 
os.environ.get("PYTHONDONTWRITEBYTECODE", ""),
                        "PYTHONPATH" : pythonpath,
                        "__PORTAGE_TEST_PATH_OVERRIDE" : fake_bin,
-- 
2.10.2

On 1/17/17, Alexandru Elisei <alexandru.eli...@gmail.com> wrote:
> Currently module functions return a message to emaint after invocation.
> Emaint prints this message then exits normally (with a success return
> code) even if the module encountered an error. This patch aims to
> change this by having each module public function return a tuple of
> (returncode, message). Emaint will inspect the return code and will
> exit unsuccessfully if necessary.
> ---
>  pym/portage/emaint/main.py                    | 11 +++++++++--
>  pym/portage/emaint/modules/binhost/binhost.py |  6 ++++--
>  pym/portage/emaint/modules/config/config.py   |  8 ++++++--
>  pym/portage/emaint/modules/logs/logs.py       |  9 +++++----
>  pym/portage/emaint/modules/merges/merges.py   | 18 +++++++++++-------
>  pym/portage/emaint/modules/move/move.py       |  9 +++++++--
>  pym/portage/emaint/modules/resume/resume.py   |  4 +++-
>  pym/portage/emaint/modules/sync/sync.py       | 19 +++++++++++++------
>  pym/portage/emaint/modules/world/world.py     |  8 ++++++--
>  9 files changed, 64 insertions(+), 28 deletions(-)
>
> diff --git a/pym/portage/emaint/main.py b/pym/portage/emaint/main.py
> index 65e3545..ef4383a 100644
> --- a/pym/portage/emaint/main.py
> +++ b/pym/portage/emaint/main.py
> @@ -115,6 +115,7 @@ class TaskHandler(object):
>               """Runs the module tasks"""
>               if tasks is None or func is None:
>                       return
> +             returncode = os.EX_OK
>               for task in tasks:
>                       inst = task()
>                       show_progress = self.show_progress_bar and self.isatty
> @@ -135,14 +136,20 @@ class TaskHandler(object):
>                               # them for other tasks if there is more to do.
>                               'options': options.copy()
>                               }
> -                     result = getattr(inst, func)(**kwargs)
> +                     rcode, msgs = getattr(inst, func)(**kwargs)
>                       if show_progress:
>                               # make sure the final progress is displayed
>                               self.progress_bar.display()
>                               print()
>                               self.progress_bar.stop()
>                       if self.callback:
> -                             self.callback(result)
> +                             self.callback(msgs)
> +                     # Keep the last error code when using the 'all' command.
> +                     if rcode != os.EX_OK:
> +                             returncode = rcode
> +
> +             if returncode != os.EX_OK:
> +                     sys.exit(returncode)
>
>
>  def print_results(results):
> diff --git a/pym/portage/emaint/modules/binhost/binhost.py
> b/pym/portage/emaint/modules/binhost/binhost.py
> index cf1213e..8cf3da6 100644
> --- a/pym/portage/emaint/modules/binhost/binhost.py
> +++ b/pym/portage/emaint/modules/binhost/binhost.py
> @@ -86,7 +86,9 @@ class BinhostHandler(object):
>               stale = set(metadata).difference(cpv_all)
>               for cpv in stale:
>                       errors.append("'%s' is not in the repository" % cpv)
> -             return errors
> +             if errors:
> +                     return (1, errors)
> +             return (os.EX_OK, None)
>
>       def fix(self,  **kwargs):
>               onProgress = kwargs.get('onProgress', None)
> @@ -177,4 +179,4 @@ class BinhostHandler(object):
>                       if maxval == 0:
>                               maxval = 1
>                       onProgress(maxval, maxval)
> -             return None
> +             return (os.EX_OK, None)
> diff --git a/pym/portage/emaint/modules/config/config.py
> b/pym/portage/emaint/modules/config/config.py
> index dad024b..a4a58d9 100644
> --- a/pym/portage/emaint/modules/config/config.py
> +++ b/pym/portage/emaint/modules/config/config.py
> @@ -36,7 +36,10 @@ class CleanConfig(object):
>                       if onProgress:
>                               onProgress(maxval, i+1)
>                               i += 1
> -             return self._format_output(messages)
> +             msgs = self._format_output(messages)
> +             if msgs:
> +                     return (1, msgs)
> +             return (os.EX_OK, None)
>
>       def fix(self, **kwargs):
>               onProgress = kwargs.get('onProgress', None)
> @@ -65,7 +68,8 @@ class CleanConfig(object):
>                               i += 1
>               if modified:
>                       writedict(configs, self.target)
> -             return self._format_output(messages, True)
> +             msgs = self._format_output(messages, True)
> +             return (os.EX_OK, msgs)
>
>       def _format_output(self, messages=[], cleaned=False):
>               output = []
> diff --git a/pym/portage/emaint/modules/logs/logs.py
> b/pym/portage/emaint/modules/logs/logs.py
> index fe65cf5..8c638d7 100644
> --- a/pym/portage/emaint/modules/logs/logs.py
> +++ b/pym/portage/emaint/modules/logs/logs.py
> @@ -40,7 +40,6 @@ class CleanLogs(object):
>                               'NUM': int: number of days
>                               'pretend': boolean
>               """
> -             messages = []
>               num_of_days = None
>               pretend = False
>               if kwargs:
> @@ -70,10 +69,12 @@ class CleanLogs(object):
>                                       clean_cmd.remove("-delete")
>
>               if not clean_cmd:
> -                     return []
> +                     return (os.EX_OK, None)
>               rval = self._clean_logs(clean_cmd, settings)
> -             messages += self._convert_errors(rval)
> -             return messages
> +             errors = self._convert_errors(rval)
> +             if errors:
> +                     return (rval, errors)
> +             return (os.EX_OK, None)
>
>
>       @staticmethod
> diff --git a/pym/portage/emaint/modules/merges/merges.py
> b/pym/portage/emaint/modules/merges/merges.py
> index 8f677c2..9a87d87 100644
> --- a/pym/portage/emaint/modules/merges/merges.py
> +++ b/pym/portage/emaint/modules/merges/merges.py
> @@ -239,7 +239,9 @@ class MergesHandler(object):
>               for pkg, mtime in failed_pkgs.items():
>                       mtime_str = time.ctime(int(mtime))
>                       errors.append("'%s' failed to merge on '%s'" % (pkg, 
> mtime_str))
> -             return errors
> +             if errors:
> +                     return (1, errors)
> +             return (os.EX_OK, None)
>
>
>       def fix(self, **kwargs):
> @@ -247,13 +249,13 @@ class MergesHandler(object):
>               module_output = kwargs.get('module_output', None)
>               failed_pkgs = self._failed_pkgs()
>               if not failed_pkgs:
> -                     return ['No failed merges found.']
> +                     return (os.EX_OK, ['No failed merges found.'])
>
>               pkg_invalid_entries = set()
>               pkg_atoms = set()
>               self._get_pkg_atoms(failed_pkgs, pkg_atoms, pkg_invalid_entries)
>               if pkg_invalid_entries:
> -                     return pkg_invalid_entries
> +                     return (1, pkg_invalid_entries)
>
>               try:
>                       self._tracking_file.save(failed_pkgs)
> @@ -261,7 +263,7 @@ class MergesHandler(object):
>                       errors = ['Unable to save failed merges to tracking 
> file: %s\n'
>                               % str(ex)]
>                       errors.append(', '.join(sorted(failed_pkgs)))
> -                     return errors
> +                     return (1, errors)
>               self._remove_failed_dirs(failed_pkgs)
>               results = self._emerge_pkg_atoms(module_output, pkg_atoms)
>               # list any new failed merges
> @@ -276,12 +278,14 @@ class MergesHandler(object):
>                       if not vardb.cpv_exists(pkg_name):
>                               still_failed_pkgs[pkg] = mtime
>               self._tracking_file.save(still_failed_pkgs)
> -             return results
> +             if still_failed_pkgs:
> +                     return (1, results)
> +             return (os.EX_OK, results)
>
>
>       def purge(self, **kwargs):
>               """Attempt to remove previously saved tracking file."""
>               if not self._tracking_file.exists():
> -                     return ['Tracking file not found.']
> +                     return (os.EX_OK, ['Tracking file not found.'])
>               self._tracking_file.purge()
> -             return ['Removed tracking file.']
> +             return (os.EX_OK, ['Removed tracking file.'])
> diff --git a/pym/portage/emaint/modules/move/move.py
> b/pym/portage/emaint/modules/move/move.py
> index 41ca167..1a566c3 100644
> --- a/pym/portage/emaint/modules/move/move.py
> +++ b/pym/portage/emaint/modules/move/move.py
> @@ -123,7 +123,10 @@ class MoveHandler(object):
>                               errors.append("'%s' has outdated metadata" % 
> cpv)
>                       if onProgress:
>                               onProgress(maxval, i+1)
> -             return errors
> +
> +             if errors:
> +                     return (1, errors)
> +             return (os.EX_OK, None)
>
>       def fix(self,  **kwargs):
>               onProgress = kwargs.get('onProgress', None)
> @@ -156,7 +159,9 @@ class MoveHandler(object):
>               # Searching for updates in all the metadata is relatively slow, 
> so this
>               # is where the progress bar comes out of indeterminate mode.
>               self._tree.dbapi.update_ents(allupdates, onProgress=onProgress)
> -             return errors
> +             if errors:
> +                     return(1, errors)
> +             return (os.EX_OK, None)
>
>  class MoveInstalled(MoveHandler):
>
> diff --git a/pym/portage/emaint/modules/resume/resume.py
> b/pym/portage/emaint/modules/resume/resume.py
> index 1bada52..648e8c1 100644
> --- a/pym/portage/emaint/modules/resume/resume.py
> +++ b/pym/portage/emaint/modules/resume/resume.py
> @@ -2,6 +2,7 @@
>  # Distributed under the terms of the GNU General Public License v2
>
>  import portage
> +import os
>
>
>  class CleanResume(object):
> @@ -37,7 +38,7 @@ class CleanResume(object):
>                       finally:
>                               if onProgress:
>                                       onProgress(maxval, i+1)
> -             return messages
> +             return (os.EX_OK, messages)
>
>       def fix(self,  **kwargs):
>               onProgress = kwargs.get('onProgress', None)
> @@ -56,3 +57,4 @@ class CleanResume(object):
>                                       onProgress(maxval, i+1)
>               if delete_count:
>                       mtimedb.commit()
> +             return (os.EX_OK, None)
> diff --git a/pym/portage/emaint/modules/sync/sync.py
> b/pym/portage/emaint/modules/sync/sync.py
> index 15d63e2..03a684b 100644
> --- a/pym/portage/emaint/modules/sync/sync.py
> +++ b/pym/portage/emaint/modules/sync/sync.py
> @@ -127,8 +127,8 @@ class SyncRepos(object):
>                               % (bold(", ".join(repos))) + "\n   ...returning"
>                               ]
>                       if return_messages:
> -                             return msgs
> -                     return
> +                             return (1, msgs)
> +                     return (1, None)
>               return self._sync(selected, return_messages,
>                       emaint_opts=options)
>
> @@ -211,8 +211,8 @@ class SyncRepos(object):
>                       msgs.append("Emaint sync, nothing to sync... returning")
>                       if return_messages:
>                               msgs.extend(self.rmessage([('None', os.EX_OK)], 
> 'sync'))
> -                             return msgs
> -                     return
> +                             return (os.EX_OK, msgs)
> +                     return (os.EX_OK, None)
>               # Portage needs to ensure a sane umask for the files it creates.
>               os.umask(0o22)
>
> @@ -232,6 +232,7 @@ class SyncRepos(object):
>               sync_scheduler.wait()
>               retvals = sync_scheduler.retvals
>               msgs.extend(sync_scheduler.msgs)
> +             returncode = sync_scheduler.returncode
>
>               if retvals:
>                       msgs.extend(self.rmessage(retvals, 'sync'))
> @@ -244,6 +245,8 @@ class SyncRepos(object):
>                       rcode = sync_manager.perform_post_sync_hook('')
>                       if rcode:
>                               msgs.extend(self.rmessage([('None', rcode)], 
> 'post-sync'))
> +                             if rcode != os.EX_OK:
> +                                     returncode = rcode
>
>               # Reload the whole config.
>               portage._sync_mode = False
> @@ -254,8 +257,8 @@ class SyncRepos(object):
>                       self.emerge_config.opts)
>
>               if return_messages:
> -                     return msgs
> -             return
> +                     return (returncode, msgs)
> +             return (returncode, None)
>
>
>       def _do_pkg_moves(self):
> @@ -323,6 +326,7 @@ class SyncScheduler(AsyncScheduler):
>               self._init_graph()
>               self.retvals = []
>               self.msgs = []
> +             self.returncode = os.EX_OK
>
>       def _init_graph(self):
>               '''
> @@ -360,6 +364,9 @@ class SyncScheduler(AsyncScheduler):
>                       returncode, message, updatecache_flg, hooks_enabled = 
> task.result
>                       if message:
>                               self.msgs.append(message)
> +             else:
> +                     # Keep the last unsuccessful sync return code.
> +                     self.returncode = returncode
>               repo = task.kwargs['repo'].name
>               self._running_repos.remove(repo)
>               self.retvals.append((repo, returncode))
> diff --git a/pym/portage/emaint/modules/world/world.py
> b/pym/portage/emaint/modules/world/world.py
> index 2c9dbff..d8a4e69 100644
> --- a/pym/portage/emaint/modules/world/world.py
> +++ b/pym/portage/emaint/modules/world/world.py
> @@ -65,7 +65,9 @@ class WorldHandler(object):
>                       errors += ["'%s' is not installed" % x for x in 
> self.not_installed]
>               else:
>                       errors.append(self.world_file + " could not be opened 
> for reading")
> -             return errors
> +             if errors:
> +                     return (1, errors)
> +             return (os.EX_OK, None)
>
>       def fix(self, **kwargs):
>               onProgress = kwargs.get('onProgress', None)
> @@ -83,7 +85,9 @@ class WorldHandler(object):
>                               except portage.exception.PortageException:
>                                       errors.append("%s could not be opened 
> for writing" % \
>                                               self.world_file)
> -                     return errors
> +                     if errors:
> +                             return (1, errors)
> +                     return (os.EX_OK, None)
>               finally:
>                       world_set.unlock()
>
> --
> 2.10.2
>

Reply via email to