OLD | NEW |
(Empty) | |
| 1 # Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. |
| 4 |
| 5 import json |
| 6 import logging |
| 7 import os |
| 8 import sys |
| 9 import tempfile |
| 10 import threading |
| 11 |
| 12 # TODO(jbudorick): Update this once dependency_manager moves to catapult. |
| 13 _TELEMETRY_PATH = os.path.abspath(os.path.join( |
| 14 os.path.dirname(__file__), os.pardir, os.pardir, os.pardir, |
| 15 'tools', 'telemetry')) |
| 16 sys.path.append(_TELEMETRY_PATH) |
| 17 from catapult_base import dependency_manager # pylint: disable=import-error |
| 18 |
| 19 |
| 20 class _Environment(object): |
| 21 |
| 22 def __init__(self): |
| 23 self._config = None |
| 24 self._config_init_lock = threading.Lock() |
| 25 |
| 26 def Initialize(self, configs=None, config_files=None): |
| 27 """Initialize devil's environment. |
| 28 |
| 29 This uses all configurations provided via |configs| and |config_files| |
| 30 to determine the locations of devil's dependencies. Configurations should |
| 31 all take the form described by catapult_base.dependency_manager.BaseConfig. |
| 32 If no configurations are provided, a default one will be used if available. |
| 33 |
| 34 Args: |
| 35 configs: An optional list of dict configurations. |
| 36 config_files: An optional list of files to load |
| 37 """ |
| 38 |
| 39 # Make sure we only initialize self._config once. |
| 40 with self._config_init_lock: |
| 41 if self._config is not None: |
| 42 return |
| 43 self._config = {} |
| 44 |
| 45 self._InitializeRecursive(configs=configs, config_files=config_files) |
| 46 |
| 47 def _InitializeRecursive(self, configs=None, config_files=None): |
| 48 # This recurses through configs to create temporary files for each and |
| 49 # take advantage of context managers to appropriately close those files. |
| 50 # TODO(jbudorick): Remove this recursion if/when dependency_manager |
| 51 # supports loading configurations directly from a dict. |
| 52 if configs: |
| 53 with tempfile.NamedTemporaryFile() as next_config_file: |
| 54 next_config_file.write(json.dumps(configs[0])) |
| 55 next_config_file.flush() |
| 56 self._InitializeRecursive( |
| 57 configs=configs[1:], |
| 58 config_files=[next_config_file.name] + (config_files or [])) |
| 59 else: |
| 60 self._InitializeImpl(config_files) |
| 61 |
| 62 def _InitializeImpl(self, config_files): |
| 63 if not config_files: |
| 64 config_files = [] |
| 65 if 'DEVIL_ENV_CONFIG' in os.environ: |
| 66 config_files.append(os.environ.get('DEVIL_ENV_CONFIG')) |
| 67 |
| 68 dm = dependency_manager.DependencyManager( |
| 69 [dependency_manager.BaseConfig(c) for c in config_files]) |
| 70 platform = 'linux_android' |
| 71 |
| 72 android_sdk_path = dm.FetchPath('android_sdk', platform) |
| 73 |
| 74 if os.path.exists(android_sdk_path): |
| 75 self._config['android_sdk_path'] = android_sdk_path |
| 76 |
| 77 # Chromium's hooks always download the SDK extras even if they aren't |
| 78 # downloading the SDK, so we have to check for the existence of the |
| 79 # particular components we care about. |
| 80 |
| 81 try: |
| 82 adb_path = dm.FetchPath('adb_path', platform) |
| 83 except dependency_manager.NoPathFoundError: |
| 84 adb_path = os.path.join( |
| 85 self.android_sdk_path, 'platform-tools', 'adb') |
| 86 if os.path.exists(adb_path): |
| 87 self._config['adb_path'] = adb_path |
| 88 |
| 89 build_tools_path = os.path.join(self.android_sdk_path, 'build-tools') |
| 90 if os.path.exists(build_tools_path): |
| 91 build_tools_contents = os.listdir(build_tools_path) |
| 92 if build_tools_contents: |
| 93 if len(build_tools_contents) > 1: |
| 94 build_tools_contents.sort() |
| 95 logging.warning( |
| 96 'More than one set of build-tools provided by the Android SDK:' |
| 97 ' %s', ','.join(build_tools_contents)) |
| 98 logging.warning('Defaulting to %s', build_tools_contents[-1]) |
| 99 self._config['android_sdk_build_tools_path'] = os.path.join( |
| 100 self.android_sdk_path, 'build-tools', build_tools_contents[-1]) |
| 101 |
| 102 try: |
| 103 self._config['forwarder_host_path'] = dm.FetchPath( |
| 104 'forwarder_host', platform) |
| 105 self._config['forwarder_device_path'] = dm.FetchPath( |
| 106 'forwarder_device', platform) |
| 107 except dependency_manager.NoPathFoundError: |
| 108 logging.info('Unable to locate forwarder binaries.') |
| 109 |
| 110 try: |
| 111 self._config['md5sum_host_path'] = dm.FetchPath('md5sum_host', platform) |
| 112 self._config['md5sum_device_path'] = dm.FetchPath( |
| 113 'md5sum_device', platform) |
| 114 except dependency_manager.NoPathFoundError: |
| 115 logging.info('Unable to locate md5sum binaries.') |
| 116 |
| 117 try: |
| 118 self._config['pymock_path'] = dm.FetchPath('pymock', platform) |
| 119 except dependency_manager.NoPathFoundError: |
| 120 logging.info('Unable to locate pymock.') |
| 121 |
| 122 def __getattr__(self, name): |
| 123 if self._config is None: |
| 124 self.Initialize() |
| 125 |
| 126 if name not in self._config: |
| 127 raise EnvironmentError('devil environment has no %r attribute' % name) |
| 128 |
| 129 return self._config[name] |
| 130 |
| 131 |
| 132 config = _Environment() |
| 133 |
| 134 |
| 135 def GenerateDynamicConfig(deps): |
| 136 """Generate a configuration dict from the provided deps dict. |
| 137 |
| 138 Args: |
| 139 deps: A dict mapping dependency names to lists of local files. |
| 140 Returns: |
| 141 A BaseConfig-compatible dict. |
| 142 """ |
| 143 return { |
| 144 'config_type': 'BaseConfig', |
| 145 'dependencies': { |
| 146 k: { |
| 147 'file_info': { |
| 148 'linux_android': { |
| 149 'local_paths': v |
| 150 } |
| 151 } |
| 152 } for k, v in deps.iteritems() |
| 153 } |
| 154 } |
| 155 |
OLD | NEW |