From 7d20329894d95c0d0437f29a018826f7ac9a0410 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Behmo?= Date: Thu, 21 Apr 2022 16:24:34 +0200 Subject: [PATCH] feat: `local stop` on `dev start` (and vice versa) Running `local start` while a dev platform is still running is a common sourse of mistakes. Here we introduce a new action to automatically stop local and dev projects whenever a project with a different name is started. --- CHANGELOG.md | 1 + docs/tutorials/arm64.rst | 1 - tutor/commands/compose.py | 6 ++++++ tutor/commands/dev.py | 25 ++++++++++++++++++------- tutor/commands/local.py | 13 ++++++++++++- tutor/hooks/consts.py | 7 +++++++ 6 files changed, 44 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b34793..376da6f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ Note: Breaking changes between versions are indicated by "💥". ## Unreleased +- [Improvement] Add the `COMPOSE_PROJECT_STARTED` action and run `dev stop` on `local start` (and vice versa). - [Feature] Introduce `local/dev copyfrom` command to copy contents from a container. - [Bugfix] Fix a race condition that could prevent a newly provisioned LMS container from starting due to a `FileExistsError` when creating data folders. - [Deprecation] Mark `tutor dev runserver` as deprecated in favor of `tutor dev start`. Since `start` now supports bind-mounting and breakpoint debugging, `runserver` is redundant and will be removed in a future release. diff --git a/docs/tutorials/arm64.rst b/docs/tutorials/arm64.rst index 80be43f..b5b3099 100644 --- a/docs/tutorials/arm64.rst +++ b/docs/tutorials/arm64.rst @@ -52,7 +52,6 @@ From this point on, use Tutor as normal. For example, start Open edX and run mig Or for a development environment:: - tutor local stop tutor dev start -d tutor dev init diff --git a/tutor/commands/compose.py b/tutor/commands/compose.py index f19f8bf..ea2c0a3 100644 --- a/tutor/commands/compose.py +++ b/tutor/commands/compose.py @@ -24,6 +24,12 @@ class ComposeJobRunner(jobs.BaseComposeJobRunner): """ Run docker-compose with the right yml files. """ + if "start" in command or "up" in command or "restart" in command: + # Note that we don't trigger the action on "run". That's because we + # don't want to trigger the action for every initialization script. + hooks.Actions.COMPOSE_PROJECT_STARTED.do( + self.root, self.config, self.project_name + ) self.__update_docker_compose_tmp() args = [] for docker_compose_path in self.docker_compose_files: diff --git a/tutor/commands/dev.py b/tutor/commands/dev.py index 657aeef..a3778cb 100644 --- a/tutor/commands/dev.py +++ b/tutor/commands/dev.py @@ -2,13 +2,13 @@ import typing as t import click -from .. import config as tutor_config -from .. import env as tutor_env -from .. import exceptions, fmt -from .. import interactive as interactive_config -from .. import utils -from ..types import Config, get_typed -from . import compose +from tutor import config as tutor_config +from tutor import env as tutor_env +from tutor import exceptions, fmt, hooks +from tutor import interactive as interactive_config +from tutor import utils +from tutor.commands import compose +from tutor.types import Config, get_typed class DevJobRunner(compose.ComposeJobRunner): @@ -128,6 +128,17 @@ def runserver( context.invoke(compose.run, mounts=mounts, args=args) +@hooks.Actions.COMPOSE_PROJECT_STARTED.add() +def _stop_on_local_start(root: str, config: Config, project_name: str) -> None: + """ + Stop the dev platform as soon as a platform with a different project name is + started. + """ + runner = DevJobRunner(root, config) + if project_name != runner.project_name: + runner.docker_compose("stop") + + dev.add_command(quickstart) dev.add_command(runserver) compose.add_commands(dev) diff --git a/tutor/commands/local.py b/tutor/commands/local.py index a7848e2..f731049 100644 --- a/tutor/commands/local.py +++ b/tutor/commands/local.py @@ -4,7 +4,7 @@ import click from tutor import config as tutor_config from tutor import env as tutor_env -from tutor import exceptions, fmt +from tutor import exceptions, fmt, hooks from tutor import interactive as interactive_config from tutor import utils from tutor.commands import compose @@ -166,6 +166,17 @@ def upgrade(context: click.Context, from_release: t.Optional[str]) -> None: context.invoke(config_save_command) +@hooks.Actions.COMPOSE_PROJECT_STARTED.add() +def _stop_on_dev_start(root: str, config: Config, project_name: str) -> None: + """ + Stop the local platform as soon as a platform with a different project name is + started. + """ + runner = LocalJobRunner(root, config) + if project_name != runner.project_name: + runner.docker_compose("stop") + + local.add_command(quickstart) local.add_command(upgrade) compose.add_commands(local) diff --git a/tutor/hooks/consts.py b/tutor/hooks/consts.py index 929f95f..f017944 100644 --- a/tutor/hooks/consts.py +++ b/tutor/hooks/consts.py @@ -25,6 +25,13 @@ class Actions: # Do stuff here """ + #: Triggered whenever a "docker-compose start", "up" or "restart" command is executed. + #: + #: :parameter: str root: project root. + #: :parameter: dict[str, ...] config: project configuration. + #: :parameter: str name: docker-compose project name. + COMPOSE_PROJECT_STARTED = actions.get("compose:project:started") + #: Called whenever the core project is ready to run. This action is called as soon #: as possible. This is the right time to discover plugins, for instance. In #: particular, we auto-discover the following plugins: