From b46c29f155ad06d9fcb5f263f51ada27023d7046 Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Mon, 8 Feb 2016 19:24:58 -0500 Subject: [PATCH] Add support for extensionless files Provides support for serving files without their extension. The requested URL `/path/to/file` will serve the file `/path/to/file.html`. The feature is off by default (when `default_extension` is set to `None`), and is activated when `default_extension` is set to an extension (i.e. `".html"`). --- livereload/cli.py | 9 +++++++-- livereload/handlers.py | 21 +++++++++++++++++++++ livereload/server.py | 9 ++++++++- 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/livereload/cli.py b/livereload/cli.py index e99a404..96ac80c 100644 --- a/livereload/cli.py +++ b/livereload/cli.py @@ -28,7 +28,12 @@ type=int, default=0 ) - +parser.add_argument( + '-e', '--extension', + help='Default extension for extensionless files', + type=str, + default=None, +) def main(argv=None): args = parser.parse_args() @@ -36,4 +41,4 @@ def main(argv=None): # Create a new application server = Server() server.watcher.watch(args.directory, delay=args.wait) - server.serve(host=args.host, port=args.port, root=args.directory) + server.serve(host=args.host, port=args.port, root=args.directory, default_extension=args.extension) diff --git a/livereload/handlers.py b/livereload/handlers.py index aab4eff..8827831 100644 --- a/livereload/handlers.py +++ b/livereload/handlers.py @@ -150,3 +150,24 @@ def get(self): class StaticFileHandler(web.StaticFileHandler): def should_return_304(self): return False + + def initialize(self, path, default_filename=None, default_extension=None): + super(StaticFileHandler, self).initialize(path, default_filename) + self.default_extension = default_extension + + def validate_absolute_path(self, root, absolute_path): + """ + Validate and return the absolute path. + + Same behavior as parent StaticFileHandler class, except that + if the file is not found and does not have a file extension, + then ``default_extension`` is appended to the filename is it + is set and such a file exists. + """ + if (self.default_extension is not None + and not os.path.exists(absolute_path) + and os.path.splitext(absolute_path)[1] == '' + and os.path.exists(absolute_path + self.default_extension)): + # Append self.default_extension to extensionless file name. + absolute_path += self.default_extension + return super(StaticFileHandler, self).validate_absolute_path(root, absolute_path) diff --git a/livereload/server.py b/livereload/server.py index c195cc8..13cae90 100644 --- a/livereload/server.py +++ b/livereload/server.py @@ -167,6 +167,7 @@ class Server(object): """ def __init__(self, app=None, watcher=None): self.root = None + self.default_extension = None self.app = app if not watcher: @@ -257,11 +258,12 @@ def get_web_handlers(self, script): (r'/(.*)', StaticFileHandler, { 'path': self.root or '.', 'default_filename': 'index.html', + 'default_extension': self.default_extension, }), ] def serve(self, port=5500, liveport=None, host=None, root=None, debug=None, - open_url=False, restart_delay=2, open_url_delay=None): + open_url=False, restart_delay=2, open_url_delay=None, default_extension=None): """Start serve the server with the given port. :param port: serve on this port, default is 5500 @@ -272,11 +274,16 @@ def serve(self, port=5500, liveport=None, host=None, root=None, debug=None, via Tornado (and causes polling). Defaults to True when ``self.app`` is set, otherwise False. :param open_url_delay: open webbrowser after the delay seconds + :param default_extension: serve extensionless files with this extension + (set to ``".html"`` and ``foo/bar`` returns the file + ``foo/bar.html``). Default is None (disabled). """ host = host or '127.0.0.1' if root is not None: self.root = root + self.default_extension = default_extension + self._setup_logging() logger.info('Serving on http://%s:%s' % (host, port))