diff --git a/inttest/depplugins/depplugins_rt.erl b/inttest/depplugins/depplugins_rt.erl
new file mode 100644
index 0000000..7b106eb
--- /dev/null
+++ b/inttest/depplugins/depplugins_rt.erl
@@ -0,0 +1,50 @@
+%%% @doc Plugin handling test
+%%%
+%%% This test checks if plugins are loaded correctly.
+%%%
+%%% It has three applications:
+%%%
+%%% - fish. top-level module, has one dependency: `dependsonplugin'.
+%%% - dependsonplugin. This depends on some pre-compile actions by the
+%%% plugin. In the test the plugin creates a file `pre.compile' in the
+%%% top-level folder of this application.
+%%% - testplugin. This is a plugin application which creates the file.
+%%%
+
+-module(depplugins_rt).
+-compile(export_all).
+
+-include_lib("eunit/include/eunit.hrl").
+
+files() ->
+ [
+ {copy, "../../rebar", "rebar"},
+ {copy, "rebar.config", "rebar.config"},
+ {create, "ebin/fish.app", app(fish, [])},
+
+ {create, "deps/dependsonplugin/ebin/dependsonplugin.app",
+ app(dependsonplugin, [])},
+ {copy, "rebar_dependsonplugin.config",
+ "deps/dependsonplugin/rebar.config"},
+ {copy, "testplugin_mod.erl",
+ "deps/testplugin/plugins/testplugin_mod.erl"},
+ {create, "deps/testplugin/ebin/testplugin.app",
+ app(testplugin, [])}
+ ].
+
+run(_Dir) ->
+ ?assertMatch({ok, _}, retest_sh:run("./rebar compile", [])),
+ ?assertEqual(true, filelib:is_regular("deps/dependsonplugin/pre.compile")),
+ ok.
+
+%%
+%% Generate the contents of a simple .app file
+%%
+app(Name, Modules) ->
+ App = {application, Name,
+ [{description, atom_to_list(Name)},
+ {vsn, "1"},
+ {modules, Modules},
+ {registered, []},
+ {applications, [kernel, stdlib]}]},
+ io_lib:format("~p.\n", [App]).
diff --git a/inttest/depplugins/rebar.config b/inttest/depplugins/rebar.config
new file mode 100644
index 0000000..3a2e34e
--- /dev/null
+++ b/inttest/depplugins/rebar.config
@@ -0,0 +1 @@
+{deps, [dependsonplugin]}.
diff --git a/inttest/depplugins/rebar_dependsonplugin.config b/inttest/depplugins/rebar_dependsonplugin.config
new file mode 100644
index 0000000..df36213
--- /dev/null
+++ b/inttest/depplugins/rebar_dependsonplugin.config
@@ -0,0 +1,2 @@
+{deps, [testplugin]}.
+{plugins, [testplugin_mod]}.
diff --git a/inttest/depplugins/testplugin_mod.erl b/inttest/depplugins/testplugin_mod.erl
new file mode 100644
index 0000000..055bbc7
--- /dev/null
+++ b/inttest/depplugins/testplugin_mod.erl
@@ -0,0 +1,6 @@
+-module(testplugin_mod).
+-compile(export_all).
+
+pre_compile(Config, _) ->
+ ok = file:write_file("pre.compile", <<"Yadda!">>),
+ rebar_log:log(info, "Wrote ~p/pre.compile~n", [rebar_utils:get_cwd()]).
diff --git a/src/rebar_core.erl b/src/rebar_core.erl
index 36923a5..3172d64 100644
--- a/src/rebar_core.erl
+++ b/src/rebar_core.erl
@@ -530,35 +530,41 @@ plugin_modules(Config, PredirsAssoc, FoundModules, MissingModules) ->
load_plugin_modules(Config, PredirsAssoc, Modules) ->
Cwd = rebar_utils:get_cwd(),
- PluginDir = case rebar_config:get_local(Config, plugin_dir, undefined) of
- undefined ->
- filename:join(Cwd, "plugins");
- Dir ->
- Dir
- end,
+ PluginDirs = case rebar_config:get_local(Config, plugin_dir, undefined) of
+ undefined ->
+ % Plugin can be in the project's "plugins" folder
+ [filename:join(Cwd, "plugins")];
+ Dir ->
+ [Dir]
+ end ++
+ % We also want to include this case:
+ % Plugin can be in "plugins" directory of the plugin base directory. For
+ % example, Cwd depends on Plugin, and deps/Plugin/plugins/Plugin.erl is the
+ % plugin.
+ [
+ filename:join(Dir, "plugins") ||
+ Dir <- get_plugin_base_dirs(Cwd, PredirsAssoc)
+ ],
%% Find relevant sources in base_dir and plugin_dir
Erls = string:join([atom_to_list(M)++"\\.erl" || M <- Modules], "|"),
RE = "^" ++ Erls ++ "\$",
- BaseDir = get_plugin_base_dir(Cwd, PredirsAssoc),
%% If a plugin is found both in base_dir and plugin_dir, the clash
%% will provoke an error and we'll abort.
- Sources = rebar_utils:find_files(PluginDir, RE, false)
- ++ rebar_utils:find_files(BaseDir, RE, false),
+ Sources = [rebar_utils:find_files(PD, RE, false) || PD <- PluginDirs],
%% Compile and load plugins
- Loaded = [load_plugin(Src) || Src <- Sources],
+ Loaded = [load_plugin(Src) || Src <- lists:append(Sources)],
FilterMissing = is_missing_plugin(Loaded),
NotLoaded = [V || V <- Modules, FilterMissing(V)],
{Loaded, NotLoaded}.
-get_plugin_base_dir(Cwd, PredirsAssoc) ->
- case dict:find(Cwd, PredirsAssoc) of
- {ok, BaseDir} ->
- BaseDir;
- error ->
- Cwd
- end.
+%% @doc PredirsAssoc is a dictionary of plugindir -> 'parent' pairs
+%% 'parent' in this case depends on plugin; therefore we have to give
+%% all plugins that Cwd ('parent' in this case) depends on.
+get_plugin_base_dirs(Cwd, PredirsAssoc) ->
+ [PluginDir || {PluginDir, Master} <- dict:to_list(PredirsAssoc),
+ Master =:= Cwd].
is_missing_plugin(Loaded) ->
fun(Mod) -> not lists:member(Mod, Loaded) end.