changeset 240:24e91cbae6e0

New recipe command `<java:ant>` for running Ant builds.
author cmlenz
date Sun, 02 Oct 2005 14:40:51 +0000
parents bc7b77236011
children d3c8a74922cd
files bitten/build/config.py bitten/build/javatools.py bitten/build/pythontools.py bitten/build/tests/config.py scripts/build.py setup.py
diffstat 6 files changed, 133 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- a/bitten/build/config.py
+++ b/bitten/build/config.py
@@ -8,10 +8,13 @@
 # are also available at http://bitten.cmlenz.net/wiki/License.
 
 from ConfigParser import SafeConfigParser
+import logging
 import os
 import platform
 import re
 
+log = logging.getLogger('bitten.config')
+
 
 class Configuration(object):
     """Encapsulates the configuration of a build machine.
@@ -101,6 +104,22 @@
 
     _VAR_RE = re.compile(r'\$\{(?P<ref>\w[\w.]*?\w)(?:\:(?P<def>.+))?\}')
 
+    def get_dirpath(self, key):
+        dirpath = self[key]
+        if dirpath:
+            if os.path.isdir(dirpath):
+                return dirpath
+            log.warning('Invalid %s: %s is not a directory', key, dirpath)
+        return None
+
+    def get_filepath(self, key):
+        filepath = self[key]
+        if filepath:
+            if os.path.isfile(filepath):
+                return filepath
+            log.warning('Invalid %s: %s is not a file', key, filepath)
+        return None
+
     def interpolate(self, text):
         """Interpolate configuration properties into a string.
         
new file mode 100644
--- /dev/null
+++ b/bitten/build/javatools.py
@@ -0,0 +1,65 @@
+# -*- coding: iso8859-1 -*-
+#
+# Copyright (C) 2005 Christopher Lenz <cmlenz@gmx.de>
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://bitten.cmlenz.net/wiki/License.
+
+import logging
+import os
+import tempfile
+
+from bitten.build import CommandLine
+from bitten.util import xmlio
+
+log = logging.getLogger('bitten.build.javatools')
+
+def ant(ctxt, file_=None, target=None, keep_going=False):
+    """Run an Ant build."""
+    executable = 'ant'
+    ant_home = ctxt.config.get_dirpath('ant.home')
+    if ant_home:
+        executable = os.path.join(ant_home, 'bin', 'ant')
+
+    logfile = tempfile.NamedTemporaryFile(prefix='ant_log', suffix='.xml')
+    args = ['-noinput', '-listener', 'org.apache.tools.ant.XmlLogger',
+            '-Dant.XmlLogger.stylesheet.uri', '""',
+            '-DXmlLogger.file', logfile.name]
+    if file_:
+        args += ['-buildfile', ctxt.resolve(file_)]
+    if keep_going:
+        args.append('-keep-going')
+    if target:
+        args.append(target)
+
+    cmdline = CommandLine(executable, args, cwd=ctxt.basedir)
+    for out, err in cmdline.execute():
+        if out is not None:
+            log.info(out)
+        if err is not None:
+            log.error(err)
+
+    log_elem = xmlio.Fragment()
+    try:
+        xml_log = xmlio.parse(logfile)
+        def collect_log_messages(node):
+            for child in node.children():
+                if child.name == 'message':
+                    if child.attr['priority'] == 'debug':
+                        continue
+                    log_elem.append(xmlio.Element('message',
+                                                  level=child.attr['priority'])[
+                        child.gettext().replace(ctxt.basedir + os.sep, '')
+                                       .replace(ctxt.basedir, '')
+                    ])
+                else:
+                    collect_log_messages(child)
+        collect_log_messages(xml_log)
+    except xmlio.ParseError, e:
+        log.warning('Error parsing Ant XML log file (%s)', e)
+    ctxt.log(log_elem)
+
+    if cmdline.returncode != 0:
+        ctxt.error('Ant failed (%s)' % cmdline.returncode)
--- a/bitten/build/pythontools.py
+++ b/bitten/build/pythontools.py
@@ -28,11 +28,9 @@
     is returned; otherwise the path to the current Python interpreter is
     returned.
     """
-    python_path = ctxt.config['python.path']
+    python_path = ctxt.config.get_filepath('python.path')
     if python_path:
-        if os.path.isfile(python_path):
-            return python_path
-        log.warning('Invalid python.path: %s is not a file')
+        return python_path
     return sys.executable
 
 def distutils(ctxt, command='build', file_='setup.py'):
--- a/bitten/build/tests/config.py
+++ b/bitten/build/tests/config.py
@@ -45,9 +45,8 @@
         self.assertEqual('VERSION', config['version'])
 
     def test_sysinfo_configfile_override(self):
-        inifile, ininame = tempfile.mkstemp(prefix='bitten_test')
-        try:
-            os.write(inifile, """
+        inifile = tempfile.NamedTemporaryFile(prefix='bitten_test')
+        inifile.write("""
 [machine]
 name = MACHINE
 processor = PROCESSOR
@@ -57,16 +56,14 @@
 family = FAMILY
 version = VERSION
 """)
