OLD | NEW |
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 logging | 6 import logging |
7 import os | 7 import os |
8 | 8 |
9 from file_system import FileNotFoundError | 9 from file_system import FileNotFoundError |
10 import third_party.json_schema_compiler.json_parse as json_parse | 10 import third_party.json_schema_compiler.json_parse as json_parse |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
43 def _FormatValue(value): | 43 def _FormatValue(value): |
44 """Inserts commas every three digits for integer values. It is magic. | 44 """Inserts commas every three digits for integer values. It is magic. |
45 """ | 45 """ |
46 s = str(value) | 46 s = str(value) |
47 return ','.join([s[max(0, i - 3):i] for i in range(len(s), 0, -3)][::-1]) | 47 return ','.join([s[max(0, i - 3):i] for i in range(len(s), 0, -3)][::-1]) |
48 | 48 |
49 class _JSCModel(object): | 49 class _JSCModel(object): |
50 """Uses a Model from the JSON Schema Compiler and generates a dict that | 50 """Uses a Model from the JSON Schema Compiler and generates a dict that |
51 a Handlebar template can use for a data source. | 51 a Handlebar template can use for a data source. |
52 """ | 52 """ |
53 def __init__(self, json, ref_resolver, disable_refs): | 53 def __init__(self, |
| 54 json, |
| 55 ref_resolver, |
| 56 disable_refs, |
| 57 availability_data_source): |
54 self._ref_resolver = ref_resolver | 58 self._ref_resolver = ref_resolver |
55 self._disable_refs = disable_refs | 59 self._disable_refs = disable_refs |
| 60 self._availability_data_source = availability_data_source |
56 clean_json = copy.deepcopy(json) | 61 clean_json = copy.deepcopy(json) |
57 if _RemoveNoDocs(clean_json): | 62 if _RemoveNoDocs(clean_json): |
58 self._namespace = None | 63 self._namespace = None |
59 else: | 64 else: |
60 self._namespace = model.Namespace(clean_json, clean_json['namespace']) | 65 self._namespace = model.Namespace(clean_json, clean_json['namespace']) |
61 | 66 |
62 def _FormatDescription(self, description): | 67 def _FormatDescription(self, description): |
63 if self._disable_refs: | 68 if self._disable_refs: |
64 return description | 69 return description |
65 return self._ref_resolver.ResolveAllLinks(description, | 70 return self._ref_resolver.ResolveAllLinks(description, |
66 namespace=self._namespace.name) | 71 namespace=self._namespace.name) |
67 | 72 |
68 def _GetLink(self, link): | 73 def _GetLink(self, link): |
69 if self._disable_refs: | 74 if self._disable_refs: |
70 type_name = link.split('.', 1)[-1] | 75 type_name = link.split('.', 1)[-1] |
71 return { 'href': '#type-%s' % type_name, 'text': link, 'name': link } | 76 return { 'href': '#type-%s' % type_name, 'text': link, 'name': link } |
72 return self._ref_resolver.SafeGetLink(link, namespace=self._namespace.name) | 77 return self._ref_resolver.SafeGetLink(link, namespace=self._namespace.name) |
73 | 78 |
74 def ToDict(self): | 79 def ToDict(self): |
75 if self._namespace is None: | 80 if self._namespace is None: |
76 return {} | 81 return {} |
77 return { | 82 return { |
78 'name': self._namespace.name, | 83 'name': self._namespace.name, |
| 84 'description': self._namespace.description, |
| 85 'availability': self._GetAvailability(), |
79 'types': self._GenerateTypes(self._namespace.types.values()), | 86 'types': self._GenerateTypes(self._namespace.types.values()), |
80 'functions': self._GenerateFunctions(self._namespace.functions), | 87 'functions': self._GenerateFunctions(self._namespace.functions), |
81 'events': self._GenerateEvents(self._namespace.events), | 88 'events': self._GenerateEvents(self._namespace.events), |
82 'properties': self._GenerateProperties(self._namespace.properties) | 89 'properties': self._GenerateProperties(self._namespace.properties) |
83 } | 90 } |
84 | 91 |
| 92 def _GetAvailability(self): |
| 93 """Finds the earliest version of chrome where an API was available using |
| 94 AvailabilityDataSource. Also [temporarily] creates a string describing the |
| 95 availability depending on its original format. |
| 96 """ |
| 97 availability_string = 'Not Currently Available' |
| 98 availability = self._availability_data_source.FindEarliestAvailability( |
| 99 self._namespace.name) |
| 100 |
| 101 if availability is not None: |
| 102 if availability.isdigit(): |
| 103 availability_string = 'Chrome %s' % availability |
| 104 else: |
| 105 availability_string = ('Chrome %s Channel Only' % |
| 106 availability.capitalize()) |
| 107 return availability_string |
| 108 |
85 def _GenerateTypes(self, types): | 109 def _GenerateTypes(self, types): |
86 return [self._GenerateType(t) for t in types] | 110 return [self._GenerateType(t) for t in types] |
87 | 111 |
88 def _GenerateType(self, type_): | 112 def _GenerateType(self, type_): |
89 type_dict = { | 113 type_dict = { |
90 'name': type_.simple_name, | 114 'name': type_.simple_name, |
91 'description': self._FormatDescription(type_.description), | 115 'description': self._FormatDescription(type_.description), |
92 'properties': self._GenerateProperties(type_.properties), | 116 'properties': self._GenerateProperties(type_.properties), |
93 'functions': self._GenerateFunctions(type_.functions), | 117 'functions': self._GenerateFunctions(type_.functions), |
94 'events': self._GenerateEvents(type_.events), | 118 'events': self._GenerateEvents(type_.events), |
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
261 self._samples = samples | 285 self._samples = samples |
262 | 286 |
263 def get(self, key): | 287 def get(self, key): |
264 return self._samples.FilterSamples(key, self._api_name) | 288 return self._samples.FilterSamples(key, self._api_name) |
265 | 289 |
266 class APIDataSource(object): | 290 class APIDataSource(object): |
267 """This class fetches and loads JSON APIs from the FileSystem passed in with | 291 """This class fetches and loads JSON APIs from the FileSystem passed in with |
268 |compiled_fs_factory|, so the APIs can be plugged into templates. | 292 |compiled_fs_factory|, so the APIs can be plugged into templates. |
269 """ | 293 """ |
270 class Factory(object): | 294 class Factory(object): |
271 def __init__(self, compiled_fs_factory, base_path): | 295 def __init__(self, |
| 296 compiled_fs_factory, |
| 297 base_path, |
| 298 availability_data_source_factory): |
272 def create_compiled_fs(fn, category): | 299 def create_compiled_fs(fn, category): |
273 return compiled_fs_factory.Create( | 300 return compiled_fs_factory.Create( |
274 fn, APIDataSource, category=category, version=_VERSION) | 301 fn, APIDataSource, category=category, version=_VERSION) |
275 | 302 |
276 self._permissions_cache = create_compiled_fs(self._LoadPermissions, | 303 self._permissions_cache = create_compiled_fs(self._LoadPermissions, |
277 'permissions') | 304 'permissions') |
278 | 305 |
279 self._json_cache = create_compiled_fs( | 306 self._json_cache = create_compiled_fs( |
280 lambda api_name, api: self._LoadJsonAPI(api, False), | 307 lambda api_name, api: self._LoadJsonAPI(api, False), |
281 'json') | 308 'json') |
282 self._idl_cache = create_compiled_fs( | 309 self._idl_cache = create_compiled_fs( |
283 lambda api_name, api: self._LoadIdlAPI(api, False), | 310 lambda api_name, api: self._LoadIdlAPI(api, False), |
284 'idl') | 311 'idl') |
285 | 312 |
286 # These caches are used if an APIDataSource does not want to resolve the | 313 # These caches are used if an APIDataSource does not want to resolve the |
287 # $refs in an API. This is needed to prevent infinite recursion in | 314 # $refs in an API. This is needed to prevent infinite recursion in |
288 # ReferenceResolver. | 315 # ReferenceResolver. |
289 self._json_cache_no_refs = create_compiled_fs( | 316 self._json_cache_no_refs = create_compiled_fs( |
290 lambda api_name, api: self._LoadJsonAPI(api, True), | 317 lambda api_name, api: self._LoadJsonAPI(api, True), |
291 'json-no-refs') | 318 'json-no-refs') |
292 self._idl_cache_no_refs = create_compiled_fs( | 319 self._idl_cache_no_refs = create_compiled_fs( |
293 lambda api_name, api: self._LoadIdlAPI(api, True), | 320 lambda api_name, api: self._LoadIdlAPI(api, True), |
294 'idl-no-refs') | 321 'idl-no-refs') |
295 | 322 |
296 self._idl_names_cache = create_compiled_fs(self._GetIDLNames, 'idl-names') | 323 self._idl_names_cache = create_compiled_fs(self._GetIDLNames, 'idl-names') |
297 self._names_cache = create_compiled_fs(self._GetAllNames, 'names') | 324 self._names_cache = create_compiled_fs(self._GetAllNames, 'names') |
298 | 325 |
299 self._base_path = base_path | 326 self._base_path = base_path |
300 | 327 self._availability_data_source = availability_data_source_factory.Create() |
301 # These must be set later via the SetFooDataSourceFactory methods. | 328 # These must be set later via the SetFooDataSourceFactory methods. |
302 self._ref_resolver_factory = None | 329 self._ref_resolver_factory = None |
303 self._samples_data_source_factory = None | 330 self._samples_data_source_factory = None |
304 | 331 |
305 def SetSamplesDataSourceFactory(self, samples_data_source_factory): | 332 def SetSamplesDataSourceFactory(self, samples_data_source_factory): |
306 self._samples_data_source_factory = samples_data_source_factory | 333 self._samples_data_source_factory = samples_data_source_factory |
307 | 334 |
308 def SetReferenceResolverFactory(self, ref_resolver_factory): | 335 def SetReferenceResolverFactory(self, ref_resolver_factory): |
309 self._ref_resolver_factory = ref_resolver_factory | 336 self._ref_resolver_factory = ref_resolver_factory |
310 | 337 |
(...skipping 25 matching lines...) Expand all Loading... |
336 samples, | 363 samples, |
337 disable_refs) | 364 disable_refs) |
338 | 365 |
339 def _LoadPermissions(self, file_name, json_str): | 366 def _LoadPermissions(self, file_name, json_str): |
340 return json_parse.Parse(json_str) | 367 return json_parse.Parse(json_str) |
341 | 368 |
342 def _LoadJsonAPI(self, api, disable_refs): | 369 def _LoadJsonAPI(self, api, disable_refs): |
343 return _JSCModel( | 370 return _JSCModel( |
344 json_parse.Parse(api)[0], | 371 json_parse.Parse(api)[0], |
345 self._ref_resolver_factory.Create() if not disable_refs else None, | 372 self._ref_resolver_factory.Create() if not disable_refs else None, |
346 disable_refs).ToDict() | 373 disable_refs, |
| 374 self._availability_data_source).ToDict() |
347 | 375 |
348 def _LoadIdlAPI(self, api, disable_refs): | 376 def _LoadIdlAPI(self, api, disable_refs): |
349 idl = idl_parser.IDLParser().ParseData(api) | 377 idl = idl_parser.IDLParser().ParseData(api) |
350 return _JSCModel( | 378 return _JSCModel( |
351 idl_schema.IDLSchema(idl).process()[0], | 379 idl_schema.IDLSchema(idl).process()[0], |
352 self._ref_resolver_factory.Create() if not disable_refs else None, | 380 self._ref_resolver_factory.Create() if not disable_refs else None, |
353 disable_refs).ToDict() | 381 disable_refs, |
| 382 self._availability_data_source).ToDict() |
354 | 383 |
355 def _GetIDLNames(self, base_dir, apis): | 384 def _GetIDLNames(self, base_dir, apis): |
356 return self._GetExtNames(apis, ['idl']) | 385 return self._GetExtNames(apis, ['idl']) |
357 | 386 |
358 def _GetAllNames(self, base_dir, apis): | 387 def _GetAllNames(self, base_dir, apis): |
359 return self._GetExtNames(apis, ['json', 'idl']) | 388 return self._GetExtNames(apis, ['json', 'idl']) |
360 | 389 |
361 def _GetExtNames(self, apis, exts): | 390 def _GetExtNames(self, apis, exts): |
362 return [model.UnixName(os.path.splitext(api)[0]) for api in apis | 391 return [model.UnixName(os.path.splitext(api)[0]) for api in apis |
363 if os.path.splitext(api)[1][1:] in exts] | 392 if os.path.splitext(api)[1][1:] in exts] |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
423 return feature_data | 452 return feature_data |
424 | 453 |
425 def _GenerateHandlebarContext(self, handlebar_dict, path): | 454 def _GenerateHandlebarContext(self, handlebar_dict, path): |
426 handlebar_dict['permissions'] = self._GetFeatureData(path) | 455 handlebar_dict['permissions'] = self._GetFeatureData(path) |
427 handlebar_dict['samples'] = _LazySamplesGetter(path, self._samples) | 456 handlebar_dict['samples'] = _LazySamplesGetter(path, self._samples) |
428 return handlebar_dict | 457 return handlebar_dict |
429 | 458 |
430 def _GetAsSubdirectory(self, name): | 459 def _GetAsSubdirectory(self, name): |
431 if name.startswith('experimental_'): | 460 if name.startswith('experimental_'): |
432 parts = name[len('experimental_'):].split('_', 1) | 461 parts = name[len('experimental_'):].split('_', 1) |
433 parts[1] = 'experimental_%s' % parts[1] | 462 if len(parts) > 1: |
434 return '/'.join(parts) | 463 parts[1] = 'experimental_%s' % parts[1] |
| 464 return '/'.join(parts) |
| 465 else: |
| 466 return '%s/%s' % (parts[0], name) |
435 return name.replace('_', '/', 1) | 467 return name.replace('_', '/', 1) |
436 | 468 |
437 def get(self, key): | 469 def _DetermineNamesForGet(self, key): |
438 if key.endswith('.html') or key.endswith('.json') or key.endswith('.idl'): | 470 if key.endswith('.html') or key.endswith('.json') or key.endswith('.idl'): |
439 path, ext = os.path.splitext(key) | 471 path, ext = os.path.splitext(key) |
440 else: | 472 else: |
441 path = key | 473 path = key |
442 unix_name = model.UnixName(path) | 474 unix_name = model.UnixName(path) |
443 idl_names = self._idl_names_cache.GetFromFileListing(self._base_path) | |
444 names = self._names_cache.GetFromFileListing(self._base_path) | 475 names = self._names_cache.GetFromFileListing(self._base_path) |
445 if unix_name not in names and self._GetAsSubdirectory(unix_name) in names: | 476 if unix_name not in names and self._GetAsSubdirectory(unix_name) in names: |
446 unix_name = self._GetAsSubdirectory(unix_name) | 477 unix_name = self._GetAsSubdirectory(unix_name) |
| 478 return (path, unix_name) |
447 | 479 |
| 480 def _DetermineCacheForGet(self, unix_name): |
| 481 idl_names = self._idl_names_cache.GetFromFileListing(self._base_path) |
448 if self._disable_refs: | 482 if self._disable_refs: |
449 cache, ext = ( | 483 cache, ext = ( |
450 (self._idl_cache_no_refs, '.idl') if (unix_name in idl_names) else | 484 (self._idl_cache_no_refs, '.idl') if (unix_name in idl_names) else |
451 (self._json_cache_no_refs, '.json')) | 485 (self._json_cache_no_refs, '.json')) |
452 else: | 486 else: |
453 cache, ext = ((self._idl_cache, '.idl') if (unix_name in idl_names) else | 487 cache, ext = ((self._idl_cache, '.idl') if (unix_name in idl_names) else |
454 (self._json_cache, '.json')) | 488 (self._json_cache, '.json')) |
| 489 return (cache, ext) |
| 490 |
| 491 def get(self, key): |
| 492 path, unix_name = self._DetermineNamesForGet(key) |
| 493 cache, ext = self._DetermineCacheForGet(unix_name) |
455 return self._GenerateHandlebarContext( | 494 return self._GenerateHandlebarContext( |
456 cache.GetFromFile('%s/%s%s' % (self._base_path, unix_name, ext)), | 495 cache.GetFromFile('%s/%s%s' % (self._base_path, unix_name, ext)), |
457 path) | 496 path) |
OLD | NEW |