changeset 131:3ed8f568f60a

Fix error handling so that reports are still generated even if a command has failed.
author cmlenz
date Fri, 12 Aug 2005 19:11:16 +0000
parents 091ead7d2876
children c43b72672dde
files bitten/build/ctools.py bitten/build/pythontools.py bitten/recipe.py bitten/slave.py bitten/util/xmlio.py scripts/build.py
diffstat 6 files changed, 45 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
--- a/bitten/build/ctools.py
+++ b/bitten/build/ctools.py
@@ -49,4 +49,4 @@
             xmlio.SubElement(log_elem, 'message', level='error')[err]
     ctxt.log(log_elem)
     if cmdline.returncode != 0:
-        raise BuildError, 'make failed (%s)' % cmdline.returncode
+        ctxt.error('make failed (%s)' % cmdline.returncode)
--- a/bitten/build/pythontools.py
+++ b/bitten/build/pythontools.py
@@ -47,7 +47,7 @@
             xmlio.SubElement(log_elem, 'message', level=level)[err]
     ctxt.log(log_elem)
     if cmdline.returncode != 0:
-        raise BuildError, 'distutils failed (%s)' % cmdline.returncode
+        ctxt.error('distutils failed (%s)' % cmdline.returncode)
 
 def pylint(ctxt, file=None):
     """Extract data from a `pylint` run written to a file."""
@@ -78,7 +78,7 @@
         finally:
             fd.close()
     except IOError, e:
-        raise BuildError, 'Error opening pylint results file (%s)' % e
+        log.warning('Error opening pylint results file (%s)', e)
 
 def trace(ctxt, summary=None, coverdir=None, include=None, exclude=None):
     """Extract data from a `trace.py` run."""
@@ -125,7 +125,7 @@
         finally:
             summary_file.close()
     except IOError, e:
-        raise BuildError, 'Error opening unittest results file (%s)' % e
+        log.warning('Error opening unittest results file (%s)', e)
 
 
 def unittest(ctxt, file=None):
@@ -147,4 +147,4 @@
         finally:
             fd.close()
     except IOError, e:
-        raise BuildError, 'Error opening unittest results file (%s)' % e
+        log.warning('Error opening unittest results file (%s)', e)
--- a/bitten/recipe.py
+++ b/bitten/recipe.py
@@ -44,6 +44,9 @@
         self.basedir = os.path.realpath(basedir)
         self.output = []
 
+    def error(self, message):
+        self.output.append((Recipe.ERROR, self.current_function, message))
+
     def log(self, xml_elem):
         self.output.append((Recipe.LOG, self.current_function, xml_elem))
 
@@ -80,19 +83,22 @@
     def execute(self, ctxt):
         ctxt.current_step = self
         try:
-            try:
-                for function, args in self:
-                    ctxt.current_function = function.__name__
-                    function(ctxt, **args)
-                    ctxt.current_function = None
-            except BuildError, e:
-                if self.onerror == 'fail':
-                    raise BuildError, e
-                log.warning('Ignoring error in step %s (%s)', self.id, e)
+            for function, args in self:
+                ctxt.current_function = function.__name__
+                function(ctxt, **args)
+                ctxt.current_function = None
         finally:
             ctxt.current_step = None
+        errors = []
         while ctxt.output:
-            yield ctxt.output.pop()
+            type, function, output = ctxt.output.pop()
+            yield type, function, output
+            if type == Recipe.ERROR:
+                errors.append((function, output))
+        if errors:
+            if self.onerror == 'fail':
+                raise BuildError, 'Build step %s failed' % self.id
+            log.warning('Ignoring error in step %s (%s)', self.id, e)
 
     def _args(self, elem):
         return dict([(name.replace('-', '_'), value) for name, value
@@ -116,8 +122,10 @@
     """A build recipe.
     
     Iterate over this object to get the individual build steps in the order they
-    have been defined in the recipe file."""
+    have been defined in the recipe file.
+    """
 
+    ERROR = 'error'
     LOG = 'log'
     REPORT = 'report'
 
--- a/bitten/slave.py
+++ b/bitten/slave.py
@@ -174,15 +174,28 @@
                 log.info('Executing build step "%s"', step.id)
                 started = datetime.utcnow()
                 try:
-                    xml = xmlio.Element('step', id=step.id, result='success',
+                    xml = xmlio.Element('step', id=step.id,
                                         description=step.description,
                                         time=started.isoformat())
-                    for type, function, output in step.execute(recipe.ctxt):
-                        xmlio.SubElement(xml, type, type=function)[output]
+                    step_failed = False
+                    try:
+                        for type, function, output in step.execute(recipe.ctxt):
+                            if type == Recipe.ERROR:
+                                step_failed = True
+                            xmlio.SubElement(xml, type, type=function)[output]
+                    except BuildError, e:
+                        log.error('Build step %s failed', step.id)
+                        failed = True
                     xml.attr['duration'] = (datetime.utcnow() - started).seconds
-                    log.info('Build step %s completed successfully', step.id)
+                    if step_failed:
+                        xml.attr['result'] = 'failure'
+                        log.warning('Build step %s failed', step.id)
+                    else:
+                        xml.attr['result'] = 'success'
+                        log.info('Build step %s completed successfully',
+                                 step.id)
                     self.channel.send_ans(msgno, beep.Payload(xml))
-                except (BuildError, InvalidRecipeError), e:
+                except InvalidRecipeError, e:
                     log.warning('Build step %s failed: %s', step.id, e)
                     duration = datetime.utcnow() - started
                     failed = True
--- a/bitten/util/xmlio.py
+++ b/bitten/util/xmlio.py
@@ -205,7 +205,7 @@
         return self.children()
 
     def gettext(self):
-        return ''.join([c.nodeValue for c in self._node.childNodes])
+        return ''.join([c.nodeValue or '' for c in self._node.childNodes])
 
     def write(self, out, newlines=False):
         """Serializes the element and writes the XML to the given output
--- a/scripts/build.py
+++ b/scripts/build.py
@@ -54,7 +54,8 @@
             print
             print '-->', step.description or step.id
             for type, function, output in step.execute(recipe.ctxt):
-                pass
+                if type == Recipe.ERROR:
+                    log.error('Failure in step "%s": %s', step.id, output)
             if step.id in steps_to_run:
                 steps_to_run[step.id] = True
 
Copyright (C) 2012-2017 Edgewall Software