diff --git a/dotbot/context.py b/dotbot/context.py index 3ce9e6e..31e93c9 100644 --- a/dotbot/context.py +++ b/dotbot/context.py @@ -8,11 +8,11 @@ class Context: Contextual data and information for plugins. """ - def __init__(self, base_directory, options=Namespace()): + def __init__(self, base_directory, options=Namespace(), plugins=None): self._base_directory = base_directory self._defaults = {} self._options = options - pass + self._plugins = plugins def set_base_directory(self, base_directory): self._base_directory = base_directory @@ -31,3 +31,7 @@ class Context: def options(self): return copy.deepcopy(self._options) + + def plugins(self): + # shallow copy is ok here + return copy.copy(self._plugins) diff --git a/dotbot/dispatcher.py b/dotbot/dispatcher.py index f89683d..6660d88 100644 --- a/dotbot/dispatcher.py +++ b/dotbot/dispatcher.py @@ -17,18 +17,18 @@ class Dispatcher: plugins=None, ): self._log = Messenger() - self._setup_context(base_directory, options) + self._setup_context(base_directory, options, plugins) plugins = plugins or [] self._plugins = [plugin(self._context) for plugin in plugins] self._only = only self._skip = skip self._exit = exit_on_failure - def _setup_context(self, base_directory, options): + def _setup_context(self, base_directory, options, plugins): path = os.path.abspath(os.path.expanduser(base_directory)) if not os.path.exists(path): raise DispatchError("Nonexistent base directory") - self._context = Context(path, options) + self._context = Context(path, options, plugins) def dispatch(self, tasks): success = True diff --git a/tests/dotbot_plugin_context_plugin.py b/tests/dotbot_plugin_context_plugin.py new file mode 100644 index 0000000..f1615e9 --- /dev/null +++ b/tests/dotbot_plugin_context_plugin.py @@ -0,0 +1,18 @@ +# https://github.com/anishathalye/dotbot/issues/339 +# plugins should be able to instantiate a Dispatcher with all the plugins + +import dotbot +from dotbot.dispatcher import Dispatcher + + +class Dispatch(dotbot.Plugin): + def can_handle(self, directive): + return directive == "dispatch" + + def handle(self, directive, data): + dispatcher = Dispatcher( + base_directory=self._context.base_directory(), + options=self._context.options(), + plugins=self._context.plugins(), + ) + return dispatcher.dispatch(data) diff --git a/tests/test_cli.py b/tests/test_cli.py index 5868e6f..cc270b4 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -170,3 +170,17 @@ def test_disable_builtin_plugins(home, dotfiles, run_dotbot): run_dotbot("--disable-built-in-plugins") assert not os.path.exists(os.path.join(home, ".f")) + + +def test_plugin_context_plugin(capfd, home, dotfiles, run_dotbot): + """Verify that the plugin context is available to plugins.""" + + plugin_file = os.path.join( + os.path.dirname(os.path.abspath(__file__)), "dotbot_plugin_context_plugin.py" + ) + shutil.copy(plugin_file, os.path.join(dotfiles.directory, "plugin.py")) + dotfiles.write_config([{"dispatch": [{"shell": [{"command": "echo apple", "stdout": True}]}]}]) + run_dotbot("--plugin", os.path.join(dotfiles.directory, "plugin.py")) + + stdout = capfd.readouterr().out.splitlines() + assert any(line.startswith("apple") for line in stdout)