OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 | 2 |
3 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 3 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
6 """Server for viewing the compiled C++ code from tools/json_schema_compiler. | 6 """Server for viewing the compiled C++ code from tools/json_schema_compiler. |
7 """ | 7 """ |
8 | 8 |
9 import cc_generator | 9 import cc_generator |
10 import code | 10 import code |
11 import cpp_type_generator | 11 import cpp_type_generator |
12 import cpp_util | 12 import cpp_util |
13 import h_generator | 13 import h_generator |
14 import idl_schema | 14 import idl_schema |
15 import json_schema | 15 import json_schema |
16 import model | 16 import model |
17 import optparse | 17 import optparse |
18 import os | 18 import os |
19 import schema_loader | 19 import shlex |
20 import urlparse | 20 import urlparse |
21 from highlighters import ( | 21 from highlighters import ( |
22 pygments_highlighter, none_highlighter, hilite_me_highlighter) | 22 pygments_highlighter, none_highlighter, hilite_me_highlighter) |
23 from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer | 23 from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer |
| 24 from cpp_namespace_environment import CppNamespaceEnvironment |
| 25 from schema_loader import SchemaLoader |
24 | 26 |
25 | 27 |
26 class CompilerHandler(BaseHTTPRequestHandler): | 28 class CompilerHandler(BaseHTTPRequestHandler): |
27 """A HTTPRequestHandler that outputs the result of tools/json_schema_compiler. | 29 """A HTTPRequestHandler that outputs the result of tools/json_schema_compiler. |
28 """ | 30 """ |
29 def do_GET(self): | 31 def do_GET(self): |
30 parsed_url = urlparse.urlparse(self.path) | 32 parsed_url = urlparse.urlparse(self.path) |
31 request_path = self._GetRequestPath(parsed_url) | 33 request_path = self._GetRequestPath(parsed_url) |
32 | 34 |
33 chromium_favicon = 'http://codereview.chromium.org/static/favicon.ico' | 35 chromium_favicon = 'http://codereview.chromium.org/static/favicon.ico' |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
169 var cachedValue = localStorage[highlighterStyle.id + 'Value']; | 171 var cachedValue = localStorage[highlighterStyle.id + 'Value']; |
170 if (cachedValue) | 172 if (cachedValue) |
171 highlighterStyle.value = cachedValue; | 173 highlighterStyle.value = cachedValue; |
172 }); | 174 }); |
173 })(); | 175 })(); |
174 | 176 |
175 window.addEventListener('hashchange', updateEverything, false); | 177 window.addEventListener('hashchange', updateEverything, false); |
176 updateEverything(); | 178 updateEverything(); |
177 </script>''') | 179 </script>''') |
178 | 180 |
179 def _LoadModel(self, basedir, name): | |
180 """Loads and returns the model for the |name| API from either its JSON or | |
181 IDL file, e.g. | |
182 name=contextMenus will be loaded from |basedir|/context_menus.json, | |
183 name=alarms will be loaded from |basedir|/alarms.idl. | |
184 """ | |
185 loaders = { | |
186 'json': json_schema.Load, | |
187 'idl': idl_schema.Load | |
188 } | |
189 # APIs are referred to like "webRequest" but that's in a file | |
190 # "web_request.json" so we need to unixify the name. | |
191 unix_name = model.UnixName(name) | |
192 for loader_ext, loader_fn in loaders.items(): | |
193 file_path = '%s/%s.%s' % (basedir, unix_name, loader_ext) | |
194 if os.path.exists(file_path): | |
195 # For historical reasons these files contain a singleton list with the | |
196 # model, so just return that single object. | |
197 return (loader_fn(file_path)[0], file_path) | |
198 raise ValueError('File for model "%s" not found' % name) | |
199 | |
200 def _ShowCompiledFile(self, parsed_url, head, body): | 181 def _ShowCompiledFile(self, parsed_url, head, body): |
201 """Show the compiled version of a json or idl file given the path to the | 182 """Show the compiled version of a json or idl file given the path to the |
202 compiled file. | 183 compiled file. |
203 """ | 184 """ |
204 api_model = model.Model() | 185 api_model = model.Model() |
205 | 186 |
206 request_path = self._GetRequestPath(parsed_url) | 187 request_path = self._GetRequestPath(parsed_url) |
207 (file_root, file_ext) = os.path.splitext(request_path) | 188 (file_root, file_ext) = os.path.splitext(request_path) |
208 (filedir, filename) = os.path.split(file_root) | 189 (filedir, filename) = os.path.split(file_root) |
209 | 190 |
| 191 schema_loader = SchemaLoader("./", |
| 192 filedir, |
| 193 self.server.include_rules, |
| 194 self.server.cpp_namespace_pattern) |
210 try: | 195 try: |
211 # Get main file. | 196 # Get main file. |
212 (api_def, file_path) = self._LoadModel(filedir, filename) | 197 namespace = schema_loader.ResolveNamespace(filename) |
213 namespace = api_model.AddNamespace(api_def, file_path) | |
214 type_generator = cpp_type_generator.CppTypeGenerator( | 198 type_generator = cpp_type_generator.CppTypeGenerator( |
215 api_model, | 199 api_model, |
216 schema_loader.SchemaLoader(filedir), | 200 schema_loader, |
217 namespace) | 201 namespace) |
218 | 202 |
219 # Get the model's dependencies. | |
220 for dependency in api_def.get('dependencies', []): | |
221 # Dependencies can contain : in which case they don't refer to APIs, | |
222 # rather, permissions or manifest keys. | |
223 if ':' in dependency: | |
224 continue | |
225 (api_def, file_path) = self._LoadModel(filedir, dependency) | |
226 referenced_namespace = api_model.AddNamespace(api_def, file_path) | |
227 if referenced_namespace: | |
228 type_generator.AddNamespace(referenced_namespace, | |
229 cpp_util.Classname(referenced_namespace.name).lower()) | |
230 | |
231 # Generate code | 203 # Generate code |
232 cpp_namespace = 'generated_api_schemas' | 204 cpp_namespace = 'generated_api_schemas' |
233 if file_ext == '.h': | 205 if file_ext == '.h': |
234 cpp_code = (h_generator.HGenerator(type_generator, cpp_namespace) | 206 cpp_code = (h_generator.HGenerator(type_generator) |
235 .Generate(namespace).Render()) | 207 .Generate(namespace).Render()) |
236 elif file_ext == '.cc': | 208 elif file_ext == '.cc': |
237 cpp_code = (cc_generator.CCGenerator(type_generator, cpp_namespace) | 209 cpp_code = (cc_generator.CCGenerator(type_generator) |
238 .Generate(namespace).Render()) | 210 .Generate(namespace).Render()) |
239 else: | 211 else: |
240 self.send_error(404, "File not found: %s" % request_path) | 212 self.send_error(404, "File not found: %s" % request_path) |
241 return | 213 return |
242 | 214 |
243 # Do highlighting on the generated code | 215 # Do highlighting on the generated code |
244 (highlighter_param, style_param) = self._GetHighlighterParams(parsed_url) | 216 (highlighter_param, style_param) = self._GetHighlighterParams(parsed_url) |
245 head.Append('<style>' + | 217 head.Append('<style>' + |
246 self.server.highlighters[highlighter_param].GetCSS(style_param) + | 218 self.server.highlighters[highlighter_param].GetCSS(style_param) + |
247 '</style>') | 219 '</style>') |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
321 # cc/h panes will automatically update via the hash change event. | 293 # cc/h panes will automatically update via the hash change event. |
322 html.Append('<li><a href="#%s">%s</a>' % | 294 html.Append('<li><a href="#%s">%s</a>' % |
323 (filename, filename)) | 295 (filename, filename)) |
324 | 296 |
325 html.Append('</ul>') | 297 html.Append('</ul>') |
326 | 298 |
327 return html.Render() | 299 return html.Render() |
328 | 300 |
329 | 301 |
330 class PreviewHTTPServer(HTTPServer, object): | 302 class PreviewHTTPServer(HTTPServer, object): |
331 def __init__(self, server_address, handler, highlighters): | 303 def __init__(self, |
| 304 server_address, |
| 305 handler, |
| 306 highlighters, |
| 307 include_rules, |
| 308 cpp_namespace_pattern): |
332 super(PreviewHTTPServer, self).__init__(server_address, handler) | 309 super(PreviewHTTPServer, self).__init__(server_address, handler) |
333 self.highlighters = highlighters | 310 self.highlighters = highlighters |
| 311 self.include_rules = include_rules |
| 312 self.cpp_namespace_pattern = cpp_namespace_pattern |
334 | 313 |
335 | 314 |
336 if __name__ == '__main__': | 315 if __name__ == '__main__': |
337 parser = optparse.OptionParser( | 316 parser = optparse.OptionParser( |
338 description='Runs a server to preview the json_schema_compiler output.', | 317 description='Runs a server to preview the json_schema_compiler output.', |
339 usage='usage: %prog [option]...') | 318 usage='usage: %prog [option]...') |
340 parser.add_option('-p', '--port', default='8000', | 319 parser.add_option('-p', '--port', default='8000', |
341 help='port to run the server on') | 320 help='port to run the server on') |
| 321 parser.add_option('-n', '--namespace', default='generated_api_schemas', |
| 322 help='C++ namespace for generated files. e.g extensions::api.') |
| 323 parser.add_option('-I', '--include-rules', |
| 324 help='A list of paths to include when searching for referenced objects,' |
| 325 ' with the namespace separated by a \':\'. Example: ' |
| 326 '/foo/bar:Foo::Bar::%(namespace)s') |
342 | 327 |
343 (opts, argv) = parser.parse_args() | 328 (opts, argv) = parser.parse_args() |
344 | 329 |
| 330 def split_path_and_namespace(path_and_namespace): |
| 331 if ':' not in path_and_namespace: |
| 332 raise ValueError('Invalid include rule "%s". Rules must be of ' |
| 333 'the form path:namespace' % path_and_namespace) |
| 334 return path_and_namespace.split(':', 1) |
| 335 |
| 336 include_rules = [] |
| 337 if opts.include_rules: |
| 338 include_rules = map(split_path_and_namespace, |
| 339 shlex.split(opts.include_rules)) |
| 340 |
345 try: | 341 try: |
346 print('Starting previewserver on port %s' % opts.port) | 342 print('Starting previewserver on port %s' % opts.port) |
347 print('The extension documentation can be found at:') | 343 print('The extension documentation can be found at:') |
348 print('') | 344 print('') |
349 print(' http://localhost:%s/chrome/common/extensions/api' % opts.port) | 345 print(' http://localhost:%s/chrome/common/extensions/api' % opts.port) |
350 print('') | 346 print('') |
351 | 347 |
352 highlighters = { | 348 highlighters = { |
353 'hilite': hilite_me_highlighter.HiliteMeHighlighter(), | 349 'hilite': hilite_me_highlighter.HiliteMeHighlighter(), |
354 'none': none_highlighter.NoneHighlighter() | 350 'none': none_highlighter.NoneHighlighter() |
355 } | 351 } |
356 try: | 352 try: |
357 highlighters['pygments'] = pygments_highlighter.PygmentsHighlighter() | 353 highlighters['pygments'] = pygments_highlighter.PygmentsHighlighter() |
358 except ImportError as e: | 354 except ImportError as e: |
359 pass | 355 pass |
360 | 356 |
361 server = PreviewHTTPServer(('', int(opts.port)), | 357 server = PreviewHTTPServer(('', int(opts.port)), |
362 CompilerHandler, | 358 CompilerHandler, |
363 highlighters) | 359 highlighters, |
| 360 include_rules, |
| 361 opts.namespace) |
364 server.serve_forever() | 362 server.serve_forever() |
365 except KeyboardInterrupt: | 363 except KeyboardInterrupt: |
366 server.socket.close() | 364 server.socket.close() |
OLD | NEW |