Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(600)

Unified Diff: build/android/pylib/device/device_utils.py

Issue 659533002: New run shell implementation for DeviceUtils (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: build/android/pylib/device/device_utils.py
diff --git a/build/android/pylib/device/device_utils.py b/build/android/pylib/device/device_utils.py
index 75b2ae06ced358d9863cdda2c5a383cdf6e5298b..5d04a22135221d0eac8ad38f734774e595402520 100644
--- a/build/android/pylib/device/device_utils.py
+++ b/build/android/pylib/device/device_utils.py
@@ -11,6 +11,7 @@ Eventually, this will be based on adb_wrapper.
import multiprocessing
import os
import pipes
+import re
import sys
import tempfile
import time
@@ -86,6 +87,7 @@ class DeviceUtils(object):
self._commands_installed = False
self._default_timeout = default_timeout
self._default_retries = default_retries
+ self._cache = {}
assert(hasattr(self, decorators.DEFAULT_TIMEOUT_ATTR))
assert(hasattr(self, decorators.DEFAULT_RETRIES_ATTR))
@@ -144,8 +146,8 @@ class DeviceUtils(object):
raise device_errors.CommandFailedError(
'Could not enable root.', device=str(self))
- @decorators.WithTimeoutAndRetriesFromInstance()
- def GetExternalStoragePath(self, timeout=None, retries=None):
+ def GetExternalStoragePath(self, timeout=_DEFAULT_TIMEOUT,
jbudorick 2014/10/14 16:55:19 I'm not crazy about moving the timeout/retry bound
+ retries=_DEFAULT_RETRIES):
"""Get the device's path to its SD card.
Args:
@@ -160,14 +162,16 @@ class DeviceUtils(object):
CommandTimeoutError on timeout.
DeviceUnreachableError on missing device.
"""
- return self._GetExternalStoragePathImpl()
+ if 'external_storage' in self._cache:
+ return self._cache['external_storage']
- def _GetExternalStoragePathImpl(self):
- try:
- return self.old_interface.GetExternalStorage()
- except AssertionError as e:
- raise device_errors.CommandFailedError(
- str(e), device=str(self)), None, sys.exc_info()[2]
+ value = self._NewRunShellImpl('echo $EXTERNAL_STORAGE', timeout=timeout,
+ retries=retries).rstrip()
+ if not value:
jbudorick 2014/10/14 16:55:19 I'm not sure that this _has_ to be an error (altho
perezju 2014/10/15 09:22:54 This is what the current implementation does, so n
+ raise device_errors.CommandFailedError('$EXTERNAL_STORAGE is not set',
+ str(self))
+ self._cache['external_storage'] = value
jbudorick 2014/10/14 16:55:19 I like the idea of caching things like this and ce
perezju 2014/10/15 09:22:54 Acknowledged.
+ return value
@decorators.WithTimeoutAndRetriesFromInstance()
def WaitUntilFullyBooted(self, wifi=False, timeout=None, retries=None):
@@ -326,6 +330,51 @@ class DeviceUtils(object):
output = self.old_interface.RunShellCommand(cmd, timeout_time=timeout)
return output
+ def _NewRunShellImpl(self, cmd, cwd=None, env=None, as_root=False,
jbudorick 2014/10/14 16:55:19 I'm not sure about eliminating check_return here.
perezju 2014/10/15 09:22:54 I would argue that we shouldn't make it easy for c
+ timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
+ """Proposed new interface to run ADB shell commands.
+
+ When the command to run |cmd| is given as a string, it will be interpreted
+ and run by the shell on the device.
+
+ Alternatively, one can supply |cmd| as a sequence containing the name of
+ the command to run followed by its arguments. In this case, arguments are
+ passed to the command exactly as given, without any further processing by
+ the shell. This allows to easily pass arguments containing spaces or
+ special characters without having to worry about getting quoting right.
+
+ Args:
+ cmd: A string with the full command to run on the device, or a sequence
+ containing the command and its arguments.
+ cwd: The device directory in which the command should be run.
+ env: The environment variables with which the command should be run.
+ as_root: A boolean indicating whether the shell command should be run
+ with root privileges.
+ timeout: timeout in seconds
+ retries: number of retries
+
+ Returns:
+ The output of the command as a single string.
+
+ Raises:
+ CommandFailedError if the exit status of the command run is non-zero.
+ CommandTimeoutError on timeout.
+ """
+ def env_quote(key, value):
+ if not re.match('^[a-zA-Z_][a-zA-Z0-9_]*$', key):
jbudorick 2014/10/14 16:55:19 Compile the regex as a constant and then use that
perezju 2014/10/15 09:22:54 Acknowledged.
+ raise KeyError('Invalid shell variable name %r' % key)
+ return '%s=%s' % (key, pipes.quote(value))
+
+ if not isinstance(cmd, basestring):
+ cmd = ' '.join(pipes.quote(s) for s in cmd)
+ if as_root and not self._HasRootImpl():
+ cmd = 'su -c %s' % cmd
+ if env is not None:
+ cmd = '%s %s' % (' '.join(env_quote(*kv) for kv in env.iteritems()), cmd)
jbudorick 2014/10/14 16:55:19 This seems a little more readable to me: env_qu
perezju 2014/10/15 09:22:54 Acknowledged.
+ if cwd is not None:
+ cmd = 'cd %s && %s' % (pipes.quote(cwd), cmd)
+ return self.adb.Shell(cmd, expect_rc=0, timeout=timeout, retries=retries)
+
@decorators.WithTimeoutAndRetriesFromInstance()
def KillAll(self, process_name, signum=9, as_root=False, blocking=False,
timeout=None, retries=None):
@@ -622,7 +671,7 @@ class DeviceUtils(object):
zip_proc.start()
zip_proc.join()
- zip_on_device = '%s/tmp.zip' % self._GetExternalStoragePathImpl()
+ zip_on_device = '%s/tmp.zip' % self.GetExternalStoragePath()
try:
self.adb.Push(zip_file.name, zip_on_device)
self._RunShellCommandImpl(
« no previous file with comments | « no previous file | build/android/pylib/device/device_utils_test.py » ('j') | build/android/pylib/device/device_utils_test.py » ('J')

Powered by Google App Engine
This is Rietveld 408576698