Merge "adb unittest: get test_unicode_paths passing on win32"
diff --git a/adb/device.py b/adb/device.py
index 5b33ff2..c5b5eea 100644
--- a/adb/device.py
+++ b/adb/device.py
@@ -17,6 +17,7 @@
import os
import re
import subprocess
+import tempfile
class FindDeviceError(RuntimeError):
@@ -99,6 +100,36 @@
return _get_unique_device(product)
+# Call this instead of subprocess.check_output() to work-around issue in Python
+# 2's subprocess class on Windows where it doesn't support Unicode. This
+# writes the command line to a UTF-8 batch file that is properly interpreted
+# by cmd.exe.
+def _subprocess_check_output(*popenargs, **kwargs):
+ # Only do this slow work-around if Unicode is in the cmd line.
+ if (os.name == 'nt' and
+ any(isinstance(arg, unicode) for arg in popenargs[0])):
+ # cmd.exe requires a suffix to know that it is running a batch file
+ tf = tempfile.NamedTemporaryFile('wb', suffix='.cmd', delete=False)
+ # @ in batch suppresses echo of the current line.
+ # Change the codepage to 65001, the UTF-8 codepage.
+ tf.write('@chcp 65001 > nul\r\n')
+ tf.write('@')
+ # Properly quote all the arguments and encode in UTF-8.
+ tf.write(subprocess.list2cmdline(popenargs[0]).encode('utf-8'))
+ tf.close()
+
+ try:
+ result = subprocess.check_output(['cmd.exe', '/c', tf.name],
+ **kwargs)
+ except subprocess.CalledProcessError as e:
+ # Show real command line instead of the cmd.exe command line.
+ raise subprocess.CalledProcessError(e.returncode, popenargs[0],
+ output=e.output)
+ finally:
+ os.remove(tf.name)
+ return result
+ else:
+ return subprocess.check_output(*popenargs, **kwargs)
class AndroidDevice(object):
# Delimiter string to indicate the start of the exit code.
@@ -166,13 +197,13 @@
def _simple_call(self, cmd):
logging.info(' '.join(self.adb_cmd + cmd))
- return subprocess.check_output(
+ return _subprocess_check_output(
self.adb_cmd + cmd, stderr=subprocess.STDOUT)
def shell(self, cmd):
logging.info(' '.join(self.adb_cmd + ['shell'] + cmd))
cmd = self._make_shell_cmd(cmd)
- out = subprocess.check_output(cmd)
+ out = _subprocess_check_output(cmd)
rc, out = self._parse_shell_output(out)
if rc != 0:
error = subprocess.CalledProcessError(rc, cmd)
diff --git a/adb/test_device.py b/adb/test_device.py
index aed70f9..2006937 100644
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -457,19 +457,24 @@
def test_unicode_paths(self):
"""Ensure that we can support non-ASCII paths, even on Windows."""
- name = u'로보카 폴리'.encode('utf-8')
+ name = u'로보카 폴리'
## push.
- tf = tempfile.NamedTemporaryFile('wb', suffix=name)
- self.device.push(tf.name, '/data/local/tmp/adb-test-{}'.format(name))
+ tf = tempfile.NamedTemporaryFile('wb', suffix=name, delete=False)
+ tf.close()
+ self.device.push(tf.name, u'/data/local/tmp/adb-test-{}'.format(name))
+ os.remove(tf.name)
self.device.shell(['rm', '-f', '/data/local/tmp/adb-test-*'])
# pull.
- cmd = ['touch', '"/data/local/tmp/adb-test-{}"'.format(name)]
+ cmd = ['touch', u'"/data/local/tmp/adb-test-{}"'.format(name)]
self.device.shell(cmd)
- tf = tempfile.NamedTemporaryFile('wb', suffix=name)
- self.device.pull('/data/local/tmp/adb-test-{}'.format(name), tf.name)
+ tf = tempfile.NamedTemporaryFile('wb', suffix=name, delete=False)
+ tf.close()
+ self.device.pull(u'/data/local/tmp/adb-test-{}'.format(name), tf.name)
+ os.remove(tf.name)
+ self.device.shell(['rm', '-f', '/data/local/tmp/adb-test-*'])
def main():