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 "cs_remote_path": "cs_path111",
27 "local_paths": ["local_path1110", "local_path1111"]
30 "cloud_storage_hash": "hash_for_platform2",
31 "download_path": "download_path2",
32 "cs_remote_path": "cs_path2",
33 "local_paths": ["local_path20", "local_path21"]
38 "dependency_name_2": {
45 Required feilds: "dependencies" and "config_type".
46 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 Also note that platform names are often of the form os_architechture.
58 More information on the fields can be found in dependencies_info.py
60 def __init__(self
, file_path
, writable
=False):
61 """ Initialize a BaseConfig for the DependencyManager.
64 writable: False: This config will be used to lookup information.
65 True: This config will be used to update information.
67 file_path: Path to a file containing a json dictionary in the expected
68 json format for this config class. Base format expected:
70 { "config_type": config_type,
71 "dependencies": dependencies_dict }
73 config_type: must match the return value of GetConfigType.
74 dependencies: A dictionary with the information needed to
75 create dependency_info instances for the given
78 See dependency_info.py for more information.
80 self
._config
_path
= file_path
81 self
._writable
= writable
83 raise ValueError('Must supply config file path.')
84 if not os
.path
.exists(file_path
):
86 raise exceptions
.EmptyConfigError(file_path
)
87 self
._config
_data
= {}
88 self
.CreateEmptyConfig(file_path
)
90 with
open(file_path
, 'r') as f
:
91 config_data
= json
.load(f
)
93 raise exceptions
.EmptyConfigError(file_path
)
94 config_type
= config_data
.pop('config_type', None)
95 if config_type
!= self
.GetConfigType():
97 'Supplied config_type (%s) is not the expected type (%s) in file '
98 '%s' % (config_type
, self
.GetConfigType(), file_path
))
99 self
._config
_data
= config_data
.get('dependencies', {})
101 def IterDependencyInfo(self
):
102 """ Yields a DependencyInfo for each dependency/platform pair.
105 ReadWriteError: If called when the config is writable.
106 ValueError: If any of the dependencies contain partial information for
107 downloading from cloud_storage. (See dependency_info.py)
110 raise exceptions
.ReadWriteError(
111 'Trying to read dependency info from a writable config. File for '
112 'config: %s' % self
._config
_path
)
113 for dep
in self
._config
_data
:
115 base_path
= os
.path
.dirname(self
._config
_path
)
116 dependency_dict
= self
._config
_data
.get(dep
, {})
117 platforms_dict
= dependency_dict
.get('file_info')
118 cs_bucket
= dependency_dict
.get('cloud_storage_bucket', None)
119 cs_base_folder
= dependency_dict
.get('cloud_storage_base_folder', '')
120 for platform
in platforms_dict
:
121 platform_info
= platforms_dict
.get(platform
)
122 local_paths
= platform_info
.get('local_paths', [])
125 for path
in local_paths
:
126 path
= self
._FormatPath
(path
)
127 paths
.append(os
.path
.abspath(os
.path
.join(base_path
, path
)))
130 download_path
= platform_info
.get('download_path', None)
132 download_path
= self
._FormatPath
(download_path
)
133 download_path
= os
.path
.abspath(
134 os
.path
.join(base_path
, download_path
))
136 cs_remote_path
= None
137 cs_hash
= platform_info
.get('cloud_storage_hash', None)
139 cs_remote_file
= '%s_%s' % (dep
, cs_hash
)
140 cs_remote_path
= cs_remote_file
if not cs_base_folder
else (
141 '%s/%s' % (cs_base_folder
, cs_remote_file
))
143 if download_path
or cs_remote_path
or cs_hash
:
144 dep_info
= dependency_info
.DependencyInfo(
145 dep
, platform
, self
._config
_path
, cs_bucket
=cs_bucket
,
146 cs_remote_path
=cs_remote_path
, download_path
=download_path
,
147 cs_hash
=cs_hash
, local_paths
=local_paths
)
149 dep_info
= dependency_info
.DependencyInfo(
150 dep
, platform
, self
._config
_path
, local_paths
=local_paths
)
154 def CreateEmptyConfig(cls
, file_path
):
155 """Create an empty BaseConfig json dict and write it out to |file_path|.
158 ValueError: If the path already exists.
160 if os
.path
.exists(file_path
):
161 raise ValueError('File already exists, and would be overwritten.')
162 json_dict
= {'config_type': cls
.GetConfigType(),
164 with
open(file_path
, 'w') as outfile
:
165 json
.dump(json_dict
, outfile
, indent
=2, sort_keys
=True)
169 def GetConfigType(cls
):
173 def config_path(self
):
174 return self
._config
_path
176 def UpdateCloudStorageDependency(
177 self
, dependency
, platform
, dependency_path
, version
=None):
178 """Update the cloud storage hash and the version for the given dependency.
180 # TODO(aiolos): Only allow the config to be updated if writable is True to
181 # avoid data changing underneath the dependency manager.
182 raise NotImplementedError
184 def GetVersion(self
, dependency
, platform
):
185 """Return the Version information for the given dependency."""
186 raise NotImplementedError
189 def _FormatPath(cls
, file_path
):
190 """Format |file_path| for the current file system.
192 We may be downloading files for another platform, so paths must be
193 downloadable on the current system.
197 if os
.path
.sep
!= '\\':
198 return file_path
.replace('\\', os
.path
.sep
)
199 elif os
.path
.sep
!= '/':
200 return file_path
.replace('/', os
.path
.sep
)