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
5class DependencyInfo(object):
6  def __init__(self, dependency, platform, config_path, local_path_info=None,
7               cloud_storage_info=None):
8    """ Container for the information needed for each dependency/platform pair
9    in the dependency_manager.
10
11    Args:
12        Required:
13          dependency: Name of the dependency.
14          platform: Name of the platform to be run on.
15          config_path: Path to the config_path this information came from. Used
16                       for error messages to improve debugging.
17
18        Optional:
19          local_path_info: A LocalPathInfo instance.
20          cloud_storage_info: An instance of CloudStorageInfo.
21    """
22    # TODO(aiolos): update the above doc string for A) the usage of zip files
23    # and B) supporting lists of local_paths to be checked for most recently
24    # changed files.
25    if not dependency or not platform:
26      raise ValueError(
27          'Must supply both a dependency and platform to DependencyInfo')
28
29    self._dependency = dependency
30    self._platform = platform
31    self._config_paths = [config_path]
32    self._local_path_info = local_path_info
33    self._cloud_storage_info = cloud_storage_info
34
35  def Update(self, new_dep_info):
36    """Add the information from |new_dep_info| to this instance.
37    """
38    self._config_paths.extend(new_dep_info.config_paths)
39    if (self.dependency != new_dep_info.dependency or
40        self.platform != new_dep_info.platform):
41      raise ValueError(
42          'Cannot update DependencyInfo with different dependency or platform.'
43          'Existing dep: %s, existing platform: %s. New dep: %s, new platform:'
44          '%s. Config_paths conflicting: %s' % (
45              self.dependency, self.platform, new_dep_info.dependency,
46              new_dep_info.platform, self.config_paths))
47    if new_dep_info.has_cloud_storage_info:
48      if self.has_cloud_storage_info:
49        raise ValueError(
50            'Overriding cloud storage data is not allowed when updating a '
51            'DependencyInfo. Conflict in dependency %s on platform %s in '
52            'config_paths: %s.' % (self.dependency, self.platform,
53                                   self.config_paths))
54      else:
55        self._cloud_storage_info = new_dep_info._cloud_storage_info
56    if not self._local_path_info:
57      self._local_path_info = new_dep_info._local_path_info
58    else:
59      self._local_path_info.Update(new_dep_info._local_path_info)
60
61  def GetRemotePath(self):
62    """Gets the path to a downloaded version of the dependency.
63
64    May not download the file if it has already been downloaded.
65    Will unzip the downloaded file if specified in the config
66    via unzipped_hash.
67
68    Returns: A path to an executable that was stored in cloud_storage, or None
69       if not found.
70
71    Raises:
72        CredentialsError: If cloud_storage credentials aren't configured.
73        PermissionError: If cloud_storage credentials are configured, but not
74            with an account that has permission to download the needed file.
75        NotFoundError: If the needed file does not exist where expected in
76            cloud_storage or the downloaded zip file.
77        ServerError: If an internal server error is hit while downloading the
78            needed file.
79        CloudStorageError: If another error occured while downloading the remote
80            path.
81        FileNotFoundError: If the download was otherwise unsuccessful.
82    """
83    if self.has_cloud_storage_info:
84      return self._cloud_storage_info.GetRemotePath()
85    return None
86
87  def GetRemotePathVersion(self):
88    if self.has_cloud_storage_info:
89      return self._cloud_storage_info.version_in_cs
90    return None
91
92  def GetLocalPath(self):
93    """Gets the path to a local version of the dependency.
94
95    Returns: A path to a local dependency, or None if not found.
96
97    """
98    if self.has_local_path_info:
99      return self._local_path_info.GetLocalPath()
100    return None
101
102  @property
103  def dependency(self):
104    return self._dependency
105
106  @property
107  def platform(self):
108    return self._platform
109
110  @property
111  def config_paths(self):
112    return self._config_paths
113
114  @property
115  def local_path_info(self):
116    return self._local_path_info
117
118  @property
119  def has_cloud_storage_info(self):
120    return bool(self._cloud_storage_info)
121
122  @property
123  def has_local_path_info(self):
124    return bool(self._local_path_info)
125
126  @property
127  def cloud_storage_info(self):
128    return self._cloud_storage_info
129