summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/rebar.app.src2
-rw-r--r--src/rebar3.erl9
-rw-r--r--src/rebar_dir.erl2
-rw-r--r--src/rebar_plugins.erl50
-rw-r--r--src/rebar_prv_as.erl7
-rw-r--r--src/rebar_prv_install_deps.erl47
-rw-r--r--src/rebar_prv_plugins.erl67
-rw-r--r--src/rebar_prv_plugins_upgrade.erl96
-rw-r--r--src/rebar_state.erl52
-rw-r--r--test/rebar_compile_SUITE.erl133
-rw-r--r--test/rebar_plugins_SUITE.erl201
11 files changed, 470 insertions, 196 deletions
diff --git a/src/rebar.app.src b/src/rebar.app.src
index e9f0677..6d081a2 100644
--- a/src/rebar.app.src
+++ b/src/rebar.app.src
@@ -44,6 +44,8 @@
rebar_prv_lock,
rebar_prv_new,
rebar_prv_packages,
+ rebar_prv_plugins,
+ rebar_prv_plugins_upgrade,
rebar_prv_release,
rebar_prv_report,
rebar_prv_shell,
diff --git a/src/rebar3.erl b/src/rebar3.erl
index e324687..5c0559f 100644
--- a/src/rebar3.erl
+++ b/src/rebar3.erl
@@ -95,12 +95,12 @@ run_aux(State, RawArgs) ->
%% Process each command, resetting any state between each one
BaseDir = rebar_state:get(State, base_dir, ?DEFAULT_BASE_DIR),
State3 = rebar_state:set(State2, base_dir,
- filename:join(filename:absname(rebar_state:dir(State2)), BaseDir)),
+ filename:join(filename:absname(rebar_state:dir(State2)), BaseDir)),
{ok, Providers} = application:get_env(rebar, providers),
%% Providers can modify profiles stored in opts, so set default after initializing providers
State4 = rebar_state:create_logic_providers(Providers, State3),
- State5 = rebar_plugins:install(State4),
+ State5 = rebar_plugins:project_apps_install(State4),
State6 = rebar_state:default(State5, rebar_state:opts(State5)),
{Task, Args} = parse_args(RawArgs),
@@ -133,13 +133,14 @@ init_config() ->
%% We don't want to worry about global plugin install state effecting later
%% usage. So we throw away the global profile state used for plugin install.
- GlobalConfigThrowAway = rebar_state:current_profiles(GlobalConfig, ["global"]),
+ GlobalConfigThrowAway = rebar_state:current_profiles(GlobalConfig, [global]),
GlobalState = rebar_plugins:handle_plugins(global,
rebar_state:get(GlobalConfigThrowAway, plugins, []),
GlobalConfigThrowAway),
GlobalPlugins = rebar_state:providers(GlobalState),
GlobalConfig2 = rebar_state:set(GlobalConfig, plugins, []),
- rebar_state:providers(rebar_state:new(GlobalConfig2, Config1), GlobalPlugins);
+ GlobalConfig3 = rebar_state:set(GlobalConfig2, {plugins, global}, rebar_state:get(GlobalConfigThrowAway, plugins, [])),
+ rebar_state:providers(rebar_state:new(GlobalConfig3, Config1), GlobalPlugins);
false ->
rebar_state:new(Config1)
end,
diff --git a/src/rebar_dir.erl b/src/rebar_dir.erl
index cb643ab..e226633 100644
--- a/src/rebar_dir.erl
+++ b/src/rebar_dir.erl
@@ -35,6 +35,7 @@ base_dir(State) ->
profile_dir(State, Profiles) ->
{BaseDir, ProfilesStrings} = case [ec_cnv:to_list(P) || P <- Profiles] of
["global" | _] -> {?MODULE:global_cache_dir(State), [""]};
+ ["bootstrap", "default"] -> {rebar_state:get(State, base_dir, ?DEFAULT_BASE_DIR), ["default"]};
["default"] -> {rebar_state:get(State, base_dir, ?DEFAULT_BASE_DIR), ["default"]};
%% drop `default` from the profile dir if it's implicit and reverse order
%% of profiles to match order passed to `as`
@@ -43,7 +44,6 @@ profile_dir(State, Profiles) ->
ProfilesDir = string:join(ProfilesStrings, "+"),
filename:join(BaseDir, ProfilesDir).
-
-spec deps_dir(rebar_state:t()) -> file:filename_all().
deps_dir(State) ->
filename:join(base_dir(State), rebar_state:get(State, deps_dir, ?DEFAULT_DEPS_DIR)).
diff --git a/src/rebar_plugins.erl b/src/rebar_plugins.erl
index 88cb8b8..a267b9d 100644
--- a/src/rebar_plugins.erl
+++ b/src/rebar_plugins.erl
@@ -3,7 +3,10 @@
-module(rebar_plugins).
--export([install/1, handle_plugins/2, handle_plugins/3]).
+-export([project_apps_install/1
+ ,install/1
+ ,handle_plugins/3
+ ,handle_plugins/4]).
-include("rebar.hrl").
@@ -11,26 +14,35 @@
%% Public API
%% ===================================================================
--spec install(rebar_state:t()) -> rebar_state:t().
-install(State) ->
- Plugins = rebar_state:get(State, plugins, []),
-
+-spec project_apps_install(rebar_state:t()) -> rebar_state:t().
+project_apps_install(State) ->
+ Profiles = rebar_state:current_profiles(State),
ProjectApps = rebar_state:project_apps(State),
- OtherPlugins = lists:flatmap(fun(App) ->
- AppDir = rebar_app_info:dir(App),
- C = rebar_config:consult(AppDir),
- S = rebar_state:new(rebar_state:new(), C, AppDir),
- rebar_state:get(S, plugins, [])
- end, ProjectApps),
-
- handle_plugins(Plugins++OtherPlugins, State).
+ lists:foldl(fun(Profile, StateAcc) ->
+ Plugins = rebar_state:get(State, {plugins, Profile}, []),
+ handle_plugins(Profile, Plugins, StateAcc),
+ lists:foldl(fun(App, StateAcc1) ->
+ AppDir = rebar_app_info:dir(App),
+ C = rebar_config:consult(AppDir),
+ S = rebar_state:new(rebar_state:new(), C, AppDir),
+ Plugins2 = rebar_state:get(S, {plugins, Profile}, []),
+ handle_plugins(Profile, Plugins2, StateAcc1)
+ end, StateAcc, ProjectApps)
+ end, State, Profiles).
--spec handle_plugins([rebar_prv_install_deps:dep()], rebar_state:t()) -> rebar_state:t().
-handle_plugins(Plugins, State) ->
- handle_plugins(default, Plugins, State).
+-spec install(rebar_state:t()) -> rebar_state:t().
+install(State) ->
+ Profiles = rebar_state:current_profiles(State),
+ lists:foldl(fun(Profile, StateAcc) ->
+ Plugins = rebar_state:get(State, {plugins, Profile}, []),
+ handle_plugins(Profile, Plugins, StateAcc)
+ end, State, Profiles).
handle_plugins(Profile, Plugins, State) ->
+ handle_plugins(Profile, Plugins, State, false).
+
+handle_plugins(Profile, Plugins, State, Upgrade) ->
%% Set deps dir to plugins dir so apps are installed there
Locks = rebar_state:lock(State),
DepsDir = rebar_state:get(State, deps_dir, ?DEFAULT_DEPS_DIR),
@@ -39,7 +51,7 @@ handle_plugins(Profile, Plugins, State) ->
%% Install each plugin individually so if one fails to install it doesn't effect the others
{PluginProviders, State2} =
lists:foldl(fun(Plugin, {PluginAcc, StateAcc}) ->
- {NewPlugins, NewState} = handle_plugin(Profile, Plugin, StateAcc),
+ {NewPlugins, NewState} = handle_plugin(Profile, Plugin, StateAcc, Upgrade),
{PluginAcc++NewPlugins, NewState}
end, {[], State1}, Plugins),
@@ -49,9 +61,9 @@ handle_plugins(Profile, Plugins, State) ->
rebar_state:create_logic_providers(PluginProviders, State4).
-handle_plugin(Profile, Plugin, State) ->
+handle_plugin(Profile, Plugin, State, Upgrade) ->
try
- {ok, Apps, State2} = rebar_prv_install_deps:handle_deps(Profile, State, [Plugin]),
+ {ok, Apps, State2} = rebar_prv_install_deps:handle_deps(Profile, State, [Plugin], Upgrade),
{no_cycle, Sorted} = rebar_prv_install_deps:find_cycles(Apps),
ToBuild = rebar_prv_install_deps:cull_compile(Sorted, []),
diff --git a/src/rebar_prv_as.erl b/src/rebar_prv_as.erl
index d8f19d4..ead7b01 100644
--- a/src/rebar_prv_as.erl
+++ b/src/rebar_prv_as.erl
@@ -38,13 +38,14 @@ do(State) ->
{error, "At least one profile must be specified when using `as`"};
_ ->
State1 = rebar_state:apply_profiles(State, [list_to_atom(X) || X <- Profiles]),
+ State2 = rebar_plugins:project_apps_install(State1),
{FirstTask, FirstTaskArgs} = hd(Tasks),
FirstTaskAtom = list_to_atom(FirstTask),
- case rebar_core:process_namespace(State1, FirstTaskAtom) of
- {ok, State2, NewTask} ->
+ case rebar_core:process_namespace(State2, FirstTaskAtom) of
+ {ok, State3, NewTask} ->
rebar_prv_do:do_tasks(
[{atom_to_list(NewTask),FirstTaskArgs}|tl(Tasks)],
- State2
+ State3
);
{error, Reason} ->
{error, Reason}
diff --git a/src/rebar_prv_install_deps.erl b/src/rebar_prv_install_deps.erl
index 61bbb62..806293b 100644
--- a/src/rebar_prv_install_deps.erl
+++ b/src/rebar_prv_install_deps.erl
@@ -234,22 +234,26 @@ handle_pkg_dep(Profile, Pkg, Packages, Upgrade, DepsDir, Fetched, Seen, Locks, S
BaseDir = rebar_state:get(State, base_dir, []),
S1 = rebar_state:new(rebar_state:set(rebar_state:new(), base_dir, BaseDir),
C, rebar_app_info:dir(AppInfo1)),
- S2 = rebar_state:apply_profiles(S1, Profiles),
- S3 = rebar_state:apply_overrides(S2, Name),
- AppInfo2 = rebar_app_info:state(AppInfo1, S3),
+ S2 = rebar_state:apply_overrides(S1, Name),
+
+ Plugins = rebar_state:get(S2, plugins, []),
+ S3 = rebar_state:set(S2, {plugins, Profile}, Plugins),
+
+ S4 = rebar_state:apply_profiles(S3, Profiles),
+ AppInfo2 = rebar_app_info:state(AppInfo1, S4),
%% Dep may have plugins to install. Find and install here.
- S4 = rebar_plugins:handle_plugins(rebar_state:get(S3, plugins, []), S3),
- AppInfo3 = rebar_app_info:state(AppInfo2, S4),
+ S5 = rebar_plugins:install(S4),
+ AppInfo3 = rebar_app_info:state(AppInfo2, S5),
{[AppInfo3 | Fetched], NewSeen, NewState}.
maybe_lock(Profile, AppInfo, Seen, State, Level) ->
+ Name = rebar_app_info:name(AppInfo),
case rebar_app_info:is_checkout(AppInfo) of
false ->
case Profile of
default ->
- Name = rebar_app_info:name(AppInfo),
case sets:is_element(Name, Seen) of
false ->
Locks = rebar_state:lock(State),
@@ -264,10 +268,10 @@ maybe_lock(Profile, AppInfo, Seen, State, Level) ->
{Seen, State}
end;
_ ->
- {Seen, State}
+ {sets:add_element(Name, Seen), State}
end;
true ->
- {Seen, State}
+ {sets:add_element(Name, Seen), State}
end.
package_to_app(DepsDir, Packages, {Name, Vsn, Level}, IsLock, State) ->
@@ -367,7 +371,6 @@ handle_upgrade(AppInfo, Profile, SrcDeps, PkgDeps, SrcApps, Level, State, Locks)
{true, AppInfo1} ->
handle_dep(AppInfo1, Profile, SrcDeps, PkgDeps, SrcApps,
Level, State, Locks);
-
{false, AppInfo1} ->
{[AppInfo1|SrcDeps], PkgDeps, SrcApps, State, Locks}
end;
@@ -378,7 +381,7 @@ handle_upgrade(AppInfo, Profile, SrcDeps, PkgDeps, SrcApps, Level, State, Locks)
handle_dep(AppInfo, Profile, SrcDeps, PkgDeps, SrcApps, Level, State, Locks) ->
DepsDir = profile_dep_dir(State, Profile),
{AppInfo1, NewSrcDeps, NewPkgDeps, NewLocks, State1} =
- handle_dep(State, DepsDir, AppInfo, Locks, Level),
+ handle_dep(State, Profile, DepsDir, AppInfo, Locks, Level),
AppInfo2 = rebar_app_info:dep_level(AppInfo1, Level),
{NewSrcDeps ++ SrcDeps
,NewPkgDeps++PkgDeps
@@ -386,9 +389,9 @@ handle_dep(AppInfo, Profile, SrcDeps, PkgDeps, SrcApps, Level, State, Locks) ->
,State1
,NewLocks}.
--spec handle_dep(rebar_state:t(), file:filename_all(), rebar_app_info:t(), list(), integer()) ->
+-spec handle_dep(rebar_state:t(), atom(), file:filename_all(), rebar_app_info:t(), list(), integer()) ->
{rebar_app_info:t(), [rebar_app_info:t()], [pkg_dep()], [integer()]}.
-handle_dep(State, DepsDir, AppInfo, Locks, Level) ->
+handle_dep(State, Profile, DepsDir, AppInfo, Locks, Level) ->
Profiles = rebar_state:current_profiles(State),
Name = rebar_app_info:name(AppInfo),
@@ -396,20 +399,24 @@ handle_dep(State, DepsDir, AppInfo, Locks, Level) ->
S = rebar_app_info:state(AppInfo),
S1 = rebar_state:new(S, C, rebar_app_info:dir(AppInfo)),
- S2 = rebar_state:apply_profiles(S1, Profiles),
- S3 = rebar_state:apply_overrides(S2, Name),
- AppInfo1 = rebar_app_info:state(AppInfo, S3),
+ S2 = rebar_state:apply_overrides(S1, Name),
+
+ Plugins = rebar_state:get(S2, plugins, []),
+ S3 = rebar_state:set(S2, {plugins, Profile}, Plugins),
+
+ S4 = rebar_state:apply_profiles(S3, Profiles),
+ AppInfo1 = rebar_app_info:state(AppInfo, S4),
%% Dep may have plugins to install. Find and install here.
- S4 = rebar_plugins:handle_plugins(rebar_state:get(S3, plugins, []), S3),
- AppInfo2 = rebar_app_info:state(AppInfo1, S4),
+ S5 = rebar_plugins:install(S4),
+ AppInfo2 = rebar_app_info:state(AppInfo1, S5),
%% Upgrade lock level to be the level the dep will have in this dep tree
- Deps = rebar_state:get(S4, deps, []),
+ Deps = rebar_state:get(S5, deps, []),
NewLocks = [{DepName, Source, LockLevel+Level} ||
- {DepName, Source, LockLevel} <- rebar_state:get(S4, {locks, default}, [])],
+ {DepName, Source, LockLevel} <- rebar_state:get(S5, {locks, default}, [])],
AppInfo3 = rebar_app_info:deps(AppInfo2, rebar_state:deps_names(Deps)),
- {SrcDeps, PkgDeps} = parse_deps(DepsDir, Deps, S4, Locks, Level+1),
+ {SrcDeps, PkgDeps} = parse_deps(DepsDir, Deps, S5, Locks, Level+1),
{AppInfo3, SrcDeps, PkgDeps, Locks++NewLocks, State}.
-spec maybe_fetch(rebar_app_info:t(), atom(), boolean(),
diff --git a/src/rebar_prv_plugins.erl b/src/rebar_prv_plugins.erl
new file mode 100644
index 0000000..328958e
--- /dev/null
+++ b/src/rebar_prv_plugins.erl
@@ -0,0 +1,67 @@
+-module(rebar_prv_plugins).
+
+-behaviour(provider).
+
+-export([init/1,
+ do/1,
+ format_error/1]).
+
+-include("rebar.hrl").
+-include_lib("providers/include/providers.hrl").
+
+-define(PROVIDER, list).
+-define(NAMESPACE, plugins).
+-define(DEPS, []).
+
+-spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
+init(State) ->
+ State1 = rebar_state:add_provider(
+ State,
+ providers:create([
+ {name, ?PROVIDER},
+ {module, ?MODULE},
+ {namespace, ?NAMESPACE},
+ {bare, true},
+ {deps, ?DEPS},
+ {example, "rebar3 plugins list"},
+ {short_desc, "List local and global plugins for this project"},
+ {desc, "List local and global plugins for this project"},
+ {opts, []}])),
+ {ok, State1}.
+
+-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
+do(State) ->
+ GlobalConfigFile = rebar_dir:global_config(),
+ GlobalConfig = rebar_state:new(rebar_config:consult_file(GlobalConfigFile)),
+ GlobalPlugins = rebar_state:get(GlobalConfig, plugins, []),
+ GlobalPluginsDir = filename:join(rebar_dir:global_cache_dir(State), "plugins"),
+ display_plugins("Global plugins", GlobalPluginsDir, GlobalPlugins),
+
+ Plugins = rebar_state:get(State, plugins, []),
+ PluginsDir =rebar_dir:plugins_dir(State),
+ display_plugins("Local plugins", PluginsDir, Plugins),
+ {ok, State}.
+
+-spec format_error(any()) -> iolist().
+format_error(Reason) ->
+ io_lib:format("~p", [Reason]).
+
+display_plugins(_Header, _Dir, []) ->
+ ok;
+display_plugins(Header, Dir, Plugins) ->
+ ?CONSOLE("--- ~s ---", [Header]),
+ display_plugins(Dir, Plugins),
+ ?CONSOLE("", []).
+
+display_plugins(Dir, Plugins) ->
+ lists:foreach(fun(Plugin) ->
+ Name = if is_atom(Plugin) -> Plugin;
+ is_tuple(Plugin) -> element(1, Plugin)
+ end,
+ case rebar_app_info:discover(filename:join(Dir, Name)) of
+ {ok, _App} ->
+ ?CONSOLE("~s", [Name]);
+ not_found ->
+ ?DEBUG("Unable to find plugin ~s", [Name])
+ end
+ end, Plugins).
diff --git a/src/rebar_prv_plugins_upgrade.erl b/src/rebar_prv_plugins_upgrade.erl
new file mode 100644
index 0000000..fbd8365
--- /dev/null
+++ b/src/rebar_prv_plugins_upgrade.erl
@@ -0,0 +1,96 @@
+-module(rebar_prv_plugins_upgrade).
+
+-behaviour(provider).
+
+-export([init/1,
+ do/1,
+ format_error/1]).
+
+-include("rebar.hrl").
+-include_lib("providers/include/providers.hrl").
+
+-define(PROVIDER, upgrade).
+-define(NAMESPACE, plugins).
+-define(DEPS, []).
+
+-spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
+init(State) ->
+ State1 = rebar_state:add_provider(
+ State,
+ providers:create([
+ {name, ?PROVIDER},
+ {module, ?MODULE},
+ {namespace, ?NAMESPACE},
+ {bare, true},
+ {deps, ?DEPS},
+ {example, "rebar3 plugins upgrade <plugin>"},
+ {short_desc, "Uprade plugins"},
+ {desc, "List or upgrade plugins"},
+ {opts, [{plugin, undefined, undefined, string,
+ "Plugin to upgrade"}]}])),
+ {ok, State1}.
+
+-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
+do(State) ->
+ {Args, _} = rebar_state:command_parsed_args(State),
+ Plugin = proplists:get_value(plugin, Args, <<"">>),
+ upgrade(Plugin, State).
+
+-spec format_error(any()) -> iolist().
+format_error({not_found, Plugin}) ->
+ io_lib:format("Plugin to upgrade not found: ~s", [Plugin]);
+format_error(Reason) ->
+ io_lib:format("~p", [Reason]).
+
+upgrade(Plugin, State) ->
+ Profiles = rebar_state:current_profiles(State),
+ Dep = ec_lists:search(fun(Profile) ->
+ Plugins = rebar_state:get(State, {plugins, Profile}, []),
+ case find(list_to_atom(Plugin), Plugins) of
+ false ->
+ not_found;
+ P ->
+ {ok, P}
+ end
+ end, Profiles),
+
+ case Dep of
+ not_found ->
+ ?PRV_ERROR({not_found, Plugin});
+ {ok, P, Profile} ->
+ State1 = rebar_state:set(State, deps_dir, ?DEFAULT_PLUGINS_DIR),
+ {ok, Apps, _State2} = rebar_prv_install_deps:handle_deps(Profile
+ ,State1
+ ,[P]
+ ,true),
+
+ {no_cycle, Sorted} = rebar_prv_install_deps:find_cycles(Apps),
+ ToBuild = rebar_prv_install_deps:cull_compile(Sorted, []),
+
+ %% Add already built plugin deps to the code path
+ CodePaths = [rebar_app_info:ebin_dir(A) || A <- Apps -- ToBuild],
+ code:add_pathsa(CodePaths),
+
+ %% Build plugin and its deps
+ [build_plugin(AppInfo, Apps, State) || AppInfo <- ToBuild],
+ {ok, State}
+ end.
+
+find(_Plugin, []) ->
+ false;
+find(Plugin, [Plugin | _Plugins]) ->
+ Plugin;
+find(Plugin, [Plugin1 | Plugins]) when is_tuple(Plugin1) ->
+ case element(1, Plugin1) =:= Plugin of
+ true ->
+ Plugin1;
+ false ->
+ find(Plugin, Plugins)
+ end.
+
+build_plugin(AppInfo, Apps, State) ->
+ Providers = rebar_state:providers(State),
+ AppDir = rebar_app_info:dir(AppInfo),
+ C = rebar_config:consult(AppDir),
+ S = rebar_state:new(rebar_state:all_deps(rebar_state:new(), Apps), C, AppDir),
+ rebar_prv_compile:compile(S, Providers, AppInfo).
diff --git a/src/rebar_state.erl b/src/rebar_state.erl
index 7c61db2..8125026 100644
--- a/src/rebar_state.erl
+++ b/src/rebar_state.erl
@@ -82,7 +82,8 @@ new() ->
new(Config) when is_list(Config) ->
BaseState = base_state(),
Deps = proplists:get_value(deps, Config, []),
- Terms = [{{deps, default}, Deps} | Config],
+ Plugins = proplists:get_value(plugins, Config, []),
+ Terms = [{{deps, default}, Deps}, {{plugins, default}, Plugins} | Config],
true = rebar_config:verify_config_format(Terms),
Opts = dict:from_list(Terms),
BaseState#state_t { dir = rebar_dir:get_cwd(),
@@ -95,7 +96,8 @@ new(Profile, Config) when is_atom(Profile)
BaseState = base_state(),
Deps = proplists:get_value(deps, Config, []),
- Terms = [{{deps, default}, Deps} | Config],
+ Plugins = proplists:get_value(plugins, Config, []),
+ Terms = [{{deps, default}, Deps}, {{plugins, default}, Plugins} | Config],
true = rebar_config:verify_config_format(Terms),
Opts = dict:from_list(Terms),
BaseState#state_t { dir = rebar_dir:get_cwd(),
@@ -112,18 +114,19 @@ new(ParentState, Config, Dir) ->
Opts = ParentState#state_t.opts,
LocalOpts = case rebar_config:consult_lock_file(filename:join(Dir, ?LOCK_FILE)) of
[D] ->
- %% We want the top level deps only from the lock file.
- %% This ensures deterministic overrides for configs.
- Deps = [X || X <- D, element(3, X) =:= 0],
-
- Terms = [{{locks, default}, D}, {{deps, default}, Deps} | Config],
- true = rebar_config:verify_config_format(Terms),
- dict:from_list(Terms);
+ %% We want the top level deps only from the lock file.
+ %% This ensures deterministic overrides for configs.
+ Deps = [X || X <- D, element(3, X) =:= 0],
+ Plugins = proplists:get_value(plugins, Config, []),
+ Terms = [{{locks, default}, D}, {{deps, default}, Deps}, {{plugins, default}, Plugins} | Config],
+ true = rebar_config:verify_config_format(Terms),
+ dict:from_list(Terms);
_ ->
- D = proplists:get_value(deps, Config, []),
- Terms = [{{deps, default}, D} | Config],
- true = rebar_config:verify_config_format(Terms),
- dict:from_list(Terms)
+ D = proplists:get_value(deps, Config, []),
+ Plugins = proplists:get_value(plugins, Config, []),
+ Terms = [{{deps, default}, D}, {{plugins, default}, Plugins} | Config],
+ true = rebar_config:verify_config_format(Terms),
+ dict:from_list(Terms)
end,
NewOpts = merge_opts(LocalOpts, Opts),
@@ -257,14 +260,17 @@ apply_overrides(State=#state_t{overrides=Overrides}, AppName) ->
StateAcc
end, State1, Overrides),
- lists:foldl(fun({add, N, O}, StateAcc) when N =:= Name ->
+ State3 = lists:foldl(fun({add, N, O}, StateAcc) when N =:= Name ->
lists:foldl(fun({Key, Value}, StateAcc1) ->
OldValue = rebar_state:get(StateAcc1, Key, []),
rebar_state:set(StateAcc1, Key, Value++OldValue)
end, StateAcc, O);
(_, StateAcc) ->
StateAcc
- end, State2, Overrides).
+ end, State2, Overrides),
+
+ Opts = opts(State3),
+ State3#state_t{default=Opts}.
add_to_profile(State, Profile, KVs) when is_atom(Profile), is_list(KVs) ->
Profiles = rebar_state:get(State, profiles, []),
@@ -280,6 +286,7 @@ apply_profiles(State, [default]) ->
apply_profiles(State=#state_t{default = Defaults, current_profiles=CurrentProfiles}, Profiles) ->
AppliedProfiles = deduplicate(CurrentProfiles ++ Profiles),
ConfigProfiles = rebar_state:get(State, profiles, []),
+
NewOpts =
lists:foldl(fun(default, OptsAcc) ->
OptsAcc;
@@ -303,11 +310,18 @@ do_deduplicate([Head | Rest], Acc) ->
merge_opts(Profile, NewOpts, OldOpts) ->
Opts = merge_opts(NewOpts, OldOpts),
- case dict:find(deps, NewOpts) of
+ Opts2 = case dict:find(plugins, NewOpts) of
{ok, Value} ->
- dict:store({deps, Profile}, Value, Opts);
+ dict:store({plugins, Profile}, Value, Opts);
error ->
Opts
+ end,
+
+ case dict:find(deps, NewOpts) of
+ {ok, Value2} ->
+ dict:store({deps, Profile}, Value2, Opts2);
+ error ->
+ Opts2
end.
merge_opts(NewOpts, OldOpts) ->
@@ -315,6 +329,10 @@ merge_opts(NewOpts, OldOpts) ->
NewValue;
({deps, _}, NewValue, _OldValue) ->
NewValue;
+ (plugins, NewValue, _OldValue) ->
+ NewValue;
+ ({plugins, _}, NewValue, _OldValue) ->
+ NewValue;
(profiles, NewValue, OldValue) ->
dict:to_list(merge_opts(dict:from_list(NewValue), dict:from_list(OldValue)));
(_Key, NewValue, OldValue) when is_list(NewValue) ->
diff --git a/test/rebar_compile_SUITE.erl b/test/rebar_compile_SUITE.erl
index 7025eef..7e72404 100644
--- a/test/rebar_compile_SUITE.erl
+++ b/test/rebar_compile_SUITE.erl
@@ -18,9 +18,6 @@
deps_in_path/1,
delete_beam_if_source_deleted/1,
checkout_priority/1,
- compile_plugins/1,
- compile_global_plugins/1,
- complex_plugins/1,
highest_version_of_pkg_dep/1,
parse_transform_test/1]).
@@ -49,8 +46,7 @@ all() ->
build_all_srcdirs, recompile_when_hrl_changes,
recompile_when_opts_change, dont_recompile_when_opts_dont_change,
dont_recompile_yrl_or_xrl, delete_beam_if_source_deleted,
- deps_in_path, checkout_priority, compile_plugins, compile_global_plugins,
- complex_plugins, highest_version_of_pkg_dep, parse_transform_test].
+ deps_in_path, checkout_priority, highest_version_of_pkg_dep, parse_transform_test].
build_basic_app(Config) ->
AppDir = ?config(apps, Config),
@@ -399,133 +395,6 @@ checkout_priority(Config) ->
?assertEqual(Vsn2, proplists:get_value(vsn, DepProps)),
?assertEqual(Vsn2, proplists:get_value(vsn, PkgProps)).
-%% Tests that compiling a project installs and compiles the plugins of deps
-compile_plugins(Config) ->
- AppDir = ?config(apps, Config),
-
- Name = rebar_test_utils:create_random_name("app1_"),
- Vsn = rebar_test_utils:create_random_vsn(),
- rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
-
- DepName = rebar_test_utils:create_random_name("dep1_"),
- PluginName = rebar_test_utils:create_random_name("plugin1_"),
-
- Plugins = rebar_test_utils:expand_deps(git, [{PluginName, Vsn, []}]),
- mock_git_resource:mock([{deps, rebar_test_utils:flat_deps(Plugins)}]),
-
- mock_pkg_resource:mock([{pkgdeps, [{{list_to_binary(DepName), list_to_binary(Vsn)}, []}]},
- {config, [{plugins, [
- {list_to_atom(PluginName),
- {git, "http://site.com/user/"++PluginName++".git",
- {tag, Vsn}}}]}]}]),
-
- RConfFile =
- rebar_test_utils:create_config(AppDir,
- [{deps, [
- list_to_atom(DepName)
- ]}]),
- {ok, RConf} = file:consult(RConfFile),
-
- %% Build with deps.
- rebar_test_utils:run_and_check(
- Config, RConf, ["compile"],
- {ok, [{app, Name}, {plugin, PluginName}, {dep, DepName}]}
- ).
-
-%% Tests that compiling a project installs and compiles the global plugins
-compile_global_plugins(Config) ->
- AppDir = ?config(apps, Config),
- GlobalDir = filename:join(AppDir, "global"),
- GlobalConfigDir = filename:join([GlobalDir, ".config", "rebar3"]),
- GlobalConfig = filename:join([GlobalDir, ".config", "rebar3", "rebar.config"]),
-
- meck:new(rebar_dir, [passthrough]),
- meck:expect(rebar_dir, global_config, fun() -> GlobalConfig end),
- meck:expect(rebar_dir, global_cache_dir, fun(_) -> GlobalDir end),
-
- Name = rebar_test_utils:create_random_name("app1_"),
- Vsn = rebar_test_utils:create_random_vsn(),
- Vsn2 = rebar_test_utils:create_random_vsn(),
- rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
-
- DepName = rebar_test_utils:create_random_name("dep1_"),
- PluginName = rebar_test_utils:create_random_name("plugin1_"),
-
- mock_git_resource:mock([{deps, [{list_to_atom(PluginName), Vsn},
- {list_to_atom(PluginName), Vsn2},
- {{iolist_to_binary(DepName), iolist_to_binary(Vsn)}, []}]}]),
-
-
- rebar_test_utils:create_config(GlobalConfigDir,
- [{plugins, [
- {list_to_atom(PluginName), {git, "http://site.com/user/"++PluginName++".git", {tag, Vsn}}}
- ]}]),
- RConfFile =
- rebar_test_utils:create_config(AppDir,
- [{deps, [
- {list_to_atom(DepName), {git, "http://site.com/user/"++DepName++".git", {tag, Vsn}}}
- ]},
- {plugins, [
- {list_to_atom(PluginName), {git, "http://site.com/user/"++PluginName++".git", {tag, Vsn2}}}
- ]}]),
- {ok, RConf} = file:consult(RConfFile),
-
- %% Runs global plugin install
- rebar3:init_config(),
-
- %% Build with deps.
- rebar_test_utils:run_and_check(
- Config, RConf, ["compile"],
- {ok, [{app, Name},
- {global_plugin, PluginName, Vsn},
- {plugin, PluginName, Vsn2},
- {dep, DepName}]}
- ),
-
- meck:unload(rebar_dir).
-
-%% Tests installing of plugin with transitive deps
-complex_plugins(Config) ->
- AppDir = ?config(apps, Config),
-
- meck:new(rebar_dir, [passthrough]),
-
- Name = rebar_test_utils:create_random_name("app1_"),
- Vsn = rebar_test_utils:create_random_vsn(),
- Vsn2 = rebar_test_utils:create_random_vsn(),
- rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
-
- DepName = rebar_test_utils:create_random_name("dep1_"),
- DepName2 = rebar_test_utils:create_random_name("dep2_"),
- DepName3 = rebar_test_utils:create_random_name("dep3_"),
- PluginName = rebar_test_utils:create_random_name("plugin1_"),
-
- Deps = rebar_test_utils:expand_deps(git, [{PluginName, Vsn2, [{DepName2, Vsn,
- [{DepName3, Vsn, []}]}]}
- ,{DepName, Vsn, []}]),
- mock_git_resource:mock([{deps, rebar_test_utils:flat_deps(Deps)}]),
-
- RConfFile =
- rebar_test_utils:create_config(AppDir,
- [{deps, [
- {list_to_atom(DepName), {git, "http://site.com/user/"++DepName++".git", {tag, Vsn}}}
- ]},
- {plugins, [
- {list_to_atom(PluginName), {git, "http://site.com/user/"++PluginName++".git", {tag, Vsn2}}}
- ]}]),
- {ok, RConf} = file:consult(RConfFile),
-
- %% Build with deps.
- rebar_test_utils:run_and_check(
- Config, RConf, ["compile"],
- {ok, [{app, Name},
- {plugin, PluginName, Vsn2},
- {plugin, DepName2},
- {plugin, DepName3},
- {dep, DepName}]}
- ),
-
- meck:unload(rebar_dir).
highest_version_of_pkg_dep(Config) ->
AppDir = ?config(apps, Config),
diff --git a/test/rebar_plugins_SUITE.erl b/test/rebar_plugins_SUITE.erl
new file mode 100644
index 0000000..adfeafe
--- /dev/null
+++ b/test/rebar_plugins_SUITE.erl
@@ -0,0 +1,201 @@
+-module(rebar_plugins_SUITE).
+
+-export([suite/0,
+ init_per_suite/1,
+ end_per_suite/1,
+ init_per_testcase/2,
+ end_per_testcase/2,
+ all/0,
+ compile_plugins/1,
+ compile_global_plugins/1,
+ complex_plugins/1,
+ upgrade/1]).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("eunit/include/eunit.hrl").
+-include_lib("kernel/include/file.hrl").
+
+suite() ->
+ [].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_testcase(_, Config) ->
+ rebar_test_utils:init_rebar_state(Config).
+
+end_per_testcase(_, _Config) ->
+ catch meck:unload().
+
+all() ->
+ [compile_plugins, compile_global_plugins, complex_plugins, upgrade].
+
+%% Tests that compiling a project installs and compiles the plugins of deps
+compile_plugins(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("app1_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ DepName = rebar_test_utils:create_random_name("dep1_"),
+ PluginName = rebar_test_utils:create_random_name("plugin1_"),
+
+ Plugins = rebar_test_utils:expand_deps(git, [{PluginName, Vsn, []}]),
+ mock_git_resource:mock([{deps, rebar_test_utils:flat_deps(Plugins)}]),
+
+ mock_pkg_resource:mock([{pkgdeps, [{{list_to_binary(DepName), list_to_binary(Vsn)}, []}]},
+ {config, [{plugins, [
+ {list_to_atom(PluginName),
+ {git, "http://site.com/user/"++PluginName++".git",
+ {tag, Vsn}}}]}]}]),
+
+ RConfFile =
+ rebar_test_utils:create_config(AppDir,
+ [{deps, [
+ list_to_atom(DepName)
+ ]}]),
+ {ok, RConf} = file:consult(RConfFile),
+
+ %% Build with deps.
+ rebar_test_utils:run_and_check(
+ Config, RConf, ["compile"],
+ {ok, [{app, Name}, {plugin, PluginName}, {dep, DepName}]}
+ ).
+
+%% Tests that compiling a project installs and compiles the global plugins
+compile_global_plugins(Config) ->
+ AppDir = ?config(apps, Config),
+ GlobalDir = filename:join(AppDir, "global"),
+ GlobalConfigDir = filename:join([GlobalDir, ".config", "rebar3"]),
+ GlobalConfig = filename:join([GlobalDir, ".config", "rebar3", "rebar.config"]),
+
+ meck:new(rebar_dir, [passthrough]),
+ meck:expect(rebar_dir, global_config, fun() -> GlobalConfig end),
+ meck:expect(rebar_dir, global_cache_dir, fun(_) -> GlobalDir end),
+
+ Name = rebar_test_utils:create_random_name("app1_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ Vsn2 = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ DepName = rebar_test_utils:create_random_name("dep1_"),
+ PluginName = rebar_test_utils:create_random_name("plugin1_"),
+
+ mock_git_resource:mock([{deps, [{list_to_atom(PluginName), Vsn},
+ {list_to_atom(PluginName), Vsn2},
+ {{iolist_to_binary(DepName), iolist_to_binary(Vsn)}, []}]}]),
+
+
+ rebar_test_utils:create_config(GlobalConfigDir,
+ [{plugins, [
+ {list_to_atom(PluginName), {git, "http://site.com/user/"++PluginName++".git", {tag, Vsn}}}
+ ]}]),
+ RConfFile =
+ rebar_test_utils:create_config(AppDir,
+ [{deps, [
+ {list_to_atom(DepName), {git, "http://site.com/user/"++DepName++".git", {tag, Vsn}}}
+ ]},
+ {plugins, [
+ {list_to_atom(PluginName), {git, "http://site.com/user/"++PluginName++".git", {tag, Vsn2}}}
+ ]}]),
+ {ok, RConf} = file:consult(RConfFile),
+
+ %% Runs global plugin install
+ rebar3:init_config(),
+
+ %% Build with deps.
+ rebar_test_utils:run_and_check(
+ Config, RConf, ["compile"],
+ {ok, [{app, Name},
+ {global_plugin, PluginName, Vsn},
+ {plugin, PluginName, Vsn2},
+ {dep, DepName}]}
+ ),
+
+ meck:unload(rebar_dir).
+
+%% Tests installing of plugin with transitive deps
+complex_plugins(Config) ->
+ AppDir = ?config(apps, Config),
+
+ meck:new(rebar_dir, [passthrough]),
+
+ Name = rebar_test_utils:create_random_name("app1_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ Vsn2 = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ DepName = rebar_test_utils:create_random_name("dep1_"),
+ DepName2 = rebar_test_utils:create_random_name("dep2_"),
+ DepName3 = rebar_test_utils:create_random_name("dep3_"),
+ PluginName = rebar_test_utils:create_random_name("plugin1_"),
+
+ Deps = rebar_test_utils:expand_deps(git, [{PluginName, Vsn2, [{DepName2, Vsn,
+ [{DepName3, Vsn, []}]}]}
+ ,{DepName, Vsn, []}]),
+ mock_git_resource:mock([{deps, rebar_test_utils:flat_deps(Deps)}]),
+
+ RConfFile =
+ rebar_test_utils:create_config(AppDir,
+ [{deps, [
+ {list_to_atom(DepName), {git, "http://site.com/user/"++DepName++".git", {tag, Vsn}}}
+ ]},
+ {plugins, [
+ {list_to_atom(PluginName), {git, "http://site.com/user/"++PluginName++".git", {tag, Vsn2}}}
+ ]}]),
+ {ok, RConf} = file:consult(RConfFile),
+
+ %% Build with deps.
+ rebar_test_utils:run_and_check(
+ Config, RConf, ["compile"],
+ {ok, [{app, Name},
+ {plugin, PluginName, Vsn2},
+ {plugin, DepName2},
+ {plugin, DepName3},
+ {dep, DepName}]}
+ ),
+
+ meck:unload(rebar_dir).
+
+upgrade(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("app1_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ PkgName = rebar_test_utils:create_random_name("pkg1_"),
+ mock_git_resource:mock([]),
+ mock_pkg_resource:mock([
+ {pkgdeps, [{{iolist_to_binary(PkgName), <<"0.1.0">>}, []},
+ {{iolist_to_binary(PkgName), <<"0.0.1">>}, []},
+ {{iolist_to_binary(PkgName), <<"0.1.1">>}, []}]}
+ ]),
+
+ RConfFile = rebar_test_utils:create_config(AppDir, [{plugins, [list_to_atom(PkgName)]}]),
+ {ok, RConf} = file:consult(RConfFile),
+
+ %% Build with deps.
+ rebar_test_utils:run_and_check(
+ Config, RConf, ["compile"],
+ {ok, [{app, Name}, {plugin, PkgName, <<"0.1.1">>}]}
+ ),
+
+ catch mock_pkg_resource:unmock(),
+ mock_pkg_resource:mock([
+ {pkgdeps, [{{iolist_to_binary(PkgName), <<"0.1.0">>}, []},
+ {{iolist_to_binary(PkgName), <<"0.0.1">>}, []},
+ {{iolist_to_binary(PkgName), <<"0.1.3">>}, []},
+ {{iolist_to_binary(PkgName), <<"0.1.1">>}, []}]},
+ {upgrade, [PkgName]}
+ ]),
+
+ %% Build with deps.
+ rebar_test_utils:run_and_check(
+ Config, RConf, ["plugins", "upgrade", PkgName],
+ {ok, [{app, Name}, {plugin, PkgName, <<"0.1.3">>}]}
+ ).