diff --git a/changelog.d/20231011_000434_codewithemad_save_configs.md b/changelog.d/20231011_000434_codewithemad_save_configs.md new file mode 100644 index 0000000..0afbad4 --- /dev/null +++ b/changelog.d/20231011_000434_codewithemad_save_configs.md @@ -0,0 +1 @@ +- [Improvement] You don't have to run `tutor config save` every time you enable or disable a plugin anymore. (by @CodeWithEmad) \ No newline at end of file diff --git a/tests/test_utils.py b/tests/test_utils.py index 21af475..5d5a642 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,9 +1,9 @@ import base64 import os +import subprocess import tempfile import unittest from io import StringIO -import subprocess from typing import List, Tuple from unittest.mock import MagicMock, mock_open, patch diff --git a/tutor/commands/plugins.py b/tutor/commands/plugins.py index e80b6fc..45d8bd6 100644 --- a/tutor/commands/plugins.py +++ b/tutor/commands/plugins.py @@ -1,6 +1,7 @@ from __future__ import annotations import os +import sys import tempfile import typing as t @@ -9,6 +10,7 @@ import click.shell_completion from tutor import config as tutor_config from tutor import exceptions, fmt, hooks, plugins, utils +from tutor.commands.config import save as config_save_command from tutor.plugins import indexes from tutor.plugins.base import PLUGINS_ROOT, PLUGINS_ROOT_ENV_VAR_NAME from tutor.types import Config @@ -133,17 +135,15 @@ def list_command(show_enabled_only: bool) -> None: @click.command(help="Enable a plugin") @click.argument("plugin_names", metavar="plugin", nargs=-1, type=PluginName()) -@click.pass_obj -def enable(context: Context, plugin_names: list[str]) -> None: - config = tutor_config.load_minimal(context.root) +@click.pass_context +def enable(context: click.Context, plugin_names: list[str]) -> None: + config = tutor_config.load_minimal(context.obj.root) for plugin in plugin_names: plugins.load(plugin) fmt.echo_info(f"Plugin {plugin} enabled") tutor_config.save_enabled_plugins(config) - tutor_config.save_config_file(context.root, config) - fmt.echo_info( - "You should now re-generate your environment with `tutor config save`." - ) + tutor_config.save_config_file(context.obj.root, config) + context.invoke(config_save_command, env_only=True) @click.command( @@ -153,22 +153,20 @@ def enable(context: Context, plugin_names: list[str]) -> None: @click.argument( "plugin_names", metavar="plugin", nargs=-1, type=PluginName(allow_all=True) ) -@click.pass_obj -def disable(context: Context, plugin_names: list[str]) -> None: - config = tutor_config.load_minimal(context.root) +@click.pass_context +def disable(context: click.Context, plugin_names: list[str]) -> None: + config = tutor_config.load_minimal(context.obj.root) disable_all = "all" in plugin_names disabled: list[str] = [] for plugin in tutor_config.get_enabled_plugins(config): if disable_all or plugin in plugin_names: fmt.echo_info(f"Disabling plugin {plugin}...") - hooks.Actions.PLUGIN_UNLOADED.do(plugin, context.root, config) + hooks.Actions.PLUGIN_UNLOADED.do(plugin, context.obj.root, config) disabled.append(plugin) fmt.echo_info(f"Plugin {plugin} disabled") if disabled: - tutor_config.save_config_file(context.root, config) - fmt.echo_info( - "You should now re-generate your environment with `tutor config save`." - ) + tutor_config.save_config_file(context.obj.root, config) + context.invoke(config_save_command, env_only=True) @click.command(name="update") diff --git a/tutor/config.py b/tutor/config.py index 2a0ee73..35e35c1 100644 --- a/tutor/config.py +++ b/tutor/config.py @@ -1,8 +1,8 @@ from __future__ import annotations -from copy import deepcopy -import typing as t import os +import typing as t +from copy import deepcopy from tutor import env, exceptions, fmt, hooks, plugins, serialize, utils from tutor.types import Config, ConfigValue, cast_config, get_typed diff --git a/tutor/plugins/__init__.py b/tutor/plugins/__init__.py index c5e88d2..f96afab 100644 --- a/tutor/plugins/__init__.py +++ b/tutor/plugins/__init__.py @@ -32,6 +32,17 @@ def _convert_plugin_patches() -> None: ENV_PATCHES_DICT[name].append(content) +@hooks.Actions.PLUGIN_UNLOADED.add() +def _clear_plugin_patches(plugin: str, root: str, _config: Config) -> None: + """ + After disabling a plugin, ENV_PATCHES_DICT should be cleared + and re-calculated. + + This action is run after plugins have been unloaded. + """ + ENV_PATCHES_DICT.clear() + + def is_installed(name: str) -> bool: """ Return true if the plugin is installed.