diff --git a/dotbot/cli.py b/dotbot/cli.py index f421003..3a14d2d 100644 --- a/dotbot/cli.py +++ b/dotbot/cli.py @@ -131,6 +131,11 @@ def main(): for plugin_path in plugin_paths: abspath = os.path.abspath(plugin_path) plugins.extend(module.load(abspath)) + # ensure plugins are unique to avoid duplicate execution, which + # can happen if, for example, a third-party plugin loads a + # built-in plugin, which will cause it to appear in the list + # returned by module.load above + plugins = set(plugins) if not options.config_file: log.error("No configuration file specified") exit(1) diff --git a/tests/dotbot_plugin_issue_357.py b/tests/dotbot_plugin_issue_357.py new file mode 100644 index 0000000..36609de --- /dev/null +++ b/tests/dotbot_plugin_issue_357.py @@ -0,0 +1,17 @@ +import os + +from dotbot.plugin import Plugin +from dotbot.plugins import Clean, Create, Link, Shell + +# https://github.com/anishathalye/dotbot/issues/357 +# if we import from dotbot.plugins, the built-in plugins get executed multiple times + + +class NoopPlugin(Plugin): + _directive = "noop" + + def can_handle(self, directive): + return directive == self._directive + + def handle(self, directive, data): + return True diff --git a/tests/test_cli.py b/tests/test_cli.py index cc270b4..a9fc7ae 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -159,6 +159,21 @@ def test_plugin_loading_directory(home, dotfiles, run_dotbot): assert file.read() == "directory plugin loading works" +def test_issue_357(capfd, home, dotfiles, run_dotbot): + """Verify that built-in plugins are only executed once, when + using a plugin that imports from dotbot.plugins.""" + plugin_file = os.path.join( + os.path.dirname(os.path.abspath(__file__)), "dotbot_plugin_issue_357.py" + ) + dotfiles.write_config([{"shell": [{"command": "echo apple", "stdout": True}]}]) + + run_dotbot("--plugin", plugin_file) + + assert ( + len([line for line in capfd.readouterr().out.splitlines() if line.strip() == "apple"]) == 1 + ) + + def test_disable_builtin_plugins(home, dotfiles, run_dotbot): """Verify that builtin plugins can be disabled."""