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

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: Minor changes Created 7 years, 7 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 import collections 9 import collections
9 10
11 import svn_constants
10 import third_party.json_schema_compiler.json_parse as json_parse 12 import third_party.json_schema_compiler.json_parse as json_parse
11 import third_party.json_schema_compiler.model as model 13 import third_party.json_schema_compiler.model as model
12 import third_party.json_schema_compiler.idl_schema as idl_schema 14 import third_party.json_schema_compiler.idl_schema as idl_schema
13 import third_party.json_schema_compiler.idl_parser as idl_parser 15 import third_party.json_schema_compiler.idl_parser as idl_parser
14 16
15 def _RemoveNoDocs(item): 17 def _RemoveNoDocs(item):
16 if json_parse.IsDict(item): 18 if json_parse.IsDict(item):
17 if item.get('nodoc', False): 19 if item.get('nodoc', False):
18 return True 20 return True
19 for key, value in item.items(): 21 for key, value in item.items():
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
73 def _FormatValue(value): 75 def _FormatValue(value):
74 """Inserts commas every three digits for integer values. It is magic. 76 """Inserts commas every three digits for integer values. It is magic.
75 """ 77 """
76 s = str(value) 78 s = str(value)
77 return ','.join([s[max(0, i - 3):i] for i in range(len(s), 0, -3)][::-1]) 79 return ','.join([s[max(0, i - 3):i] for i in range(len(s), 0, -3)][::-1])
78 80
79 class _JSCModel(object): 81 class _JSCModel(object):
80 """Uses a Model from the JSON Schema Compiler and generates a dict that 82 """Uses a Model from the JSON Schema Compiler and generates a dict that
81 a Handlebar template can use for a data source. 83 a Handlebar template can use for a data source.
82 """ 84 """
83 def __init__(self, json, ref_resolver, disable_refs): 85 def __init__(self,
86 json,
87 ref_resolver,
88 disable_refs,
89 availability_data_source,
90 svn_file_system):
84 self._ref_resolver = ref_resolver 91 self._ref_resolver = ref_resolver
85 self._disable_refs = disable_refs 92 self._disable_refs = disable_refs
93 self._availability_data_source = availability_data_source
94 json_string = svn_file_system.ReadSingle('%s/intro_tables.json'
not at google - send to devlin 2013/04/30 18:34:19 nicer line break would be svn_file_system.ReadSing
epeterson 2013/05/13 02:38:10 Done.
95 % svn_constants.JSON_PATH)
96 self._intro_json = json_library.loads(json_string)
86 clean_json = copy.deepcopy(json) 97 clean_json = copy.deepcopy(json)
87 if _RemoveNoDocs(clean_json): 98 if _RemoveNoDocs(clean_json):
88 self._namespace = None 99 self._namespace = None
89 else: 100 else:
90 _InlineDocs(clean_json) 101 _InlineDocs(clean_json)
91 self._namespace = model.Namespace(clean_json, clean_json['namespace']) 102 self._namespace = model.Namespace(clean_json, clean_json['namespace'])
92 103
93 def _FormatDescription(self, description): 104 def _FormatDescription(self, description):
94 if self._disable_refs: 105 if self._disable_refs:
95 return description 106 return description
96 return self._ref_resolver.ResolveAllLinks(description, 107 return self._ref_resolver.ResolveAllLinks(description,
97 namespace=self._namespace.name) 108 namespace=self._namespace.name)
98 109
99 def _GetLink(self, link): 110 def _GetLink(self, link):
100 if self._disable_refs: 111 if self._disable_refs:
101 type_name = link.split('.', 1)[-1] 112 type_name = link.split('.', 1)[-1]
102 return { 'href': '#type-%s' % type_name, 'text': link, 'name': link } 113 return { 'href': '#type-%s' % type_name, 'text': link, 'name': link }
103 return self._ref_resolver.SafeGetLink(link, namespace=self._namespace.name) 114 return self._ref_resolver.SafeGetLink(link, namespace=self._namespace.name)
104 115
105 def ToDict(self): 116 def ToDict(self):
106 if self._namespace is None: 117 if self._namespace is None:
107 return {} 118 return {}
108 return { 119 return {
109 'name': self._namespace.name, 120 'name': self._namespace.name,
121 'description': self._namespace.description,
122 'availability': self._GetAvailability(),
123 'experimental': self._CheckExperimental(),
124 'intro_permissions': self._GetPermissions(),
125 'learn_more': self._GetMoreLearning(),
110 'types': self._GenerateTypes(self._namespace.types.values()), 126 'types': self._GenerateTypes(self._namespace.types.values()),
111 'functions': self._GenerateFunctions(self._namespace.functions), 127 'functions': self._GenerateFunctions(self._namespace.functions),
112 'events': self._GenerateEvents(self._namespace.events), 128 'events': self._GenerateEvents(self._namespace.events),
113 'properties': self._GenerateProperties(self._namespace.properties) 129 'properties': self._GenerateProperties(self._namespace.properties)
114 } 130 }
115 131
132 def _GetAvailability(self):
133 """Finds the earliest stable version of chrome where an API was available
134 using AvailabilityDataSource. If an API hasn't been released to stable yet,
135 then the development channel that the API is currently available on will
136 be returned instead.
137 """
138 if not self._CheckExperimental():
139 return self._availability_data_source.GetAvailability(
140 self._namespace.name)
141 # A special message for experimental APIs' availability will be displayed.
142 return None
143
144 def _CheckExperimental(self):
145 return self._namespace.name.startswith('experimental')
146
147 def _GetPermissions(self):
148 """This is a temporary fix for generating API intro tables automatically.
149 Information on an API's permissions is pulled from a json file so that it
150 can be sent to the templates along with other relevant intro data.
151 """
152 table_info = self._intro_json.get(self._namespace.name, None)
153 try:
154 return table_info[0]['Permissions']
155 except:
156 # The intro-table will display a "Permissions: None" message.
157 return None
not at google - send to devlin 2013/04/30 18:34:19 pls don't use exceptions for control flow. Also as
epeterson 2013/05/13 02:38:10 Done.
158
159 def _GetMoreLearning(self):
160 """We can't automatically generated the "Learn more" field in an API's.
161 intro table; instead, we pull it from a json file so that it can be sent to
162 the templates along with other relevant intro data.
163 """
164 table_info = self._intro_json.get(self._namespace.name, None)
165 try:
166 return table_info[1]['Learn more']
167 except:
168 # Not all APIs have "Learn more" information.
169 return None
not at google - send to devlin 2013/04/30 18:34:19 ditto regarding the filtering, not assuming it's t
epeterson 2013/05/13 02:38:10 Done.
170
116 def _GenerateTypes(self, types): 171 def _GenerateTypes(self, types):
117 return [self._GenerateType(t) for t in types] 172 return [self._GenerateType(t) for t in types]
118 173
119 def _GenerateType(self, type_): 174 def _GenerateType(self, type_):
120 type_dict = { 175 type_dict = {
121 'name': type_.simple_name, 176 'name': type_.simple_name,
122 'description': self._FormatDescription(type_.description), 177 'description': self._FormatDescription(type_.description),
123 'properties': self._GenerateProperties(type_.properties), 178 'properties': self._GenerateProperties(type_.properties),
124 'functions': self._GenerateFunctions(type_.functions), 179 'functions': self._GenerateFunctions(type_.functions),
125 'events': self._GenerateEvents(type_.events), 180 'events': self._GenerateEvents(type_.events),
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after
292 self._samples = samples 347 self._samples = samples
293 348
294 def get(self, key): 349 def get(self, key):
295 return self._samples.FilterSamples(key, self._api_name) 350 return self._samples.FilterSamples(key, self._api_name)
296 351
297 class APIDataSource(object): 352 class APIDataSource(object):
298 """This class fetches and loads JSON APIs from the FileSystem passed in with 353 """This class fetches and loads JSON APIs from the FileSystem passed in with
299 |compiled_fs_factory|, so the APIs can be plugged into templates. 354 |compiled_fs_factory|, so the APIs can be plugged into templates.
300 """ 355 """
301 class Factory(object): 356 class Factory(object):
302 def __init__(self, compiled_fs_factory, base_path): 357 def __init__(self,
358 compiled_fs_factory,
359 base_path,
360 availability_data_source_factory,
361 svn_file_system):
303 def create_compiled_fs(fn, category): 362 def create_compiled_fs(fn, category):
304 return compiled_fs_factory.Create(fn, APIDataSource, category=category) 363 return compiled_fs_factory.Create(fn, APIDataSource, category=category)
305 364
306 self._permissions_cache = create_compiled_fs(self._LoadPermissions, 365 self._permissions_cache = create_compiled_fs(self._LoadPermissions,
307 'permissions') 366 'permissions')
308 367
309 self._json_cache = create_compiled_fs( 368 self._json_cache = create_compiled_fs(
310 lambda api_name, api: self._LoadJsonAPI(api, False), 369 lambda api_name, api: self._LoadJsonAPI(api, False),
311 'json') 370 'json')
312 self._idl_cache = create_compiled_fs( 371 self._idl_cache = create_compiled_fs(
313 lambda api_name, api: self._LoadIdlAPI(api, False), 372 lambda api_name, api: self._LoadIdlAPI(api, False),
314 'idl') 373 'idl')
315 374
316 # These caches are used if an APIDataSource does not want to resolve the 375 # These caches are used if an APIDataSource does not want to resolve the
317 # $refs in an API. This is needed to prevent infinite recursion in 376 # $refs in an API. This is needed to prevent infinite recursion in
318 # ReferenceResolver. 377 # ReferenceResolver.
319 self._json_cache_no_refs = create_compiled_fs( 378 self._json_cache_no_refs = create_compiled_fs(
320 lambda api_name, api: self._LoadJsonAPI(api, True), 379 lambda api_name, api: self._LoadJsonAPI(api, True),
321 'json-no-refs') 380 'json-no-refs')
322 self._idl_cache_no_refs = create_compiled_fs( 381 self._idl_cache_no_refs = create_compiled_fs(
323 lambda api_name, api: self._LoadIdlAPI(api, True), 382 lambda api_name, api: self._LoadIdlAPI(api, True),
324 'idl-no-refs') 383 'idl-no-refs')
325 384
326 self._idl_names_cache = create_compiled_fs(self._GetIDLNames, 'idl-names') 385 self._idl_names_cache = create_compiled_fs(self._GetIDLNames, 'idl-names')
327 self._names_cache = create_compiled_fs(self._GetAllNames, 'names') 386 self._names_cache = create_compiled_fs(self._GetAllNames, 'names')
328 387
329 self._base_path = base_path 388 self._base_path = base_path
330 389 self._availability_data_source = availability_data_source_factory.Create()
390 self._svn_file_system = svn_file_system
331 # These must be set later via the SetFooDataSourceFactory methods. 391 # These must be set later via the SetFooDataSourceFactory methods.
332 self._ref_resolver_factory = None 392 self._ref_resolver_factory = None
333 self._samples_data_source_factory = None 393 self._samples_data_source_factory = None
334 394
335 def SetSamplesDataSourceFactory(self, samples_data_source_factory): 395 def SetSamplesDataSourceFactory(self, samples_data_source_factory):
336 self._samples_data_source_factory = samples_data_source_factory 396 self._samples_data_source_factory = samples_data_source_factory
337 397
338 def SetReferenceResolverFactory(self, ref_resolver_factory): 398 def SetReferenceResolverFactory(self, ref_resolver_factory):
339 self._ref_resolver_factory = ref_resolver_factory 399 self._ref_resolver_factory = ref_resolver_factory
340 400
(...skipping 25 matching lines...) Expand all
366 samples, 426 samples,
367 disable_refs) 427 disable_refs)
368 428
369 def _LoadPermissions(self, file_name, json_str): 429 def _LoadPermissions(self, file_name, json_str):
370 return json_parse.Parse(json_str) 430 return json_parse.Parse(json_str)
371 431
372 def _LoadJsonAPI(self, api, disable_refs): 432 def _LoadJsonAPI(self, api, disable_refs):
373 return _JSCModel( 433 return _JSCModel(
374 json_parse.Parse(api)[0], 434 json_parse.Parse(api)[0],
375 self._ref_resolver_factory.Create() if not disable_refs else None, 435 self._ref_resolver_factory.Create() if not disable_refs else None,
376 disable_refs).ToDict() 436 disable_refs,
437 self._availability_data_source,
438 self._svn_file_system).ToDict()
377 439
378 def _LoadIdlAPI(self, api, disable_refs): 440 def _LoadIdlAPI(self, api, disable_refs):
379 idl = idl_parser.IDLParser().ParseData(api) 441 idl = idl_parser.IDLParser().ParseData(api)
380 return _JSCModel( 442 return _JSCModel(
381 idl_schema.IDLSchema(idl).process()[0], 443 idl_schema.IDLSchema(idl).process()[0],
382 self._ref_resolver_factory.Create() if not disable_refs else None, 444 self._ref_resolver_factory.Create() if not disable_refs else None,
383 disable_refs).ToDict() 445 disable_refs,
446 self._availability_data_source,
447 self._svn_file_system).ToDict()
384 448
385 def _GetIDLNames(self, base_dir, apis): 449 def _GetIDLNames(self, base_dir, apis):
386 return self._GetExtNames(apis, ['idl']) 450 return self._GetExtNames(apis, ['idl'])
387 451
388 def _GetAllNames(self, base_dir, apis): 452 def _GetAllNames(self, base_dir, apis):
389 return self._GetExtNames(apis, ['json', 'idl']) 453 return self._GetExtNames(apis, ['json', 'idl'])
390 454
391 def _GetExtNames(self, apis, exts): 455 def _GetExtNames(self, apis, exts):
392 return [model.UnixName(os.path.splitext(api)[0]) for api in apis 456 return [model.UnixName(os.path.splitext(api)[0]) for api in apis
393 if os.path.splitext(api)[1][1:] in exts] 457 if os.path.splitext(api)[1][1:] in exts]
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
450 return feature_data 514 return feature_data
451 515
452 def _GenerateHandlebarContext(self, handlebar_dict, path): 516 def _GenerateHandlebarContext(self, handlebar_dict, path):
453 handlebar_dict['permissions'] = self._GetFeatureData(path) 517 handlebar_dict['permissions'] = self._GetFeatureData(path)
454 handlebar_dict['samples'] = _LazySamplesGetter(path, self._samples) 518 handlebar_dict['samples'] = _LazySamplesGetter(path, self._samples)
455 return handlebar_dict 519 return handlebar_dict
456 520
457 def _GetAsSubdirectory(self, name): 521 def _GetAsSubdirectory(self, name):
458 if name.startswith('experimental_'): 522 if name.startswith('experimental_'):
459 parts = name[len('experimental_'):].split('_', 1) 523 parts = name[len('experimental_'):].split('_', 1)
460 parts[1] = 'experimental_%s' % parts[1] 524 if len(parts) > 1:
461 return '/'.join(parts) 525 parts[1] = 'experimental_%s' % parts[1]
526 return '/'.join(parts)
527 else:
528 return '%s/%s' % (parts[0], name)
462 return name.replace('_', '/', 1) 529 return name.replace('_', '/', 1)
463 530
464 def get(self, key): 531 def _DetermineNamesForGet(self, key):
465 if key.endswith('.html') or key.endswith('.json') or key.endswith('.idl'): 532 if key.endswith('.html') or key.endswith('.json') or key.endswith('.idl'):
466 path, ext = os.path.splitext(key) 533 path, ext = os.path.splitext(key)
467 else: 534 else:
468 path = key 535 path = key
469 unix_name = model.UnixName(path) 536 unix_name = model.UnixName(path)
470 idl_names = self._idl_names_cache.GetFromFileListing(self._base_path)
471 names = self._names_cache.GetFromFileListing(self._base_path) 537 names = self._names_cache.GetFromFileListing(self._base_path)
472 if unix_name not in names and self._GetAsSubdirectory(unix_name) in names: 538 if unix_name not in names and self._GetAsSubdirectory(unix_name) in names:
473 unix_name = self._GetAsSubdirectory(unix_name) 539 unix_name = self._GetAsSubdirectory(unix_name)
540 return (path, unix_name)
474 541
542 def _DetermineCacheForGet(self, unix_name):
543 idl_names = self._idl_names_cache.GetFromFileListing(self._base_path)
475 if self._disable_refs: 544 if self._disable_refs:
476 cache, ext = ( 545 cache, ext = (
477 (self._idl_cache_no_refs, '.idl') if (unix_name in idl_names) else 546 (self._idl_cache_no_refs, '.idl') if (unix_name in idl_names) else
478 (self._json_cache_no_refs, '.json')) 547 (self._json_cache_no_refs, '.json'))
479 else: 548 else:
480 cache, ext = ((self._idl_cache, '.idl') if (unix_name in idl_names) else 549 cache, ext = ((self._idl_cache, '.idl') if (unix_name in idl_names) else
481 (self._json_cache, '.json')) 550 (self._json_cache, '.json'))
551 return (cache, ext)
552
553 def get(self, key):
554 path, unix_name = self._DetermineNamesForGet(key)
555 cache, ext = self._DetermineCacheForGet(unix_name)
482 return self._GenerateHandlebarContext( 556 return self._GenerateHandlebarContext(
483 cache.GetFromFile('%s/%s%s' % (self._base_path, unix_name, ext)), 557 cache.GetFromFile('%s/%s%s' % (self._base_path, unix_name, ext)),
484 path) 558 path)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698