From 90b2724c31c36df46223f7fc57d613bcad80f28f Mon Sep 17 00:00:00 2001 From: Dougal Matthews Date: Sun, 10 May 2015 00:21:25 +0100 Subject: [PATCH] Make auto-reloading optional Fixes #445 --- mkdocs/cli.py | 12 ++++--- mkdocs/serve.py | 75 ++++++++++++++++++++++++++++++++-------- requirements/project.txt | 1 + setup.py | 1 + 4 files changed, 71 insertions(+), 18 deletions(-) diff --git a/mkdocs/cli.py b/mkdocs/cli.py index 76dac127..853a903d 100644 --- a/mkdocs/cli.py +++ b/mkdocs/cli.py @@ -15,10 +15,10 @@ from mkdocs.config import load_config log = logging.getLogger(__name__) -def configure_logging(verbose=False): +def configure_logging(log_name='mkdocs', verbose=False): '''When a --verbose flag is passed, increase the verbosity of mkdocs''' - logger = logging.getLogger('mkdocs') + logger = logging.getLogger(log_name) logger.propagate = False stream = logging.StreamHandler() formatter = logging.Formatter("%(levelname)-7s - %(message)s ") @@ -40,6 +40,7 @@ strict_help = ("Enable strict mode. This will cause MkDocs to abort the build " theme_help = "The theme to use when building your documentation." theme_choices = utils.get_theme_names() site_dir_help = "The directory to output the result of the documentation build." +reload_help = "Enable and disable the live reloading in the development server." @click.group() @@ -49,7 +50,7 @@ def cli(verbose): """ MkDocs - Project documentation with Markdown. """ - configure_logging(verbose) + configure_logging(verbose=verbose) @cli.command(name="serve") @@ -57,13 +58,16 @@ def cli(verbose): @click.option('--dev-addr', help=dev_addr_help, metavar='') @click.option('--strict', is_flag=True, help=strict_help) @click.option('--theme', type=click.Choice(theme_choices), help=theme_help) -def serve_command(dev_addr, config_file, strict, theme): +@click.option('--livereload/--no-livereload', default=True, help=reload_help) +def serve_command(dev_addr, config_file, strict, theme, livereload): """Run the builtin development server""" + configure_logging('tornado') serve.serve( config_file=config_file, dev_addr=dev_addr, strict=strict, theme=theme, + livereload=livereload, ) diff --git a/mkdocs/serve.py b/mkdocs/serve.py index 5503804a..8b5ec076 100644 --- a/mkdocs/serve.py +++ b/mkdocs/serve.py @@ -1,19 +1,68 @@ +import logging +import shutil import tempfile -from livereload import Server - from mkdocs.build import build from mkdocs.config import load_config +log = logging.getLogger(__name__) -def serve(config_file=None, dev_addr=None, strict=None, theme=None): + +def _livereload(host, port, config, builder, site_dir): + + # We are importing here for anyone that has issues with livereload. Even if + # this fails, the --no-livereload alternative should still work. + from livereload import Server + + server = Server() + + # Watch the documentation files, the config file and the theme files. + server.watch(config['docs_dir'], builder) + server.watch(config['config_file_path'], builder) + + for d in config['theme_dir']: + server.watch(d, builder) + + server.serve(root=site_dir, host=host, port=int(port), restart_delay=0) + + +def _static_server(host, port, site_dir): + + # Importing here to seperate the code paths from the --livereload + # alternative. + from tornado import ioloop + from tornado import web + + application = web.Application([ + (r"/(.*)", web.StaticFileHandler, { + "path": site_dir, + "default_filename": "index.html" + }), + ]) + application.listen(port=port, address=host) + + log.info('Running at: http://%s:%s/', host, port) + log.info('Hold ctrl+c to quit.') + try: + ioloop.IOLoop.instance().start() + except KeyboardInterrupt: + log.info('Stopping server...') + + +def serve(config_file=None, dev_addr=None, strict=None, theme=None, + livereload=True): """ - Start the devserver, and rebuild the docs whenever any changes take effect. + Start the MkDocs development server + + By default it will serve the documentation on http://localhost:8000/ and + it will rebuild the documentation and refresh the page automatically + whenever a file is edited. """ # Create a temporary build directory, and set some options to serve it tempdir = tempfile.mkdtemp() def builder(): + log.info("Rebuilding documentation...") config = load_config( config_file=config_file, dev_addr=dev_addr, @@ -27,14 +76,12 @@ def serve(config_file=None, dev_addr=None, strict=None, theme=None): # Perform the initial build config = builder() - server = Server() - - # Watch the documentation files, the config file and the theme files. - server.watch(config['docs_dir'], builder) - server.watch(config['config_file_path'], builder) - - for d in config['theme_dir']: - server.watch(d, builder) - host, port = config['dev_addr'].split(':', 1) - server.serve(root=tempdir, host=host, port=int(port), restart_delay=0) + + try: + if livereload: + _livereload(host, port, config, builder, tempdir) + else: + _static_server(host, port, tempdir) + finally: + shutil.rmtree(tempdir) diff --git a/requirements/project.txt b/requirements/project.txt index ba998a5b..90eab790 100644 --- a/requirements/project.txt +++ b/requirements/project.txt @@ -5,3 +5,4 @@ livereload>=2.3.2 Markdown>=2.5 PyYAML>=3.10 six>=1.9.0 +tornado>=4.1 diff --git a/setup.py b/setup.py index f27c7896..398568f4 100755 --- a/setup.py +++ b/setup.py @@ -81,6 +81,7 @@ setup( 'Markdown>=2.3.1,<2.5' if PY26 else 'Markdown>=2.3.1', 'PyYAML>=3.10', 'six>=1.9.0', + 'tornado>=4.1', ], entry_points={ 'console_scripts': [