blob: 777f6dced90051cb7aa65f6f82e201ec00e4f1ba [file] [log] [blame]
#!/usr/bin/env python
# Copyright (c) 2012 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# This helps you preview the apps and extensions docs.
#
# ./preview.py --help
#
# There are two modes: server- and render- mode. The default is server, in which
# a webserver is started on a port (default 8000). Navigating to paths on
# http://localhost:8000, for example
#
# http://localhost:8000/extensions/tabs.html
#
# will render the documentation for the extension tabs API.
#
# On the other hand, render mode statically renders docs to stdout. Use this
# to save the output (more convenient than needing to save the page in a
# browser), handy when uploading the docs somewhere (e.g. for a review),
# and for profiling the server. For example,
#
# ./preview.py -r extensions/tabs.html
#
# will output the documentation for the tabs API on stdout and exit immediately.
# NOTE: RUN THIS FIRST. Or all third_party imports will fail.
import build_server
# Copy all the files necessary to run the server. These are cleaned up when the
# server quits.
build_server.main()
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
import logging
import optparse
import posixpath
import time
from local_renderer import LocalRenderer
class _RequestHandler(BaseHTTPRequestHandler):
'''A HTTPRequestHandler that outputs the docs page generated by Handler.
'''
def do_GET(self):
# Sanitize path to guarantee that it stays within the server.
if not posixpath.abspath(self.path.lstrip('/')).startswith(
posixpath.abspath('')):
return
# Rewrite paths that would otherwise be served from app.yaml.
self.path = {
'/robots.txt': '../../server2/robots.txt',
'/favicon.ico': '../../server2/chrome-32.ico',
'/apple-touch-icon-precomposed.png': '../../server2/chrome-128.png'
}.get(self.path, self.path)
response = LocalRenderer.Render(self.path, headers=dict(self.headers))
self.protocol_version = 'HTTP/1.1'
self.send_response(response.status)
for k, v in response.headers.iteritems():
self.send_header(k, v)
self.end_headers()
self.wfile.write(response.content.ToString())
if __name__ == '__main__':
parser = optparse.OptionParser(
description='Runs a server to preview the extension documentation.',
usage='usage: %prog [option]...')
parser.add_option('-p', '--port', default='8000',
help='port to run the server on')
parser.add_option('-r', '--render', default='',
help='statically render a page and print to stdout rather than starting '
'the server, e.g. apps/storage.html. The path may optionally end '
'with #n where n is the number of times to render the page before '
'printing it, e.g. apps/storage.html#50, to use for profiling.')
parser.add_option('-s', '--stat',
help='Print profile stats at the end of the run using the given '
'profiling option (like "tottime"). -t is ignored if this is set.')
parser.add_option('-t', '--time', action='store_true',
help='Print the time taken rendering rather than the result.')
(opts, argv) = parser.parse_args()
if opts.render:
if opts.render.find('#') >= 0:
(path, iterations) = opts.render.rsplit('#', 1)
extra_iterations = int(iterations) - 1
else:
path = opts.render
extra_iterations = 0
if opts.stat:
import cProfile, pstats, StringIO
pr = cProfile.Profile()
pr.enable()
elif opts.time:
start_time = time.time()
response = LocalRenderer.Render(path)
if response.status != 200:
print('Error status: %s' % response.status)
exit(1)
for _ in range(extra_iterations):
LocalRenderer.Render(path)
if opts.stat:
pr.disable()
s = StringIO.StringIO()
pstats.Stats(pr, stream=s).sort_stats(opts.stat).print_stats()
print(s.getvalue())
elif opts.time:
print('Took %s seconds' % (time.time() - start_time))
else:
print(response.content.ToString())
exit()
print('Starting previewserver on port %s' % opts.port)
print('')
print('The extension documentation can be found at:')
print('')
print(' http://localhost:%s/extensions/' % opts.port)
print('')
print('The apps documentation can be found at:')
print('')
print(' http://localhost:%s/apps/' % opts.port)
print('')
logging.getLogger().setLevel(logging.INFO)
server = HTTPServer(('', int(opts.port)), _RequestHandler)
try:
server.serve_forever()
finally:
server.socket.close()