changeset 146:affd91b4c6fb

Add a `<python:exec>` recipe command so that things like Pylint can be executed without using a Makefile.
author cmlenz
date Sat, 20 Aug 2005 20:35:15 +0000
parents 0221d7cdf59a
children 395b67aa072e
files Makefile bitten/build/ctools.py bitten/build/pythontools.py bitten/recipe.py recipe.xml
diffstat 5 files changed, 94 insertions(+), 36 deletions(-) [+]
line wrap: on
line diff
deleted file mode 100644
--- a/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-PYLINT_MSGS = C0101,E0201,E0213,W0103,W0704,R0921,R0923
-PYTHONPATH = .
-
-all: pylint
-
-pylint:
-	PYTHONPATH=$(PYTHONPATH) pylint --parseable=yes --include-ids=yes \
-	--disable-msg=$(PYLINT_MSGS) --ignore=tests \
-	bitten > build/pylint-results.txt
--- a/bitten/build/ctools.py
+++ b/bitten/build/ctools.py
@@ -26,11 +26,11 @@
 
 log = logging.getLogger('bitten.build.ctools')
 
-def make(ctxt, target=None, file=None, jobs=None, keep_going=False):
+def make(ctxt, target=None, file_=None, jobs=None, keep_going=False):
     """Execute a Makefile target."""
     args = ['--directory', ctxt.basedir]
-    if file:
-        args += ['--file', ctxt.resolve(file)]
+    if file_:
+        args += ['--file', ctxt.resolve(file_)]
     if jobs:
         args += ['--jobs', int(jobs)]
     if keep_going:
@@ -40,13 +40,15 @@
 
     log_elem = xmlio.Fragment()
     cmdline = Commandline('make', args)
-    for out, err in cmdline.execute(timeout=100.0):
-        if out:
+    for out, err in cmdline.execute():
+        if out is not None:
             log.info(out)
-            xmlio.SubElement(log_elem, 'message', level='info')[out]
-        if err:
+            if out:
+                xmlio.SubElement(log_elem, 'message', level='info')[out]
+        if err is not None:
             log.error(err)
-            xmlio.SubElement(log_elem, 'message', level='error')[err]
+            if err:
+                xmlio.SubElement(log_elem, 'message', level='error')[err]
     ctxt.log(log_elem)
     if cmdline.returncode != 0:
         ctxt.error('make failed (%s)' % cmdline.returncode)
--- a/bitten/build/pythontools.py
+++ b/bitten/build/pythontools.py
@@ -21,8 +21,9 @@
 import logging
 import os
 import re
+import shlex
 
-from bitten.build import BuildError
+from bitten.recipe import Recipe
 from bitten.util import xmlio
 from bitten.util.cmdline import Commandline
 
@@ -32,11 +33,12 @@
     """Execute a `distutils` command."""
     cmdline = Commandline('python', ['setup.py', command], cwd=ctxt.basedir)
     log_elem = xmlio.Fragment()
-    for out, err in cmdline.execute(timeout=100.0):
-        if out:
-            log.info(out)
+    for out, err in cmdline.execute():
+        if out is not None:
+            if out:
+                log.info(out)
             xmlio.SubElement(log_elem, 'message', level='info')[out]
-        if err:
+        if err is not None:
             level = 'error'
             if err.startswith('warning: '):
                 err = err[9:]
@@ -44,14 +46,67 @@
                 log.warning(err)
             else:
                 log.error(err)
-            xmlio.SubElement(log_elem, 'message', level=level)[err]
+            if err:
+                xmlio.SubElement(log_elem, 'message', level=level)[err]
     ctxt.log(log_elem)
     if cmdline.returncode != 0:
         ctxt.error('distutils failed (%s)' % cmdline.returncode)
 
