Don't buffer stdout/stderr in command_wrapper.py

Otherwise, commands that take a long time to complete, but produce some status
output, such as gsutil cp, will cause the buildbot's timeout to trigger.

BUG=none
TEST=manually, works on linux :)

Review URL: http://codereview.chromium.org/10085001

git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/command_wrapper/bin@134087 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/command_wrapper.py b/command_wrapper.py
index 249db31..91f9b6e 100755
--- a/command_wrapper.py
+++ b/command_wrapper.py
@@ -1,6 +1,6 @@
 #!/usr/bin/python
 #
-# Copyright (c) 2011 The Chromium Authors. All rights reserved.
+# 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.
 
@@ -25,6 +25,7 @@
 
 
 LOG_TIMEOUT = 10
+ON_POSIX = 'posix' in sys.builtin_module_names
 
 
 def LogCommand(options, command_id,
@@ -81,6 +82,15 @@
   return wrapper['result']
 
 
+def Tee(fd, string_buffer, forward_fd):
+  """Read characters from fd and both append them to a buffer and write them to
+  forward_fd."""
+  for char in iter(lambda: fd.read(1), ''):
+    string_buffer += char
+    forward_fd.write(char)
+  fd.close()
+
+
 def main(argv):
   parser = optparse.OptionParser()
   parser.add_option('-r', '--retries', dest='retries',
@@ -113,10 +123,24 @@
     tm = time.time()
     p = subprocess.Popen(cmd, shell=True,
                          stdout=subprocess.PIPE,
-                         stderr=subprocess.PIPE)
-    (p_stdout, p_stderr) = p.communicate()
-    sys.stdout.write(p_stdout)
-    sys.stderr.write(p_stderr)
+                         stderr=subprocess.PIPE,
+                         close_fds=ON_POSIX)
+    p_stdout = ''
+    t_stdout = threading.Thread(target=Tee,
+                                args=(p.stdout, p_stdout, sys.stdout))
+    t_stdout.start()
+
+    p_stderr = ''
+    t_stderr = threading.Thread(target=Tee,
+                                args=(p.stderr, p_stderr, sys.stderr))
+    t_stderr.start()
+
+    p.wait()
+
+    t_stdout.join()
+    t_stderr.join()
+
+
     runtime = time.time() - tm
     accept = RunWithTimeout(LOG_TIMEOUT, LogCommand,
                             options, command_id, r, cmd,