| 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 os | |
| 6 import sys | |
| 7 | |
| 8 sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname( | |
| 9 os.path.abspath(__file__))))) | |
| 10 from catapult_base.dependency_manager import base_config | |
| 11 from catapult_base.dependency_manager import exceptions | |
| 12 | |
| 13 | |
| 14 DEFAULT_TYPE = 'default' | |
| 15 | |
| 16 | |
| 17 class DependencyManager(object): | |
| 18 def __init__(self, configs, supported_config_types=None): | |
| 19 """Manages file dependencies found locally or in cloud_storage. | |
| 20 | |
| 21 Args: | |
| 22 configs: A list of instances of BaseConfig or it's subclasses, passed | |
| 23 in decreasing order of precedence. | |
| 24 supported_config_types: A list of whitelisted config_types. | |
| 25 No restrictions if None is specified. | |
| 26 | |
| 27 Raises: | |
| 28 ValueError: If |configs| is not a list of instances of BaseConfig or | |
| 29 its subclasses. | |
| 30 UnsupportedConfigFormatError: If supported_config_types is specified and | |
| 31 configs contains a config not in the supported config_types. | |
| 32 | |
| 33 Example: DependencyManager([config1, config2, config3]) | |
| 34 No requirements on the type of Config, and any dependencies that have | |
| 35 local files for the same platform will first look in those from | |
| 36 config1, then those from config2, and finally those from config3. | |
| 37 """ | |
| 38 if configs is None or type(configs) != list: | |
| 39 raise ValueError( | |
| 40 'Must supply a list of config files to DependencyManager') | |
| 41 # self._lookup_dict is a dictionary with the following format: | |
| 42 # { dependency1: {platform1: dependency_info1, | |
| 43 # platform2: dependency_info2} | |
| 44 # dependency2: {platform1: dependency_info3, | |
| 45 # ...} | |
| 46 # ...} | |
| 47 # | |
| 48 # Where the dependencies and platforms are strings, and the | |
| 49 # dependency_info's are DependencyInfo instances. | |
| 50 self._lookup_dict = {} | |
| 51 self.supported_configs = supported_config_types or [] | |
| 52 for config in configs: | |
| 53 self._UpdateDependencies(config) | |
| 54 | |
| 55 def FetchPath(self, dependency, platform): | |
| 56 """Get a path to an executable for |dependency|, downloading as needed. | |
| 57 | |
| 58 A path to a default executable may be returned if a platform specific | |
| 59 version is not specified in the config(s). | |
| 60 | |
| 61 Args: | |
| 62 dependency: Name of the desired dependency, as given in the config(s) | |
| 63 used in this DependencyManager. | |
| 64 platform: Name of the platform the dependency will run on. Often of the | |
| 65 form 'os_architecture'. Must match those specified in the config(s) | |
| 66 used in this DependencyManager. | |
| 67 Returns: | |
| 68 A path to an executable of |dependency| that will run on |platform|, | |
| 69 downloading from cloud storage if needed. | |
| 70 | |
| 71 Raises: | |
| 72 NoPathFoundError: If a local copy of the executable cannot be found and | |
| 73 a remote path could not be downloaded from cloud_storage. | |
| 74 CredentialsError: If cloud_storage credentials aren't configured. | |
| 75 PermissionError: If cloud_storage credentials are configured, but not | |
| 76 with an account that has permission to download the remote file. | |
| 77 NotFoundError: If the remote file does not exist where expected in | |
| 78 cloud_storage. | |
| 79 ServerError: If an internal server error is hit while downloading the | |
| 80 remote file. | |
| 81 CloudStorageError: If another error occured while downloading the remote | |
| 82 path. | |
| 83 FileNotFoundError: If an attempted download was otherwise unsuccessful. | |
| 84 | |
| 85 """ | |
| 86 dependency_info = self._GetDependencyInfo(dependency, platform) | |
| 87 if not dependency_info: | |
| 88 raise exceptions.NoPathFoundError(dependency, platform) | |
| 89 path = dependency_info.GetLocalPath() | |
| 90 if not path or not os.path.exists(path): | |
| 91 path = dependency_info.GetRemotePath() | |
| 92 if not path or not os.path.exists(path): | |
| 93 raise exceptions.NoPathFoundError(dependency, platform) | |
| 94 return path | |
| 95 | |
| 96 def LocalPath(self, dependency, platform): | |
| 97 """Get a path to a locally stored executable for |dependency|. | |
| 98 | |
| 99 A path to a default executable may be returned if a platform specific | |
| 100 version is not specified in the config(s). | |
| 101 Will not download the executable. | |
| 102 | |
| 103 Args: | |
| 104 dependency: Name of the desired dependency, as given in the config(s) | |
| 105 used in this DependencyManager. | |
| 106 platform: Name of the platform the dependency will run on. Often of the | |
| 107 form 'os_architecture'. Must match those specified in the config(s) | |
| 108 used in this DependencyManager. | |
| 109 Returns: | |
| 110 A path to an executable for |dependency| that will run on |platform|. | |
| 111 | |
| 112 Raises: | |
| 113 NoPathFoundError: If a local copy of the executable cannot be found. | |
| 114 """ | |
| 115 dependency_info = self._GetDependencyInfo(dependency, platform) | |
| 116 if not dependency_info: | |
| 117 raise exceptions.NoPathFoundError(dependency, platform) | |
| 118 local_path = dependency_info.GetLocalPath() | |
| 119 if not local_path or not os.path.exists(local_path): | |
| 120 raise exceptions.NoPathFoundError(dependency, platform) | |
| 121 return local_path | |
| 122 | |
| 123 def _UpdateDependencies(self, config): | |
| 124 """Add the dependency information stored in |config| to this instance. | |
| 125 | |
| 126 Args: | |
| 127 config: An instances of BaseConfig or a subclasses. | |
| 128 | |
| 129 Raises: | |
| 130 UnsupportedConfigFormatError: If supported_config_types was specified | |
| 131 and config is not in the supported config_types. | |
| 132 """ | |
| 133 if not isinstance(config, base_config.BaseConfig): | |
| 134 raise ValueError('Must use a BaseConfig or subclass instance with the ' | |
| 135 'DependencyManager.') | |
| 136 if (self.supported_configs and | |
| 137 config.GetConfigType() not in self.supported_configs): | |
| 138 raise exceptions.UnsupportedConfigFormatError(config.GetConfigType(), | |
| 139 config.config_path) | |
| 140 for dep_info in config.IterDependencyInfo(): | |
| 141 dependency = dep_info.dependency | |
| 142 platform = dep_info.platform | |
| 143 if dependency not in self._lookup_dict: | |
| 144 self._lookup_dict[dependency] = {} | |
| 145 if platform not in self._lookup_dict[dependency]: | |
| 146 self._lookup_dict[dependency][platform] = dep_info | |
| 147 else: | |
| 148 self._lookup_dict[dependency][platform].Update(dep_info) | |
| 149 | |
| 150 | |
| 151 def _GetDependencyInfo(self, dependency, platform): | |
| 152 """Get information for |dependency| on |platform|, or a default if needed. | |
| 153 | |
| 154 Args: | |
| 155 dependency: Name of the desired dependency, as given in the config(s) | |
| 156 used in this DependencyManager. | |
| 157 platform: Name of the platform the dependency will run on. Often of the | |
| 158 form 'os_architecture'. Must match those specified in the config(s) | |
| 159 used in this DependencyManager. | |
| 160 | |
| 161 Returns: The dependency_info for |dependency| on |platform| if it exists. | |
| 162 Or the default version of |dependency| if it exists, or None if neither | |
| 163 exist. | |
| 164 """ | |
| 165 if not self._lookup_dict or dependency not in self._lookup_dict: | |
| 166 return None | |
| 167 dependency_dict = self._lookup_dict[dependency] | |
| 168 device_type = platform | |
| 169 if not device_type in dependency_dict: | |
| 170 device_type = DEFAULT_TYPE | |
| 171 return dependency_dict.get(device_type) | |
| 172 | |
| OLD | NEW |