Chromium Code Reviews| 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 availability = AvailabilityInfo(channel, version) | |
| 225 self._object_store.Set(api_name, availability) | |
| 226 return availability | |
|
epeterson
2013/07/16 00:28:23
Previously if an API had an entry in api_availabil
not at google - send to devlin
2013/07/16 22:25:00
Umm yeah I remember something like this, since we
epeterson
2013/07/17 23:48:23
Done.
| |
| 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 |