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.
8 from catapult_base
.dependency_manager
import dependency_info
9 from catapult_base
.dependency_manager
import exceptions
12 class BaseConfig(object):
13 """A basic config class for use with the DependencyManager.
15 Initiated with a json file in the following format:
17 { "config_type": "BaseConfig",
20 "cloud_storage_base_folder": "base_folder1",
21 "cloud_storage_bucket": "bucket1",
24 "cloud_storage_hash": "hash_for_platform1",
25 "download_path": "download_path111",
26 "version_in_cs": "1.11.1.11."
27 "local_paths": ["local_path1110", "local_path1111"]
30 "cloud_storage_hash": "hash_for_platform2",
31 "download_path": "download_path2",
32 "local_paths": ["local_path20", "local_path21"]
37 "dependency_name_2": {
44 Required fields: "dependencies" and "config_type".
45 Note that config_type must be "BaseConfig"
48 "cloud_storage_base_folder" is a top level folder in the given
49 "cloud_storage_bucket" where all of the dependency files are stored
50 at "dependency_name"_"cloud_storage_hash".
52 "download_path" and all paths in "local_paths" are relative to the
53 config file's location.
55 All or none of the following cloud storage related fields must be
56 included in each platform dictionary:
57 "cloud_storage_hash", "download_path", "cs_remote_path"
59 "version_in_cs" is an optional cloud storage field, but is dependent
60 on the above cloud storage related fields.
63 Also note that platform names are often of the form os_architechture.
66 More information on the fields can be found in dependencies_info.py
68 def __init__(self
, file_path
, writable
=False):
69 """ Initialize a BaseConfig for the DependencyManager.
72 writable: False: This config will be used to lookup information.
73 True: This config will be used to update information.
75 file_path: Path to a file containing a json dictionary in the expected
76 json format for this config class. Base format expected:
78 { "config_type": config_type,
79 "dependencies": dependencies_dict }
81 config_type: must match the return value of GetConfigType.
82 dependencies: A dictionary with the information needed to
83 create dependency_info instances for the given
86 See dependency_info.py for more information.
88 self
._config
_path
= file_path
89 self
._writable
= writable
91 raise ValueError('Must supply config file path.')
92 if not os
.path
.exists(file_path
):
94 raise exceptions
.EmptyConfigError(file_path
)
95 self
._config
_data
= {}
96 self
.CreateEmptyConfig(file_path
)
98 with
open(file_path
, 'r') as f
:
99 config_data
= json
.load(f
)
101 raise exceptions
.EmptyConfigError(file_path
)
102 config_type
= config_data
.pop('config_type', None)
103 if config_type
!= self
.GetConfigType():
105 'Supplied config_type (%s) is not the expected type (%s) in file '
106 '%s' % (config_type
, self
.GetConfigType(), file_path
))
107 self
._config
_data
= config_data
.get('dependencies', {})
109 def IterDependencyInfo(self
):
110 """ Yields a DependencyInfo for each dependency/platform pair.
113 ReadWriteError: If called when the config is writable.
114 ValueError: If any of the dependencies contain partial information for
115 downloading from cloud_storage. (See dependency_info.py)
118 raise exceptions
.ReadWriteError(
119 'Trying to read dependency info from a writable config. File for '
120 'config: %s' % self
._config
_path
)
121 for dep
in self
._config
_data
:
123 base_path
= os
.path
.dirname(self
._config
_path
)
124 dependency_dict
= self
._config
_data
.get(dep
, {})
125 platforms_dict
= dependency_dict
.get('file_info')
126 cs_bucket
= dependency_dict
.get('cloud_storage_bucket', None)
127 cs_base_folder
= dependency_dict
.get('cloud_storage_base_folder', '')
128 for platform
in platforms_dict
:
129 platform_info
= platforms_dict
.get(platform
)
130 local_paths
= platform_info
.get('local_paths', [])
133 for path
in local_paths
:
134 path
= self
._FormatPath
(path
)
135 paths
.append(os
.path
.abspath(os
.path
.join(base_path
, path
)))
138 download_path
= platform_info
.get('download_path', None)
140 download_path
= self
._FormatPath
(download_path
)
141 download_path
= os
.path
.abspath(
142 os
.path
.join(base_path
, download_path
))
144 cs_remote_path
= None
145 cs_hash
= platform_info
.get('cloud_storage_hash', None)
147 cs_remote_file
= '%s_%s' % (dep
, cs_hash
)
148 cs_remote_path
= cs_remote_file
if not cs_base_folder
else (
149 '%s/%s' % (cs_base_folder
, cs_remote_file
))
151 version_in_cs
= platform_info
.get('version_in_cs', None)
153 if download_path
or cs_remote_path
or cs_hash
or version_in_cs
:
154 dep_info
= dependency_info
.DependencyInfo(
155 dep
, platform
, self
._config
_path
, cs_bucket
=cs_bucket
,
156 cs_remote_path
=cs_remote_path
, download_path
=download_path
,
157 cs_hash
=cs_hash
, version_in_cs
=version_in_cs
,
158 local_paths
=local_paths
)
160 dep_info
= dependency_info
.DependencyInfo(
161 dep
, platform
, self
._config
_path
, local_paths
=local_paths
)
165 def CreateEmptyConfig(cls
, file_path
):
166 """Create an empty BaseConfig json dict and write it out to |file_path|.
169 ValueError: If the path already exists.
171 if os
.path
.exists(file_path
):
172 raise ValueError('File already exists, and would be overwritten.')
173 json_dict
= {'config_type': cls
.GetConfigType(),
175 with
open(file_path
, 'w') as outfile
:
176 json
.dump(json_dict
, outfile
, indent
=2, sort_keys
=True)
180 def GetConfigType(cls
):
184 def config_path(self
):
185 return self
._config
_path
187 def UpdateCloudStorageDependency(
188 self
, dependency
, platform
, dependency_path
, version
=None):
189 """Update the cloud storage hash and the version for the given dependency.
191 # TODO(aiolos): Only allow the config to be updated if writable is True to
192 # avoid data changing underneath the dependency manager.
193 raise NotImplementedError
195 def GetVersion(self
, dependency
, platform
):
196 """Return the Version information for the given dependency."""
197 if not self
._config
_data
(dependency
):
198 raise ValueError('Dependency %s is not in config.' % dependency
)
199 if not self
.config_data
[dependency
].get(platform
):
200 raise ValueError('Dependency %s has no information for platform %s in '
201 'this config.' % (dependency
, platform
))
202 return self
._config
_data
[dependency
][platform
].get('version_in_cs')
205 def _FormatPath(cls
, file_path
):
206 """Format |file_path| for the current file system.
208 We may be downloading files for another platform, so paths must be
209 downloadable on the current system.
213 if os
.path
.sep
!= '\\':
214 return file_path
.replace('\\', os
.path
.sep
)
215 elif os
.path
.sep
!= '/':
216 return file_path
.replace('/', os
.path
.sep
)