1 #!/usr/bin/env python 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 3 # Use of this source code is governed by a BSD-style license that can be 4 # found in the LICENSE file. 5 6 # This helps you preview the apps and extensions docs. 7 # 8 # ./preview.py --help 9 # 10 # There are two modes: server- and render- mode. The default is server, in which 11 # a webserver is started on a port (default 8000). Navigating to paths on 12 # http://localhost:8000, for example 13 # 14 # http://localhost:8000/extensions/tabs.html 15 # 16 # will render the documentation for the extension tabs API. 17 # 18 # On the other hand, render mode statically renders docs to stdout. Use this 19 # to save the output (more convenient than needing to save the page in a 20 # browser), handy when uploading the docs somewhere (e.g. for a review), 21 # and for profiling the server. For example, 22 # 23 # ./preview.py -r extensions/tabs.html 24 # 25 # will output the documentation for the tabs API on stdout and exit immediately. 26 27 # NOTE: RUN THIS FIRST. Or all third_party imports will fail. 28 import build_server 29 # Copy all the files necessary to run the server. These are cleaned up when the 30 # server quits. 31 build_server.main() 32 33 from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer 34 import logging 35 import optparse 36 import posixpath 37 import time 38 39 from local_renderer import LocalRenderer 40 41 class _RequestHandler(BaseHTTPRequestHandler): 42 '''A HTTPRequestHandler that outputs the docs page generated by Handler. 43 ''' 44 def do_GET(self): 45 # Sanitize path to guarantee that it stays within the server. 46 if not posixpath.abspath(self.path.lstrip('/')).startswith( 47 posixpath.abspath('')): 48 return 49 50 # Rewrite paths that would otherwise be served from app.yaml. 51 self.path = { 52 '/robots.txt': '../../server2/robots.txt', 53 '/favicon.ico': '../../server2/chrome-32.ico', 54 '/apple-touch-icon-precomposed.png': '../../server2/chrome-128.png' 55 }.get(self.path, self.path) 56 response = LocalRenderer.Render(self.path, headers=dict(self.headers)) 57 self.protocol_version = 'HTTP/1.1' 58 self.send_response(response.status) 59 for k, v in response.headers.iteritems(): 60 self.send_header(k, v) 61 self.end_headers() 62 self.wfile.write(response.content.ToString()) 63 64 if __name__ == '__main__': 65 parser = optparse.OptionParser( 66 description='Runs a server to preview the extension documentation.', 67 usage='usage: %prog [option]...') 68 parser.add_option('-p', '--port', default='8000', 69 help='port to run the server on') 70 parser.add_option('-r', '--render', default='', 71 help='statically render a page and print to stdout rather than starting ' 72 'the server, e.g. apps/storage.html. The path may optionally end ' 73 'with #n where n is the number of times to render the page before ' 74 'printing it, e.g. apps/storage.html#50, to use for profiling.') 75 parser.add_option('-t', '--time', action='store_true', 76 help='Print the time taken rendering rather than the result.') 77 78 (opts, argv) = parser.parse_args() 79 80 if opts.render: 81 if opts.render.find('#') >= 0: 82 (path, iterations) = opts.render.rsplit('#', 1) 83 extra_iterations = int(iterations) - 1 84 else: 85 path = opts.render 86 extra_iterations = 0 87 88 if opts.time: 89 start_time = time.time() 90 91 response = LocalRenderer.Render(path) 92 if response.status != 200: 93 print('Error status: %s' % response.status) 94 exit(1) 95 96 for _ in range(extra_iterations): 97 LocalRenderer.Render(path) 98 99 if opts.time: 100 print('Took %s seconds' % (time.time() - start_time)) 101 else: 102 print(response.content.ToString()) 103 exit() 104 105 print('Starting previewserver on port %s' % opts.port) 106 print('') 107 print('The extension documentation can be found at:') 108 print('') 109 print(' http://localhost:%s/extensions/' % opts.port) 110 print('') 111 print('The apps documentation can be found at:') 112 print('') 113 print(' http://localhost:%s/apps/' % opts.port) 114 print('') 115 116 logging.getLogger().setLevel(logging.INFO) 117 server = HTTPServer(('', int(opts.port)), _RequestHandler) 118 try: 119 server.serve_forever() 120 finally: 121 server.socket.close() 122