When packages fail with --jobs > 1 and the "echo" elog module is not enabled,
authorZac Medico <zmedico@gentoo.org>
Tue, 15 Jul 2008 09:50:41 +0000 (09:50 -0000)
committerZac Medico <zmedico@gentoo.org>
Tue, 15 Jul 2008 09:50:41 +0000 (09:50 -0000)
emulate elog's mod_echo module to show the 'error' level messages, which should
include the important die message. This is implemented by adding a private
hook inside elog_process() which the scheduler uses to collect error messages.

svn path=/main/trunk/; revision=11056

pym/_emerge/__init__.py
pym/portage/elog/__init__.py

index 786824790ea79cce122dd0c8bd9db530955a214b..ac21e5f3fe6fda7a261fcdc3c7a27596fd4653ce 100644 (file)
@@ -8391,6 +8391,7 @@ class Scheduler(PollScheduler):
                self._completed_tasks = set()
                self._failed_pkgs = []
                self._failed_pkgs_all = []
+               self._failed_pkgs_die_msgs = []
                self._failed_fetches = []
                self._parallel_fetch = False
                merge_count = len([x for x in mergelist \
@@ -8847,6 +8848,29 @@ class Scheduler(PollScheduler):
 
                self._logger.log(" *** Finished. Cleaning up...")
 
+               background = self._max_jobs > 1
+               if self._failed_pkgs_all and background and \
+                       self._failed_pkgs_die_msgs and \
+                       not _flush_elog_mod_echo():
+
+                       printer = portage.output.EOutput()
+                       for mysettings, key, logentries in self._failed_pkgs_die_msgs:
+                               root_msg = ""
+                               if mysettings["ROOT"] != "/":
+                                       root_msg = " merged to %s" % mysettings["ROOT"]
+                               print
+                               printer.einfo("Error messages for package %s%s:" % \
+                                       (colorize("INFORM", key), root_msg))
+                               print
+                               for phase in portage.const.EBUILD_PHASES:
+                                       if phase not in logentries:
+                                               continue
+                                       for msgtype, msgcontent in logentries[phase]:
+                                               if isinstance(msgcontent, basestring):
+                                                       msgcontent = [msgcontent]
+                                               for line in msgcontent:
+                                                       printer.eerror(line.strip("\n"))
+
                if len(self._failed_pkgs_all) > 1:
                        _flush_elog_mod_echo()
                        msg = "The following packages have " + \
@@ -8865,6 +8889,12 @@ class Scheduler(PollScheduler):
 
                return rval
 
+       def _elog_listener(self, mysettings, key, logentries, fulltext):
+               errors = portage.elog.filter_loglevels(logentries, ["ERROR"])
+               if errors:
+                       self._failed_pkgs_die_msgs.append(
+                               (mysettings, key, errors))
+
        def _add_packages(self):
                pkg_queue = self._pkg_queue
                for pkg in self._mergelist:
@@ -8928,14 +8958,14 @@ class Scheduler(PollScheduler):
                self._add_packages()
                pkg_queue = self._pkg_queue
                failed_pkgs = self._failed_pkgs
+               portage.elog._emerge_elog_listener = self._elog_listener
                rval = os.EX_OK
 
                try:
                        self._main_loop()
                finally:
                        self._main_loop_cleanup()
-                       # discard any failures and return the
-                       # exist status of the last one
+                       portage.elog._emerge_elog_listener = None
                        if failed_pkgs:
                                pkg, rval = failed_pkgs[-1]
 
@@ -9905,13 +9935,18 @@ def _flush_elog_mod_echo():
        """
        Dump the mod_echo output now so that our other
        notifications are shown last.
+       @rtype: bool
+       @returns: True if messages were shown, False otherwise.
        """
+       messages_shown = False
        try:
                from portage.elog import mod_echo
        except ImportError:
                pass # happens during downgrade to a version without the module
        else:
+               messages_shown = bool(mod_echo._items)
                mod_echo.finalize()
+       return messages_shown
 
 def post_emerge(trees, mtimedb, retval):
        """
index ea81e841188b8f5a16908d57c21aaf0e7ac3abaa..50a51e9fd4871c8b2088b6d78ec07eecd0e4340f 100644 (file)
@@ -53,10 +53,11 @@ def _load_mod(name):
                _elog_mod_imports[name] = m
        return m
 
+_emerge_elog_listener = None
 _elog_atexit_handlers = []
 _preserve_logentries = {}
 def elog_process(cpv, mysettings, phasefilter=None):
-       global _elog_atexit_handlers, _preserve_logentries
+       global _elog_atexit_handlers, _emerge_elog_listener, _preserve_logentries
        
        logsystems = mysettings.get("PORTAGE_ELOG_SYSTEM","").split()
        for s in logsystems:
@@ -100,6 +101,10 @@ def elog_process(cpv, mysettings, phasefilter=None):
 
                default_fulllog = _combine_logentries(default_logentries)
 
+               if _emerge_elog_listener is not None:
+                       _emerge_elog_listener(mysettings, str(key),
+                               default_logentries, default_fulllog)
+
                # pass the processing to the individual modules
                logsystems = mysettings["PORTAGE_ELOG_SYSTEM"].split()
                for s in logsystems: