OLD | NEW |
1 # Copyright 2013 The Chromium Authors. All rights reserved. | 1 # Copyright 2013 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 import collections | 5 import collections |
6 import os | 6 import os |
7 | 7 |
8 from branch_utility import BranchUtility | 8 from branch_utility import BranchUtility |
9 from compiled_file_system import CompiledFileSystem | 9 from compiled_file_system import CompiledFileSystem |
10 from file_system import FileNotFoundError | 10 from file_system import FileNotFoundError |
(...skipping 26 matching lines...) Expand all Loading... |
37 # The channel information dict is nested within a list for whitelisting | 37 # The channel information dict is nested within a list for whitelisting |
38 # purposes. | 38 # purposes. |
39 return feature.get('channel') | 39 return feature.get('channel') |
40 # Features can contain a list of entries. Take the newest branch. | 40 # Features can contain a list of entries. Take the newest branch. |
41 return BranchUtility.NewestChannel(entry.get('channel') | 41 return BranchUtility.NewestChannel(entry.get('channel') |
42 for entry in feature) | 42 for entry in feature) |
43 | 43 |
44 def _GetChannelFromApiFeatures(api_name, file_system): | 44 def _GetChannelFromApiFeatures(api_name, file_system): |
45 try: | 45 try: |
46 return _GetChannelFromFeatures(api_name, file_system, _API_FEATURES) | 46 return _GetChannelFromFeatures(api_name, file_system, _API_FEATURES) |
47 except FileNotFoundError as e: | 47 except FileNotFoundError: |
48 # TODO(epeterson) Remove except block once _api_features is in all channels. | 48 # TODO(epeterson) Remove except block once _api_features is in all channels. |
49 return None | 49 return None |
50 | 50 |
51 def _GetChannelFromPermissionFeatures(api_name, file_system): | 51 def _GetChannelFromPermissionFeatures(api_name, file_system): |
52 return _GetChannelFromFeatures(api_name, file_system, _PERMISSION_FEATURES) | 52 return _GetChannelFromFeatures(api_name, file_system, _PERMISSION_FEATURES) |
53 | 53 |
54 def _GetChannelFromManifestFeatures(api_name, file_system): | 54 def _GetChannelFromManifestFeatures(api_name, file_system): |
55 return _GetChannelFromFeatures(#_manifest_features uses unix_style API names | 55 return _GetChannelFromFeatures(#_manifest_features uses unix_style API names |
56 model.UnixName(api_name), | 56 model.UnixName(api_name), |
57 file_system, | 57 file_system, |
(...skipping 10 matching lines...) Expand all Loading... |
68 def _ExistsInExtensionApi(api_name, file_system): | 68 def _ExistsInExtensionApi(api_name, file_system): |
69 '''Parses the api/extension_api.json file (available in Chrome versions | 69 '''Parses the api/extension_api.json file (available in Chrome versions |
70 before 18) for an API namespace. If this is successfully found, then the API | 70 before 18) for an API namespace. If this is successfully found, then the API |
71 is considered to have been 'stable' for the given version. | 71 is considered to have been 'stable' for the given version. |
72 ''' | 72 ''' |
73 try: | 73 try: |
74 extension_api_json = file_system.GetFromFile(_EXTENSION_API) | 74 extension_api_json = file_system.GetFromFile(_EXTENSION_API) |
75 api_rows = [row.get('namespace') for row in extension_api_json | 75 api_rows = [row.get('namespace') for row in extension_api_json |
76 if 'namespace' in row] | 76 if 'namespace' in row] |
77 return True if api_name in api_rows else False | 77 return True if api_name in api_rows else False |
78 except FileNotFoundError as e: | 78 except FileNotFoundError: |
79 # This should only happen on preview.py since extension_api.json is no | 79 # This should only happen on preview.py since extension_api.json is no |
80 # longer present in trunk. | 80 # longer present in trunk. |
81 return False | 81 return False |
82 | 82 |
83 class AvailabilityFinder(object): | 83 class AvailabilityFinder(object): |
84 '''Uses API data sources generated by a ChromeVersionDataSource in order to | 84 '''Uses API data sources generated by a ChromeVersionDataSource in order to |
85 search the filesystem for the earliest existence of a specified API throughout | 85 search the filesystem for the earliest existence of a specified API throughout |
86 the different versions of Chrome; this constitutes an API's availability. | 86 the different versions of Chrome; this constitutes an API's availability. |
87 ''' | 87 ''' |
88 class Factory(object): | 88 class Factory(object): |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
145 on the stable channel. When a version is found where the API is no longer | 145 on the stable channel. When a version is found where the API is no longer |
146 available on stable, returns the previous version number (the last known | 146 available on stable, returns the previous version number (the last known |
147 version where the API was stable). | 147 version where the API was stable). |
148 ''' | 148 ''' |
149 available = True | 149 available = True |
150 while available: | 150 while available: |
151 if version < 5: | 151 if version < 5: |
152 # SVN data isn't available below version 5. | 152 # SVN data isn't available below version 5. |
153 return version + 1 | 153 return version + 1 |
154 available = False | 154 available = False |
| 155 available_channel = None |
155 features_fs, names_fs = self._CreateFeaturesAndNamesFileSystems(version) | 156 features_fs, names_fs = self._CreateFeaturesAndNamesFileSystems(version) |
156 if version >= 28: | 157 if version >= 28: |
157 # The _api_features.json file first appears in version 28 and should be | 158 # The _api_features.json file first appears in version 28 and should be |
158 # the most reliable for finding API availabilities, so it gets checked | 159 # the most reliable for finding API availabilities, so it gets checked |
159 # first. The _permission_features.json and _manifest_features.json files | 160 # first. The _permission_features.json and _manifest_features.json files |
160 # are present in Chrome 20 and onwards. Fall back to a check for file | 161 # are present in Chrome 20 and onwards. Fall back to a check for file |
161 # system existence if the API is not stable in any of the _features.json | 162 # system existence if the API is not stable in any of the _features.json |
162 # files. | 163 # files. |
163 available = _GetChannelFromApiFeatures(api_name, features_fs) == _STABLE | 164 available_channel = _GetChannelFromApiFeatures(api_name, features_fs) |
164 if version >= 20: | 165 if version >= 20: |
165 # Check other _features.json files/file existence if the API wasn't | 166 # Check other _features.json files/file existence if the API wasn't |
166 # found in _api_features.json, or if _api_features.json wasn't present. | 167 # found in _api_features.json, or if _api_features.json wasn't present. |
167 available = available or ( | 168 available_channel = available_channel or ( |
168 _GetChannelFromPermissionFeatures(api_name, features_fs) == _STABLE | 169 _GetChannelFromPermissionFeatures(api_name, features_fs) |
169 or _GetChannelFromManifestFeatures(api_name, features_fs) == _STABLE | 170 or _GetChannelFromManifestFeatures(api_name, features_fs)) |
170 or _ExistsInFileSystem(api_name, names_fs)) | 171 if available_channel is None: |
| 172 available = _ExistsInFileSystem(api_name, names_fs) |
| 173 else: |
| 174 available = available_channel == _STABLE |
171 elif version >= 18: | 175 elif version >= 18: |
172 # These versions are a little troublesome. Version 19 has | 176 # These versions are a little troublesome. Version 19 has |
173 # _permission_features.json, but it lacks 'channel' information. | 177 # _permission_features.json, but it lacks 'channel' information. |
174 # Version 18 lacks all of the _features.json files. For now, we're using | 178 # Version 18 lacks all of the _features.json files. For now, we're using |
175 # a simple check for filesystem existence here. | 179 # a simple check for filesystem existence here. |
176 available = _ExistsInFileSystem(api_name, names_fs) | 180 available = _ExistsInFileSystem(api_name, names_fs) |
177 elif version >= 5: | 181 elif version >= 5: |
178 # Versions 17 and down to 5 have an extension_api.json file which | 182 # Versions 17 and down to 5 have an extension_api.json file which |
179 # contains namespaces for each API that was available at the time. We | 183 # contains namespaces for each API that was available at the time. We |
180 # can use this file to check for API existence. | 184 # can use this file to check for API existence. |
181 available = _ExistsInExtensionApi(api_name, features_fs) | 185 available = _ExistsInExtensionApi(api_name, features_fs) |
182 | 186 |
183 if not available: | 187 if not available: |
184 return version + 1 | 188 return version + 1 |
185 version -= 1 | 189 version -= 1 |
186 | 190 |
187 def _GetAvailableChannelForVersion(self, api_name, version): | 191 def _GetAvailableChannelForVersion(self, api_name, version): |
188 '''Searches through the _features files for a given |version| and returns | 192 '''Searches through the _features files for a given |version| and returns |
189 the channel that the given API is determined to be available on. | 193 the channel that the given API is determined to be available on. |
190 ''' | 194 ''' |
191 features_fs, names_fs = self._CreateFeaturesAndNamesFileSystems(version) | 195 features_fs, names_fs = self._CreateFeaturesAndNamesFileSystems(version) |
192 channel = (_GetChannelFromApiFeatures(api_name, features_fs) | 196 available_channel = (_GetChannelFromApiFeatures(api_name, features_fs) |
193 or _GetChannelFromPermissionFeatures(api_name, features_fs) | 197 or _GetChannelFromPermissionFeatures(api_name, features_fs) |
194 or _GetChannelFromManifestFeatures(api_name, features_fs)) | 198 or _GetChannelFromManifestFeatures(api_name, features_fs)) |
195 if channel is None and _ExistsInFileSystem(api_name, names_fs): | 199 if available_channel is None and _ExistsInFileSystem(api_name, names_fs): |
196 # If an API is not represented in any of the _features files, but exists | 200 # If an API is not represented in any of the _features files, but exists |
197 # in the filesystem, then assume it is available in this version. | 201 # in the filesystem, then assume it is available in this version. |
198 # The windows API is an example of this. | 202 # The windows API is an example of this. |
199 return self._branch_utility.GetChannelForVersion(version) | 203 return self._branch_utility.GetChannelForVersion(version) |
200 | 204 |
201 return channel | 205 return available_channel |
202 | 206 |
203 def GetApiAvailability(self, api_name): | 207 def GetApiAvailability(self, api_name): |
204 '''Determines the availability for an API by testing several scenarios. | 208 '''Determines the availability for an API by testing several scenarios. |
205 (i.e. Is the API experimental? Only available on certain development | 209 (i.e. Is the API experimental? Only available on certain development |
206 channels? If it's stable, when did it first become stable? etc.) | 210 channels? If it's stable, when did it first become stable? etc.) |
207 ''' | 211 ''' |
208 availability = self._object_store.Get(api_name).Get() | 212 availability = self._object_store.Get(api_name).Get() |
209 if availability is not None: | 213 if availability is not None: |
210 return availability | 214 return availability |
211 | 215 |
212 # Check for a predetermined availability for this API. | 216 # Check for a predetermined availability for this API. |
213 api_info = self._json_cache.GetFromFile(_API_AVAILABILITIES).get(api_name) | 217 api_info = self._json_cache.GetFromFile(_API_AVAILABILITIES).get(api_name) |
214 if api_info is not None: | 218 if api_info is not None: |
215 channel = api_info.get('channel') | 219 channel = api_info.get('channel') |
216 return AvailabilityInfo( | 220 if channel == _STABLE: |
217 channel, | 221 version = api_info.get('version') |
218 api_info.get('version') if channel == _STABLE else None) | 222 else: |
| 223 version = self._branch_utility.GetChannelInfo(channel).version |
| 224 # The file data for predetermined availabilities is already cached, so |
| 225 # skip caching this result. |
| 226 return AvailabilityInfo(channel, version) |
219 | 227 |
220 # Check for the API in the development channels. | 228 # Check for the API in the development channels. |
221 availability = None | 229 availability = None |
222 for channel_info in self._branch_utility.GetAllChannelInfo(): | 230 for channel_info in self._branch_utility.GetAllChannelInfo(): |
223 available_channel = self._GetAvailableChannelForVersion( | 231 available_channel = self._GetAvailableChannelForVersion( |
224 api_name, | 232 api_name, |
225 channel_info.version) | 233 channel_info.version) |
226 # If the |available_channel| for the API is the same as, or older than, | 234 # If the |available_channel| for the API is the same as, or older than, |
227 # the channel we're checking, then the API is available on this channel. | 235 # the channel we're checking, then the API is available on this channel. |
228 if (available_channel is not None and | 236 if (available_channel is not None and |
229 BranchUtility.NewestChannel((available_channel, channel_info.channel)) | 237 BranchUtility.NewestChannel((available_channel, channel_info.channel)) |
230 == channel_info.channel): | 238 == channel_info.channel): |
231 availability = AvailabilityInfo(channel_info.channel, | 239 availability = AvailabilityInfo(channel_info.channel, |
232 channel_info.version) | 240 channel_info.version) |
233 break | 241 break |
234 | 242 |
235 # The API should at least be available on trunk. It's a bug otherwise. | 243 # The API should at least be available on trunk. It's a bug otherwise. |
236 assert availability, 'No availability found for %s' % api_name | 244 assert availability, 'No availability found for %s' % api_name |
237 | 245 |
238 # If the API is in stable, find the chrome version in which it became | 246 # If the API is in stable, find the chrome version in which it became |
239 # stable. | 247 # stable. |
240 if availability.channel == _STABLE: | 248 if availability.channel == _STABLE: |
241 availability.version = self._FindEarliestStableAvailability( | 249 availability.version = self._FindEarliestStableAvailability( |
242 api_name, | 250 api_name, |
243 availability.version) | 251 availability.version) |
244 | 252 |
245 self._object_store.Set(api_name, availability) | 253 self._object_store.Set(api_name, availability) |
246 return availability | 254 return availability |
OLD | NEW |