chiark / gitweb /
Fixed Bug where long outputs to stderr during build process caused a hang
authorChristopher <christopher@gittner.org>
Sat, 12 Oct 2013 16:20:32 +0000 (18:20 +0200)
committerDaniel Martí <mvdan@mvdan.cc>
Wed, 16 Oct 2013 21:19:11 +0000 (23:19 +0200)
fdroidserver/build.py

index dbdfa0878211daab06c6fb9b39d4934b015711ff..e10b3b1311462fc14099da1c18a731aa1702151d 100644 (file)
@@ -27,12 +27,36 @@ import tarfile
 import traceback
 import time
 import json
+import Queue
+import threading
 from optparse import OptionParser
 
 import common
 from common import BuildException
 from common import VCSException
 
+class AsynchronousFileReader(threading.Thread):
+    '''
+    Helper class to implement asynchronous reading of a file
+    in a separate thread. Pushes read lines on a queue to
+    be consumed in another thread.
+    '''
+    def __init__(self, fd, queue):
+        assert isinstance(queue, Queue.Queue)
+        assert callable(fd.readline)
+        threading.Thread.__init__(self)
+        self._fd = fd
+        self._queue = queue
+    def run(self):
+        '''The body of the tread: read lines and put them on the queue.'''
+        for line in iter(self._fd.readline, ''):
+            self._queue.put(line)
+    def eof(self):
+        '''Check whether there is no more content to expect.'''
+        return not self.is_alive() and self._queue.empty()
 
 def get_builder_vm_id():
     vd = os.path.join('builder', '.vagrant')
@@ -448,20 +472,36 @@ def build_local(app, thisbuild, vcs, build_dir, output_dir, srclib_dir, extlib_d
 
         p = subprocess.Popen(['bash', '-x', '-c', cmd], cwd=root_dir,
                 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-        for line in iter(p.stdout.readline, ''):
-            if verbose:
-                # Output directly to console
-                sys.stdout.write(line)
-                sys.stdout.flush()
-            else:
-                output += line
-        for line in iter(p.stderr.readline, ''):
-            if verbose:
-                # Output directly to console
-                sys.stdout.write(line)
-                sys.stdout.flush()
-            else:
-                error += line
+        
+        stdout_queue = Queue.Queue()
+        stdout_reader = AsynchronousFileReader(p.stdout, stdout_queue)
+        stdout_reader.start()
+        stderr_queue = Queue.Queue()
+        stderr_reader = AsynchronousFileReader(p.stderr, stderr_queue)
+        stderr_reader.start()
+        
+        # Check the queues if we received some output (until there is nothing more to get).
+        while not stdout_reader.eof() or not stderr_reader.eof():
+            # Show what we received from standard output.
+            while not stdout_queue.empty():
+                line = stdout_queue.get()
+                if verbose:
+                    # Output directly to console
+                    sys.stdout.write(line)
+                    sys.stdout.flush()
+                else:
+                    error += line
+            # Show what we received from standard error.
+            while not stderr_queue.empty():
+                line = stderr_queue.get()
+                if verbose:
+                    # Output directly to console
+                    sys.stdout.write(line)
+                    sys.stdout.flush()
+                else:
+                    error += line
+
         p.communicate()
         if p.returncode != 0:
             raise BuildException("Error running build command for %s:%s" %