1
0
Fork 0
mirror of synced 2024-12-22 06:01:07 -05:00

Make set of plugins available in context

This is useful for plugins like dotbot-if [1] that want to instantiate
their own Dispatcher. Previously, the Dispatcher found the set of
available plugins on its own, but as of
b5499c7dc5, this was changed so that
plugins are passed in.

Given that it has been over two years since this behavior has been
broken/changed, reverting to the previous behavior of having the
Dispatcher auto-load plugins might not be ideal, which is why this patch
instead makes the set of plugins available via the Context for plugins
to use.

This was reported in the Dotbot repository [2], and earlier in dotbot-if
[3]. dotbot-if is currently using a workaround [4] that was originally
implemented in dotbot-ifplatform [5].

[1]: https://github.com/wonderbeyond/dotbot-if
[2]: https://github.com/anishathalye/dotbot/issues/339
[3]: https://github.com/wonderbeyond/dotbot-if/issues/1
[4]: https://github.com/wonderbeyond/dotbot-if/pull/2
[5]: e35b5c0d71
This commit is contained in:
Anish Athalye 2024-12-07 18:16:01 -05:00
parent 4edfa82607
commit 8c2dc8cbc6
4 changed files with 41 additions and 5 deletions

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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)