diff --git a/README.rst b/README.rst index dbf2935..4aeaa72 100644 --- a/README.rst +++ b/README.rst @@ -67,6 +67,7 @@ which can seen by running ``sphinx-autobuild --help``: --delay DELAY how long to wait before opening the browser --watch DIR additional directories to watch --pre-build COMMAND additional command(s) to run prior to building the documentation + --post-build COMMAND additional command(s) to run after building the documentation Using with Makefile ------------------- @@ -140,6 +141,19 @@ to avoid needing to manually manage ports and opening browser windows sphinx-autobuild --port=0 --open-browser pikachu/docs pikachu/docs/_build/html & sphinx-autobuild --port=0 --open-browser magikarp/docs magickarp/docs/_build/html & +Notifications for build cycles +------------------------------ + +As an example of using the ``--pre-build`` and ``--post-build`` arguments, +the command below uses `notify-send` to send a notification when a build +starts and finishes. + +.. code-block:: bash + + sphinx-autobuild docs docs/_build/html/ \ + --pre-build 'notify-send "sphinx-autobuild: build start"' \ + --post-build 'notify-send "sphinx-autobuild: build end"' + Relevant Sphinx Bugs ==================== diff --git a/sphinx_autobuild/__main__.py b/sphinx_autobuild/__main__.py index 2a37a03..ed40ace 100644 --- a/sphinx_autobuild/__main__.py +++ b/sphinx_autobuild/__main__.py @@ -49,11 +49,12 @@ def main(argv=()): url_host = f"{host_name}:{port_num}" pre_build_commands = list(map(shlex.split, args.pre_build)) - + post_build_commands = list(map(shlex.split, args.post_build)) builder = Builder( build_args, url_host=url_host, pre_build_commands=pre_build_commands, + post_build_commands=post_build_commands, ) watch_dirs = [src_dir] + args.additional_watched_dirs @@ -233,6 +234,13 @@ def _add_autobuild_arguments(parser): default=[], help="additional command(s) to run prior to building the documentation", ) + group.add_argument( + "--post-build", + action="append", + metavar="COMMAND", + default=[], + help="additional command(s) to run after building the documentation", + ) return group diff --git a/sphinx_autobuild/build.py b/sphinx_autobuild/build.py index f0d8126..5f4470a 100644 --- a/sphinx_autobuild/build.py +++ b/sphinx_autobuild/build.py @@ -15,9 +15,12 @@ class Builder: - def __init__(self, sphinx_args, *, url_host, pre_build_commands): + def __init__( + self, sphinx_args, *, url_host, pre_build_commands, post_build_commands + ): self.sphinx_args = sphinx_args self.pre_build_commands = pre_build_commands + self.post_build_commands = post_build_commands self.uri = f"http://{url_host}" def __call__(self, *, changed_paths: Sequence[Path]): @@ -35,24 +38,7 @@ def __call__(self, *, changed_paths: Sequence[Path]): show_message(f"Detected changes ({', '.join(rel_paths)})") show_message("Rebuilding...") - try: - for command in self.pre_build_commands: - show_message("pre-build") - show_command(command) - subprocess.run(command, check=True) - except subprocess.CalledProcessError as e: - print(f"Pre-build command exited with exit code: {e.returncode}") - print( - "Please fix the cause of the error above or press Ctrl+C to stop the " - "server." - ) - print( - "The server will continue serving the build folder, but the contents " - "being served are no longer in sync with the documentation sources. " - "Please fix the cause of the error above or press Ctrl+C to stop the " - "server." - ) - traceback.print_exception(e) + if self._run_commands(self.pre_build_commands, "pre-build") != 0: return if sphinx.version_info[:3] >= (7, 2, 3): @@ -70,5 +56,33 @@ def __call__(self, *, changed_paths: Sequence[Path]): "Please fix the cause of the error above or press Ctrl+C to stop the " "server." ) + else: + # Run the post-build commands only if the build was successful + self._run_commands(self.post_build_commands, "post-build") + # Remind the user of the server URL for convenience. show_message(f"Serving on {self.uri}") + + def _run_commands(self, commands, log_context): + try: + for command in commands: + show_message(log_context) + show_command(command) + subprocess.run(command, check=True) + except subprocess.CalledProcessError as e: + print( + f"{log_context.title()} command exited with exit code: {e.returncode}" + ) + print( + "Please fix the cause of the error above or press Ctrl+C to stop the " + "server." + ) + print( + "The server will continue serving the build folder, but the contents " + "being served are no longer in sync with the documentation sources. " + "Please fix the cause of the error above or press Ctrl+C to stop the " + "server." + ) + traceback.print_exception(e) + return e.returncode + return 0 diff --git a/tests/test_application.py b/tests/test_application.py index b937c13..6919d9a 100644 --- a/tests/test_application.py +++ b/tests/test_application.py @@ -21,7 +21,10 @@ def test_application(tmp_path): url_host = "127.0.0.1:7777" ignore_handler = IgnoreFilter([out_dir], []) builder = Builder( - [str(src_dir), str(out_dir)], url_host=url_host, pre_build_commands=[] + [str(src_dir), str(out_dir)], + url_host=url_host, + pre_build_commands=[], + post_build_commands=[], ) app = _create_app([src_dir], ignore_handler, builder, out_dir, url_host) client = TestClient(app)