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

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

Issue 12996003: Dynamically generate a heading for Extension Docs API pages (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Finding earliest 'stable' availability using features files Created 7 years, 8 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 (c) 2012 The Chromium Authors. All rights reserved. 1 # Copyright (c) 2012 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 copy 5 import copy
6 import json as json_library
6 import logging 7 import logging
7 import os 8 import os
8 9
10 import svn_constants
9 import third_party.json_schema_compiler.json_parse as json_parse 11 import third_party.json_schema_compiler.json_parse as json_parse
10 import third_party.json_schema_compiler.model as model 12 import third_party.json_schema_compiler.model as model
11 import third_party.json_schema_compiler.idl_schema as idl_schema 13 import third_party.json_schema_compiler.idl_schema as idl_schema
12 import third_party.json_schema_compiler.idl_parser as idl_parser 14 import third_party.json_schema_compiler.idl_parser as idl_parser
13 15
14 def _RemoveNoDocs(item): 16 def _RemoveNoDocs(item):
15 if json_parse.IsDict(item): 17 if json_parse.IsDict(item):
16 if item.get('nodoc', False): 18 if item.get('nodoc', False):
17 return True 19 return True
18 for key, value in item.items(): 20 for key, value in item.items():
(...skipping 16 matching lines...) Expand all
35 def _FormatValue(value): 37 def _FormatValue(value):
36 """Inserts commas every three digits for integer values. It is magic. 38 """Inserts commas every three digits for integer values. It is magic.
37 """ 39 """
38 s = str(value) 40 s = str(value)
39 return ','.join([s[max(0, i - 3):i] for i in range(len(s), 0, -3)][::-1]) 41 return ','.join([s[max(0, i - 3):i] for i in range(len(s), 0, -3)][::-1])
40 42
41 class _JSCModel(object): 43 class _JSCModel(object):
42 """Uses a Model from the JSON Schema Compiler and generates a dict that 44 """Uses a Model from the JSON Schema Compiler and generates a dict that
43 a Handlebar template can use for a data source. 45 a Handlebar template can use for a data source.
44 """ 46 """
45 def __init__(self, json, ref_resolver, disable_refs): 47 def __init__(self,
48 json,
49 ref_resolver,
50 disable_refs,
51 availability_data_source,
52 svn_file_system):
46 self._ref_resolver = ref_resolver 53 self._ref_resolver = ref_resolver
47 self._disable_refs = disable_refs 54 self._disable_refs = disable_refs
55 self._availability_data_source = availability_data_source
56 json_string = svn_file_system.ReadSingle('%s/intro_tables.json'
57 % svn_constants.JSON_PATH)
58 self._intro_json = json_library.loads(json_string)
48 clean_json = copy.deepcopy(json) 59 clean_json = copy.deepcopy(json)
49 if _RemoveNoDocs(clean_json): 60 if _RemoveNoDocs(clean_json):
50 self._namespace = None 61 self._namespace = None
51 else: 62 else:
52 self._namespace = model.Namespace(clean_json, clean_json['namespace']) 63 self._namespace = model.Namespace(clean_json, clean_json['namespace'])
53 64
54 def _FormatDescription(self, description): 65 def _FormatDescription(self, description):
55 if self._disable_refs: 66 if self._disable_refs:
56 return description 67 return description
57 return self._ref_resolver.ResolveAllLinks(description, 68 return self._ref_resolver.ResolveAllLinks(description,
58 namespace=self._namespace.name) 69 namespace=self._namespace.name)
59 70
60 def _GetLink(self, link): 71 def _GetLink(self, link):
61 if self._disable_refs: 72 if self._disable_refs:
62 type_name = link.split('.', 1)[-1] 73 type_name = link.split('.', 1)[-1]
63 return { 'href': '#type-%s' % type_name, 'text': link, 'name': link } 74 return { 'href': '#type-%s' % type_name, 'text': link, 'name': link }
64 return self._ref_resolver.SafeGetLink(link, namespace=self._namespace.name) 75 return self._ref_resolver.SafeGetLink(link, namespace=self._namespace.name)
65 76
66 def ToDict(self): 77 def ToDict(self):
67 if self._namespace is None: 78 if self._namespace is None:
68 return {} 79 return {}
69 return { 80 return {
70 'name': self._namespace.name, 81 'name': self._namespace.name,
82 'description': self._namespace.description,
83 'availability': self._GetAvailability(),
84 'experimental': self._CheckExperimental(),
85 'intro_permissions': self._GetPermissions(),
86 'learn_more': self._GetMoreLearning(),
71 'types': self._GenerateTypes(self._namespace.types.values()), 87 'types': self._GenerateTypes(self._namespace.types.values()),
72 'functions': self._GenerateFunctions(self._namespace.functions), 88 'functions': self._GenerateFunctions(self._namespace.functions),
73 'events': self._GenerateEvents(self._namespace.events), 89 'events': self._GenerateEvents(self._namespace.events),
74 'properties': self._GenerateProperties(self._namespace.properties) 90 'properties': self._GenerateProperties(self._namespace.properties)
75 } 91 }
76 92
93 def _GetAvailability(self):
94 """Finds the earliest stable version of chrome where an API was available
95 using AvailabilityDataSource. If an API hasn't been released to stable yet,
96 then the development channel that the API is currently available on will
97 be returned instead.
98 """
99 if not self._CheckExperimental():
100 return self._availability_data_source.GetAvailability(
101 self._namespace.name)
102 # A special message for experimental APIs' availability will be displayed.
103 return None
104
105 def _CheckExperimental(self):
106 return self._namespace.name.startswith('experimental')
107
108 def _GetPermissions(self):
109 """This is a temporary fix for generating API intro tables automatically.
110 Information on an API's permissions is pulled from a json file so that it
111 can be sent to the templates along with other relevant intro data.
112 """
113 table_info = self._intro_json.get(self._namespace.name, None)
114 try:
115 return table_info[0]['Permissions']
116 except:
117 # The intro-table will display a "Permissions: None" message.
118 return None
119
120 def _GetMoreLearning(self):
121 """We can't automatically generated the "Learn more" field in an API's.
122 intro table; instead, we pull it from a json file so that it can be sent to
123 the templates along with other relevant intro data.
124 """
125 table_info = self._intro_json.get(self._namespace.name, None)
126 try:
127 return table_info[1]['Learn more']
128 except:
129 # Not all APIs have "Learn more" information.
130 return None
131
77 def _GenerateTypes(self, types): 132 def _GenerateTypes(self, types):
78 return [self._GenerateType(t) for t in types] 133 return [self._GenerateType(t) for t in types]
79 134
80 def _GenerateType(self, type_): 135 def _GenerateType(self, type_):
81 type_dict = { 136 type_dict = {
82 'name': type_.simple_name, 137 'name': type_.simple_name,
83 'description': self._FormatDescription(type_.description), 138 'description': self._FormatDescription(type_.description),
84 'properties': self._GenerateProperties(type_.properties), 139 'properties': self._GenerateProperties(type_.properties),
85 'functions': self._GenerateFunctions(type_.functions), 140 'functions': self._GenerateFunctions(type_.functions),
86 'events': self._GenerateEvents(type_.events), 141 'events': self._GenerateEvents(type_.events),
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after
253 self._samples = samples 308 self._samples = samples
254 309
255 def get(self, key): 310 def get(self, key):
256 return self._samples.FilterSamples(key, self._api_name) 311 return self._samples.FilterSamples(key, self._api_name)
257 312
258 class APIDataSource(object): 313 class APIDataSource(object):
259 """This class fetches and loads JSON APIs from the FileSystem passed in with 314 """This class fetches and loads JSON APIs from the FileSystem passed in with
260 |compiled_fs_factory|, so the APIs can be plugged into templates. 315 |compiled_fs_factory|, so the APIs can be plugged into templates.
261 """ 316 """
262 class Factory(object): 317 class Factory(object):
263 def __init__(self, compiled_fs_factory, base_path): 318 def __init__(self,
319 compiled_fs_factory,
320 base_path,
321 availability_data_source_factory,
322 svn_file_system):
264 def create_compiled_fs(fn, category): 323 def create_compiled_fs(fn, category):
265 return compiled_fs_factory.Create(fn, APIDataSource, category=category) 324 return compiled_fs_factory.Create(fn, APIDataSource, category=category)
266 325
267 self._permissions_cache = create_compiled_fs(self._LoadPermissions, 326 self._permissions_cache = create_compiled_fs(self._LoadPermissions,
268 'permissions') 327 'permissions')
269 328
270 self._json_cache = create_compiled_fs( 329 self._json_cache = create_compiled_fs(
271 lambda api_name, api: self._LoadJsonAPI(api, False), 330 lambda api_name, api: self._LoadJsonAPI(api, False),
272 'json') 331 'json')
273 self._idl_cache = create_compiled_fs( 332 self._idl_cache = create_compiled_fs(
274 lambda api_name, api: self._LoadIdlAPI(api, False), 333 lambda api_name, api: self._LoadIdlAPI(api, False),
275 'idl') 334 'idl')
276 335
277 # These caches are used if an APIDataSource does not want to resolve the 336 # These caches are used if an APIDataSource does not want to resolve the
278 # $refs in an API. This is needed to prevent infinite recursion in 337 # $refs in an API. This is needed to prevent infinite recursion in
279 # ReferenceResolver. 338 # ReferenceResolver.
280 self._json_cache_no_refs = create_compiled_fs( 339 self._json_cache_no_refs = create_compiled_fs(
281 lambda api_name, api: self._LoadJsonAPI(api, True), 340 lambda api_name, api: self._LoadJsonAPI(api, True),
282 'json-no-refs') 341 'json-no-refs')
283 self._idl_cache_no_refs = create_compiled_fs( 342 self._idl_cache_no_refs = create_compiled_fs(
284 lambda api_name, api: self._LoadIdlAPI(api, True), 343 lambda api_name, api: self._LoadIdlAPI(api, True),
285 'idl-no-refs') 344 'idl-no-refs')
286 345
287 self._idl_names_cache = create_compiled_fs(self._GetIDLNames, 'idl-names') 346 self._idl_names_cache = create_compiled_fs(self._GetIDLNames, 'idl-names')
288 self._names_cache = create_compiled_fs(self._GetAllNames, 'names') 347 self._names_cache = create_compiled_fs(self._GetAllNames, 'names')
289 348
290 self._base_path = base_path 349 self._base_path = base_path
291 350 self._availability_data_source = availability_data_source_factory.Create()
351 self._svn_file_system = svn_file_system
292 # These must be set later via the SetFooDataSourceFactory methods. 352 # These must be set later via the SetFooDataSourceFactory methods.
293 self._ref_resolver_factory = None 353 self._ref_resolver_factory = None
294 self._samples_data_source_factory = None 354 self._samples_data_source_factory = None
295 355
296 def SetSamplesDataSourceFactory(self, samples_data_source_factory): 356 def SetSamplesDataSourceFactory(self, samples_data_source_factory):
297 self._samples_data_source_factory = samples_data_source_factory 357 self._samples_data_source_factory = samples_data_source_factory
298 358
299 def SetReferenceResolverFactory(self, ref_resolver_factory): 359 def SetReferenceResolverFactory(self, ref_resolver_factory):
300 self._ref_resolver_factory = ref_resolver_factory 360 self._ref_resolver_factory = ref_resolver_factory
301 361
(...skipping 25 matching lines...) Expand all
327 samples, 387 samples,
328 disable_refs) 388 disable_refs)
329 389
330 def _LoadPermissions(self, file_name, json_str): 390 def _LoadPermissions(self, file_name, json_str):
331 return json_parse.Parse(json_str) 391 return json_parse.Parse(json_str)
332 392
333 def _LoadJsonAPI(self, api, disable_refs): 393 def _LoadJsonAPI(self, api, disable_refs):
334 return _JSCModel( 394 return _JSCModel(
335 json_parse.Parse(api)[0], 395 json_parse.Parse(api)[0],
336 self._ref_resolver_factory.Create() if not disable_refs else None, 396 self._ref_resolver_factory.Create() if not disable_refs else None,
337 disable_refs).ToDict() 397 disable_refs,
398 self._availability_data_source,
399 self._svn_file_system).ToDict()
338 400
339 def _LoadIdlAPI(self, api, disable_refs): 401 def _LoadIdlAPI(self, api, disable_refs):
340 idl = idl_parser.IDLParser().ParseData(api) 402 idl = idl_parser.IDLParser().ParseData(api)
341 return _JSCModel( 403 return _JSCModel(
342 idl_schema.IDLSchema(idl).process()[0], 404 idl_schema.IDLSchema(idl).process()[0],
343 self._ref_resolver_factory.Create() if not disable_refs else None, 405 self._ref_resolver_factory.Create() if not disable_refs else None,
344 disable_refs).ToDict() 406 disable_refs,
407 self._availability_data_source,
408 self._svn_file_system).ToDict()
345 409
346 def _GetIDLNames(self, base_dir, apis): 410 def _GetIDLNames(self, base_dir, apis):
347 return self._GetExtNames(apis, ['idl']) 411 return self._GetExtNames(apis, ['idl'])
348 412
349 def _GetAllNames(self, base_dir, apis): 413 def _GetAllNames(self, base_dir, apis):
350 return self._GetExtNames(apis, ['json', 'idl']) 414 return self._GetExtNames(apis, ['json', 'idl'])
351 415
352 def _GetExtNames(self, apis, exts): 416 def _GetExtNames(self, apis, exts):
353 return [model.UnixName(os.path.splitext(api)[0]) for api in apis 417 return [model.UnixName(os.path.splitext(api)[0]) for api in apis
354 if os.path.splitext(api)[1][1:] in exts] 418 if os.path.splitext(api)[1][1:] in exts]
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
411 return feature_data 475 return feature_data
412 476
413 def _GenerateHandlebarContext(self, handlebar_dict, path): 477 def _GenerateHandlebarContext(self, handlebar_dict, path):
414 handlebar_dict['permissions'] = self._GetFeatureData(path) 478 handlebar_dict['permissions'] = self._GetFeatureData(path)
415 handlebar_dict['samples'] = _LazySamplesGetter(path, self._samples) 479 handlebar_dict['samples'] = _LazySamplesGetter(path, self._samples)
416 return handlebar_dict 480 return handlebar_dict
417 481
418 def _GetAsSubdirectory(self, name): 482 def _GetAsSubdirectory(self, name):
419 if name.startswith('experimental_'): 483 if name.startswith('experimental_'):
420 parts = name[len('experimental_'):].split('_', 1) 484 parts = name[len('experimental_'):].split('_', 1)
421 parts[1] = 'experimental_%s' % parts[1] 485 if len(parts) > 1:
422 return '/'.join(parts) 486 parts[1] = 'experimental_%s' % parts[1]
487 return '/'.join(parts)
488 else:
489 return '%s/%s' % (parts[0], name)
423 return name.replace('_', '/', 1) 490 return name.replace('_', '/', 1)
424 491
425 def get(self, key): 492 def _DetermineNamesForGet(self, key):
426 if key.endswith('.html') or key.endswith('.json') or key.endswith('.idl'): 493 if key.endswith('.html') or key.endswith('.json') or key.endswith('.idl'):
427 path, ext = os.path.splitext(key) 494 path, ext = os.path.splitext(key)
428 else: 495 else:
429 path = key 496 path = key
430 unix_name = model.UnixName(path) 497 unix_name = model.UnixName(path)
431 idl_names = self._idl_names_cache.GetFromFileListing(self._base_path)
432 names = self._names_cache.GetFromFileListing(self._base_path) 498 names = self._names_cache.GetFromFileListing(self._base_path)
433 if unix_name not in names and self._GetAsSubdirectory(unix_name) in names: 499 if unix_name not in names and self._GetAsSubdirectory(unix_name) in names:
434 unix_name = self._GetAsSubdirectory(unix_name) 500 unix_name = self._GetAsSubdirectory(unix_name)
501 return (path, unix_name)
435 502
503 def _DetermineCacheForGet(self, unix_name):
504 idl_names = self._idl_names_cache.GetFromFileListing(self._base_path)
436 if self._disable_refs: 505 if self._disable_refs:
437 cache, ext = ( 506 cache, ext = (
438 (self._idl_cache_no_refs, '.idl') if (unix_name in idl_names) else 507 (self._idl_cache_no_refs, '.idl') if (unix_name in idl_names) else
439 (self._json_cache_no_refs, '.json')) 508 (self._json_cache_no_refs, '.json'))
440 else: 509 else:
441 cache, ext = ((self._idl_cache, '.idl') if (unix_name in idl_names) else 510 cache, ext = ((self._idl_cache, '.idl') if (unix_name in idl_names) else
442 (self._json_cache, '.json')) 511 (self._json_cache, '.json'))
512 return (cache, ext)
513
514 def get(self, key):
515 path, unix_name = self._DetermineNamesForGet(key)
516 cache, ext = self._DetermineCacheForGet(unix_name)
443 return self._GenerateHandlebarContext( 517 return self._GenerateHandlebarContext(
444 cache.GetFromFile('%s/%s%s' % (self._base_path, unix_name, ext)), 518 cache.GetFromFile('%s/%s%s' % (self._base_path, unix_name, ext)),
445 path) 519 path)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698