changeset 68:234600bf0d49

Fixes for Windows compatibility: * implementation of {{{bitten.util.cmdline}}} for windows, based on temporary files * the recipe tools now close the files they opened so that they can be properly deleted after the build completed * Wrapper batch files for client and server
author cmlenz
date Thu, 30 Jun 2005 12:28:54 +0000
parents 6ffa99b442bf
children b92d7c7d70fd
files bitten/build/pythontools.py bitten/recipe.py bitten/slave.py bitten/util/cmdline.py scripts/bitten.bat scripts/bittend.bat setup.py
diffstat 7 files changed, 99 insertions(+), 65 deletions(-) [+]
line wrap: on
line diff
--- a/bitten/build/pythontools.py
+++ b/bitten/build/pythontools.py
@@ -32,7 +32,7 @@
         if err:
             print '[distutils] %s' % err
     if cmdline.returncode != 0:
-        raise BuildError, "Executing distutils failed (%s)" % cmdline.returncode
+        raise BuildError, 'Executing distutils failed (%s)' % cmdline.returncode
 
 def pylint(ctxt, file=None):
     """Extract data from a `pylint` run written to a file."""
@@ -41,18 +41,21 @@
                          r'\[(?P<type>[A-Z])(?:, (?P<tag>[\w\.]+))?\] '
                          r'(?P<msg>.*)$')
 
-    fd = open(ctxt.resolve(file), 'r')
     try:
-        for line in fd:
-            match = _msg_re.search(line)
-            if match:
-                filename = match.group('file')
-                if filename.startswith(ctxt.basedir):
-                    filename = filename[len(ctxt.basedir) + 1:]
-                lineno = int(match.group('line'))
-                # TODO: emit to build master
-    finally:
-        fd.close()
+        fd = open(ctxt.resolve(file), 'r')
+        try:
+            for line in fd:
+                match = _msg_re.search(line)
+                if match:
+                    filename = match.group('file')
+                    if filename.startswith(ctxt.basedir):
+                        filename = filename[len(ctxt.basedir) + 1:]
+                    lineno = int(match.group('line'))
+                    # TODO: emit to build master
+        finally:
+            fd.close()
+    except IOError, e:
+        raise BuildError, '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."""
@@ -63,18 +66,21 @@
     """Extract data from a unittest results file in XML format."""
     assert file, 'Missing required attribute "file"'
 
-    fd = open(ctxt.resolve(file), 'r')
     try:
-        from xml.dom import minidom
-        root = minidom.parse(fd).documentElement
-        assert root.tagName == 'unittest-results'
-        for test in root.getElementsByTagName('test'):
-            filename = test.getAttribute('file')
-            if filename.startswith(ctxt.basedir):
-                filename = filename[len(ctxt.basedir) + 1:]
-            duration = float(test.getAttribute('duration'))
-            name = test.getAttribute('name')
-            status = test.getAttribute('status')
-            # TODO: emit to build master
-    finally:
-        fd.close()
+        fd = open(ctxt.resolve(file), 'r')
+        try:
+            from xml.dom import minidom
+            root = minidom.parse(fd).documentElement
+            assert root.tagName == 'unittest-results'
+            for test in root.getElementsByTagName('test'):
+                filename = test.getAttribute('file')
+                if filename.startswith(ctxt.basedir):
+                    filename = filename[len(ctxt.basedir) + 1:]
+                duration = float(test.getAttribute('duration'))
+                name = test.getAttribute('name')
+                status = test.getAttribute('status')
+                # TODO: emit to build master
+        finally:
+            fd.close()
+    except IOError, e:
+        raise BuildError, 'Error opening unittest results file (%s)' % e
--- a/bitten/recipe.py
+++ b/bitten/recipe.py
@@ -36,7 +36,7 @@
         self.basedir = basedir
 
     def resolve(self, *path):
-        return os.path.join(self.basedir, *path)
+        return os.path.normpath(os.path.join(self.basedir, *path))
 
 
 class Step(object):
--- a/bitten/slave.py
+++ b/bitten/slave.py
@@ -21,6 +21,7 @@
 import logging
 import os
 import platform
+import sys
 import tempfile
 import time
 
@@ -64,7 +65,6 @@
                 raise beep.TerminateSession, 'Registration failed!'
             logging.info('Registration successful')
 
-        
         system, node, release, version, machine, processor = platform.uname()
         system, release, version = platform.system_alias(system, release,
                                                          version)
--- a/bitten/util/cmdline.py
+++ b/bitten/util/cmdline.py
@@ -31,7 +31,6 @@
 class Commandline(object):
     """Simple helper for executing subprocesses."""
     # TODO: Use 'subprocess' module if available (Python >= 2.4)
