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 from copy import copy | 5 from copy import copy |
6 import logging | 6 import logging |
7 import os | 7 import os |
8 import posixpath | 8 import posixpath |
9 | 9 |
10 from data_source import DataSource | 10 from data_source import DataSource |
11 from docs_server_utils import StringIdentity | 11 from docs_server_utils import StringIdentity |
12 from environment import IsPreviewServer | 12 from environment import IsPreviewServer |
13 from extensions_paths import JSON_TEMPLATES, PRIVATE_TEMPLATES | 13 from extensions_paths import JSON_TEMPLATES, PRIVATE_TEMPLATES |
14 from file_system import FileNotFoundError | 14 from file_system import FileNotFoundError |
15 from future import Future, Collect | 15 from future import Future, Collect |
| 16 from platform_util import GetPlatforms |
16 import third_party.json_schema_compiler.json_parse as json_parse | 17 import third_party.json_schema_compiler.json_parse as json_parse |
17 import third_party.json_schema_compiler.model as model | 18 import third_party.json_schema_compiler.model as model |
18 from environment import IsPreviewServer | 19 from environment import IsPreviewServer |
19 from third_party.json_schema_compiler.memoize import memoize | 20 from third_party.json_schema_compiler.memoize import memoize |
20 | 21 |
21 | 22 |
22 def _CreateId(node, prefix): | 23 def _CreateId(node, prefix): |
23 if node.parent is not None and not isinstance(node.parent, model.Namespace): | 24 if node.parent is not None and not isinstance(node.parent, model.Namespace): |
24 return '-'.join([prefix, node.parent.simple_name, node.simple_name]) | 25 return '-'.join([prefix, node.parent.simple_name, node.simple_name]) |
25 return '-'.join([prefix, node.simple_name]) | 26 return '-'.join([prefix, node.simple_name]) |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
64 return _GetByNameDict(event_list[0]) | 65 return _GetByNameDict(event_list[0]) |
65 | 66 |
66 | 67 |
67 class _JSCModel(object): | 68 class _JSCModel(object): |
68 '''Uses a Model from the JSON Schema Compiler and generates a dict that | 69 '''Uses a Model from the JSON Schema Compiler and generates a dict that |
69 a Handlebar template can use for a data source. | 70 a Handlebar template can use for a data source. |
70 ''' | 71 ''' |
71 | 72 |
72 def __init__(self, | 73 def __init__(self, |
73 namespace, | 74 namespace, |
74 availability_finder, | 75 availability, |
75 json_cache, | 76 json_cache, |
76 template_cache, | 77 template_cache, |
77 features_bundle, | 78 features_bundle, |
78 event_byname_function): | 79 event_byname_future): |
79 self._availability_finder = availability_finder | 80 self._availability = availability |
80 self._api_availabilities = json_cache.GetFromFile( | 81 self._api_availabilities = json_cache.GetFromFile( |
81 posixpath.join(JSON_TEMPLATES, 'api_availabilities.json')) | 82 posixpath.join(JSON_TEMPLATES, 'api_availabilities.json')) |
82 self._intro_tables = json_cache.GetFromFile( | 83 self._intro_tables = json_cache.GetFromFile( |
83 posixpath.join(JSON_TEMPLATES, 'intro_tables.json')) | 84 posixpath.join(JSON_TEMPLATES, 'intro_tables.json')) |
84 self._api_features = features_bundle.GetAPIFeatures() | 85 self._api_features = features_bundle.GetAPIFeatures() |
85 self._template_cache = template_cache | 86 self._template_cache = template_cache |
86 self._event_byname_function = event_byname_function | 87 self._event_byname_future = event_byname_future |
87 self._namespace = namespace | 88 self._namespace = namespace |
88 | 89 |
89 def _GetLink(self, link): | 90 def _GetLink(self, link): |
90 ref = link if '.' in link else (self._namespace.name + '.' + link) | 91 ref = link if '.' in link else (self._namespace.name + '.' + link) |
91 return { 'ref': ref, 'text': link, 'name': link } | 92 return { 'ref': ref, 'text': link, 'name': link } |
92 | 93 |
93 def ToDict(self): | 94 def ToDict(self): |
94 if self._namespace is None: | 95 if self._namespace is None: |
95 return {} | 96 return {} |
96 chrome_dot_name = 'chrome.%s' % self._namespace.name | 97 chrome_dot_name = 'chrome.%s' % self._namespace.name |
(...skipping 11 matching lines...) Expand all Loading... |
108 'properties': self._GenerateProperties(self._namespace.properties), | 109 'properties': self._GenerateProperties(self._namespace.properties), |
109 'introList': self._GetIntroTableList(), | 110 'introList': self._GetIntroTableList(), |
110 'channelWarning': self._GetChannelWarning(), | 111 'channelWarning': self._GetChannelWarning(), |
111 } | 112 } |
112 if self._namespace.deprecated: | 113 if self._namespace.deprecated: |
113 as_dict['deprecated'] = self._namespace.deprecated | 114 as_dict['deprecated'] = self._namespace.deprecated |
114 | 115 |
115 as_dict['byName'] = _GetByNameDict(as_dict) | 116 as_dict['byName'] = _GetByNameDict(as_dict) |
116 return as_dict | 117 return as_dict |
117 | 118 |
118 def _GetAPIAvailability(self): | |
119 return self._availability_finder.GetAPIAvailability(self._namespace.name) | |
120 | |
121 def _GetChannelWarning(self): | 119 def _GetChannelWarning(self): |
122 if not self._IsExperimental(): | 120 if not self._IsExperimental(): |
123 return { self._GetAPIAvailability().channel_info.channel: True } | 121 return { |
| 122 self._availability.channel_info.channel: True |
| 123 } |
124 return None | 124 return None |
125 | 125 |
126 def _IsExperimental(self): | 126 def _IsExperimental(self): |
127 return self._namespace.name.startswith('experimental') | 127 return self._namespace.name.startswith('experimental') |
128 | 128 |
129 def _GenerateTypes(self, types): | 129 def _GenerateTypes(self, types): |
130 return [self._GenerateType(t) for t in types] | 130 return [self._GenerateType(t) for t in types] |
131 | 131 |
132 def _GenerateType(self, type_): | 132 def _GenerateType(self, type_): |
133 type_dict = { | 133 type_dict = { |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
183 for condition in event.conditions], | 183 for condition in event.conditions], |
184 'actions': [self._GetLink(action) for action in event.actions], | 184 'actions': [self._GetLink(action) for action in event.actions], |
185 'supportsRules': event.supports_rules, | 185 'supportsRules': event.supports_rules, |
186 'supportsListeners': event.supports_listeners, | 186 'supportsListeners': event.supports_listeners, |
187 'properties': [], | 187 'properties': [], |
188 'id': _CreateId(event, 'event'), | 188 'id': _CreateId(event, 'event'), |
189 'byName': {}, | 189 'byName': {}, |
190 } | 190 } |
191 self._AddCommonProperties(event_dict, event) | 191 self._AddCommonProperties(event_dict, event) |
192 # Add the Event members to each event in this object. | 192 # Add the Event members to each event in this object. |
193 if self._event_byname_function: | 193 if self._event_byname_future: |
194 event_dict['byName'].update(self._event_byname_function()) | 194 event_dict['byName'].update(self._event_byname_future.Get()) |
195 # We need to create the method description for addListener based on the | 195 # We need to create the method description for addListener based on the |
196 # information stored in |event|. | 196 # information stored in |event|. |
197 if event.supports_listeners: | 197 if event.supports_listeners: |
198 callback_object = model.Function(parent=event, | 198 callback_object = model.Function(parent=event, |
199 name='callback', | 199 name='callback', |
200 json={}, | 200 json={}, |
201 namespace=event.parent, | 201 namespace=event.parent, |
202 origin='') | 202 origin='') |
203 callback_object.params = event.params | 203 callback_object.params = event.params |
204 if event.callback: | 204 if event.callback: |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
347 } | 347 } |
348 | 348 |
349 def _GetIntroAvailabilityRow(self): | 349 def _GetIntroAvailabilityRow(self): |
350 ''' Generates the 'Availability' row data for an API intro table. | 350 ''' Generates the 'Availability' row data for an API intro table. |
351 ''' | 351 ''' |
352 if self._IsExperimental(): | 352 if self._IsExperimental(): |
353 status = 'experimental' | 353 status = 'experimental' |
354 version = None | 354 version = None |
355 scheduled = None | 355 scheduled = None |
356 else: | 356 else: |
357 availability = self._GetAPIAvailability() | 357 status = self._availability.channel_info.channel |
358 status = availability.channel_info.channel | 358 version = self._availability.channel_info.version |
359 version = availability.channel_info.version | 359 scheduled = self._availability.scheduled |
360 scheduled = availability.scheduled | |
361 return { | 360 return { |
362 'title': 'Availability', | 361 'title': 'Availability', |
363 'content': [{ | 362 'content': [{ |
364 'partial': self._template_cache.GetFromFile( | 363 'partial': self._template_cache.GetFromFile( |
365 posixpath.join(PRIVATE_TEMPLATES, | 364 posixpath.join(PRIVATE_TEMPLATES, |
366 'intro_tables', | 365 'intro_tables', |
367 '%s_message.html' % status)).Get(), | 366 '%s_message.html' % status)).Get(), |
368 'version': version, | 367 'version': version, |
369 'scheduled': scheduled | 368 'scheduled': scheduled |
370 }] | 369 }] |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
468 | 467 |
469 class APIDataSource(DataSource): | 468 class APIDataSource(DataSource): |
470 '''This class fetches and loads JSON APIs from the FileSystem passed in with | 469 '''This class fetches and loads JSON APIs from the FileSystem passed in with |
471 |compiled_fs_factory|, so the APIs can be plugged into templates. | 470 |compiled_fs_factory|, so the APIs can be plugged into templates. |
472 ''' | 471 ''' |
473 def __init__(self, server_instance, request): | 472 def __init__(self, server_instance, request): |
474 file_system = server_instance.host_file_system_provider.GetTrunk() | 473 file_system = server_instance.host_file_system_provider.GetTrunk() |
475 self._json_cache = server_instance.compiled_fs_factory.ForJson(file_system) | 474 self._json_cache = server_instance.compiled_fs_factory.ForJson(file_system) |
476 self._template_cache = server_instance.compiled_fs_factory.ForTemplates( | 475 self._template_cache = server_instance.compiled_fs_factory.ForTemplates( |
477 file_system) | 476 file_system) |
478 self._availability_finder = server_instance.availability_finder | 477 self._platform_bundle = server_instance.platform_bundle |
479 self._api_models = server_instance.api_models | |
480 self._features_bundle = server_instance.features_bundle | |
481 self._model_cache = server_instance.object_store_creator.Create( | 478 self._model_cache = server_instance.object_store_creator.Create( |
482 APIDataSource, | 479 APIDataSource, |
483 # Update the models when any of templates, APIs, or Features change. | 480 # Update the models when any of templates, APIs, or Features change. |
484 category=StringIdentity(self._json_cache.GetIdentity(), | 481 category=StringIdentity(self._json_cache.GetIdentity(), |
485 self._template_cache.GetIdentity(), | 482 self._template_cache.GetIdentity(), |
486 self._api_models.GetIdentity(), | 483 self._platform_bundle.GetIdentity())) |
487 self._features_bundle.GetIdentity())) | |
488 | 484 |
489 # This caches the result of _LoadEventByName. | 485 # This caches the result of _LoadEventByName. |
490 self._event_byname = None | 486 self._event_byname_futures = {} |
491 self._samples = server_instance.samples_data_source_factory.Create(request) | 487 self._samples = server_instance.samples_data_source_factory.Create(request) |
492 | 488 |
493 def _LoadEventByName(self): | 489 def _LoadEventByName(self, platform): |
494 '''All events have some members in common. We source their description | 490 '''All events have some members in common. We source their description |
495 from Event in events.json. | 491 from Event in events.json. |
496 ''' | 492 ''' |
497 if self._event_byname is None: | 493 if platform not in self._event_byname_futures: |
498 self._event_byname = _GetEventByNameFromEvents( | 494 future = self._GetSchemaModel(platform, 'events') |
499 self._GetSchemaModel('events').Get()) | 495 self._event_byname_futures[platform] = Future( |
500 return self._event_byname | 496 callback=lambda: _GetEventByNameFromEvents(future.Get())) |
| 497 return self._event_byname_futures[platform] |
501 | 498 |
502 def _GetSchemaModel(self, api_name): | 499 def _GetSchemaModel(self, platform, api_name): |
503 jsc_model_future = self._model_cache.Get(api_name) | 500 object_store_key = '/'.join((platform, api_name)) |
504 model_future = self._api_models.GetModel(api_name) | 501 jsc_model_future = self._model_cache.Get(object_store_key) |
| 502 model_future = self._platform_bundle.GetAPIModels(platform).GetModel( |
| 503 api_name) |
505 def resolve(): | 504 def resolve(): |
506 jsc_model = jsc_model_future.Get() | 505 jsc_model = jsc_model_future.Get() |
507 if jsc_model is None: | 506 if jsc_model is None: |
508 jsc_model = _JSCModel( | 507 jsc_model = _JSCModel( |
509 model_future.Get(), | 508 model_future.Get(), |
510 self._availability_finder, | 509 self._platform_bundle.GetAvailabilityFinder( |
| 510 platform).GetAPIAvailability(api_name), |
511 self._json_cache, | 511 self._json_cache, |
512 self._template_cache, | 512 self._template_cache, |
513 self._features_bundle, | 513 self._platform_bundle.GetFeaturesBundle(platform), |
514 self._LoadEventByName).ToDict() | 514 self._LoadEventByName(platform)).ToDict() |
515 self._model_cache.Set(api_name, jsc_model) | 515 self._model_cache.Set(object_store_key, jsc_model) |
516 return jsc_model | 516 return jsc_model |
517 return Future(callback=resolve) | 517 return Future(callback=resolve) |
518 | 518 |
519 def _GetImpl(self, api_name): | 519 def _GetImpl(self, platform, api_name): |
520 handlebar_dict_future = self._GetSchemaModel(api_name) | 520 handlebar_dict_future = self._GetSchemaModel(platform, api_name) |
521 def resolve(): | 521 def resolve(): |
522 handlebar_dict = handlebar_dict_future.Get() | 522 handlebar_dict = handlebar_dict_future.Get() |
523 # Parsing samples on the preview server takes seconds and doesn't add | 523 # Parsing samples on the preview server takes seconds and doesn't add |
524 # anything. Don't do it. | 524 # anything. Don't do it. |
525 if not IsPreviewServer(): | 525 if not IsPreviewServer(): |
526 handlebar_dict['samples'] = _LazySamplesGetter( | 526 handlebar_dict['samples'] = _LazySamplesGetter( |
527 handlebar_dict['name'], | 527 handlebar_dict['name'], |
528 self._samples) | 528 self._samples) |
529 return handlebar_dict | 529 return handlebar_dict |
530 return Future(callback=resolve) | 530 return Future(callback=resolve) |
531 | 531 |
532 def get(self, api_name): | 532 def get(self, platform): |
533 return self._GetImpl(api_name).Get() | 533 '''Return a getter object so that templates can perform lookups such |
| 534 as apis.extensions.runtime. |
| 535 ''' |
| 536 getter = lambda: 0 |
| 537 getter.get = lambda api_name: self._GetImpl(platform, api_name).Get() |
| 538 return getter |
534 | 539 |
535 def Cron(self): | 540 def Cron(self): |
536 futures = [self._GetImpl(name) for name in self._api_models.GetNames()] | 541 futures = [] |
| 542 for platform in GetPlatforms(): |
| 543 futures += [self._GetImpl(platform, name) |
| 544 for name in self._platform_bundle.GetAPIModels(platform).GetNames()] |
537 return Collect(futures, except_pass=FileNotFoundError) | 545 return Collect(futures, except_pass=FileNotFoundError) |
OLD | NEW |