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')
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" %