-    # TODO: Windows implementation based on temporary files
 
     def __init__(self, executable, args, cwd=None):
         """Initialize the Commandline object.
@@ -49,16 +48,37 @@
         self.returncode = None
 
     if os.name == 'nt': # windows
+
         def execute(self, timeout=None):
-            raise NotImplementedError
+            args = [self.executable] + self.arguments
+            for idx, arg in enumerate(args):
+                if arg.find(' ') >= 0:
+                    args[idx] = '"%s"' % arg
+            logging.debug('Executing %s', args)
+
+            import tempfile
+            out_name = tempfile.mktemp()
+            err_name = tempfile.mktemp()
+            cmd = "( %s ) > %s 2> %s" % (' '.join(args), out_name, err_name)
+            self.returncode = os.system(cmd) >> 8
+
+            out_file = file(out_name, 'r')
+            err_file = file(err_name, 'r')
+            out_lines = out_file.readlines()
+            err_lines = err_file.readlines()
+            out_file.close()
+            err_file.close()
+            for out_line, err_line in self._combine(out_lines, err_lines):
+                yield out_line, err_line
 
     else: # posix
+
         def execute(self, timeout=None):
             import fcntl, popen2, select
             if self.cwd:
                 os.chdir(self.cwd)
 
-            logging.debug('Executing %s', self)
+            logging.debug('Executing %s', [self.executable] + self.arguments)
             pipe = popen2.Popen3([self.executable] + self.arguments,
                                  capturestderr=True)
             pipe.tochild.close()
@@ -99,38 +119,38 @@
                 time.sleep(.1)
             self.returncode = pipe.wait()
 
-        def _combine(self, *iterables):
-            iterables = [iter(iterable) for iterable in iterables]
-            size = len(iterables)
-            while [iterable for iterable in iterables if iterable is not None]:
-                to_yield = [None] * size
-                for idx, iterable in enumerate(iterables):
-                    if iterable is None:
-                        continue
-                    try:
-                        to_yield[idx] = iterable.next()
-                    except StopIteration:
-                        iterables[idx] = None
-                yield tuple(to_yield)
+    def _combine(self, *iterables):
+        iterables = [iter(iterable) for iterable in iterables]
+        size = len(iterables)
+        while [iterable for iterable in iterables if iterable is not None]:
+            to_yield = [None] * size
+            for idx, iterable in enumerate(iterables):
+                if iterable is None:
+                    continue
+                try:
+                    to_yield[idx] = iterable.next()
+                except StopIteration:
+                    iterables[idx] = None
+            yield tuple(to_yield)
 
-        def _extract_lines(self, data):
-            extracted = []
-            def _endswith_linesep(string):
-                for linesep in ('\n', '\r\n', '\r'):
-                    if string.endswith(linesep):
-                        return True
-            buf = ''.join(data)
-            lines = buf.splitlines(True)
-            if len(lines) > 1:
-                extracted += lines[:-1]
-                if _endswith_linesep(lines[-1]):
-                    extracted.append(lines[-1])
-                    buf = ''
-                else:
-                    buf = lines[-1]
-            elif _endswith_linesep(buf):
-                extracted.append(buf)
+    def _extract_lines(self, data):
+        extracted = []
+        def _endswith_linesep(string):
+            for linesep in ('\n', '\r\n', '\r'):
+                if string.endswith(linesep):
+                    return True
+        buf = ''.join(data)
+        lines = buf.splitlines(True)
+        if len(lines) > 1:
+            extracted += lines[:-1]
+            if _endswith_linesep(lines[-1]):
+                extracted.append(lines[-1])
                 buf = ''
-            data[:] = [buf]
+            else:
+                buf = lines[-1]
+        elif _endswith_linesep(buf):
+            extracted.append(buf)
+            buf = ''
+        data[:] = [buf]
 
-            return [line.rstrip() for line in extracted]
+        return [line.rstrip() for line in extracted]
new file mode 100644
--- /dev/null
+++ b/scripts/bitten.bat
@@ -0,0 +1,2 @@
+@echo off
+python -c "import sys; from bitten import slave; sys.argv[0] = r'%0'; slave.main()" %*
new file mode 100644
--- /dev/null
+++ b/scripts/bittend.bat
@@ -0,0 +1,2 @@
+@echo off
+python -c "import sys; from bitten import master; sys.argv[0] = r'%0'; master.main()" %*
--- a/setup.py
+++ b/setup.py
@@ -20,12 +20,16 @@
 # Author: Christopher Lenz <cmlenz@gmx.de>
 
 from distutils.core import setup
+from distutils import util
 
 from bitten import __version__ as VERSION
 from bitten.util.testrunner import unittest
 
+scripts = ['scripts/bitten', 'scripts/bittend']
+if util.get_platform()[:3] == 'win':
+    scripts = [script + '.bat' for script in scripts]
+
 setup(name='bitten', version=VERSION,
       packages=['bitten', 'bitten.build', 'bitten.trac_ext', 'bitten.util'],
-      scripts=['scripts/bitten', 'scripts/bittend'],
-      author="Christopher Lenz", author_email="cmlenz@gmx.de",
+      scripts=scripts, author="Christopher Lenz", author_email="cmlenz@gmx.de",
       url="http://bitten.cmlenz.net/", cmdclass={'unittest': unittest})
Copyright (C) 2012-2017 Edgewall Software