# Copyright (c) 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. """Syncronized Standard IO Linebuffer implemented with cStringIO.""" import cStringIO import threading import Queue class StdioBuffer(object): def __init__(self, shard): self.queue = Queue.Queue() self.completed = 0 self.shard = shard def _pipe_handler(self, system_pipe, program_pipe): """Helper method for collecting stdio output. Output is collected until a newline is seen, at which point an event is triggered and the line is pushed to a buffer as a (stdio, line) tuple.""" buf = cStringIO.StringIO() pipe_running = True while pipe_running: char = program_pipe.read(1) if not char and self.shard.poll() is not None: pipe_running = False buf.write(char) if char == '\n' or not pipe_running: line = buf.getvalue() if line: self.queue.put((system_pipe, line)) if not pipe_running: self.queue.put((system_pipe, None)) buf.close() buf = cStringIO.StringIO() def handle_pipe(self, system_pipe, program_pipe): t = threading.Thread(target=self._pipe_handler, args=[system_pipe, program_pipe]) t.start() return t def readline(self): """Emits a tuple of (sys.stderr, line), (sys.stdout, line), or (None, None) if the process has finished. This is a blocking call.""" while True: (pipe, line) = self.queue.get(True) if line: return (pipe, line) self.completed += 1 if self.completed >= 2: return (None, None)