-            os.close(inifile)
-            config = Configuration(ininame)
+        inifile.seek(0)
+        config = Configuration(inifile.name)
 
-            self.assertEqual('MACHINE', config['machine'])
-            self.assertEqual('PROCESSOR', config['processor'])
-            self.assertEqual('OS', config['os'])
-            self.assertEqual('FAMILY', config['family'])
-            self.assertEqual('VERSION', config['version'])
-        finally:
-            os.remove(ininame)
+        self.assertEqual('MACHINE', config['machine'])
+        self.assertEqual('PROCESSOR', config['processor'])
+        self.assertEqual('OS', config['os'])
+        self.assertEqual('FAMILY', config['family'])
+        self.assertEqual('VERSION', config['version'])
 
     def test_package_properties(self):
         config = Configuration(properties={
@@ -78,21 +75,44 @@
         self.assertEqual('2.3.5', config['python.version'])
 
     def test_package_configfile(self):
-        inifile, ininame = tempfile.mkstemp(prefix='bitten_test')
-        try:
-            os.write(inifile, """
+        inifile = tempfile.NamedTemporaryFile(prefix='bitten_test')
+        inifile.write("""
 [python]
 path = /usr/local/bin/python2.3
 version = 2.3.5
 """)
-            os.close(inifile)
-            config = Configuration(ininame)
+        inifile.seek(0)
+        config = Configuration(inifile.name)
 
-            self.assertEqual(True, 'python' in config.packages)
-            self.assertEqual('/usr/local/bin/python2.3', config['python.path'])
-            self.assertEqual('2.3.5', config['python.version'])
+        self.assertEqual(True, 'python' in config.packages)
+        self.assertEqual('/usr/local/bin/python2.3', config['python.path'])
+        self.assertEqual('2.3.5', config['python.version'])
+
+    def test_get_dirpath_non_existant(self):
+        tempdir = tempfile.mkdtemp()
+        os.rmdir(tempdir)
+        config = Configuration(properties={'somepkg.home': tempdir})
+        self.assertEqual(None, config.get_dirpath('somepkg.home'))
+
+    def test_get_dirpath(self):
+        tempdir = tempfile.mkdtemp()
+        try:
+            config = Configuration(properties={'somepkg.home': tempdir})
+            self.assertEqual(tempdir, config.get_dirpath('somepkg.home'))
         finally:
-            os.remove(ininame)
+            os.rmdir(tempdir)
+
+    def test_get_filepath_non_existant(self):
+        testfile, testname = tempfile.mkstemp(prefix='bitten_test')
+        os.close(testfile)
+        os.remove(testname)
+        config = Configuration(properties={'somepkg.path': testname})
+        self.assertEqual(None, config.get_filepath('somepkg.path'))
+
+    def test_get_filepath(self):
+        testfile = tempfile.NamedTemporaryFile(prefix='bitten_test')
+        config = Configuration(properties={'somepkg.path': testfile.name})
+        self.assertEqual(testfile.name, config.get_filepath('somepkg.path'))
 
     def test_interpolate(self):
         config = Configuration(properties={
--- a/scripts/build.py
+++ b/scripts/build.py
@@ -24,6 +24,9 @@
                           version='%%prog %s' % VERSION)
     parser.add_option('-f', '--recipe-file', action='store', dest='recipe_file',
                       metavar='FILE', help='read build recipe from FILE')
+    parser.add_option('--print-logs', action='store_const',
+                      dest='print_logs', const=True,
+                      help='print build logs')
     parser.add_option('--print-reports', action='store_const',
                       dest='print_reports', const=True,
                       help='print generated reports')
@@ -54,6 +57,8 @@
                 for type, category, generator, output in step.execute(recipe.ctxt):
                     if type == Recipe.ERROR:
                         log.error('Failure in step "%s": %s', step.id, output)
+                    elif type == Recipe.LOG and options.print_logs:
+                        output.write(sys.stdout, newlines=True)
                     elif type == Recipe.REPORT and options.print_reports:
                         output.write(sys.stdout, newlines=True)
                 if step.id in steps_to_run:
--- a/setup.py
+++ b/setup.py
@@ -46,6 +46,7 @@
             NS + 'sh#pipe = bitten.build.shtools:pipe',
             NS + 'c#configure = bitten.build.ctools:configure',
             NS + 'c#make = bitten.build.ctools:make',
+            NS + 'java#ant = bitten.build.javatools:ant',
             NS + 'python#distutils = bitten.build.pythontools:distutils',
             NS + 'python#exec = bitten.build.pythontools:exec_',
             NS + 'python#pylint = bitten.build.pythontools:pylint',
Copyright (C) 2012-2017 Edgewall Software