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

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

Issue 2101243005: Add a snapshot of flutter/engine/src/build to our sdk (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: add README.dart Created 4 years, 6 months 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/chrome_test_server_spawner.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
new file mode 100644
index 0000000000000000000000000000000000000000..f8815531a56922b9db6734bef01392f7c2bea90f
--- /dev/null
+++ b/build/android/pylib/cmd_helper.py
@@ -0,0 +1,261 @@
+# 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.
+
+"""A wrapper for subprocess to make calling shell commands easier."""
+
+import logging
+import os
+import pipes
+import select
+import signal
+import string
+import StringIO
+import subprocess
+import time
+
+# fcntl is not available on Windows.
+try:
+ import fcntl
+except ImportError:
+ fcntl = None
+
+_SafeShellChars = frozenset(string.ascii_letters + string.digits + '@%_-+=:,./')
+
+def SingleQuote(s):
+ """Return an shell-escaped version of the string using single quotes.
+
+ Reliably quote a string which may contain unsafe characters (e.g. space,
+ quote, or other special characters such as '$').
+
+ The returned value can be used in a shell command line as one token that gets
+ to be interpreted literally.
+
+ Args:
+ s: The string to quote.
+
+ Return:
+ The string quoted using single quotes.
+ """
+ return pipes.quote(s)
+
+def DoubleQuote(s):
+ """Return an shell-escaped version of the string using double quotes.
+
+ Reliably quote a string which may contain unsafe characters (e.g. space
+ or quote characters), while retaining some shell features such as variable
+ interpolation.
+
+ The returned value can be used in a shell command line as one token that gets
+ to be further interpreted by the shell.
+
+ The set of characters that retain their special meaning may depend on the
+ shell implementation. This set usually includes: '$', '`', '\', '!', '*',
+ and '@'.
+
+ Args:
+ s: The string to quote.
+
+ Return:
+ The string quoted using double quotes.
+ """
+ if not s:
+ return '""'
+ elif all(c in _SafeShellChars for c in s):
+ return s
+ else:
+ return '"' + s.replace('"', '\\"') + '"'
+
+
+def Popen(args, stdout=None, stderr=None, shell=None, cwd=None, env=None):
+ return subprocess.Popen(
+ args=args, cwd=cwd, stdout=stdout, stderr=stderr,
+ shell=shell, close_fds=True, env=env,
+ preexec_fn=lambda: signal.signal(signal.SIGPIPE, signal.SIG_DFL))
+
+
+def Call(args, stdout=None, stderr=None, shell=None, cwd=None, env=None):
+ pipe = Popen(args, stdout=stdout, stderr=stderr, shell=shell, cwd=cwd,
+ env=env)
+ pipe.communicate()
+ return pipe.wait()
+
+
+def RunCmd(args, cwd=None):
+ """Opens a subprocess to execute a program and returns its return value.
+
+ Args:
+ args: A string or a sequence of program arguments. The program to execute is
+ 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.
+
+ Returns:
+ Return code from the command execution.
+ """
+ logging.info(str(args) + ' ' + (cwd or ''))
+ return Call(args, cwd=cwd)
+
+
+def GetCmdOutput(args, cwd=None, shell=False):
+ """Open a subprocess to execute a program and returns its output.
+
+ Args:
+ args: A string or a sequence of program arguments. The program to execute is
+ 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.
+
+ Returns:
+ Captures and returns the command's stdout.
+ Prints the command's stderr to logger (which defaults to stdout).
+ """
+ (_, output) = GetCmdStatusAndOutput(args, cwd, shell)
+ return output
+
+
+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):
+ """Executes a subprocess and returns its exit code and output.
+
+ Args:
+ args: A string or a sequence of program arguments. The program to execute is
+ 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. Must be True if args
+ is a string and False if args is a sequence.
+
+ Returns:
+ The 2-tuple (exit code, output).
+ """
+ _ValidateAndLogCommand(args, cwd, shell)
+ pipe = Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+ shell=shell, cwd=cwd)
+ stdout, stderr = pipe.communicate()
+
+ if stderr:
+ logging.critical(stderr)
+ if len(stdout) > 4096:
+ logging.debug('Truncated output:')
+ logging.debug(stdout[:4096])
+ return (pipe.returncode, stdout)
+
+
+class TimeoutError(Exception):
+ """Module-specific timeout exception."""
+ pass
+
+
+def _IterProcessStdout(process, timeout=None, buffer_size=4096,
+ poll_interval=1):
+ assert fcntl, 'fcntl module is required'
+ try:
+ # 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
+ read_fds, _, _ = select.select([child_fd], [], [], poll_interval)
+ if child_fd in read_fds:
+ data = os.read(child_fd, buffer_size)
+ if not data:
+ break
+ yield data
+ if process.poll() is not None:
+ break
+ finally:
+ try:
+ # Make sure the process doesn't stick around if we fail with an
+ # exception.
+ process.kill()
+ 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/chrome_test_server_spawner.py ('k') | build/android/pylib/cmd_helper_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698