Commit 740a6c0b authored by maruel@chromium.org's avatar maruel@chromium.org

Using lists is faster than cStringIO.

Clean up stdin management.
Remove stale comments.

R=dpranke@chromium.org
BUG=
TEST=


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

git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/depot_tools@113065 0039d316-1c4b-4281-b951-d872f2087c98
parent bc3a53cb
......@@ -173,25 +173,22 @@ class Popen(subprocess.Popen):
self.stdout_cb = None
self.stderr_cb = None
self.stdout_void = False
self.stderr_void = False
def fix(stream):
self.stdin_is_void = False
self.stdout_is_void = False
self.stderr_is_void = False
if kwargs.get('stdin') is VOID:
kwargs['stdin'] = open(os.devnull, 'r')
self.stdin_is_void = True
for stream in ('stdout', 'stderr'):
if kwargs.get(stream) in (VOID, os.devnull):
# Replaces VOID with handle to /dev/null.
# Create a temporary file to workaround python's deadlock.
# http://docs.python.org/library/subprocess.html#subprocess.Popen.wait
# When the pipe fills up, it will deadlock this process. Using a real
# file works around that issue.
kwargs[stream] = open(os.devnull, 'w')
setattr(self, stream + '_void', True)
setattr(self, stream + '_is_void', True)
if callable(kwargs.get(stream)):
# Callable stdout/stderr should be used only with call() wrappers.
setattr(self, stream + '_cb', kwargs[stream])
kwargs[stream] = PIPE
fix('stdout')
fix('stderr')
self.start = time.time()
self.timeout = None
self.shell = kwargs.get('shell', None)
......@@ -288,6 +285,9 @@ class Popen(subprocess.Popen):
target=_queue_pipe_read, args=(self.stderr, 'stderr'))
if input:
threads['stdin'] = threading.Thread(target=write_stdin)
elif self.stdin:
# Pipe but no input, make sure it's closed.
self.stdin.close()
for t in threads.itervalues():
t.start()
......@@ -346,20 +346,19 @@ class Popen(subprocess.Popen):
stderr = None
# Convert to a lambda to workaround python's deadlock.
# http://docs.python.org/library/subprocess.html#subprocess.Popen.wait
# When the pipe fills up, it will deadlock this process. Using a thread
# works around that issue. No need for thread safe function since the call
# backs are guaranteed to be called from the main thread.
if self.stdout and not self.stdout_cb and not self.stdout_void:
stdout = cStringIO.StringIO()
self.stdout_cb = stdout.write
if self.stderr and not self.stderr_cb and not self.stderr_void:
stderr = cStringIO.StringIO()
self.stderr_cb = stderr.write
# When the pipe fills up, it would deadlock this process.
if self.stdout and not self.stdout_cb and not self.stdout_is_void:
stdout = []
self.stdout_cb = stdout.append
if self.stderr and not self.stderr_cb and not self.stderr_is_void:
stderr = []
self.stderr_cb = stderr.append
self._tee_threads(input)
if stdout:
stdout = stdout.getvalue()
if stderr:
stderr = stderr.getvalue()
if stdout is not None:
stdout = ''.join(stdout)
stderr = None
if stderr is not None:
stderr = ''.join(stderr)
return (stdout, stderr)
......@@ -374,17 +373,16 @@ def communicate(args, timeout=None, **kwargs):
"""
stdin = kwargs.pop('stdin', None)
if stdin is not None:
if stdin is VOID:
kwargs['stdin'] = open(os.devnull, 'r')
stdin = None
else:
assert isinstance(stdin, basestring)
if isinstance(stdin, basestring):
# When stdin is passed as an argument, use it as the actual input data and
# set the Popen() parameter accordingly.
kwargs['stdin'] = PIPE
else:
kwargs['stdin'] = stdin
stdin = None
proc = Popen(args, **kwargs)
if stdin not in (None, VOID):
if stdin:
return proc.communicate(stdin, timeout), proc.returncode
else:
return proc.communicate(None, timeout), proc.returncode
......
......@@ -400,6 +400,16 @@ class S2Test(BaseTestCase):
self._check_res(res, None, None, 10)
self._run_test(fn)
def test_stdin_empty(self):
def fn(c, e, un):
stdin = ''
res = subprocess2.communicate(
e + ['--read'],
stdin=stdin,
universal_newlines=un)
self._check_res(res, None, None, 0)
self._run_test(fn)
def test_stdin_void(self):
res = subprocess2.communicate(self.exe + ['--read'], stdin=VOID)
self._check_res(res, None, None, 0)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment