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