Chromium Code Reviews| 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(filedir, | |
| 192 filedir, | |
| 193 self.server.include_rules, | |
| 194 '') | |
| 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. | 203 # Get the model's dependencies. |
| 220 for dependency in api_def.get('dependencies', []): | 204 for dependency in namespace.dependencies: |
| 221 # Dependencies can contain : in which case they don't refer to APIs, | 205 # Dependencies can contain : in which case they don't refer to APIs, |
| 222 # rather, permissions or manifest keys. | 206 # rather, permissions or manifest keys. |
| 223 if ':' in dependency: | 207 if ':' in dependency: |
| 224 continue | 208 continue |
| 225 (api_def, file_path) = self._LoadModel(filedir, dependency) | 209 (api_def, file_path) = self._LoadModel(filedir, dependency) |
| 226 referenced_namespace = api_model.AddNamespace(api_def, file_path) | 210 referenced_namespace = api_model.AddNamespace(api_def, file_path) |
| 227 if referenced_namespace: | 211 if referenced_namespace: |
| 228 type_generator.AddNamespace(referenced_namespace, | 212 type_generator.AddNamespace(referenced_namespace, |
| 229 cpp_util.Classname(referenced_namespace.name).lower()) | 213 cpp_util.Classname(referenced_namespace.name).lower()) |
| 230 | 214 |
| 231 # Generate code | 215 # Generate code |
| 232 cpp_namespace = 'generated_api_schemas' | 216 cpp_namespace = 'generated_api_schemas' |
| 233 if file_ext == '.h': | 217 if file_ext == '.h': |
| 234 cpp_code = (h_generator.HGenerator(type_generator, cpp_namespace) | 218 cpp_code = (h_generator.HGenerator(type_generator) |
| 235 .Generate(namespace).Render()) | 219 .Generate(namespace).Render()) |
| 236 elif file_ext == '.cc': | 220 elif file_ext == '.cc': |
| 237 cpp_code = (cc_generator.CCGenerator(type_generator, cpp_namespace) | 221 cpp_code = (cc_generator.CCGenerator(type_generator) |
| 238 .Generate(namespace).Render()) | 222 .Generate(namespace).Render()) |
| 239 else: | 223 else: |
| 240 self.send_error(404, "File not found: %s" % request_path) | 224 self.send_error(404, "File not found: %s" % request_path) |
| 241 return | 225 return |
| 242 | 226 |
| 243 # Do highlighting on the generated code | 227 # Do highlighting on the generated code |
| 244 (highlighter_param, style_param) = self._GetHighlighterParams(parsed_url) | 228 (highlighter_param, style_param) = self._GetHighlighterParams(parsed_url) |
| 245 head.Append('<style>' + | 229 head.Append('<style>' + |
| 246 self.server.highlighters[highlighter_param].GetCSS(style_param) + | 230 self.server.highlighters[highlighter_param].GetCSS(style_param) + |
| 247 '</style>') | 231 '</style>') |
| 248 body.Append(self.server.highlighters[highlighter_param] | 232 body.Append(self.server.highlighters[highlighter_param] |
| 249 .GetCodeElement(cpp_code, style_param)) | 233 .GetCodeElement(cpp_code, style_param)) |
| 250 except IOError: | 234 except IOError: |
| 251 self.send_error(404, "File not found: %s" % request_path) | 235 self.send_error(404, "File not found: %s" % request_path) |
| 236 raise | |
| 252 return | 237 return |
|
not at google - send to devlin
2014/08/28 19:22:09
No point returning after a raise - but I prefer th
lfg
2014/08/28 19:33:35
Oops, that was left over after I debugged this cod
| |
| 253 except (TypeError, KeyError, AttributeError, | 238 except (TypeError, KeyError, AttributeError, |
| 254 AssertionError, NotImplementedError) as error: | 239 AssertionError, NotImplementedError) as error: |
| 255 body.Append('<pre>') | 240 body.Append('<pre>') |
| 256 body.Append('compiler error: %s' % error) | 241 body.Append('compiler error: %s' % error) |
| 257 body.Append('Check server log for more details') | 242 body.Append('Check server log for more details') |
| 258 body.Append('</pre>') | 243 body.Append('</pre>') |
| 259 raise | 244 raise |
| 260 | 245 |
| 261 def _GetHighlighterParams(self, parsed_url): | 246 def _GetHighlighterParams(self, parsed_url): |
| 262 """Get the highlighting parameters from a parsed url. | 247 """Get the highlighting parameters from a parsed url. |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 321 # cc/h panes will automatically update via the hash change event. | 306 # cc/h panes will automatically update via the hash change event. |
| 322 html.Append('<li><a href="#%s">%s</a>' % | 307 html.Append('<li><a href="#%s">%s</a>' % |
| 323 (filename, filename)) | 308 (filename, filename)) |
| 324 | 309 |
| 325 html.Append('</ul>') | 310 html.Append('</ul>') |
| 326 | 311 |
| 327 return html.Render() | 312 return html.Render() |
| 328 | 313 |
| 329 | 314 |
| 330 class PreviewHTTPServer(HTTPServer, object): | 315 class PreviewHTTPServer(HTTPServer, object): |
| 331 def __init__(self, server_address, handler, highlighters): | 316 def __init__(self, server_address, handler, highlighters, include_rules): |
| 332 super(PreviewHTTPServer, self).__init__(server_address, handler) | 317 super(PreviewHTTPServer, self).__init__(server_address, handler) |
| 333 self.highlighters = highlighters | 318 self.highlighters = highlighters |
| 319 self.include_rules = include_rules | |
| 334 | 320 |
| 335 | 321 |
| 336 if __name__ == '__main__': | 322 if __name__ == '__main__': |
| 337 parser = optparse.OptionParser( | 323 parser = optparse.OptionParser( |
| 338 description='Runs a server to preview the json_schema_compiler output.', | 324 description='Runs a server to preview the json_schema_compiler output.', |
| 339 usage='usage: %prog [option]...') | 325 usage='usage: %prog [option]...') |
| 340 parser.add_option('-p', '--port', default='8000', | 326 parser.add_option('-p', '--port', default='8000', |
| 341 help='port to run the server on') | 327 help='port to run the server on') |
| 328 parser.add_option('-I', '--include-rules', | |
| 329 help='A list of paths to include when searching for referenced objects,' | |
| 330 ' with the namespace separated by a \':\'. Example: ' | |
| 331 '/foo/bar:Foo::Bar::%(namespace)s') | |
| 342 | 332 |
| 343 (opts, argv) = parser.parse_args() | 333 (opts, argv) = parser.parse_args() |
| 344 | 334 |
| 335 def split_path_and_namespace(path_and_namespace): | |
| 336 if ':' not in path_and_namespace: | |
| 337 raise ValueError('Invalid include rule "%s". Rules must be of ' | |
| 338 'the form path:namespace' % path_and_namespace) | |
| 339 return path_and_namespace.split(':', 1) | |
| 340 | |
| 341 include_rules = [] | |
| 342 if opts.include_rules: | |
| 343 include_rules = map(split_path_and_namespace, | |
| 344 shlex.split(opts.include_rules)) | |
| 345 | |
| 345 try: | 346 try: |
| 346 print('Starting previewserver on port %s' % opts.port) | 347 print('Starting previewserver on port %s' % opts.port) |
| 347 print('The extension documentation can be found at:') | 348 print('The extension documentation can be found at:') |
| 348 print('') | 349 print('') |
| 349 print(' http://localhost:%s/chrome/common/extensions/api' % opts.port) | 350 print(' http://localhost:%s/chrome/common/extensions/api' % opts.port) |
| 350 print('') | 351 print('') |
| 351 | 352 |
| 352 highlighters = { | 353 highlighters = { |
| 353 'hilite': hilite_me_highlighter.HiliteMeHighlighter(), | 354 'hilite': hilite_me_highlighter.HiliteMeHighlighter(), |
| 354 'none': none_highlighter.NoneHighlighter() | 355 'none': none_highlighter.NoneHighlighter() |
| 355 } | 356 } |
| 356 try: | 357 try: |
| 357 highlighters['pygments'] = pygments_highlighter.PygmentsHighlighter() | 358 highlighters['pygments'] = pygments_highlighter.PygmentsHighlighter() |
| 358 except ImportError as e: | 359 except ImportError as e: |
| 359 pass | 360 pass |
| 360 | 361 |
| 361 server = PreviewHTTPServer(('', int(opts.port)), | 362 server = PreviewHTTPServer(('', int(opts.port)), |
| 362 CompilerHandler, | 363 CompilerHandler, |
| 363 highlighters) | 364 highlighters, |
| 365 include_rules) | |
| 364 server.serve_forever() | 366 server.serve_forever() |
| 365 except KeyboardInterrupt: | 367 except KeyboardInterrupt: |
| 366 server.socket.close() | 368 server.socket.close() |
| OLD | NEW |