Fix python3 compatibility on windows

* Use six.ensure_bytes in pylib/py/generator/ninja.py
* Pass universal_newlines=True to subprocess.Popen calls in
  pylib/gyp/win_tool.py and pylib/gyp/msvs_emulation.py, so that
  captured stdout is read as string instead of as raw bytes
* Replace str.translate calls with re.sub. Python3 doesn't support this
  str.translate with two arguments. re.sub() works the same in python2
  and 3.

Note: six.ensure_binary requires six>=1.15.0 (released 2020-05-21).

Bug: 227327945
Change-Id: I750a290b865bc6d9555f833237b72b9f3efa3b69
Reviewed-on: https://chromium-review.googlesource.com/c/external/gyp/+/3557378
Reviewed-by: Mark Mentovai <mark@chromium.org>
diff --git a/pylib/gyp/generator/ninja.py b/pylib/gyp/generator/ninja.py
index bf04e56..3bcfe35 100644
--- a/pylib/gyp/generator/ninja.py
+++ b/pylib/gyp/generator/ninja.py
@@ -14,6 +14,7 @@
 import signal
 import subprocess
 import sys
+import six
 import gyp
 import gyp.common
 from gyp.common import OrderedSet
@@ -751,7 +752,7 @@
         if self.flavor == 'win':
           # WriteNewNinjaRule uses unique_name for creating an rsp file on win.
           extra_bindings.append(('unique_name',
-              hashlib.md5(outputs[0]).hexdigest()))
+              hashlib.md5(six.ensure_binary(outputs[0])).hexdigest()))
 
         self.ninja.build(outputs, rule_name, self.GypPathToNinja(source),
                          implicit=inputs,
diff --git a/pylib/gyp/msvs_emulation.py b/pylib/gyp/msvs_emulation.py
index fde7e1f..c01c135 100644
--- a/pylib/gyp/msvs_emulation.py
+++ b/pylib/gyp/msvs_emulation.py
@@ -140,7 +140,8 @@
   if not dxsdk_dir:
     # Setup params to pass to and attempt to launch reg.exe.
     cmd = ['reg.exe', 'query', r'HKLM\Software\Microsoft\DirectX', '/s']
-    p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+    p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+                         universal_newlines=True)
     for line in p.communicate()[0].splitlines():
       if 'InstallPath' in line:
         dxsdk_dir = line.split('    ')[3] + "\\"
@@ -1052,7 +1053,8 @@
     args = vs.SetupScript(arch)
     args.extend(('&&', 'set'))
     popen = subprocess.Popen(
-        args, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+        args, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
+        universal_newlines=True)
     variables, _ = popen.communicate()
     if popen.returncode != 0:
       raise Exception('"%s" failed with error %d' % (args, popen.returncode))
@@ -1073,7 +1075,8 @@
     args = vs.SetupScript(arch)
     args.extend(('&&',
       'for', '%i', 'in', '(cl.exe)', 'do', '@echo', 'LOC:%~$PATH:i'))
-    popen = subprocess.Popen(args, shell=True, stdout=subprocess.PIPE)
+    popen = subprocess.Popen(args, shell=True, stdout=subprocess.PIPE,
+                             universal_newlines=True)
     output, _ = popen.communicate()
     cl_paths[arch] = _ExtractCLPath(output)
   return cl_paths
diff --git a/pylib/gyp/win_tool.py b/pylib/gyp/win_tool.py
index 8973484..e7c0dd8 100755
--- a/pylib/gyp/win_tool.py
+++ b/pylib/gyp/win_tool.py
@@ -130,7 +130,8 @@
     # For that reason, since going through the shell doesn't seem necessary on
     # non-Windows don't do that there.
     link = subprocess.Popen(args, shell=sys.platform == 'win32', env=env,
-                            stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+                            stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
+                            universal_newlines=True)
     out, _ = link.communicate()
     for line in out.splitlines():
       if (not line.startswith('   Creating library ') and
@@ -197,8 +198,8 @@
       # and sometimes doesn't unfortunately.
       with open(our_manifest, 'r') as our_f:
         with open(assert_manifest, 'r') as assert_f:
-          our_data = our_f.read().translate(None, string.whitespace)
-          assert_data = assert_f.read().translate(None, string.whitespace)
+          our_data = re.sub(r'\s+', '', our_f.read())
+          assert_data = re.sub(r'\s+', '', assert_f.read())
       if our_data != assert_data:
         os.unlink(out)
         def dump(filename):
@@ -223,7 +224,8 @@
     tool)."""
     env = self._GetEnv(arch)
     popen = subprocess.Popen(args, shell=True, env=env,
-                             stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+                             stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
+                             universal_newlines=True)
     out, _ = popen.communicate()
     for line in out.splitlines():
       if line and 'manifest authoring warning 81010002' not in line:
@@ -255,7 +257,8 @@
         idl]
     env = self._GetEnv(arch)
     popen = subprocess.Popen(args, shell=True, env=env,
-                             stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+                             stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
+                             universal_newlines=True)
     out, _ = popen.communicate()
     # Filter junk out of stdout, and write filtered versions. Output we want
     # to filter is pairs of lines that look like this:
@@ -274,7 +277,8 @@
     """Filter logo banner from invocations of asm.exe."""
     env = self._GetEnv(arch)
     popen = subprocess.Popen(args, shell=True, env=env,
-                             stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+                             stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
+                             universal_newlines=True)
     out, _ = popen.communicate()
     for line in out.splitlines():
       if (not line.startswith('Copyright (C) Microsoft Corporation') and
@@ -289,7 +293,8 @@
     don't support the /nologo flag."""
     env = self._GetEnv(arch)
     popen = subprocess.Popen(args, shell=True, env=env,
-                             stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+                             stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
+                             universal_newlines=True)
     out, _ = popen.communicate()
     for line in out.splitlines():
       if (not line.startswith('Microsoft (R) Windows (R) Resource Compiler') and