Bug 1623701 - Ensure processhandler.py supports Python 3.5 r=ahal
☠☠ backed out by 9a1f3a08f98c ☠ ☠
authorRicky Stewart <rstewart@mozilla.com>
Thu, 26 Mar 2020 14:33:46 +0000
changeset 520570 14968570b2f5b1404de61b617f18276e22fb96eb
parent 520569 60ac254277739ce86aea4fc15d06d62a28b551e9
child 520571 e62f3effd132a282c68aac769922710fad287bc5
push id37253
push usernerli@mozilla.com
push dateThu, 26 Mar 2020 21:36:52 +0000
treeherdermozilla-central@c644dd16e2cc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersahal
bugs1623701
milestone76.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 1623701 - Ensure processhandler.py supports Python 3.5 r=ahal Differential Revision: https://phabricator.services.mozilla.com/D67532
testing/mozbase/mozprocess/mozprocess/processhandler.py
--- a/testing/mozbase/mozprocess/mozprocess/processhandler.py
+++ b/testing/mozbase/mozprocess/mozprocess/processhandler.py
@@ -1,15 +1,16 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # 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, print_function, unicode_literals
 
 import errno
+import io
 import os
 import signal
 import subprocess
 import sys
 import threading
 import traceback
 from datetime import datetime
 
@@ -122,27 +123,42 @@ class ProcessHandlerMixin(object):
                 'stdin': stdin,
                 'stdout': stdout,
                 'stderr': stderr,
                 'preexec_fn': preexec_fn,
                 'close_fds': close_fds,
                 'shell': shell,
                 'cwd': cwd,
                 'env': env,
-                'universal_newlines': universal_newlines,
                 'startupinfo': startupinfo,
                 'creationflags': creationflags,
             }
-            if six.PY3 and universal_newlines:
+            if six.PY2:
+                kwargs['universal_newlines'] = universal_newlines
+            if six.PY3 and sys.version_info.minor >= 6:
+                kwargs['universal_newlines'] = universal_newlines
                 kwargs['encoding'] = encoding
             try:
                 subprocess.Popen.__init__(self, args, **kwargs)
             except OSError:
                 print(args, file=sys.stderr)
                 raise
+            # We need to support Python 3.5 for now, which doesn't support the
+            # "encoding" argument to the Popen constructor. For now, emulate it
+            # by patching the streams so that they return consistent values.
+            # This can be removed once we remove support for Python 3.5.
+            if six.PY3 and sys.version_info.minor == 5 and universal_newlines:
+                if self.stdin is not None:
+                    self.stdin = io.TextIOWrapper(self.stdin, encoding=encoding)
+                if self.stdout is not None:
+                    self.stdout = io.TextIOWrapper(self.stdout,
+                                                   encoding=encoding)
+                if self.stderr is not None:
+                    self.stderr = io.TextIOWrapper(self.stderr,
+                                                   encoding=encoding)
 
         def debug(self, msg):
             if not MOZPROCESS_DEBUG:
                 return
             thread = threading.current_thread().name
             print("DBG::MOZPROC PID:{} ({}) | {}".format(self.pid, thread, msg))
 
         def __del__(self):
@@ -1137,35 +1153,32 @@ class StoreOutput(object):
 
     def __call__(self, line):
         self.output.append(line)
 
 
 class StreamOutput(object):
     """pass output to a stream and flush"""
 
-    def __init__(self, stream):
+    def __init__(self, stream, text=True):
         self.stream = stream
+        self.text = text
 
     def __call__(self, line):
-        try:
-            self.stream.write(line + '\n'.encode('utf8'))
-        except UnicodeDecodeError:
-            # TODO: Workaround for bug #991866 to make sure we can display when
-            # when normal UTF-8 display is failing
-            self.stream.write(line.decode('iso8859-1') + '\n')
+        ensure = six.ensure_text if self.text else six.ensure_binary
+        self.stream.write(ensure(line + '\n'))
         self.stream.flush()
 
 
 class LogOutput(StreamOutput):
     """pass output to a file"""
 
     def __init__(self, filename):
         self.file_obj = open(filename, 'a')
-        StreamOutput.__init__(self, self.file_obj)
+        StreamOutput.__init__(self, self.file_obj, True)
 
     def __del__(self):
         if self.file_obj is not None:
             self.file_obj.close()
 
 
 # front end class with the default handlers
 
@@ -1197,19 +1210,22 @@ class ProcessHandler(ProcessHandlerMixin
 
         if logfile:
             logoutput = LogOutput(logfile)
             kwargs['processOutputLine'].append(logoutput)
 
         if stream is True:
             # Print to standard output only if no outputline provided
             if not kwargs['processOutputLine']:
-                kwargs['processOutputLine'].append(StreamOutput(sys.stdout))
+                kwargs['processOutputLine'].append(
+                    StreamOutput(sys.stdout,
+                                 kwargs.get('universal_newlines', False)))
         elif stream:
-            streamoutput = StreamOutput(stream)
+            streamoutput = StreamOutput(stream,
+                                        kwargs.get('universal_newlines', False))
             kwargs['processOutputLine'].append(streamoutput)
 
         self.output = None
         if storeOutput:
             storeoutput = StoreOutput()
             self.output = storeoutput.output
             kwargs['processOutputLine'].append(storeoutput)