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 extensions_paths import API_PATHS | 8 from extensions_paths import API_PATHS |
9 from features_bundle import HasParent, GetParentName | 9 from features_bundle import HasParent, GetParentName |
10 from file_system import FileNotFoundError | 10 from file_system import FileNotFoundError |
11 from future import All, Future | 11 from future import All, Future, Race |
12 from operator import itemgetter | 12 from operator import itemgetter |
| 13 from path_util import Join |
13 from platform_util import PlatformToExtensionType | 14 from platform_util import PlatformToExtensionType |
14 from schema_util import ProcessSchema | 15 from schema_util import ProcessSchema |
15 from third_party.json_schema_compiler.json_schema import DeleteNodes | 16 from third_party.json_schema_compiler.json_schema import DeleteNodes |
16 from third_party.json_schema_compiler.model import Namespace, UnixName | 17 from third_party.json_schema_compiler.model import Namespace, UnixName |
17 | 18 |
18 | 19 |
19 def GetNodeCategories(): | 20 def GetNodeCategories(): |
20 '''Returns a tuple of the possible categories a node may belong to. | 21 '''Returns a tuple of the possible categories a node may belong to. |
21 ''' | 22 ''' |
22 return ('types', 'functions', 'events', 'properties') | 23 return ('types', 'functions', 'events', 'properties') |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
79 | 80 |
80 def GetNames(self): | 81 def GetNames(self): |
81 # API names appear alongside some of their methods/events/etc in the | 82 # API names appear alongside some of their methods/events/etc in the |
82 # features file. APIs are those which either implicitly or explicitly have | 83 # features file. APIs are those which either implicitly or explicitly have |
83 # no parent feature (e.g. app, app.window, and devtools.inspectedWindow are | 84 # no parent feature (e.g. app, app.window, and devtools.inspectedWindow are |
84 # APIs; runtime.onConnectNative is not). | 85 # APIs; runtime.onConnectNative is not). |
85 api_features = self._features_bundle.GetAPIFeatures().Get() | 86 api_features = self._features_bundle.GetAPIFeatures().Get() |
86 return [name for name, feature in api_features.iteritems() | 87 return [name for name, feature in api_features.iteritems() |
87 if not HasParent(name, feature, api_features)] | 88 if not HasParent(name, feature, api_features)] |
88 | 89 |
89 def GetModel(self, api_name): | 90 def _GetPotentialPathsForModel(self, api_name): |
| 91 '''Returns the list of file system paths that the model for |api_name| |
| 92 might be located at. |
| 93 ''' |
90 # By default |api_name| is assumed to be given without a path or extension, | 94 # By default |api_name| is assumed to be given without a path or extension, |
91 # so combinations of known paths and extension types will be searched. | 95 # so combinations of known paths and extension types will be searched. |
92 api_extensions = ('.json', '.idl') | 96 api_extensions = ('.json', '.idl') |
93 api_paths = API_PATHS | 97 api_paths = API_PATHS |
94 | 98 |
95 # Callers sometimes include a file extension and/or prefix path with the | 99 # Callers sometimes include a file extension and/or prefix path with the |
96 # |api_name| argument. We believe them and narrow the search space | 100 # |api_name| argument. We believe them and narrow the search space |
97 # accordingly. | 101 # accordingly. |
98 name, ext = posixpath.splitext(api_name) | 102 name, ext = posixpath.splitext(api_name) |
99 if ext in api_extensions: | 103 if ext in api_extensions: |
100 api_extensions = (ext,) | 104 api_extensions = (ext,) |
101 api_name = name | 105 api_name = name |
102 for api_path in api_paths: | 106 for api_path in api_paths: |
103 if api_name.startswith(api_path): | 107 if api_name.startswith(api_path): |
104 api_name = api_name[len(api_path):] | 108 api_name = api_name[len(api_path):] |
105 api_paths = (api_path,) | 109 api_paths = (api_path,) |
106 break | 110 break |
107 | 111 |
108 # API names are given as declarativeContent and app.window but file names | 112 # API names are given as declarativeContent and app.window but file names |
109 # will be declarative_content and app_window. | 113 # will be declarative_content and app_window. |
110 file_name = UnixName(api_name).replace('.', '_') | 114 file_name = UnixName(api_name).replace('.', '_') |
111 # Devtools APIs are in API/devtools/ not API/, and have their | 115 # Devtools APIs are in API/devtools/ not API/, and have their |
112 # "devtools" names removed from the file names. | 116 # "devtools" names removed from the file names. |
113 basename = posixpath.basename(file_name) | 117 basename = posixpath.basename(file_name) |
114 if 'devtools_' in basename: | 118 if 'devtools_' in basename: |
115 file_name = posixpath.join( | 119 file_name = posixpath.join( |
116 'devtools', file_name.replace(basename, | 120 'devtools', file_name.replace(basename, |
117 basename.replace('devtools_' , ''))) | 121 basename.replace('devtools_' , ''))) |
118 | 122 |
119 futures = [self._model_cache.GetFromFile( | 123 return [Join(path, file_name + ext) for ext in api_extensions |
120 posixpath.join(path, '%s%s' % (file_name, ext))) | 124 for path in api_paths] |
121 for ext in api_extensions | 125 |
122 for path in api_paths] | 126 def GetModel(self, api_name): |
123 def resolve(): | 127 futures = [self._model_cache.GetFromFile(path) |
124 for future in futures: | 128 for path in self._GetPotentialPathsForModel(api_name)] |
125 try: | 129 return Race(futures, except_pass=(FileNotFoundError, ValueError)) |
126 return future.Get() | |
127 # Either the file wasn't found or there was no schema for the file | |
128 except (FileNotFoundError, ValueError): pass | |
129 # Propagate the first error if neither were found. | |
130 futures[0].Get() | |
131 return Future(callback=resolve) | |
132 | 130 |
133 def GetContentScriptAPIs(self): | 131 def GetContentScriptAPIs(self): |
134 '''Creates a dict of APIs and nodes supported by content scripts in | 132 '''Creates a dict of APIs and nodes supported by content scripts in |
135 this format: | 133 this format: |
136 | 134 |
137 { | 135 { |
138 'extension': '<ContentScriptAPI name='extension', | 136 'extension': '<ContentScriptAPI name='extension', |
139 restrictedTo=[{'node': 'onRequest'}]>', | 137 restrictedTo=[{'node': 'onRequest'}]>', |
140 ... | 138 ... |
141 } | 139 } |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
175 | 173 |
176 def IterModels(self): | 174 def IterModels(self): |
177 future_models = [(name, self.GetModel(name)) for name in self.GetNames()] | 175 future_models = [(name, self.GetModel(name)) for name in self.GetNames()] |
178 for name, future_model in future_models: | 176 for name, future_model in future_models: |
179 try: | 177 try: |
180 model = future_model.Get() | 178 model = future_model.Get() |
181 except FileNotFoundError: | 179 except FileNotFoundError: |
182 continue | 180 continue |
183 if model: | 181 if model: |
184 yield name, model | 182 yield name, model |
OLD | NEW |