summaryrefslogtreecommitdiffstats
path: root/build/android/devil/devil_env.py
diff options
context:
space:
mode:
Diffstat (limited to 'build/android/devil/devil_env.py')
-rw-r--r--build/android/devil/devil_env.py159
1 files changed, 159 insertions, 0 deletions
diff --git a/build/android/devil/devil_env.py b/build/android/devil/devil_env.py
new file mode 100644
index 0000000..1fc0220
--- /dev/null
+++ b/build/android/devil/devil_env.py
@@ -0,0 +1,159 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import json
+import logging
+import os
+import sys
+import tempfile
+import threading
+
+# TODO(jbudorick): Update this once dependency_manager moves to catapult.
+_TELEMETRY_PATH = os.path.abspath(os.path.join(
+ os.path.dirname(__file__), os.pardir, os.pardir, os.pardir,
+ 'tools', 'telemetry'))
+sys.path.append(_TELEMETRY_PATH)
+from catapult_base import dependency_manager # pylint: disable=import-error
+
+
+_DEFAULT_CONFIG_FILES = [
+ os.path.abspath(os.path.join(
+ os.path.dirname(__file__), os.pardir, 'devil_config.json')),
+]
+
+
+class _Environment(object):
+
+ def __init__(self):
+ self._config = None
+ self._config_init_lock = threading.Lock()
+
+ def Initialize(self, configs=None, config_files=None):
+ """Initialize devil's environment.
+
+ This uses all configurations provided via |configs| and |config_files|
+ to determine the locations of devil's dependencies. Configurations should
+ all take the form described by catapult_base.dependency_manager.BaseConfig.
+ If no configurations are provided, a default one will be used if available.
+
+ Args:
+ configs: An optional list of dict configurations.
+ config_files: An optional list of files to load
+ """
+
+ # Make sure we only initialize self._config once.
+ with self._config_init_lock:
+ if self._config is not None:
+ return
+ self._config = {}
+
+ self._InitializeRecursive(configs=configs, config_files=config_files)
+
+ def _InitializeRecursive(self, configs=None, config_files=None):
+ # This recurses through configs to create temporary files for each and
+ # take advantage of context managers to appropriately close those files.
+ # TODO(jbudorick): Remove this recursion if/when dependency_manager
+ # supports loading configurations directly from a dict.
+ if configs:
+ with tempfile.NamedTemporaryFile() as next_config_file:
+ next_config_file.write(json.dumps(configs[0]))
+ next_config_file.flush()
+ self._InitializeRecursive(
+ configs=configs[1:],
+ config_files=[next_config_file.name] + (config_files or []))
+ else:
+ self._InitializeImpl(config_files)
+
+ def _InitializeImpl(self, config_files):
+ if not config_files:
+ config_files = _DEFAULT_CONFIG_FILES
+
+ dm = dependency_manager.DependencyManager(
+ [dependency_manager.BaseConfig(c) for c in config_files])
+ platform = 'linux_android'
+
+ android_sdk_path = dm.FetchPath('android_sdk', platform)
+
+ if os.path.exists(android_sdk_path):
+ self._config['android_sdk_path'] = android_sdk_path
+
+ # Chromium's hooks always download the SDK extras even if they aren't
+ # downloading the SDK, so we have to check for the existence of the
+ # particular components we care about.
+
+ try:
+ adb_path = dm.FetchPath('adb_path', platform)
+ except dependency_manager.NoPathFoundError:
+ adb_path = os.path.join(
+ self.android_sdk_path, 'platform-tools', 'adb')
+ if os.path.exists(adb_path):
+ self._config['adb_path'] = adb_path
+
+ build_tools_path = os.path.join(self.android_sdk_path, 'build-tools')
+ if os.path.exists(build_tools_path):
+ build_tools_contents = os.listdir(build_tools_path)
+ if build_tools_contents:
+ if len(build_tools_contents) > 1:
+ build_tools_contents.sort()
+ logging.warning(
+ 'More than one set of build-tools provided by the Android SDK:'
+ ' %s', ','.join(build_tools_contents))
+ logging.warning('Defaulting to %s', build_tools_contents[-1])
+ self._config['android_sdk_build_tools_path'] = os.path.join(
+ self.android_sdk_path, 'build-tools', build_tools_contents[-1])
+
+ try:
+ self._config['forwarder_host_path'] = dm.FetchPath(
+ 'forwarder_host', platform)
+ self._config['forwarder_device_path'] = dm.FetchPath(
+ 'forwarder_device', platform)
+ except dependency_manager.NoPathFoundError as e:
+ logging.warning(str(e))
+
+ try:
+ self._config['md5sum_host_path'] = dm.FetchPath('md5sum_host', platform)
+ self._config['md5sum_device_path'] = dm.FetchPath(
+ 'md5sum_device', platform)
+ except dependency_manager.NoPathFoundError as e:
+ logging.warning(str(e))
+
+ try:
+ self._config['pymock_path'] = dm.FetchPath('pymock', platform)
+ except dependency_manager.NoPathFoundError as e:
+ logging.warning(str(e))
+
+ def __getattr__(self, name):
+ if self._config is None:
+ self.Initialize()
+
+ if name not in self._config:
+ raise AttributeError('devil environment has no %r attribute' % name)
+
+ return self._config[name]
+
+
+config = _Environment()
+
+
+def GenerateDynamicConfig(deps):
+ """Generate a configuration dict from the provided deps dict.
+
+ Args:
+ deps: A dict mapping dependency names to lists of local files.
+ Returns:
+ A BaseConfig-compatible dict.
+ """
+ return {
+ 'config_type': 'BaseConfig',
+ 'dependencies': {
+ k: {
+ 'file_info': {
+ 'linux_android': {
+ 'local_paths': v
+ }
+ }
+ } for k, v in deps.iteritems()
+ }
+ }
+