cygprofile: increase timeouts to allow showing web contents
[chromium-blink-merge.git] / chrome / common / extensions / docs / server2 / api_models.py
blob31c8a0757d473d1d4aa70f8b8a31700d0ca07c4d
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
3 # found in the LICENSE file.
5 import posixpath
7 from compiled_file_system import Cache, SingleFile, Unicode
8 from extensions_paths import API_PATHS
9 from features_bundle import HasParent, GetParentName
10 from file_system import FileNotFoundError
11 from future import All, Future, Race
12 from operator import itemgetter
13 from path_util import Join
14 from platform_util import PlatformToExtensionType
15 from schema_processor import SchemaProcessor, SchemaProcessorFactory
16 from third_party.json_schema_compiler.json_schema import DeleteNodes
17 from third_party.json_schema_compiler.model import Namespace, UnixName
20 def GetNodeCategories():
21 '''Returns a tuple of the possible categories a node may belong to.
22 '''
23 return ('types', 'functions', 'events', 'properties')
26 class ContentScriptAPI(object):
27 '''Represents an API available to content scripts.
29 |name| is the name of the API or API node this object represents.
30 |restrictedTo| is a list of dictionaries representing the nodes
31 of this API that are available to content scripts, or None if the
32 entire API is available to content scripts.
33 '''
34 def __init__(self, name):
35 self.name = name
36 self.restrictedTo = None
38 def __eq__(self, o):
39 return self.name == o.name and self.restrictedTo == o.restrictedTo
41 def __ne__(self, o):
42 return not (self == o)
44 def __repr__(self):
45 return ('<ContentScriptAPI name=%s, restrictedTo=%s>' %
46 (self.name, self.restrictedTo))
48 def __str__(self):
49 return repr(self)
52 class APIModels(object):
53 '''Tracks APIs and their Models.
54 '''
56 def __init__(self,
57 features_bundle,
58 compiled_fs_factory,
59 file_system,
60 object_store_creator,
61 platform,
62 schema_processor_factory):
63 self._features_bundle = features_bundle
64 self._platform = PlatformToExtensionType(platform)
65 self._model_cache = compiled_fs_factory.Create(
66 file_system, self._CreateAPIModel, APIModels, category=self._platform)
67 self._object_store = object_store_creator.Create(APIModels)
68 self._schema_processor = Future(callback=lambda:
69 schema_processor_factory.Create(False))
71 @Cache
72 @SingleFile
73 @Unicode
74 def _CreateAPIModel(self, path, data):
75 def does_not_include_platform(node):
76 return ('extension_types' in node and
77 node['extension_types'] != 'all' and
78 self._platform not in node['extension_types'])
80 schema = self._schema_processor.Get().Process(path, data)[0]
81 if not schema:
82 raise ValueError('No schema for %s' % path)
83 return Namespace(DeleteNodes(
84 schema, matcher=does_not_include_platform), path)
86 def GetNames(self):
87 # API names appear alongside some of their methods/events/etc in the
88 # features file. APIs are those which either implicitly or explicitly have
89 # no parent feature (e.g. app, app.window, and devtools.inspectedWindow are
90 # APIs; runtime.onConnectNative is not).
91 api_features = self._features_bundle.GetAPIFeatures().Get()
92 return [name for name, feature in api_features.iteritems()
93 if not HasParent(name, feature, api_features)]
95 def _GetPotentialPathsForModel(self, api_name):
96 '''Returns the list of file system paths that the model for |api_name|
97 might be located at.
98 '''
99 # By default |api_name| is assumed to be given without a path or extension,
100 # so combinations of known paths and extension types will be searched.
101 api_extensions = ('.json', '.idl')
102 api_paths = API_PATHS
104 # Callers sometimes include a file extension and/or prefix path with the
105 # |api_name| argument. We believe them and narrow the search space
106 # accordingly.
107 name, ext = posixpath.splitext(api_name)
108 if ext in api_extensions:
109 api_extensions = (ext,)
110 api_name = name
111 for api_path in api_paths:
112 if api_name.startswith(api_path):
113 api_name = api_name[len(api_path):]
114 api_paths = (api_path,)
115 break
117 # API names are given as declarativeContent and app.window but file names
118 # will be declarative_content and app_window.
119 file_name = UnixName(api_name).replace('.', '_')
120 # Devtools APIs are in API/devtools/ not API/, and have their
121 # "devtools" names removed from the file names.
122 basename = posixpath.basename(file_name)
123 if 'devtools_' in basename:
124 file_name = posixpath.join(
125 'devtools', file_name.replace(basename,
126 basename.replace('devtools_' , '')))
128 return [Join(path, file_name + ext) for ext in api_extensions
129 for path in api_paths]
131 def GetModel(self, api_name):
132 futures = [self._model_cache.GetFromFile(path)
133 for path in self._GetPotentialPathsForModel(api_name)]
134 return Race(futures, except_pass=(FileNotFoundError, ValueError))
136 def GetContentScriptAPIs(self):
137 '''Creates a dict of APIs and nodes supported by content scripts in
138 this format:
141 'extension': '<ContentScriptAPI name='extension',
142 restrictedTo=[{'node': 'onRequest'}]>',
146 content_script_apis_future = self._object_store.Get('content_script_apis')
147 api_features_future = self._features_bundle.GetAPIFeatures()
148 def resolve():
149 content_script_apis = content_script_apis_future.Get()
150 if content_script_apis is not None:
151 return content_script_apis
153 api_features = api_features_future.Get()
154 content_script_apis = {}
155 for name, feature in api_features.iteritems():
156 if 'content_script' not in feature.get('contexts', ()):
157 continue
158 parent = GetParentName(name, feature, api_features)
159 if parent is None:
160 content_script_apis[name] = ContentScriptAPI(name)
161 else:
162 # Creates a dict for the individual node.
163 node = {'node': name[len(parent) + 1:]}
164 if parent not in content_script_apis:
165 content_script_apis[parent] = ContentScriptAPI(parent)
166 if content_script_apis[parent].restrictedTo:
167 content_script_apis[parent].restrictedTo.append(node)
168 else:
169 content_script_apis[parent].restrictedTo = [node]
171 self._object_store.Set('content_script_apis', content_script_apis)
172 return content_script_apis
173 return Future(callback=resolve)
175 def Refresh(self):
176 futures = [self.GetModel(name) for name in self.GetNames()]
177 return All(futures, except_pass=(FileNotFoundError, ValueError))
179 def IterModels(self):
180 future_models = [(name, self.GetModel(name)) for name in self.GetNames()]
181 for name, future_model in future_models:
182 try:
183 model = future_model.Get()
184 except FileNotFoundError:
185 continue
186 if model:
187 yield name, model