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

Make Dispatcher have all plugins by default

This used to be the behavior, and then
b5499c7dc5 changed this, breaking some
plugins (some of which subsequently implemented workarounds). This patch
restores the behavior, so that if a Dispatcher is constructed without
explicitly passing in plugins, it has access to all plugins.

This change seems safe, in that it's unlikely that any plugins were
relying on the behavior between b5499c7dc5
and this patch, where a Dispatcher without an explicit plugin list
behaved as if there were no plugins---because such a Dispatcher is not
very useful!
This commit is contained in:
Anish Athalye 2024-12-08 18:11:13 -05:00
parent 6489f28311
commit def05688c0
4 changed files with 46 additions and 2 deletions

View file

@ -7,7 +7,7 @@ from argparse import ArgumentParser, RawTextHelpFormatter
import dotbot
from .config import ConfigReader, ReadingError
from .dispatcher import Dispatcher, DispatchError
from .dispatcher import Dispatcher, DispatchError, _all_plugins
from .messenger import Level, Messenger
from .plugins import Clean, Create, Link, Shell
from .util import module
@ -151,6 +151,7 @@ def main():
# default to directory of config file
base_directory = os.path.dirname(os.path.abspath(options.config_file))
os.chdir(base_directory)
_all_plugins[:] = plugins # for backwards compatibility, see dispatcher.py
dispatcher = Dispatcher(
base_directory,
only=options.only,

View file

@ -5,6 +5,14 @@ from .context import Context
from .messenger import Messenger
from .plugin import Plugin
# Before b5499c7dc5b300462f3ce1c2a3d9b7a76233b39b, Dispatcher auto-loaded all
# plugins, but after that change, plugins are passed in explicitly (and loaded
# in cli.py). There are some plugins that rely on the old Dispatcher behavior,
# so this is a workaround for implementing similar functionality: when
# Dispatcher is constructed without an explicit list of plugins, _all_plugins is
# used instead.
_all_plugins = [] # filled in by cli.py
class Dispatcher:
def __init__(
@ -16,9 +24,12 @@ class Dispatcher:
options=Namespace(),
plugins=None,
):
# if the caller wants no plugins, the caller needs to explicitly pass in
# plugins=[]
self._log = Messenger()
self._setup_context(base_directory, options, plugins)
plugins = plugins or []
if plugins is None:
plugins = _all_plugins
self._plugins = [plugin(self._context) for plugin in plugins]
self._only = only
self._skip = skip

View file

@ -0,0 +1,18 @@
# https://github.com/anishathalye/dotbot/issues/339, https://github.com/anishathalye/dotbot/pull/332
# if plugins instantiate a Dispatcher without explicitly passing in plugins,
# the Dispatcher should have access to all plugins (matching context.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(),
)
return dispatcher.dispatch(data)

View file

@ -199,3 +199,17 @@ def test_plugin_context_plugin(capfd, home, dotfiles, run_dotbot):
stdout = capfd.readouterr().out.splitlines()
assert any(line.startswith("apple") for line in stdout)
def test_plugin_dispatcher_no_plugins(capfd, home, dotfiles, run_dotbot):
"""Verify that plugins instantiating Dispatcher without plugins work."""
plugin_file = os.path.join(
os.path.dirname(os.path.abspath(__file__)), "dotbot_plugin_dispatcher_no_plugins.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)