-def pylint(ctxt, file=None):
+def exec_(ctxt, file_=None, module=None, output=None, args=None):
+    """Execute a python script."""
+    assert file_ or module, 'Either "file" or "module" attribute required'
+
+    if module:
+        # Script specified as module name, need to resolve that to a file
+        mod = __import__(module, globals(), locals(), [])
+        components = module.split('.')
+        for comp in components[1:]:
+            mod = getattr(mod, comp)
+        file_ = mod.__file__
+
+    if args:
+        args = shlex.split(args)
+    else:
+        args = []
+
+    output_file = None
+    if output:
+        output = ctxt.resolve(output)
+        output_file = file(output, 'w')
+
+    try:
+        cmdline = Commandline('python', [file_] + args, cwd=ctxt.basedir)
+        log_elem = xmlio.Fragment()
+        for out, err in cmdline.execute():
+            if out is not None:
+                log.info(out)
+                if output_file:
+                    output_file.write(out + os.linesep)
+                if out:
+                    xmlio.SubElement(log_elem, 'message', level='info')[out]
+            if err is not None:
+                level = 'error'
+                if err.startswith('warning: '):
+                    err = err[9:]
+                    level = 'warning'
+                    log.warning(err)
+                else:
+                    log.error(err)
+                if output_file:
+                    output_file.write(err + os.linesep)
+                if err:
+                    xmlio.SubElement(log_elem, 'message', level=level)[err]
+        ctxt.log(log_elem)
+    finally:
+        if output_file:
+            output_file.close()
+
+    if cmdline.returncode != 0:
+        ctxt.error('distutils failed (%s)' % cmdline.returncode)
+
+def pylint(ctxt, file_=None):
     """Extract data from a `pylint` run written to a file."""
-    assert file, 'Missing required attribute "file"'
+    assert file_, 'Missing required attribute "file"'
     msg_re = re.compile(r'^(?P<file>.+):(?P<line>\d+): '
                         r'\[(?P<type>[A-Z]\d*)(?:, (?P<tag>[\w\.]+))?\] '
                         r'(?P<msg>.*)$')
@@ -59,8 +114,7 @@
 
     problems = xmlio.Element('problems')
     try:
-        fd = open(ctxt.resolve(file), 'r')
-        print 'Reading Pylint results file', fd.name
+        fd = open(ctxt.resolve(file_), 'r')
         try:
             for line in fd:
                 match = msg_re.search(line)
@@ -131,13 +185,12 @@
     except IOError, e:
         log.warning('Error opening coverage summary file (%s)', e)
 
-
-def unittest(ctxt, file=None):
+def unittest(ctxt, file_=None):
     """Extract data from a unittest results file in XML format."""
-    assert file, 'Missing required attribute "file"'
+    assert file_, 'Missing required attribute "file"'
 
     try:
-        fd = open(ctxt.resolve(file), 'r')
+        fd = open(ctxt.resolve(file_), 'r')
         try:
             results = xmlio.Fragment()
             for child in xmlio.parse(fd).children():
--- a/bitten/recipe.py
+++ b/bitten/recipe.py
@@ -18,6 +18,7 @@
 #
 # Author: Christopher Lenz <cmlenz@gmx.de>
 
+import keyword
 import logging
 import os
 import time
@@ -98,25 +99,32 @@
         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)
+            log.warning('Ignoring errors in step %s (%s)', self.id,
+                        ', '.join([error[1] for error in errors]))
 
     def _args(self, elem):
-        return dict([(name.replace('-', '_'), value) for name, value
+        return dict([(self._translate_name(name), value) for name, value
                      in elem.attr.items()])
 
     def _function(self, elem):
         if not elem.namespace.startswith('bitten:'):
             # Ignore elements in foreign namespaces
             return None
-        func_name = elem.name.replace('-', '_')
+        func_name = self._translate_name(elem.name)
         try:
             module = __import__(elem.namespace[7:], globals(), locals(),
                                 func_name)
-            func = getattr(module, elem.name)
+            func = getattr(module, func_name)
             return func
         except (ImportError, AttributeError), e:
             raise InvalidRecipeError, 'Cannot load "%s" (%s)' % (elem.name, e)
 
+    def _translate_name(self, name):
+        name = name.replace('-', '_')
+        if keyword.iskeyword(name) or name in __builtins__:
+            name = name + '_'
+        return name
+
 
 class Recipe(object):
     """A build recipe.
--- a/recipe.xml
+++ b/recipe.xml
@@ -19,7 +19,11 @@
 
     <step id="lint" title="Run Pylint" onerror="ignore"
           description="Run Pylint to check for bad style and potential errors">
-        <c:make target="pylint"/>
+        <python:exec module="logilab.pylint.lint"
+            output="build/pylint-results.txt"
+            args="--parseable=yes --include-ids=yes
+                  --disable-msg=C0101,E0201,E0213,W0103,W0704,R0921,R0923
+                  --ignore=tests bitten"/>
         <reports>
             <python:pylint file="build/pylint-results.txt"/>
         </reports>
Copyright (C) 2012-2017 Edgewall Software