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. 28import build_server 29# Copy all the files necessary to run the server. These are cleaned up when the 30# server quits. 31build_server.main() 32 33from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer 34import logging 35import optparse 36import posixpath 37import time 38 39from local_renderer import LocalRenderer 40 41class _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 64if __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