Skip to content

Commit

Permalink
Make Dispatcher have all plugins by default
Browse files Browse the repository at this point in the history
This used to be the behavior, and then
b5499c7 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 b5499c7
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!
  • Loading branch information
anishathalye committed Dec 8, 2024
1 parent 6489f28 commit def0568
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 2 deletions.
3 changes: 2 additions & 1 deletion dotbot/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
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
Expand Down Expand Up @@ -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,
Expand Down
13 changes: 12 additions & 1 deletion dotbot/dispatcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@
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__(
Expand All @@ -16,9 +24,12 @@ def __init__(
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
Expand Down
18 changes: 18 additions & 0 deletions tests/dotbot_plugin_dispatcher_no_plugins.py
Original file line number Diff line number Diff line change
@@ -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)
14 changes: 14 additions & 0 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

0 comments on commit def0568

Please sign in to comment.