OLD | NEW |
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 import posixpath | 5 import posixpath |
6 | 6 |
7 from compiled_file_system import SingleFile, Unicode | 7 from compiled_file_system import SingleFile, Unicode |
8 from docs_server_utils import StringIdentity | |
9 from extensions_paths import API_PATHS | 8 from extensions_paths import API_PATHS |
10 from features_bundle import HasParentFeature | 9 from features_bundle import HasParent, GetParentName |
11 from file_system import FileNotFoundError | 10 from file_system import FileNotFoundError |
12 from future import Collect, Future | 11 from future import Collect, Future |
| 12 from operator import itemgetter |
13 from platform_util import PlatformToExtensionType | 13 from platform_util import PlatformToExtensionType |
14 from schema_util import ProcessSchema | 14 from schema_util import ProcessSchema |
15 from third_party.json_schema_compiler.json_schema import DeleteNodes | 15 from third_party.json_schema_compiler.json_schema import DeleteNodes |
16 from third_party.json_schema_compiler.model import Namespace, UnixName | 16 from third_party.json_schema_compiler.model import Namespace, UnixName |
17 | 17 |
18 | 18 |
| 19 class ContentScriptAPI(object): |
| 20 '''Represents an API available to content scripts. |
| 21 |
| 22 |name| is the name of the API or API node this object represents. |
| 23 |restrictedTo| is a list of dictionaries representing the nodes |
| 24 of this API that are available to content scripts, or None if the |
| 25 entire API is available to content scripts. |
| 26 ''' |
| 27 def __init__(self, name): |
| 28 self.name = name |
| 29 self.restrictedTo = None |
| 30 |
| 31 def __eq__(self, o): |
| 32 return self.name == o.name and self.restrictedTo == o.restrictedTo |
| 33 |
| 34 def __ne__(self, o): |
| 35 return not (self == o) |
| 36 |
| 37 def __repr__(self): |
| 38 return '<ContentScriptAPI name=%s, restrictedTo=%s>' % (name, restrictedTo) |
| 39 |
| 40 def __str__(self): |
| 41 return repr(self) |
| 42 |
| 43 |
19 class APIModels(object): | 44 class APIModels(object): |
20 '''Tracks APIs and their Models. | 45 '''Tracks APIs and their Models. |
21 ''' | 46 ''' |
22 | 47 |
23 def __init__(self, | 48 def __init__(self, |
24 features_bundle, | 49 features_bundle, |
25 compiled_fs_factory, | 50 compiled_fs_factory, |
26 file_system, | 51 file_system, |
| 52 object_store_creator, |
27 platform): | 53 platform): |
28 self._features_bundle = features_bundle | 54 self._features_bundle = features_bundle |
29 self._platform = PlatformToExtensionType(platform) | 55 self._platform = PlatformToExtensionType(platform) |
30 self._model_cache = compiled_fs_factory.Create( | 56 self._model_cache = compiled_fs_factory.Create( |
31 file_system, self._CreateAPIModel, APIModels, category=self._platform) | 57 file_system, self._CreateAPIModel, APIModels, category=self._platform) |
| 58 self._object_store = object_store_creator.Create(APIModels) |
32 | 59 |
33 @SingleFile | 60 @SingleFile |
34 @Unicode | 61 @Unicode |
35 def _CreateAPIModel(self, path, data): | 62 def _CreateAPIModel(self, path, data): |
36 def does_not_include_platform(node): | 63 def does_not_include_platform(node): |
37 return ('extension_types' in node and | 64 return ('extension_types' in node and |
38 node['extension_types'] != 'all' and | 65 node['extension_types'] != 'all' and |
39 self._platform not in node['extension_types']) | 66 self._platform not in node['extension_types']) |
40 | 67 |
41 schema = ProcessSchema(path, data)[0] | 68 schema = ProcessSchema(path, data)[0] |
42 if not schema: | 69 if not schema: |
43 raise ValueError('No schema for %s' % path) | 70 raise ValueError('No schema for %s' % path) |
44 return Namespace(DeleteNodes( | 71 return Namespace(DeleteNodes( |
45 schema, matcher=does_not_include_platform), schema['namespace']) | 72 schema, matcher=does_not_include_platform), schema['namespace']) |
46 | 73 |
47 def GetNames(self): | 74 def GetNames(self): |
48 # API names appear alongside some of their methods/events/etc in the | 75 # API names appear alongside some of their methods/events/etc in the |
49 # features file. APIs are those which either implicitly or explicitly have | 76 # features file. APIs are those which either implicitly or explicitly have |
50 # no parent feature (e.g. app, app.window, and devtools.inspectedWindow are | 77 # no parent feature (e.g. app, app.window, and devtools.inspectedWindow are |
51 # APIs; runtime.onConnectNative is not). | 78 # APIs; runtime.onConnectNative is not). |
52 api_features = self._features_bundle.GetAPIFeatures().Get() | 79 api_features = self._features_bundle.GetAPIFeatures().Get() |
53 return [name for name, feature in api_features.iteritems() | 80 return [name for name, feature in api_features.iteritems() |
54 if not HasParentFeature(name, feature, api_features)] | 81 if not HasParent(name, feature, api_features)] |
55 | 82 |
56 def GetModel(self, api_name): | 83 def GetModel(self, api_name): |
57 # By default |api_name| is assumed to be given without a path or extension, | 84 # By default |api_name| is assumed to be given without a path or extension, |
58 # so combinations of known paths and extension types will be searched. | 85 # so combinations of known paths and extension types will be searched. |
59 api_extensions = ('.json', '.idl') | 86 api_extensions = ('.json', '.idl') |
60 api_paths = API_PATHS | 87 api_paths = API_PATHS |
61 | 88 |
62 # Callers sometimes include a file extension and/or prefix path with the | 89 # Callers sometimes include a file extension and/or prefix path with the |
63 # |api_name| argument. We believe them and narrow the search space | 90 # |api_name| argument. We believe them and narrow the search space |
64 # accordingly. | 91 # accordingly. |
(...skipping 25 matching lines...) Expand all Loading... |
90 def resolve(): | 117 def resolve(): |
91 for future in futures: | 118 for future in futures: |
92 try: | 119 try: |
93 return future.Get() | 120 return future.Get() |
94 # Either the file wasn't found or there was no schema for the file | 121 # Either the file wasn't found or there was no schema for the file |
95 except (FileNotFoundError, ValueError): pass | 122 except (FileNotFoundError, ValueError): pass |
96 # Propagate the first error if neither were found. | 123 # Propagate the first error if neither were found. |
97 futures[0].Get() | 124 futures[0].Get() |
98 return Future(callback=resolve) | 125 return Future(callback=resolve) |
99 | 126 |
| 127 def GetContentScriptAPIs(self): |
| 128 '''Creates a dict of APIs and nodes supported by content scripts in |
| 129 this format: |
| 130 |
| 131 { |
| 132 'extension': '<ContentScriptAPI name='extension', |
| 133 restrictedTo=[{'node': 'onRequest'}]>', |
| 134 ... |
| 135 } |
| 136 ''' |
| 137 content_script_apis_future = self._object_store.Get('content_script_apis') |
| 138 api_features_future = self._features_bundle.GetAPIFeatures() |
| 139 def resolve(): |
| 140 content_script_apis = content_script_apis_future.Get() |
| 141 if content_script_apis is not None: |
| 142 return content_script_apis |
| 143 |
| 144 api_features = api_features_future.Get() |
| 145 content_script_apis = {} |
| 146 for name, feature in api_features.iteritems(): |
| 147 if 'content_script' not in feature.get('contexts', ()): |
| 148 continue |
| 149 parent = GetParentName(name, feature, api_features) |
| 150 if parent is None: |
| 151 content_script_apis[name] = ContentScriptAPI(name) |
| 152 else: |
| 153 # Creates a dict for the individual node. |
| 154 node = {'node': name[len(parent) + 1:]} |
| 155 if parent not in content_script_apis: |
| 156 content_script_apis[parent] = ContentScriptAPI(parent) |
| 157 if content_script_apis[parent].restrictedTo: |
| 158 content_script_apis[parent].restrictedTo.append(node) |
| 159 else: |
| 160 content_script_apis[parent].restrictedTo = [node] |
| 161 |
| 162 self._object_store.Set('content_script_apis', content_script_apis) |
| 163 return content_script_apis |
| 164 return Future(callback=resolve) |
| 165 |
100 def Cron(self): | 166 def Cron(self): |
101 futures = [self.GetModel(name) for name in self.GetNames()] | 167 futures = [self.GetModel(name) for name in self.GetNames()] |
102 return Collect(futures, except_pass=(FileNotFoundError, ValueError)) | 168 return Collect(futures, except_pass=(FileNotFoundError, ValueError)) |
103 | 169 |
104 def IterModels(self): | 170 def IterModels(self): |
105 future_models = [(name, self.GetModel(name)) for name in self.GetNames()] | 171 future_models = [(name, self.GetModel(name)) for name in self.GetNames()] |
106 for name, future_model in future_models: | 172 for name, future_model in future_models: |
107 try: | 173 try: |
108 model = future_model.Get() | 174 model = future_model.Get() |
109 except FileNotFoundError: | 175 except FileNotFoundError: |
110 continue | 176 continue |
111 if model: | 177 if model: |
112 yield name, model | 178 yield name, model |
OLD | NEW |