Skip to content

Commit 9a4f98c

Browse files
committed
Prevent non-umbrella project-local plugins
Only umbrella projects can have these.
1 parent 72ab1e9 commit 9a4f98c

File tree

2 files changed

+74
-3
lines changed

2 files changed

+74
-3
lines changed

src/rebar_plugins.erl

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ discover_plugins(_, State) ->
190190
%% TODO: only support this mode in an umbrella project to avoid cases where
191191
%% this is used in a project intended to be an installed dependency and accidentally
192192
%% relies on vendoring when not intended.
193-
case lists:member(global, rebar_state:current_profiles(State)) of
193+
case lists:member(global, rebar_state:current_profiles(State)) orelse not is_umbrella(State) of
194194
true ->
195195
[];
196196
false ->
@@ -213,6 +213,24 @@ discover_plugins(_, State) ->
213213
rebar_utils:sort_deps(SetUp)
214214
end.
215215

216+
is_umbrella(State) ->
217+
%% We can't know if this is an umbrella project before running app discovery,
218+
%% but plugins are installed before app discovery. So we do a heuristic.
219+
%% The lib dirs we search contain things such as apps/, lib/, etc.
220+
%% which contain sub-applications. Then there's a final search for the
221+
%% local directory ("."), which finds the top-level app in a non-umbrella
222+
%% project.
223+
%%
224+
%% So what we do here is look for the library directories without the ".",
225+
%% and if none of these paths exist but one of the src_dirs exist, then
226+
%% we know this is not an umbrella application.
227+
Root = rebar_dir:root_dir(State),
228+
LibPaths = rebar_dir:lib_dirs(State) -- ["."],
229+
SrcPaths = rebar_dir:src_dirs(rebar_state:opts(State), ["src"]),
230+
lists:any(fun(Dir) -> [] == filelib:wildcard(filename:join(Root, Dir)) end, LibPaths)
231+
andalso
232+
lists:all(fun(Dir) -> not filelib:is_dir(filename:join(Root, Dir)) end, SrcPaths).
233+
216234
prepare_plugin(AppInfo) ->
217235
%% We need to handle plugins as dependencies to avoid re-building them
218236
%% continuously. So here we copy the app directories to the dep location

test/rebar_plugins_SUITE.erl

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
use_checkout_plugins/1,
2020
%% project-local plugins
2121
complex_local_plugins/1,
22-
complex_local_project_plugins/1
22+
complex_local_project_plugins/1,
23+
local_plugins_umbrella_only/1
2324
]).
2425

2526
-include_lib("common_test/include/ct.hrl").
@@ -44,7 +45,7 @@ end_per_testcase(_, _Config) ->
4445
all() ->
4546
[compile_plugins, compile_global_plugins, complex_plugins, list, upgrade, upgrade_project_plugin,
4647
sub_app_plugins, sub_app_plugin_overrides, project_plugins, use_checkout_plugins,
47-
complex_local_plugins, complex_local_project_plugins].
48+
complex_local_plugins, complex_local_project_plugins, local_plugins_umbrella_only].
4849

4950
%% Tests that compiling a project installs and compiles the plugins of deps
5051
compile_plugins(Config) ->
@@ -527,3 +528,55 @@ complex_local_project_plugins(Config) ->
527528

528529
meck:unload(rebar_dir).
529530

531+
local_plugins_umbrella_only(Config) ->
532+
BaseDir = ?config(apps, Config),
533+
AppName = rebar_test_utils:create_random_name("app1_"),
534+
AppDir = BaseDir,
535+
LocalPluginName = rebar_test_utils:create_random_name("localplugin1_"),
536+
PluginDir = filename:join([BaseDir, "plugins", LocalPluginName]),
537+
538+
meck:new(rebar_dir, [passthrough]),
539+
540+
Vsn = rebar_test_utils:create_random_vsn(),
541+
Vsn2 = rebar_test_utils:create_random_vsn(),
542+
rebar_test_utils:create_app(AppDir, AppName, Vsn, [kernel, stdlib]),
543+
rebar_test_utils:create_app(PluginDir, LocalPluginName, Vsn, [kernel, stdlib]),
544+
545+
DepName = rebar_test_utils:create_random_name("dep1_"),
546+
DepName2 = rebar_test_utils:create_random_name("dep2_"),
547+
DepName3 = rebar_test_utils:create_random_name("dep3_"),
548+
DepName4 = rebar_test_utils:create_random_name("dep4_"),
549+
PluginName = rebar_test_utils:create_random_name("plugin1_"),
550+
551+
Deps = rebar_test_utils:expand_deps(git, [{PluginName, Vsn2, [{DepName2, Vsn,
552+
[{DepName3, Vsn, []}]}]}
553+
,{DepName, Vsn, [{DepName4, Vsn, []}]}]),
554+
{SrcDeps, _} = rebar_test_utils:flat_deps(Deps),
555+
mock_git_resource:mock([{deps, SrcDeps}]),
556+
557+
RootConfFile =
558+
rebar_test_utils:create_config(BaseDir,
559+
[{plugins, [list_to_atom(LocalPluginName)]}]),
560+
rebar_test_utils:create_config(
561+
PluginDir,
562+
[{deps, [{list_to_atom(DepName),
563+
{git, "http://site.com/user/"++DepName++".git", {tag, Vsn}}}]},
564+
{plugins, [{list_to_atom(PluginName),
565+
{git, "http://site.com/user/"++PluginName++".git", {tag, Vsn2}}}
566+
]}]
567+
),
568+
{ok, RConf} = file:consult(RootConfFile),
569+
570+
%% Build with deps.
571+
rebar_test_utils:run_and_check(
572+
Config, RConf, ["compile"],
573+
{ok, [{app, AppName},
574+
{plugin_not_exist, LocalPluginName},
575+
{plugin_not_exist, PluginName},
576+
{plugin_not_exist, DepName2},
577+
{plugin_not_exist, DepName3},
578+
{plugin_not_exist, DepName4},
579+
{plugin_not_exist, DepName}]}
580+
),
581+
582+
meck:unload(rebar_dir).

0 commit comments

Comments
 (0)