Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | |
| 1 # Copyright 2015 The Chromium Authors. All rights reserved. | 2 # Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 # 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 |
| 3 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 4 | 5 |
| 5 """Simple Markdown browser for a Git checkout.""" | 6 """Simple Markdown browser for a Git checkout.""" |
| 6 from __future__ import print_function | 7 from __future__ import print_function |
| 7 | 8 |
| 8 import SimpleHTTPServer | 9 import SimpleHTTPServer |
| 9 import SocketServer | 10 import SocketServer |
| 10 import argparse | 11 import argparse |
| 11 import codecs | 12 import codecs |
| 12 import os | 13 import os |
| 13 import re | 14 import re |
| 14 import socket | 15 import socket |
| 15 import sys | 16 import sys |
| 16 | 17 |
| 17 | 18 |
| 18 THIS_DIR = os.path.abspath(os.path.dirname(__file__)) | 19 THIS_DIR = os.path.abspath(os.path.dirname(__file__)) |
| 19 SRC_DIR = os.path.dirname(os.path.dirname(THIS_DIR)) | 20 SRC_DIR = os.path.dirname(os.path.dirname(THIS_DIR)) |
| 20 sys.path.append(os.path.join(SRC_DIR, 'third_party', 'Python-Markdown')) | 21 sys.path.append(os.path.join(SRC_DIR, 'third_party', 'Python-Markdown')) |
| 21 import markdown | 22 import markdown |
| 22 | 23 |
| 23 | 24 |
| 24 def main(argv): | 25 def main(argv): |
| 25 parser = argparse.ArgumentParser(prog='md_browser') | 26 parser = argparse.ArgumentParser(prog='md_browser') |
| 26 parser.add_argument('-p', '--port', type=int, default=8080, | 27 parser.add_argument('-p', '--port', type=int, default=8080, |
| 27 help='port to run on (default = %(default)s)') | 28 help='port to run on (default = %(default)s)') |
| 29 parser.add_argument('-d', '--directory', type=str, default=SRC_DIR) | |
| 28 args = parser.parse_args(argv) | 30 args = parser.parse_args(argv) |
| 29 | 31 |
| 30 try: | 32 try: |
| 31 s = Server(args.port, SRC_DIR) | 33 s = Server(args.port, args.directory) |
| 32 print("Listening on http://localhost:%s/" % args.port) | 34 print("Listening on http://localhost:%s/" % args.port) |
| 33 print(" Try loading http://localhost:%s/docs/README.md" % args.port) | 35 if os.path.isfile(os.path.join(args.directory, 'docs', 'README.md')): |
| 36 print(" Try loading http://localhost:%s/docs/README.md" % args.port) | |
| 37 elif os.path.isfile(os.path.join(args.directory, 'README.md')): | |
| 38 print(" Try loading http://localhost:%s/README.md" % args.port) | |
| 34 s.serve_forever() | 39 s.serve_forever() |
| 35 s.shutdown() | 40 s.shutdown() |
| 36 return 0 | 41 return 0 |
| 37 except KeyboardInterrupt: | 42 except KeyboardInterrupt: |
| 38 return 130 | 43 return 130 |
| 39 | 44 |
| 40 | 45 |
| 41 def _gitiles_slugify(value, _separator): | 46 def _gitiles_slugify(value, _separator): |
| 42 """Convert a string (representing a section title) to URL anchor name. | 47 """Convert a string (representing a section title) to URL anchor name. |
| 43 | 48 |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 64 value = re.sub(r'[^- a-zA-Z0-9]', '_', value) # Non-alphanumerics to '_'. | 69 value = re.sub(r'[^- a-zA-Z0-9]', '_', value) # Non-alphanumerics to '_'. |
| 65 value = value.replace(u' ', u'-') | 70 value = value.replace(u' ', u'-') |
| 66 value = re.sub(r'([-_])[-_]+', r'\1', value) # Fold hyphens and underscores. | 71 value = re.sub(r'([-_])[-_]+', r'\1', value) # Fold hyphens and underscores. |
| 67 return value | 72 return value |
| 68 | 73 |
| 69 | 74 |
| 70 class Server(SocketServer.TCPServer): | 75 class Server(SocketServer.TCPServer): |
| 71 def __init__(self, port, top_level): | 76 def __init__(self, port, top_level): |
| 72 SocketServer.TCPServer.__init__(self, ('0.0.0.0', port), Handler) | 77 SocketServer.TCPServer.__init__(self, ('0.0.0.0', port), Handler) |
| 73 self.port = port | 78 self.port = port |
| 74 self.top_level = top_level | 79 self.top_level = os.path.abspath(top_level) |
| 75 | 80 |
| 76 def server_bind(self): | 81 def server_bind(self): |
| 77 self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) | 82 self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) |
| 78 self.socket.bind(self.server_address) | 83 self.socket.bind(self.server_address) |
| 79 | 84 |
| 80 | 85 |
| 81 class Handler(SimpleHTTPServer.SimpleHTTPRequestHandler): | 86 class Handler(SimpleHTTPServer.SimpleHTTPRequestHandler): |
| 82 def do_GET(self): | 87 def do_GET(self): |
| 83 path = self.path | 88 path = self.path |
| 84 | 89 |
| 85 # strip off the repo and branch info, if present, for compatibility | 90 # strip off the repo and branch info, if present, for compatibility |
| 86 # with gitiles. | 91 # with gitiles. |
| 87 if path.startswith('/chromium/src/+/master'): | 92 if path.startswith('/chromium/src/+/master'): |
| 88 path = path[len('/chromium/src/+/master'):] | 93 path = path[len('/chromium/src/+/master'):] |
| 89 | 94 |
| 90 full_path = os.path.abspath(os.path.join(self.server.top_level, path[1:])) | 95 full_path = os.path.abspath(os.path.join(self.server.top_level, path[1:])) |
| 91 | 96 |
| 92 if not full_path.startswith(SRC_DIR): | 97 if not full_path.startswith(self.server.top_level): |
| 93 self._DoUnknown() | 98 self._DoUnknown() |
| 94 elif path == '/doc.css': | 99 elif path == '/doc.css': |
| 95 self._DoCSS('doc.css') | 100 self._DoCSS('doc.css') |
| 96 elif not os.path.exists(full_path): | 101 elif not os.path.exists(full_path): |
| 97 self._DoNotFound() | 102 self._DoNotFound() |
| 98 elif path.lower().endswith('.md'): | 103 elif path.lower().endswith('.md'): |
| 99 self._DoMD(path) | 104 self._DoMD(path) |
| 100 elif os.path.exists(full_path + '/README.md'): | 105 elif os.path.exists(full_path + '/README.md'): |
| 101 self._DoMD(path + '/README.md') | 106 self._DoMD(path + '/README.md') |
| 102 else: | 107 else: |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 135 | 140 |
| 136 def _DoNotFound(self): | 141 def _DoNotFound(self): |
| 137 self._WriteHeader('text/html') | 142 self._WriteHeader('text/html') |
| 138 self.wfile.write('<html><body>%s not found</body></html>' % self.path) | 143 self.wfile.write('<html><body>%s not found</body></html>' % self.path) |
| 139 | 144 |
| 140 def _DoUnknown(self): | 145 def _DoUnknown(self): |
| 141 self._WriteHeader('text/html') | 146 self._WriteHeader('text/html') |
| 142 self.wfile.write('<html><body>I do not know how to serve %s.</body>' | 147 self.wfile.write('<html><body>I do not know how to serve %s.</body>' |
| 143 '</html>' % self.path) | 148 '</html>' % self.path) |
| 144 | 149 |
| 145 def _Read(self, relpath): | 150 def _Read(self, relpath, relative_to=None): |
| 151 if relative_to is None: | |
| 152 relative_to = self.server.top_level | |
|
Dirk Pranke
2016/05/10 20:35:35
nit: it'd be a bit more idiomatic (and one less li
agable
2016/05/11 00:26:25
That disallows passing "relative_to=''", which wou
Dirk Pranke
2016/05/11 00:32:55
Hm. That seems like something I wouldn't want to s
| |
| 146 assert not relpath.startswith(os.sep) | 153 assert not relpath.startswith(os.sep) |
| 147 path = os.path.join(self.server.top_level, relpath) | 154 path = os.path.join(relative_to, relpath) |
| 148 with codecs.open(path, encoding='utf-8') as fp: | 155 with codecs.open(path, encoding='utf-8') as fp: |
| 149 return fp.read() | 156 return fp.read() |
| 150 | 157 |
| 151 def _WriteHeader(self, content_type='text/plain'): | 158 def _WriteHeader(self, content_type='text/plain'): |
| 152 self.send_response(200) | 159 self.send_response(200) |
| 153 self.send_header('Content-Type', content_type) | 160 self.send_header('Content-Type', content_type) |
| 154 self.end_headers() | 161 self.end_headers() |
| 155 | 162 |
| 156 def _WriteTemplate(self, template): | 163 def _WriteTemplate(self, template): |
| 157 contents = self._Read(os.path.join('tools', 'md_browser', template)) | 164 contents = self._Read(os.path.join('tools', 'md_browser', template), |
| 165 relative_to=SRC_DIR) | |
| 158 self.wfile.write(contents.encode('utf-8')) | 166 self.wfile.write(contents.encode('utf-8')) |
| 159 | 167 |
| 160 | 168 |
| 161 if __name__ == '__main__': | 169 if __name__ == '__main__': |
| 162 sys.exit(main(sys.argv[1:])) | 170 sys.exit(main(sys.argv[1:])) |
| OLD | NEW |