Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(63)

Side by Side Diff: chrome/common/extensions/docs/server2/availability_finder.py

Issue 337373004: Docserver: Replace instances of 'Api' with 'API' (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 from collections import Mapping 5 from collections import Mapping
6 import posixpath 6 import posixpath
7 7
8 from api_schema_graph import APISchemaGraph 8 from api_schema_graph import APISchemaGraph
9 from branch_utility import BranchUtility, ChannelInfo 9 from branch_utility import BranchUtility, ChannelInfo
10 from extensions_paths import API_PATHS, JSON_TEMPLATES 10 from extensions_paths import API_PATHS, JSON_TEMPLATES
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
89 api_info = self._json_fs.GetFromFile( 89 api_info = self._json_fs.GetFromFile(
90 JSON_TEMPLATES + 'api_availabilities.json').Get().get(api_name) 90 JSON_TEMPLATES + 'api_availabilities.json').Get().get(api_name)
91 if api_info is None: 91 if api_info is None:
92 return None 92 return None
93 if api_info['channel'] == 'stable': 93 if api_info['channel'] == 'stable':
94 return AvailabilityInfo( 94 return AvailabilityInfo(
95 self._branch_utility.GetStableChannelInfo(api_info['version'])) 95 self._branch_utility.GetStableChannelInfo(api_info['version']))
96 return AvailabilityInfo( 96 return AvailabilityInfo(
97 self._branch_utility.GetChannelInfo(api_info['channel'])) 97 self._branch_utility.GetChannelInfo(api_info['channel']))
98 98
99 def _GetApiSchemaFilename(self, api_name, file_system, version): 99 def _GetAPISchemaFilename(self, api_name, file_system, version):
100 '''Gets the name of the file which may contain the schema for |api_name| in 100 '''Gets the name of the file which may contain the schema for |api_name| in
101 |file_system|, or None if the API is not found. Note that this may be the 101 |file_system|, or None if the API is not found. Note that this may be the
102 single _EXTENSION_API file which all APIs share in older versions of Chrome, 102 single _EXTENSION_API file which all APIs share in older versions of Chrome,
103 in which case it is unknown whether the API actually exists there. 103 in which case it is unknown whether the API actually exists there.
104 ''' 104 '''
105 if version == 'trunk' or version > _ORIGINAL_FEATURES_MIN_VERSION: 105 if version == 'trunk' or version > _ORIGINAL_FEATURES_MIN_VERSION:
106 # API schema filenames switch format to unix_hacker_style. 106 # API schema filenames switch format to unix_hacker_style.
107 api_name = UnixName(api_name) 107 api_name = UnixName(api_name)
108 108
109 found_files = file_system.Read(API_PATHS, skip_not_found=True) 109 found_files = file_system.Read(API_PATHS, skip_not_found=True)
110 for path, filenames in found_files.Get().iteritems(): 110 for path, filenames in found_files.Get().iteritems():
111 try: 111 try:
112 for ext in ('json', 'idl'): 112 for ext in ('json', 'idl'):
113 filename = '%s.%s' % (api_name, ext) 113 filename = '%s.%s' % (api_name, ext)
114 if filename in filenames: 114 if filename in filenames:
115 return path + filename 115 return path + filename
116 if _EXTENSION_API in filenames: 116 if _EXTENSION_API in filenames:
117 return path + _EXTENSION_API 117 return path + _EXTENSION_API
118 except FileNotFoundError: 118 except FileNotFoundError:
119 pass 119 pass
120 return None 120 return None
121 121
122 def _GetApiSchema(self, api_name, file_system, version): 122 def _GetAPISchema(self, api_name, file_system, version):
123 '''Searches |file_system| for |api_name|'s API schema data, and processes 123 '''Searches |file_system| for |api_name|'s API schema data, and processes
124 and returns it if found. 124 and returns it if found.
125 ''' 125 '''
126 api_filename = self._GetApiSchemaFilename(api_name, file_system, version) 126 api_filename = self._GetAPISchemaFilename(api_name, file_system, version)
127 if api_filename is None: 127 if api_filename is None:
128 # No file for the API could be found in the given |file_system|. 128 # No file for the API could be found in the given |file_system|.
129 return None 129 return None
130 130
131 schema_fs = self._compiled_fs_factory.ForApiSchema(file_system) 131 schema_fs = self._compiled_fs_factory.ForAPISchema(file_system)
132 api_schemas = schema_fs.GetFromFile(api_filename).Get() 132 api_schemas = schema_fs.GetFromFile(api_filename).Get()
133 matching_schemas = [api for api in api_schemas 133 matching_schemas = [api for api in api_schemas
134 if api['namespace'] == api_name] 134 if api['namespace'] == api_name]
135 # There should only be a single matching schema per file, or zero in the 135 # There should only be a single matching schema per file, or zero in the
136 # case of no API data being found in _EXTENSION_API. 136 # case of no API data being found in _EXTENSION_API.
137 assert len(matching_schemas) <= 1 137 assert len(matching_schemas) <= 1
138 return matching_schemas or None 138 return matching_schemas or None
139 139
140 def _HasApiSchema(self, api_name, file_system, version): 140 def _HasAPISchema(self, api_name, file_system, version):
141 '''Whether or not an API schema for |api_name|exists in the given 141 '''Whether or not an API schema for |api_name|exists in the given
142 |file_system|. 142 |file_system|.
143 ''' 143 '''
144 filename = self._GetApiSchemaFilename(api_name, file_system, version) 144 filename = self._GetAPISchemaFilename(api_name, file_system, version)
145 if filename is None: 145 if filename is None:
146 return False 146 return False
147 if filename.endswith(_EXTENSION_API): 147 if filename.endswith(_EXTENSION_API):
148 return self._GetApiSchema(api_name, file_system, version) is not None 148 return self._GetAPISchema(api_name, file_system, version) is not None
149 return True 149 return True
150 150
151 def _CheckStableAvailability(self, api_name, file_system, version): 151 def _CheckStableAvailability(self, api_name, file_system, version):
152 '''Checks for availability of an API, |api_name|, on the stable channel. 152 '''Checks for availability of an API, |api_name|, on the stable channel.
153 Considers several _features.json files, file system existence, and 153 Considers several _features.json files, file system existence, and
154 extension_api.json depending on the given |version|. 154 extension_api.json depending on the given |version|.
155 ''' 155 '''
156 if version < _SVN_MIN_VERSION: 156 if version < _SVN_MIN_VERSION:
157 # SVN data isn't available below this version. 157 # SVN data isn't available below this version.
158 return False 158 return False
159 features_bundle = self._CreateFeaturesBundle(file_system) 159 features_bundle = self._CreateFeaturesBundle(file_system)
160 available_channel = None 160 available_channel = None
161 if version >= _API_FEATURES_MIN_VERSION: 161 if version >= _API_FEATURES_MIN_VERSION:
162 # The _api_features.json file first appears in version 28 and should be 162 # The _api_features.json file first appears in version 28 and should be
163 # the most reliable for finding API availability. 163 # the most reliable for finding API availability.
164 available_channel = self._GetChannelFromApiFeatures(api_name, 164 available_channel = self._GetChannelFromAPIFeatures(api_name,
165 features_bundle) 165 features_bundle)
166 if version >= _ORIGINAL_FEATURES_MIN_VERSION: 166 if version >= _ORIGINAL_FEATURES_MIN_VERSION:
167 # The _permission_features.json and _manifest_features.json files are 167 # The _permission_features.json and _manifest_features.json files are
168 # present in Chrome 20 and onwards. Use these if no information could be 168 # present in Chrome 20 and onwards. Use these if no information could be
169 # found using _api_features.json. 169 # found using _api_features.json.
170 available_channel = ( 170 available_channel = (
171 available_channel or 171 available_channel or
172 self._GetChannelFromPermissionFeatures(api_name, features_bundle) or 172 self._GetChannelFromPermissionFeatures(api_name, features_bundle) or
173 self._GetChannelFromManifestFeatures(api_name, features_bundle)) 173 self._GetChannelFromManifestFeatures(api_name, features_bundle))
174 if available_channel is not None: 174 if available_channel is not None:
175 return available_channel == 'stable' 175 return available_channel == 'stable'
176 if version >= _SVN_MIN_VERSION: 176 if version >= _SVN_MIN_VERSION:
177 # Fall back to a check for file system existence if the API is not 177 # Fall back to a check for file system existence if the API is not
178 # stable in any of the _features.json files, or if the _features files 178 # stable in any of the _features.json files, or if the _features files
179 # do not exist (version 19 and earlier). 179 # do not exist (version 19 and earlier).
180 return self._HasApiSchema(api_name, file_system, version) 180 return self._HasAPISchema(api_name, file_system, version)
181 181
182 def _CheckChannelAvailability(self, api_name, file_system, channel_info): 182 def _CheckChannelAvailability(self, api_name, file_system, channel_info):
183 '''Searches through the _features files in a given |file_system|, falling 183 '''Searches through the _features files in a given |file_system|, falling
184 back to checking the file system for API schema existence, to determine 184 back to checking the file system for API schema existence, to determine
185 whether or not an API is available on the given channel, |channel_info|. 185 whether or not an API is available on the given channel, |channel_info|.
186 ''' 186 '''
187 features_bundle = self._CreateFeaturesBundle(file_system) 187 features_bundle = self._CreateFeaturesBundle(file_system)
188 available_channel = ( 188 available_channel = (
189 self._GetChannelFromApiFeatures(api_name, features_bundle) or 189 self._GetChannelFromAPIFeatures(api_name, features_bundle) or
190 self._GetChannelFromPermissionFeatures(api_name, features_bundle) or 190 self._GetChannelFromPermissionFeatures(api_name, features_bundle) or
191 self._GetChannelFromManifestFeatures(api_name, features_bundle)) 191 self._GetChannelFromManifestFeatures(api_name, features_bundle))
192 if (available_channel is None and 192 if (available_channel is None and
193 self._HasApiSchema(api_name, file_system, channel_info.version)): 193 self._HasAPISchema(api_name, file_system, channel_info.version)):
194 # If an API is not represented in any of the _features files, but exists 194 # If an API is not represented in any of the _features files, but exists
195 # in the filesystem, then assume it is available in this version. 195 # in the filesystem, then assume it is available in this version.
196 # The chrome.windows API is an example of this. 196 # The chrome.windows API is an example of this.
197 available_channel = channel_info.channel 197 available_channel = channel_info.channel
198 # If the channel we're checking is the same as or newer than the 198 # If the channel we're checking is the same as or newer than the
199 # |available_channel| then the API is available at this channel. 199 # |available_channel| then the API is available at this channel.
200 newest = BranchUtility.NewestChannel((available_channel, 200 newest = BranchUtility.NewestChannel((available_channel,
201 channel_info.channel)) 201 channel_info.channel))
202 return available_channel is not None and newest == channel_info.channel 202 return available_channel is not None and newest == channel_info.channel
203 203
204 @memoize 204 @memoize
205 def _CreateFeaturesBundle(self, file_system): 205 def _CreateFeaturesBundle(self, file_system):
206 return FeaturesBundle(file_system, 206 return FeaturesBundle(file_system,
207 self._compiled_fs_factory, 207 self._compiled_fs_factory,
208 self._object_store_creator) 208 self._object_store_creator)
209 209
210 def _GetChannelFromApiFeatures(self, api_name, features_bundle): 210 def _GetChannelFromAPIFeatures(self, api_name, features_bundle):
211 return _GetChannelFromFeatures(api_name, features_bundle.GetAPIFeatures()) 211 return _GetChannelFromFeatures(api_name, features_bundle.GetAPIFeatures())
212 212
213 def _GetChannelFromManifestFeatures(self, api_name, features_bundle): 213 def _GetChannelFromManifestFeatures(self, api_name, features_bundle):
214 # _manifest_features.json uses unix_style API names. 214 # _manifest_features.json uses unix_style API names.
215 api_name = UnixName(api_name) 215 api_name = UnixName(api_name)
216 return _GetChannelFromFeatures(api_name, 216 return _GetChannelFromFeatures(api_name,
217 features_bundle.GetManifestFeatures()) 217 features_bundle.GetManifestFeatures())
218 218
219 def _GetChannelFromPermissionFeatures(self, api_name, features_bundle): 219 def _GetChannelFromPermissionFeatures(self, api_name, features_bundle):
220 return _GetChannelFromFeatures(api_name, 220 return _GetChannelFromFeatures(api_name,
221 features_bundle.GetPermissionFeatures()) 221 features_bundle.GetPermissionFeatures())
222 222
223 def _CheckApiAvailability(self, api_name, file_system, channel_info): 223 def _CheckAPIAvailability(self, api_name, file_system, channel_info):
224 '''Determines the availability for an API at a certain version of Chrome. 224 '''Determines the availability for an API at a certain version of Chrome.
225 Two branches of logic are used depending on whether or not the API is 225 Two branches of logic are used depending on whether or not the API is
226 determined to be 'stable' at the given version. 226 determined to be 'stable' at the given version.
227 ''' 227 '''
228 if channel_info.channel == 'stable': 228 if channel_info.channel == 'stable':
229 return self._CheckStableAvailability(api_name, 229 return self._CheckStableAvailability(api_name,
230 file_system, 230 file_system,
231 channel_info.version) 231 channel_info.version)
232 return self._CheckChannelAvailability(api_name, 232 return self._CheckChannelAvailability(api_name,
233 file_system, 233 file_system,
234 channel_info) 234 channel_info)
235 235
236 def _FindScheduled(self, api_name): 236 def _FindScheduled(self, api_name):
237 '''Determines the earliest version of Chrome where the API is stable. 237 '''Determines the earliest version of Chrome where the API is stable.
238 Unlike the code in GetApiAvailability, this checks if the API is stable 238 Unlike the code in GetAPIAvailability, this checks if the API is stable
239 even when Chrome is in dev or beta, which shows that the API is scheduled 239 even when Chrome is in dev or beta, which shows that the API is scheduled
240 to be stable in that verison of Chrome. 240 to be stable in that verison of Chrome.
241 ''' 241 '''
242 def check_scheduled(file_system, channel_info): 242 def check_scheduled(file_system, channel_info):
243 return self._CheckStableAvailability( 243 return self._CheckStableAvailability(
244 api_name, file_system, channel_info.version) 244 api_name, file_system, channel_info.version)
245 245
246 stable_channel = self._file_system_iterator.Descending( 246 stable_channel = self._file_system_iterator.Descending(
247 self._branch_utility.GetChannelInfo('dev'), check_scheduled) 247 self._branch_utility.GetChannelInfo('dev'), check_scheduled)
248 248
249 return stable_channel.version if stable_channel else None 249 return stable_channel.version if stable_channel else None
250 250
251 def GetApiAvailability(self, api_name): 251 def GetAPIAvailability(self, api_name):
252 '''Performs a search for an API's top-level availability by using a 252 '''Performs a search for an API's top-level availability by using a
253 HostFileSystemIterator instance to traverse multiple version of the 253 HostFileSystemIterator instance to traverse multiple version of the
254 SVN filesystem. 254 SVN filesystem.
255 ''' 255 '''
256 availability = self._top_level_object_store.Get(api_name).Get() 256 availability = self._top_level_object_store.Get(api_name).Get()
257 if availability is not None: 257 if availability is not None:
258 return availability 258 return availability
259 259
260 # Check for predetermined availability and cache this information if found. 260 # Check for predetermined availability and cache this information if found.
261 availability = self._GetPredeterminedAvailability(api_name) 261 availability = self._GetPredeterminedAvailability(api_name)
262 if availability is not None: 262 if availability is not None:
263 self._top_level_object_store.Set(api_name, availability) 263 self._top_level_object_store.Set(api_name, availability)
264 return availability 264 return availability
265 265
266 def check_api_availability(file_system, channel_info): 266 def check_api_availability(file_system, channel_info):
267 return self._CheckApiAvailability(api_name, file_system, channel_info) 267 return self._CheckAPIAvailability(api_name, file_system, channel_info)
268 268
269 channel_info = self._file_system_iterator.Descending( 269 channel_info = self._file_system_iterator.Descending(
270 self._branch_utility.GetChannelInfo('dev'), 270 self._branch_utility.GetChannelInfo('dev'),
271 check_api_availability) 271 check_api_availability)
272 if channel_info is None: 272 if channel_info is None:
273 # The API wasn't available on 'dev', so it must be a 'trunk'-only API. 273 # The API wasn't available on 'dev', so it must be a 'trunk'-only API.
274 channel_info = self._branch_utility.GetChannelInfo('trunk') 274 channel_info = self._branch_utility.GetChannelInfo('trunk')
275 275
276 # If the API is not stable, check when it will be scheduled to be stable. 276 # If the API is not stable, check when it will be scheduled to be stable.
277 if channel_info.channel == 'stable': 277 if channel_info.channel == 'stable':
278 scheduled = None 278 scheduled = None
279 else: 279 else:
280 scheduled = self._FindScheduled(api_name) 280 scheduled = self._FindScheduled(api_name)
281 281
282 availability = AvailabilityInfo(channel_info, scheduled=scheduled) 282 availability = AvailabilityInfo(channel_info, scheduled=scheduled)
283 283
284 self._top_level_object_store.Set(api_name, availability) 284 self._top_level_object_store.Set(api_name, availability)
285 return availability 285 return availability
286 286
287 def GetApiNodeAvailability(self, api_name): 287 def GetAPINodeAvailability(self, api_name):
288 '''Returns an APISchemaGraph annotated with each node's availability (the 288 '''Returns an APISchemaGraph annotated with each node's availability (the
289 ChannelInfo at the oldest channel it's available in). 289 ChannelInfo at the oldest channel it's available in).
290 ''' 290 '''
291 availability_graph = self._node_level_object_store.Get(api_name).Get() 291 availability_graph = self._node_level_object_store.Get(api_name).Get()
292 if availability_graph is not None: 292 if availability_graph is not None:
293 return availability_graph 293 return availability_graph
294 294
295 def assert_not_none(value): 295 def assert_not_none(value):
296 assert value is not None 296 assert value is not None
297 return value 297 return value
298 298
299 availability_graph = APISchemaGraph() 299 availability_graph = APISchemaGraph()
300 300
301 host_fs = self._host_file_system 301 host_fs = self._host_file_system
302 trunk_stat = assert_not_none(host_fs.Stat(self._GetApiSchemaFilename( 302 trunk_stat = assert_not_none(host_fs.Stat(self._GetAPISchemaFilename(
303 api_name, host_fs, 'trunk'))) 303 api_name, host_fs, 'trunk')))
304 304
305 # Weird object thing here because nonlocal is Python 3. 305 # Weird object thing here because nonlocal is Python 3.
306 previous = type('previous', (object,), {'stat': None, 'graph': None}) 306 previous = type('previous', (object,), {'stat': None, 'graph': None})
307 307
308 def update_availability_graph(file_system, channel_info): 308 def update_availability_graph(file_system, channel_info):
309 version_filename = assert_not_none(self._GetApiSchemaFilename( 309 version_filename = assert_not_none(self._GetAPISchemaFilename(
310 api_name, file_system, channel_info.version)) 310 api_name, file_system, channel_info.version))
311 version_stat = assert_not_none(file_system.Stat(version_filename)) 311 version_stat = assert_not_none(file_system.Stat(version_filename))
312 312
313 # Important optimisation: only re-parse the graph if the file changed in 313 # Important optimisation: only re-parse the graph if the file changed in
314 # the last revision. Parsing the same schema and forming a graph on every 314 # the last revision. Parsing the same schema and forming a graph on every
315 # iteration is really expensive. 315 # iteration is really expensive.
316 if version_stat == previous.stat: 316 if version_stat == previous.stat:
317 version_graph = previous.graph 317 version_graph = previous.graph
318 else: 318 else:
319 # Keep track of any new schema elements from this version by adding 319 # Keep track of any new schema elements from this version by adding
320 # them to |availability_graph|. 320 # them to |availability_graph|.
321 # 321 #
322 # Calling |availability_graph|.Lookup() on the nodes being updated 322 # Calling |availability_graph|.Lookup() on the nodes being updated
323 # will return the |annotation| object -- the current |channel_info|. 323 # will return the |annotation| object -- the current |channel_info|.
324 version_graph = APISchemaGraph(self._GetApiSchema( 324 version_graph = APISchemaGraph(self._GetAPISchema(
325 api_name, file_system, channel_info.version)) 325 api_name, file_system, channel_info.version))
326 availability_graph.Update(version_graph.Subtract(availability_graph), 326 availability_graph.Update(version_graph.Subtract(availability_graph),
327 annotation=channel_info) 327 annotation=channel_info)
328 328
329 previous.stat = version_stat 329 previous.stat = version_stat
330 previous.graph = version_graph 330 previous.graph = version_graph
331 331
332 # Continue looping until there are no longer differences between this 332 # Continue looping until there are no longer differences between this
333 # version and trunk. 333 # version and trunk.
334 return version_stat != trunk_stat 334 return version_stat != trunk_stat
335 335
336 self._file_system_iterator.Ascending( 336 self._file_system_iterator.Ascending(
337 self.GetApiAvailability(api_name).channel_info, 337 self.GetAPIAvailability(api_name).channel_info,
338 update_availability_graph) 338 update_availability_graph)
339 339
340 self._node_level_object_store.Set(api_name, availability_graph) 340 self._node_level_object_store.Set(api_name, availability_graph)
341 return availability_graph 341 return availability_graph
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698