Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(41)

Unified Diff: build/android/pylib/cmd_helper.py

Issue 812543002: Update from https://crrev.com/308331 (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « build/android/pylib/base/test_run_factory.py ('k') | build/android/pylib/cmd_helper_test.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: build/android/pylib/cmd_helper.py
diff --git a/build/android/pylib/cmd_helper.py b/build/android/pylib/cmd_helper.py
index e3abab74ffda3087eb239cddd850bbb874383161..f8815531a56922b9db6734bef01392f7c2bea90f 100644
--- a/build/android/pylib/cmd_helper.py
+++ b/build/android/pylib/cmd_helper.py
@@ -115,14 +115,20 @@ def GetCmdOutput(args, cwd=None, shell=False):
return output
-def _LogCommand(args, cwd=None):
- if not isinstance(args, basestring):
+def _ValidateAndLogCommand(args, cwd, shell):
+ if isinstance(args, basestring):
+ if not shell:
+ raise Exception('string args must be run with shell=True')
+ else:
+ if shell:
+ raise Exception('array args must be run with shell=False')
args = ' '.join(SingleQuote(c) for c in args)
if cwd is None:
cwd = ''
else:
cwd = ':' + cwd
logging.info('[host]%s> %s', cwd, args)
+ return args
def GetCmdStatusAndOutput(args, cwd=None, shell=False):
@@ -133,18 +139,13 @@ def GetCmdStatusAndOutput(args, cwd=None, shell=False):
the string or the first item in the args sequence.
cwd: If not None, the subprocess's current directory will be changed to
|cwd| before it's executed.
- shell: Whether to execute args as a shell command.
+ shell: Whether to execute args as a shell command. Must be True if args
+ is a string and False if args is a sequence.
Returns:
The 2-tuple (exit code, output).
"""
- if isinstance(args, basestring):
- if not shell:
- raise Exception('string args must be run with shell=True')
- elif shell:
- raise Exception('array args must be run with shell=False')
-
- _LogCommand(args, cwd)
+ _ValidateAndLogCommand(args, cwd, shell)
pipe = Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
shell=shell, cwd=cwd)
stdout, stderr = pipe.communicate()
@@ -162,44 +163,16 @@ class TimeoutError(Exception):
pass
-def GetCmdStatusAndOutputWithTimeout(args, timeout, cwd=None, shell=False,
- logfile=None):
- """Executes a subprocess with a timeout.
-
- Args:
- args: List of arguments to the program, the program to execute is the first
- element.
- timeout: the timeout in seconds or None to wait forever.
- cwd: If not None, the subprocess's current directory will be changed to
- |cwd| before it's executed.
- shell: Whether to execute args as a shell command.
- logfile: Optional file-like object that will receive output from the
- command as it is running.
-
- Returns:
- The 2-tuple (exit code, output).
- """
+def _IterProcessStdout(process, timeout=None, buffer_size=4096,
+ poll_interval=1):
assert fcntl, 'fcntl module is required'
- if isinstance(args, basestring):
- if not shell:
- raise Exception('string args must be run with shell=True')
- elif shell:
- raise Exception('array args must be run with shell=False')
-
- _LogCommand(args, cwd)
- process = Popen(args, cwd=cwd, shell=shell, stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT)
try:
- end_time = (time.time() + timeout) if timeout else None
- poll_interval = 1
- buffer_size = 4096
- child_fd = process.stdout.fileno()
- output = StringIO.StringIO()
-
# Enable non-blocking reads from the child's stdout.
+ child_fd = process.stdout.fileno()
fl = fcntl.fcntl(child_fd, fcntl.F_GETFL)
fcntl.fcntl(child_fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
+ end_time = (time.time() + timeout) if timeout else None
while True:
if end_time and time.time() > end_time:
raise TimeoutError
@@ -208,9 +181,7 @@ def GetCmdStatusAndOutputWithTimeout(args, timeout, cwd=None, shell=False,
data = os.read(child_fd, buffer_size)
if not data:
break
- if logfile:
- logfile.write(data)
- output.write(data)
+ yield data
if process.poll() is not None:
break
finally:
@@ -221,4 +192,70 @@ def GetCmdStatusAndOutputWithTimeout(args, timeout, cwd=None, shell=False,
except OSError:
pass
process.wait()
+
+
+def GetCmdStatusAndOutputWithTimeout(args, timeout, cwd=None, shell=False,
+ logfile=None):
+ """Executes a subprocess with a timeout.
+
+ Args:
+ args: List of arguments to the program, the program to execute is the first
+ element.
+ timeout: the timeout in seconds or None to wait forever.
+ cwd: If not None, the subprocess's current directory will be changed to
+ |cwd| before it's executed.
+ shell: Whether to execute args as a shell command. Must be True if args
+ is a string and False if args is a sequence.
+ logfile: Optional file-like object that will receive output from the
+ command as it is running.
+
+ Returns:
+ The 2-tuple (exit code, output).
+ """
+ _ValidateAndLogCommand(args, cwd, shell)
+ output = StringIO.StringIO()
+ process = Popen(args, cwd=cwd, shell=shell, stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+ for data in _IterProcessStdout(process, timeout=timeout):
+ if logfile:
+ logfile.write(data)
+ output.write(data)
return process.returncode, output.getvalue()
+
+
+def IterCmdOutputLines(args, timeout=None, cwd=None, shell=False,
+ check_status=True):
+ """Executes a subprocess and continuously yields lines from its output.
+
+ Args:
+ args: List of arguments to the program, the program to execute is the first
+ element.
+ cwd: If not None, the subprocess's current directory will be changed to
+ |cwd| before it's executed.
+ shell: Whether to execute args as a shell command. Must be True if args
+ is a string and False if args is a sequence.
+ check_status: A boolean indicating whether to check the exit status of the
+ process after all output has been read.
+
+ Yields:
+ The output of the subprocess, line by line.
+
+ Raises:
+ CalledProcessError if check_status is True and the process exited with a
+ non-zero exit status.
+ """
+ cmd = _ValidateAndLogCommand(args, cwd, shell)
+ process = Popen(args, cwd=cwd, shell=shell, stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+ buffer_output = ''
+ for data in _IterProcessStdout(process, timeout=timeout):
+ buffer_output += data
+ has_incomplete_line = buffer_output[-1] not in '\r\n'
+ lines = buffer_output.splitlines()
+ buffer_output = lines.pop() if has_incomplete_line else ''
+ for line in lines:
+ yield line
+ if buffer_output:
+ yield buffer_output
+ if check_status and process.returncode:
+ raise subprocess.CalledProcessError(process.returncode, cmd)
« no previous file with comments | « build/android/pylib/base/test_run_factory.py ('k') | build/android/pylib/cmd_helper_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698