Bug 1642672 - [mozdevice 3.2.3] Ensure content of files and process output is converted to str for Python 3, r=gbrown.
authorBob Clary <bclary@bclary.com>
Tue, 02 Jun 2020 20:43:45 +0000
changeset 533695 ea34fd156c89005e2e8e74c6e6b6663291aa08c8
parent 533694 2a670d8c9c3e98406108cafc1f281c6c2d90a583
child 533696 d03d90267a78db61c33d1b76d5635099afa7c8c9
push id37475
push userbtara@mozilla.com
push dateWed, 03 Jun 2020 16:12:12 +0000
treeherdermozilla-central@ea34fd156c89 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgbrown
bugs1642672
milestone79.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1642672 - [mozdevice 3.2.3] Ensure content of files and process output is converted to str for Python 3, r=gbrown. Differential Revision: https://phabricator.services.mozilla.com/D77844
testing/mozbase/mozdevice/mozdevice/adb.py
testing/mozbase/mozdevice/setup.py
--- a/testing/mozbase/mozdevice/mozdevice/adb.py
+++ b/testing/mozbase/mozdevice/mozdevice/adb.py
@@ -44,22 +44,17 @@ class ADBProcess(object):
 
     @property
     def stdout(self):
         """Return the contents of stdout."""
         if not self.stdout_file or self.stdout_file.closed:
             content = ""
         else:
             self.stdout_file.seek(0, os.SEEK_SET)
-            content = self.stdout_file.read().rstrip()
-            # File read() returns str on Python 2 while Python 3 returns bytes.
-            # If we are running under Python3, convert content to str to match
-            # the expectations of the existing code.
-            if six.PY3:
-                content = content.decode("utf-8")
+            content = six.ensure_str(self.stdout_file.read().rstrip())
         return content
 
     def __str__(self):
         # Remove -s <serialno> from the error message to allow bug suggestions
         # to be independent of the individual failing device.
         arg_string = ' '.join(self.args)
         arg_string = re.sub(' -s [\w-]+', '', arg_string)
         return ('args: %s, exitcode: %s, stdout: %s' % (
@@ -1046,21 +1041,19 @@ class ADBDevice(ADBCommand):
         re_returncode = re.compile(r'adb_returncode=([0-9]+)')
         file_obj.seek(0, os.SEEK_END)
 
         line = ''
         length = file_obj.tell()
         offset = 1
         while length - offset >= 0:
             file_obj.seek(-offset, os.SEEK_END)
-            char = file_obj.read(1)
+            char = six.ensure_str(file_obj.read(1))
             if not char:
                 break
-            if six.PY3:
-                char = char.decode("utf-8")
             if char != '\r' and char != '\n':
                 line = char + line
             elif line:
                 # we have collected everything up to the beginning of the line
                 break
             offset += 1
         match = re_returncode.match(line)
         if match:
@@ -1073,18 +1066,17 @@ class ADBDevice(ADBCommand):
             exitcode = None
             # We may have a situation where the adb_returncode= is not
             # at the end of the output. This happens at least in the
             # failure jit-tests on arm. To work around this
             # possibility, we can search the entire output for the
             # appropriate match.
             file_obj.seek(0, os.SEEK_SET)
             for line in file_obj:
-                if six.PY3:
-                    line = line.decode("utf-8")
+                line = six.ensure_str(line)
                 match = re_returncode.search(line)
                 if match:
                     exitcode = int(match.group(1))
                     break
             # Reset the position in the file to the end.
             file_obj.seek(0, os.SEEK_END)
 
         return exitcode
@@ -2536,22 +2528,22 @@ class ADBDevice(ADBCommand):
 
         with tempfile.NamedTemporaryFile() as tf:
             self.pull(remote, tf.name, timeout=timeout)
             with io.open(tf.name, mode='rb') as tf2:
                 # ADB pull does not support offset and length, but we can
                 # instead read only the requested portion of the local file
                 if offset is not None and length is not None:
                     tf2.seek(offset)
-                    return tf2.read(length)
+                    return six.ensure_str(tf2.read(length))
                 elif offset is not None:
                     tf2.seek(offset)
-                    return tf2.read()
+                    return six.ensure_str(tf2.read())
                 else:
-                    return tf2.read()
+                    return six.ensure_str(tf2.read())
 
     def rm(self, path, recursive=False, force=False, timeout=None, root=False):
         """Delete files or directories on the device.
 
         :param str path: The path of the remote file or directory.
         :param bool recursive: Flag specifying if the command is
             to be applied recursively to the target. Default is False.
         :param bool force: Flag which if True will not raise an
@@ -2631,17 +2623,17 @@ class ADBDevice(ADBCommand):
         try:
             for attempt in range(1, max_attempts + 1):
                 adb_process = self.shell("ps", timeout=timeout)
                 if adb_process.timedout:
                     raise ADBTimeoutError("%s" % adb_process)
                 elif adb_process.exitcode:
                     raise ADBProcessError(adb_process)
                 # first line is the headers
-                header = adb_process.stdout_file.readline()
+                header = six.ensure_str(adb_process.stdout_file.readline())
                 pid_i = -1
                 user_i = -1
                 els = header.split()
                 for i in range(len(els)):
                     item = els[i].lower()
                     if item == 'user':
                         user_i = i
                     elif item == 'pid':
@@ -2650,32 +2642,32 @@ class ADBDevice(ADBCommand):
                     break
                 # if this isn't the final attempt, don't print this as an error
                 if attempt < max_attempts:
                     self._logger.info('get_process_list: attempt: %d %s' % (attempt, header))
                 else:
                     raise ADBError('get_process_list: Unknown format: %s: %s' % (
                         header, adb_process))
             ret = []
-            line = adb_process.stdout_file.readline()
+            line = six.ensure_str(adb_process.stdout_file.readline())
             while line:
                 els = line.split()
                 try:
                     ret.append([int(els[pid_i]), els[-1], els[user_i]])
                 except ValueError:
                     self._logger.error('get_process_list: %s %s\n%s' % (
                         header, line, traceback.format_exc()))
                     raise ADBError('get_process_list: %s: %s: %s' % (
                         header, line, adb_process))
                 except IndexError:
                     self._logger.error('get_process_list: %s %s els %s pid_i %s user_i %s\n%s' % (
                         header, line, els, pid_i, user_i, traceback.format_exc()))
                     raise ADBError('get_process_list: %s: %s els %s pid_i %s user_i %s: %s' % (
                         header, line, els, pid_i, user_i, adb_process))
-                line = adb_process.stdout_file.readline()
+                line = six.ensure_str(adb_process.stdout_file.readline())
             self._logger.debug('get_process_list: %s' % ret)
             return ret
         finally:
             if adb_process and isinstance(adb_process.stdout_file, io.IOBase):
                 adb_process.stdout_file.close()
 
     def kill(self, pids, sig=None, attempts=3, wait=5,
              timeout=None, root=False):
--- a/testing/mozbase/mozdevice/setup.py
+++ b/testing/mozbase/mozdevice/setup.py
@@ -3,17 +3,17 @@
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from __future__ import absolute_import
 
 from setuptools import setup
 
 PACKAGE_NAME = 'mozdevice'
-PACKAGE_VERSION = '3.2.2'
+PACKAGE_VERSION = '3.2.3'
 
 deps = ['mozlog >= 6.0']
 
 setup(name=PACKAGE_NAME,
       version=PACKAGE_VERSION,
       description="Mozilla-authored device management",
       long_description="see https://firefox-source-docs.mozilla.org/mozbase/index.html",
       classifiers=['Programming Language :: Python :: 2.7',