aboutsummaryrefslogtreecommitdiff
path: root/catapult/devil/devil/utils/cmd_helper.py
diff options
context:
space:
mode:
Diffstat (limited to 'catapult/devil/devil/utils/cmd_helper.py')
-rw-r--r--catapult/devil/devil/utils/cmd_helper.py58
1 files changed, 48 insertions, 10 deletions
diff --git a/catapult/devil/devil/utils/cmd_helper.py b/catapult/devil/devil/utils/cmd_helper.py
index 634c9716..3a959450 100644
--- a/catapult/devil/devil/utils/cmd_helper.py
+++ b/catapult/devil/devil/utils/cmd_helper.py
@@ -10,11 +10,19 @@ import pipes
import select
import signal
import string
-import StringIO
import subprocess
import sys
import time
+CATAPULT_ROOT_PATH = os.path.abspath(
+ os.path.join(os.path.dirname(__file__), '..', '..', '..'))
+SIX_PATH = os.path.join(CATAPULT_ROOT_PATH, 'third_party', 'six')
+
+if SIX_PATH not in sys.path:
+ sys.path.append(SIX_PATH)
+
+import six
+
from devil import base_error
logger = logging.getLogger(__name__)
@@ -23,7 +31,8 @@ _SafeShellChars = frozenset(string.ascii_letters + string.digits + '@%_-+=:,./')
# Cache the string-escape codec to ensure subprocess can find it
# later. Return value doesn't matter.
-codecs.lookup('string-escape')
+if six.PY2:
+ codecs.lookup('string-escape')
def SingleQuote(s):
@@ -102,6 +111,7 @@ def Popen(args,
cwd=None,
env=None):
# preexec_fn isn't supported on windows.
+ # pylint: disable=unexpected-keyword-arg
if sys.platform == 'win32':
close_fds = (stdin is None and stdout is None and stderr is None)
preexec_fn = None
@@ -109,7 +119,8 @@ def Popen(args,
close_fds = True
preexec_fn = lambda: signal.signal(signal.SIGPIPE, signal.SIG_DFL)
- return subprocess.Popen(
+ if six.PY2:
+ return subprocess.Popen(
args=args,
cwd=cwd,
stdin=stdin,
@@ -118,8 +129,29 @@ def Popen(args,
shell=shell,
close_fds=close_fds,
env=env,
- preexec_fn=preexec_fn)
-
+ preexec_fn=preexec_fn
+ )
+ else:
+ # opens stdout in text mode, so that caller side always get 'str',
+ # and there will be no type mismatch error.
+ # Ignore any decoding error, so that caller will not crash due to
+ # uncaught exception. Decoding errors are unavoidable, as we
+ # do not know the encoding of the output, and in some output there
+ # will be multiple encodings (e.g. adb logcat)
+ return subprocess.Popen(
+ args=args,
+ cwd=cwd,
+ stdin=stdin,
+ stdout=stdout,
+ stderr=stderr,
+ shell=shell,
+ close_fds=close_fds,
+ env=env,
+ preexec_fn=preexec_fn,
+ universal_newlines=True,
+ encoding='utf-8',
+ errors='ignore'
+ )
def Call(args, stdout=None, stderr=None, shell=None, cwd=None, env=None):
pipe = Popen(
@@ -165,7 +197,7 @@ def GetCmdOutput(args, cwd=None, shell=False, env=None):
def _ValidateAndLogCommand(args, cwd, shell):
- if isinstance(args, basestring):
+ if isinstance(args, six.string_types):
if not shell:
raise Exception('string args must be run with shell=True')
else:
@@ -283,6 +315,12 @@ class TimeoutError(base_error.BaseError):
return self._output
+def _read_and_decode(fd, buffer_size):
+ data = os.read(fd, buffer_size)
+ if data and six.PY3:
+ data = data.decode('utf-8', errors='ignore')
+ return data
+
def _IterProcessStdoutFcntl(process,
iter_timeout=None,
timeout=None,
@@ -316,7 +354,7 @@ def _IterProcessStdoutFcntl(process,
read_fds, _, _ = select.select([child_fd], [], [],
iter_aware_poll_interval)
if child_fd in read_fds:
- data = os.read(child_fd, buffer_size)
+ data = _read_and_decode(child_fd, buffer_size)
if not data:
break
yield data
@@ -328,7 +366,7 @@ def _IterProcessStdoutFcntl(process,
read_fds, _, _ = select.select([child_fd], [], [],
iter_aware_poll_interval)
if child_fd in read_fds:
- data = os.read(child_fd, buffer_size)
+ data = _read_and_decode(child_fd, buffer_size)
if data:
yield data
continue
@@ -365,7 +403,7 @@ def _IterProcessStdoutQueue(process,
# TODO(jbudorick): Pick an appropriate read size here.
while True:
try:
- output_chunk = os.read(process.stdout.fileno(), buffer_size)
+ output_chunk = _read_and_decode(process.stdout.fileno(), buffer_size)
except IOError:
break
stdout_queue.put(output_chunk, True)
@@ -452,7 +490,7 @@ def GetCmdStatusAndOutputWithTimeout(args,
TimeoutError on timeout.
"""
_ValidateAndLogCommand(args, cwd, shell)
- output = StringIO.StringIO()
+ output = six.StringIO()
process = Popen(
args,
cwd=cwd,