OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 # This helps you preview the apps and extensions docs. | 6 # This helps you preview the apps and extensions docs. |
7 # | 7 # |
8 # ./preview.py --help | 8 # ./preview.py --help |
9 # | 9 # |
10 # There are two modes: server- and render- mode. The default is server, in which | 10 # There are two modes: server- and render- mode. The default is server, in which |
(...skipping 10 matching lines...) Expand all Loading... |
21 # and for profiling the server. For example, | 21 # and for profiling the server. For example, |
22 # | 22 # |
23 # ./preview.py -r extensions/tabs.html | 23 # ./preview.py -r extensions/tabs.html |
24 # | 24 # |
25 # will output the documentation for the tabs API on stdout and exit immediately. | 25 # will output the documentation for the tabs API on stdout and exit immediately. |
26 # | 26 # |
27 # Note: absolute paths into static content (e.g. /static/css/site.css) will be | 27 # Note: absolute paths into static content (e.g. /static/css/site.css) will be |
28 # relative paths (e.g. static/css/site.css) for convenient sandboxing. | 28 # relative paths (e.g. static/css/site.css) for convenient sandboxing. |
29 | 29 |
30 from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer | 30 from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer |
| 31 from local_renderer import LocalRenderer |
31 import logging | 32 import logging |
32 import optparse | 33 import optparse |
33 import os | 34 import os |
34 import shutil | |
35 from StringIO import StringIO | |
36 import sys | 35 import sys |
37 import time | 36 import time |
38 import urlparse | |
39 | 37 |
40 import build_server | 38 import build_server |
41 # Copy all the files necessary to run the server. These are cleaned up when the | 39 # Copy all the files necessary to run the server. These are cleaned up when the |
42 # server quits. | 40 # server quits. |
43 build_server.main() | 41 build_server.main() |
44 | 42 |
45 from fake_fetchers import ConfigureFakeFetchers | |
46 | |
47 class _Response(object): | |
48 def __init__(self): | |
49 self.status = 200 | |
50 self.out = StringIO() | |
51 self.headers = {} | |
52 | |
53 def set_status(self, status): | |
54 self.status = status | |
55 | |
56 class _Request(object): | |
57 def __init__(self, path): | |
58 self.headers = {} | |
59 self.path = path | |
60 self.url = 'http://localhost' + path | |
61 | |
62 def _Render(path): | |
63 response = _Response() | |
64 Handler(_Request(urlparse.urlparse(path).path), response).get() | |
65 content = response.out.getvalue() | |
66 if isinstance(content, unicode): | |
67 content = content.encode('utf-8', 'replace') | |
68 return (content, response.status, response.headers) | |
69 | |
70 def _GetLocalPath(): | 43 def _GetLocalPath(): |
71 if os.sep in sys.argv[0]: | 44 if os.sep in sys.argv[0]: |
72 return os.path.join(sys.argv[0].rsplit(os.sep, 1)[0], os.pardir, os.pardir) | 45 return os.path.join(sys.argv[0].rsplit(os.sep, 1)[0], os.pardir, os.pardir) |
73 return os.path.join(os.pardir, os.pardir) | 46 return os.path.join(os.pardir, os.pardir) |
74 | 47 |
| 48 def _Render(base_dir, path): |
| 49 renderer = LocalRenderer(base_dir) |
| 50 content, status, headers = renderer.Render(path, always_online=True) |
| 51 while status in [301, 302]: |
| 52 redirect = headers['Location'].lstrip('/') |
| 53 sys.stderr.write('<!-- Redirected %s to %s -->\n' % (path, redirect)) |
| 54 content, status, headers = renderer.Render(redirect, always_online=True) |
| 55 return (content, status, headers) |
| 56 |
75 class RequestHandler(BaseHTTPRequestHandler): | 57 class RequestHandler(BaseHTTPRequestHandler): |
| 58 class Factory(object): |
| 59 def __init__(self, base_dir): |
| 60 self._base_dir = base_dir |
| 61 |
| 62 def Create(self, *args): |
| 63 return RequestHandler(self._base_dir, *args) |
| 64 |
| 65 def __init__(self, base_dir, *args): |
| 66 self._base_dir = base_dir |
| 67 BaseHTTPRequestHandler.__init__(self, *args) |
| 68 |
76 """A HTTPRequestHandler that outputs the docs page generated by Handler. | 69 """A HTTPRequestHandler that outputs the docs page generated by Handler. |
77 """ | 70 """ |
78 def do_GET(self): | 71 def do_GET(self): |
79 content, status, headers = _Render(self.path) | 72 content, status, headers = _Render(self._base_dir, self.path) |
80 self.send_response(status) | 73 self.send_response(status) |
81 for k, v in headers.iteritems(): | 74 for k, v in headers.iteritems(): |
82 self.send_header(k, v) | 75 self.send_header(k, v) |
83 self.end_headers() | 76 self.end_headers() |
84 self.wfile.write(content) | 77 self.wfile.write(content) |
85 | 78 |
86 if __name__ == '__main__': | 79 if __name__ == '__main__': |
87 parser = optparse.OptionParser( | 80 parser = optparse.OptionParser( |
88 description='Runs a server to preview the extension documentation.', | 81 description='Runs a server to preview the extension documentation.', |
89 usage='usage: %prog [option]...') | 82 usage='usage: %prog [option]...') |
(...skipping 12 matching lines...) Expand all Loading... |
102 | 95 |
103 (opts, argv) = parser.parse_args() | 96 (opts, argv) = parser.parse_args() |
104 | 97 |
105 if (not os.path.isdir(opts.directory) or | 98 if (not os.path.isdir(opts.directory) or |
106 not os.path.isdir(os.path.join(opts.directory, 'docs')) or | 99 not os.path.isdir(os.path.join(opts.directory, 'docs')) or |
107 not os.path.isdir(os.path.join(opts.directory, 'api'))): | 100 not os.path.isdir(os.path.join(opts.directory, 'api'))): |
108 print('Specified directory does not exist or does not contain extension ' | 101 print('Specified directory does not exist or does not contain extension ' |
109 'docs.') | 102 'docs.') |
110 exit() | 103 exit() |
111 | 104 |
112 ConfigureFakeFetchers(os.path.join(opts.directory, 'docs')) | |
113 from handler import Handler | |
114 | |
115 if opts.render: | 105 if opts.render: |
116 if opts.render.find('#') >= 0: | 106 if opts.render.find('#') >= 0: |
117 (path, iterations) = opts.render.rsplit('#', 1) | 107 (path, iterations) = opts.render.rsplit('#', 1) |
118 extra_iterations = int(iterations) - 1 | 108 extra_iterations = int(iterations) - 1 |
119 else: | 109 else: |
120 path = opts.render | 110 path = opts.render |
121 extra_iterations = 0 | 111 extra_iterations = 0 |
122 | 112 |
123 if opts.time: | 113 if opts.time: |
124 start_time = time.time() | 114 start_time = time.time() |
125 | 115 |
126 content, status, headers = _Render(path) | 116 content, status, headers = _Render(opts.directory, path) |
127 if status in [301, 302]: | |
128 # Handle a single level of redirection. | |
129 redirect_path = headers['Location'].lstrip('/') | |
130 sys.stderr.write('<!-- Redirected %s to %s -->\n' % (path, redirect_path)) | |
131 content, status, headers = _Render(redirect_path) | |
132 if status != 200: | 117 if status != 200: |
133 print('Error status: %s' % status) | 118 print('Error status: %s' % status) |
134 exit(1) | 119 exit(1) |
135 | 120 |
136 for _ in range(extra_iterations): | 121 for _ in range(extra_iterations): |
137 _Render(path) | 122 _Render(opts.directory, path) |
138 | 123 |
139 if opts.time: | 124 if opts.time: |
140 print('Took %s seconds' % (time.time() - start_time)) | 125 print('Took %s seconds' % (time.time() - start_time)) |
141 else: | 126 else: |
142 # Static paths will show up as /stable/static/foo but this only makes | 127 # Static paths will show up as /stable/static/foo but this only makes |
143 # sense from a webserver. | 128 # sense from a webserver. |
144 print(content.replace('/stable/static', 'static')) | 129 print(content.replace('/stable/static', 'static')) |
145 exit() | 130 exit() |
146 | 131 |
147 print('Starting previewserver on port %s' % opts.port) | 132 print('Starting previewserver on port %s' % opts.port) |
148 print('') | 133 print('') |
149 print('The extension documentation can be found at:') | 134 print('The extension documentation can be found at:') |
150 print('') | 135 print('') |
151 print(' http://localhost:%s/extensions/' % opts.port) | 136 print(' http://localhost:%s/extensions/' % opts.port) |
152 print('') | 137 print('') |
153 print('The apps documentation can be found at:') | 138 print('The apps documentation can be found at:') |
154 print('') | 139 print('') |
155 print(' http://localhost:%s/apps/' % opts.port) | 140 print(' http://localhost:%s/apps/' % opts.port) |
156 print('') | 141 print('') |
157 | 142 |
158 logging.getLogger().setLevel(logging.INFO) | 143 logging.getLogger().setLevel(logging.INFO) |
159 server = HTTPServer(('', int(opts.port)), RequestHandler) | 144 server = HTTPServer(('', int(opts.port)), |
| 145 RequestHandler.Factory(opts.directory).Create) |
160 try: | 146 try: |
161 server.serve_forever() | 147 server.serve_forever() |
162 finally: | 148 finally: |
163 server.socket.close() | 149 server.socket.close() |
OLD | NEW |