Browse Source

Merge pull request #320 from tsloughter/dep_plugins

install dep plugins & run provider hooks the same as shell hooks (Rereopen 316)
pull/272/merge
Fred Hebert 10 years ago
parent
commit
3250faa756
18 changed files with 234 additions and 148 deletions
  1. +4
    -0
      src/rebar.app.src
  2. +12
    -12
      src/rebar3.erl
  3. +1
    -1
      src/rebar_core.erl
  4. +21
    -22
      src/rebar_fetch.erl
  5. +24
    -3
      src/rebar_hooks.erl
  6. +33
    -26
      src/rebar_plugins.erl
  7. +8
    -7
      src/rebar_prv_clean.erl
  8. +13
    -3
      src/rebar_prv_common_test.erl
  9. +13
    -9
      src/rebar_prv_compile.erl
  10. +3
    -3
      src/rebar_prv_deps.erl
  11. +12
    -3
      src/rebar_prv_eunit.erl
  12. +9
    -6
      src/rebar_prv_install_deps.erl
  13. +1
    -1
      src/rebar_prv_lock.erl
  14. +23
    -47
      src/rebar_state.erl
  15. +2
    -1
      test/mock_git_resource.erl
  16. +34
    -2
      test/rebar_compile_SUITE.erl
  17. +6
    -2
      test/rebar_resource_SUITE.erl
  18. +15
    -0
      test/rebar_test_utils.erl

+ 4
- 0
src/rebar.app.src View File

@ -23,6 +23,10 @@
%% Default log level %% Default log level
{log_level, warn}, {log_level, warn},
{resources, [{git, rebar_git_resource},
{pkg, rebar_pkg_resource},
{hg, rebar_hg_resource}]},
{providers, [rebar_prv_app_discovery, {providers, [rebar_prv_app_discovery,
rebar_prv_as, rebar_prv_as,
rebar_prv_clean, rebar_prv_clean,

+ 12
- 12
src/rebar3.erl View File

@ -77,7 +77,7 @@ run(BaseState, Commands) ->
_ = application:load(rebar), _ = application:load(rebar),
BaseState1 = rebar_state:set(BaseState, task, Commands), BaseState1 = rebar_state:set(BaseState, task, Commands),
BaseState2 = rebar_state:set(BaseState1, caller, api), BaseState2 = rebar_state:set(BaseState1, caller, api),
run_aux(BaseState2, [], Commands).
run_aux(BaseState2, Commands).
%% ==================================================================== %% ====================================================================
%% Internal functions %% Internal functions
@ -86,7 +86,7 @@ run(BaseState, Commands) ->
run(RawArgs) -> run(RawArgs) ->
_ = application:load(rebar), _ = application:load(rebar),
{GlobalPluginProviders, BaseState} = init_config(),
BaseState = init_config(),
BaseState1 = rebar_state:set(BaseState, caller, command_line), BaseState1 = rebar_state:set(BaseState, caller, command_line),
case erlang:system_info(version) of case erlang:system_info(version) of
@ -98,9 +98,9 @@ run(RawArgs) ->
end, end,
{BaseState2, _Args1} = set_options(BaseState1, {[], []}), {BaseState2, _Args1} = set_options(BaseState1, {[], []}),
run_aux(BaseState2, GlobalPluginProviders, RawArgs).
run_aux(BaseState2, RawArgs).
run_aux(State, GlobalPluginProviders, RawArgs) ->
run_aux(State, RawArgs) ->
%% Make sure crypto is running %% Make sure crypto is running
case crypto:start() of case crypto:start() of
ok -> ok; ok -> ok;
@ -124,16 +124,17 @@ run_aux(State, GlobalPluginProviders, RawArgs) ->
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), {ok, Providers} = application:get_env(rebar, providers),
{ok, PluginProviders, State4} = rebar_plugins:install(State3),
{ok, Resources} = application:get_env(rebar, resources),
State4 = rebar_state:resources(State3, Resources),
State5 = rebar_plugins:install(State4),
%% Providers can modify profiles stored in opts, so set default after initializing providers %% Providers can modify profiles stored in opts, so set default after initializing providers
AllProviders = Providers++PluginProviders++GlobalPluginProviders,
State5 = rebar_state:create_logic_providers(AllProviders, State4),
State6 = rebar_state:default(State5, rebar_state:opts(State5)),
State6 = rebar_state:create_logic_providers(Providers, State5),
State7 = rebar_state:default(State6, rebar_state:opts(State6)),
{Task, Args} = parse_args(RawArgs), {Task, Args} = parse_args(RawArgs),
rebar_core:init_command(rebar_state:command_args(State6, Args), Task).
rebar_core:init_command(rebar_state:command_args(State7, Args), Task).
init_config() -> init_config() ->
%% Initialize logging system %% Initialize logging system
@ -156,10 +157,9 @@ init_config() ->
?DEBUG("Load global config file ~p", ?DEBUG("Load global config file ~p",
[GlobalConfigFile]), [GlobalConfigFile]),
GlobalConfig = rebar_state:new(global, rebar_config:consult_file(GlobalConfigFile)), GlobalConfig = rebar_state:new(global, rebar_config:consult_file(GlobalConfigFile)),
{ok, PluginProviders, GlobalConfig1} = rebar_plugins:install(GlobalConfig),
GlobalConfig1 = rebar_plugins:install(GlobalConfig),
rebar_state:new(GlobalConfig1, Config1); rebar_state:new(GlobalConfig1, Config1);
false -> false ->
PluginProviders = [],
rebar_state:new(Config1) rebar_state:new(Config1)
end, end,
@ -175,7 +175,7 @@ init_config() ->
%% TODO: Do we need this still? I think it may still be used. %% TODO: Do we need this still? I think it may still be used.
%% Initialize vsn cache %% Initialize vsn cache
{PluginProviders, rebar_state:set(State1, vsn_cache, dict:new())}.
rebar_state:set(State1, vsn_cache, dict:new()).
parse_args([]) -> parse_args([]) ->
parse_args(["help"]); parse_args(["help"]);

+ 1
- 1
src/rebar_core.erl View File

@ -26,7 +26,7 @@
%% ------------------------------------------------------------------- %% -------------------------------------------------------------------
-module(rebar_core). -module(rebar_core).
-export([init_command/2, process_namespace/2, process_command/2]).
-export([init_command/2, process_namespace/2, process_command/2, do/2]).
-include("rebar.hrl"). -include("rebar.hrl").

+ 21
- 22
src/rebar_fetch.erl View File

@ -7,30 +7,28 @@
%% ------------------------------------------------------------------- %% -------------------------------------------------------------------
-module(rebar_fetch). -module(rebar_fetch).
-export([lock_source/2,
-export([lock_source/3,
download_source/3, download_source/3,
needs_update/2]).
needs_update/3]).
-export([format_error/1]). -export([format_error/1]).
-include("rebar.hrl"). -include("rebar.hrl").
-include_lib("providers/include/providers.hrl"). -include_lib("providers/include/providers.hrl").
%% map short versions of resources to module names
-define(RESOURCES, [{git, rebar_git_resource}, {pkg, rebar_pkg_resource},
{hg, rebar_hg_resource}]).
-spec lock_source(file:filename_all(), rebar_resource:resource()) ->
-spec lock_source(file:filename_all(), rebar_resource:resource(), rebar_state:t()) ->
rebar_resource:resource() | {error, string()}. rebar_resource:resource() | {error, string()}.
lock_source(AppDir, Source) ->
Module = get_resource_type(Source),
lock_source(AppDir, Source, State) ->
Resources = rebar_state:resources(State),
Module = get_resource_type(Source, Resources),
Module:lock(AppDir, Source). Module:lock(AppDir, Source).
-spec download_source(file:filename_all(), rebar_resource:resource(), rebar_state:t()) -> -spec download_source(file:filename_all(), rebar_resource:resource(), rebar_state:t()) ->
true | {error, any()}. true | {error, any()}.
download_source(AppDir, Source, State) -> download_source(AppDir, Source, State) ->
try try
Module = get_resource_type(Source),
Resources = rebar_state:resources(State),
Module = get_resource_type(Source, Resources),
TmpDir = ec_file:insecure_mkdtemp(), TmpDir = ec_file:insecure_mkdtemp(),
AppDir1 = ec_cnv:to_list(AppDir), AppDir1 = ec_cnv:to_list(AppDir),
case Module:download(TmpDir, Source, State) of case Module:download(TmpDir, Source, State) of
@ -64,9 +62,10 @@ download_source(AppDir, Source, State) ->
throw(?PRV_ERROR({fetch_fail, Source})) throw(?PRV_ERROR({fetch_fail, Source}))
end. end.
-spec needs_update(file:filename_all(), rebar_resource:resource()) -> boolean() | {error, string()}.
needs_update(AppDir, Source) ->
Module = get_resource_type(Source),
-spec needs_update(file:filename_all(), rebar_resource:resource(), rebar_state:t()) -> boolean() | {error, string()}.
needs_update(AppDir, Source, State) ->
Resources = rebar_state:resources(State),
Module = get_resource_type(Source, Resources),
try try
Module:needs_update(AppDir, Source) Module:needs_update(AppDir, Source)
catch catch
@ -77,17 +76,17 @@ needs_update(AppDir, Source) ->
format_error({fetch_fail, Source}) -> format_error({fetch_fail, Source}) ->
io_lib:format("Failed to fetch and copy dep: ~p", [Source]). io_lib:format("Failed to fetch and copy dep: ~p", [Source]).
get_resource_type({Type, Location}) ->
find_resource_module(Type, Location);
get_resource_type({Type, Location, _}) ->
find_resource_module(Type, Location);
get_resource_type({Type, _, _, Location}) ->
find_resource_module(Type, Location);
get_resource_type(_) ->
get_resource_type({Type, Location}, Resources) ->
find_resource_module(Type, Location, Resources);
get_resource_type({Type, Location, _}, Resources) ->
find_resource_module(Type, Location, Resources);
get_resource_type({Type, _, _, Location}, Resources) ->
find_resource_module(Type, Location, Resources);
get_resource_type(_, _) ->
rebar_pkg_resource. rebar_pkg_resource.
find_resource_module(Type, Location) ->
case lists:keyfind(Type, 1, ?RESOURCES) of
find_resource_module(Type, Location, Resources) ->
case lists:keyfind(Type, 1, Resources) of
false -> false ->
case code:which(Type) of case code:which(Type) of
non_existing -> non_existing ->

+ 24
- 3
src/rebar_hooks.erl View File

@ -1,9 +1,30 @@
-module(rebar_hooks). -module(rebar_hooks).
-export([run_compile_hooks/4]).
-export([run_all_hooks/5]).
run_compile_hooks(Dir, Type, Command, State) ->
Hooks = rebar_state:get(State, Type, []),
-spec run_all_hooks(file:filename_all(), pre | post,
atom() | {atom(), atom()} | string(),
[providers:t()], rebar_state:t()) -> ok.
run_all_hooks(Dir, Type, Command, Providers, State) ->
run_provider_hooks(Dir, Type, Command, Providers, State),
run_hooks(Dir, Type, Command, State).
run_provider_hooks(Dir, Type, Command, Providers, State) ->
State1 = rebar_state:providers(rebar_state:dir(State, Dir), Providers),
AllHooks = rebar_state:get(State1, provider_hooks, []),
TypeHooks = proplists:get_value(Type, AllHooks, []),
HookProviders = proplists:get_all_values(Command, TypeHooks),
rebar_core:do(HookProviders, State1).
run_hooks(Dir, Type, Command, State) ->
Hooks = case Type of
pre ->
rebar_state:get(State, pre_hooks, []);
post ->
rebar_state:get(State, post_hooks, []);
_ ->
[]
end,
Env = [{"REBAR_DEPS_DIR", filename:absname(rebar_dir:deps_dir(State))}], Env = [{"REBAR_DEPS_DIR", filename:absname(rebar_dir:deps_dir(State))}],
lists:foreach(fun({_, C, _}=Hook) when C =:= Command -> lists:foreach(fun({_, C, _}=Hook) when C =:= Command ->
apply_hook(Dir, Env, Hook); apply_hook(Dir, Env, Hook);

+ 33
- 26
src/rebar_plugins.erl View File

@ -3,7 +3,7 @@
-module(rebar_plugins). -module(rebar_plugins).
-export([install/1]).
-export([install/1, handle_plugins/2]).
-include("rebar.hrl"). -include("rebar.hrl").
@ -11,34 +11,45 @@
%% Public API %% Public API
%% =================================================================== %% ===================================================================
-spec install(rebar_state:t()) -> rebar_state:t().
install(State) -> install(State) ->
%% Set deps_dir to a different dir for plugin so they don't collide
OldDepsDir = rebar_state:get(State, deps_dir, ?DEFAULT_DEPS_DIR),
State1 = rebar_state:set(State, deps_dir, ?DEFAULT_PLUGINS_DIR),
DepsDir = rebar_dir:deps_dir(State1),
expand_plugins(DepsDir),
Plugins = rebar_state:get(State1, plugins, []),
PluginProviders = lists:flatten(rebar_utils:filtermap(fun(Plugin) ->
handle_plugin(Plugin, State1)
end, Plugins)),
DepsDir = rebar_dir:deps_dir(State),
Plugins = rebar_state:get(State, plugins, []),
State2 = rebar_state:set(State1, deps_dir, OldDepsDir),
{ok, PluginProviders, State2}.
ProjectApps = rebar_state:project_apps(State),
DepApps = rebar_app_discover:find_apps([DepsDir], all),
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++DepApps),
handle_plugins(Plugins++OtherPlugins, State).
-spec handle_plugins([rebar_prv_install_deps:dep()], rebar_state:t()) -> rebar_state:t().
handle_plugins(Plugins, State) ->
PluginProviders = lists:flatmap(fun(Plugin) ->
handle_plugin(Plugin, State)
end, Plugins),
rebar_state:create_logic_providers(PluginProviders, State).
-spec handle_plugin(rebar_prv_install_deps:dep(), rebar_state:t()) -> {true, any()} | false.
handle_plugin(Plugin, State) -> handle_plugin(Plugin, State) ->
try try
{ok, _, State1} = rebar_prv_install_deps:handle_deps(default, State, [Plugin]),
%% Set deps dir to plugins dir so apps are installed there
State1 = rebar_state:set(State, deps_dir, ?DEFAULT_PLUGINS_DIR),
{ok, _, State2} = rebar_prv_install_deps:handle_deps(default, State1, [Plugin]),
Apps = rebar_state:all_deps(State1),
Apps = rebar_state:all_deps(State2),
ToBuild = lists:dropwhile(fun rebar_app_info:valid/1, Apps), ToBuild = lists:dropwhile(fun rebar_app_info:valid/1, Apps),
[build_plugin(AppInfo) || AppInfo <- ToBuild], [build_plugin(AppInfo) || AppInfo <- ToBuild],
plugin_providers(Plugin) plugin_providers(Plugin)
catch catch
C:T -> C:T ->
?DEBUG("~p ~p", [C, T]), ?DEBUG("~p ~p", [C, T]),
?WARN("Plugin ~p not available. It will not be used.~n", [Plugin]),
false
?WARN("Plugin ~p not available. It will not be used.", [Plugin]),
[]
end. end.
build_plugin(AppInfo) -> build_plugin(AppInfo) ->
@ -56,21 +67,17 @@ plugin_providers(Plugin) when is_atom(Plugin) ->
validate_plugin(Plugin). validate_plugin(Plugin).
validate_plugin(Plugin) -> validate_plugin(Plugin) ->
ok = application:load(Plugin),
_ = application:load(Plugin),
case application:get_env(Plugin, providers) of case application:get_env(Plugin, providers) of
{ok, Providers} -> {ok, Providers} ->
{true, Providers};
Providers;
undefined -> undefined ->
Exports = Plugin:module_info(exports), Exports = Plugin:module_info(exports),
case lists:member({init,1}, Exports) of case lists:member({init,1}, Exports) of
false -> false ->
?WARN("Plugin ~p does not export init/1. It will not be used.~n", [Plugin]),
false;
?WARN("Plugin ~p does not export init/1. It will not be used.", [Plugin]),
[];
true -> true ->
{true, Plugin}
[Plugin]
end end
end. end.
expand_plugins(Dir) ->
Apps = filelib:wildcard(filename:join([Dir, "*", "ebin"])),
ok = code:add_pathsa(Apps).

+ 8
- 7
src/rebar_prv_clean.erl View File

@ -32,6 +32,7 @@ init(State) ->
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. -spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) -> do(State) ->
Providers = rebar_state:providers(State),
ProjectApps = rebar_state:project_apps(State), ProjectApps = rebar_state:project_apps(State),
{all, All} = handle_args(State), {all, All} = handle_args(State),
@ -46,12 +47,12 @@ do(State) ->
%% Need to allow global config vars used on deps %% Need to allow global config vars used on deps
%% Right now no way to differeniate and just give deps a new state %% Right now no way to differeniate and just give deps a new state
EmptyState = rebar_state:new(), EmptyState = rebar_state:new(),
clean_apps(EmptyState, DepApps),
clean_apps(EmptyState, Providers, DepApps),
Cwd = rebar_dir:get_cwd(), Cwd = rebar_dir:get_cwd(),
rebar_hooks:run_compile_hooks(Cwd, pre_hooks, clean, State),
clean_apps(State, ProjectApps),
rebar_hooks:run_compile_hooks(Cwd, post_hooks, clean, State),
rebar_hooks:run_all_hooks(Cwd, pre, ?PROVIDER, Providers, State),
clean_apps(State, Providers, ProjectApps),
rebar_hooks:run_all_hooks(Cwd, post, ?PROVIDER, Providers, State),
{ok, State}. {ok, State}.
@ -63,7 +64,7 @@ format_error(Reason) ->
%% Internal functions %% Internal functions
%% =================================================================== %% ===================================================================
clean_apps(State, Apps) ->
clean_apps(State, Providers, Apps) ->
lists:foreach(fun(AppInfo) -> lists:foreach(fun(AppInfo) ->
AppDir = rebar_app_info:dir(AppInfo), AppDir = rebar_app_info:dir(AppInfo),
C = rebar_config:consult(AppDir), C = rebar_config:consult(AppDir),
@ -71,9 +72,9 @@ clean_apps(State, Apps) ->
?INFO("Cleaning out ~s...", [rebar_app_info:name(AppInfo)]), ?INFO("Cleaning out ~s...", [rebar_app_info:name(AppInfo)]),
%% Legacy hook support %% Legacy hook support
rebar_hooks:run_compile_hooks(AppDir, pre_hooks, clean, S),
rebar_hooks:run_all_hooks(AppDir, pre, ?PROVIDER, Providers, S),
rebar_erlc_compiler:clean(State, rebar_app_info:out_dir(AppInfo)), rebar_erlc_compiler:clean(State, rebar_app_info:out_dir(AppInfo)),
rebar_hooks:run_compile_hooks(AppDir, post_hooks, clean, S)
rebar_hooks:run_all_hooks(AppDir, post, ?PROVIDER, Providers, S)
end, Apps). end, Apps).
handle_args(State) -> handle_args(State) ->

+ 13
- 3
src/rebar_prv_common_test.erl View File

@ -38,6 +38,11 @@ init(State) ->
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. -spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) -> do(State) ->
?INFO("Running Common Test suites...", []), ?INFO("Running Common Test suites...", []),
%% Run ct provider prehooks
Providers = rebar_state:providers(State),
Cwd = rebar_dir:get_cwd(),
rebar_hooks:run_all_hooks(Cwd, pre, ?PROVIDER, Providers, State),
try try
case setup_ct(State) of case setup_ct(State) of
{error, {no_tests_specified, Opts}} -> {error, {no_tests_specified, Opts}} ->
@ -46,9 +51,14 @@ do(State) ->
Opts -> Opts ->
Opts1 = setup_logdir(State, Opts), Opts1 = setup_logdir(State, Opts),
?DEBUG("common test opts: ~p", [Opts1]), ?DEBUG("common test opts: ~p", [Opts1]),
run_test(State, Opts1)
{ok, State1} = run_test(State, Opts1),
%% Run ct provider posthooks
rebar_hooks:run_all_hooks(Cwd, post, ?PROVIDER, Providers, State1),
{ok, State1}
end end
catch error:Reason -> ?PRV_ERROR(Reason)
catch
error:Reason ->
?PRV_ERROR(Reason)
end. end.
-spec format_error(any()) -> iolist(). -spec format_error(any()) -> iolist().
@ -251,7 +261,7 @@ join(undefined, Suites) -> Suites;
join(Dir, Suites) when is_list(Dir), is_integer(hd(Dir)) -> join(Dir, Suites) when is_list(Dir), is_integer(hd(Dir)) ->
lists:map(fun(S) -> filename:join([Dir, S]) end, Suites); lists:map(fun(S) -> filename:join([Dir, S]) end, Suites);
%% multiple dirs or a bad dir argument, try to continue anyways %% multiple dirs or a bad dir argument, try to continue anyways
join(_, Suites) -> Suites.
join(_, Suites) -> Suites.
find_suite_dirs(Suites) -> find_suite_dirs(Suites) ->
AllDirs = lists:map(fun(S) -> filename:dirname(filename:absname(S)) end, Suites), AllDirs = lists:map(fun(S) -> filename:dirname(filename:absname(S)) end, Suites),

+ 13
- 9
src/rebar_prv_compile.erl View File

@ -32,20 +32,23 @@ init(State) ->
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. -spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) -> do(State) ->
ProjectApps = rebar_state:project_apps(State), ProjectApps = rebar_state:project_apps(State),
Providers = rebar_state:providers(State),
Deps = rebar_state:deps_to_build(State), Deps = rebar_state:deps_to_build(State),
Cwd = rebar_dir:get_cwd(), Cwd = rebar_dir:get_cwd(),
rebar_hooks:run_compile_hooks(Cwd, pre_hooks, compile, State),
rebar_hooks:run_all_hooks(Cwd, pre, ?PROVIDER, Providers, State),
%% Need to allow global config vars used on deps %% Need to allow global config vars used on deps
%% Right now no way to differeniate and just give deps a new state %% Right now no way to differeniate and just give deps a new state
EmptyState = rebar_state:new(), EmptyState = rebar_state:new(),
build_apps(EmptyState, Deps),
build_apps(EmptyState, Providers, Deps),
%% Use the project State for building project apps %% Use the project State for building project apps
%% Set hooks to empty so top-level hooks aren't run for each project app %% Set hooks to empty so top-level hooks aren't run for each project app
State2 = rebar_state:set(rebar_state:set(State, post_hooks, []), pre_hooks, []), State2 = rebar_state:set(rebar_state:set(State, post_hooks, []), pre_hooks, []),
ProjectApps1 = build_apps(State2, ProjectApps),
rebar_hooks:run_compile_hooks(Cwd, post_hooks, compile, State),
ProjectApps1 = build_apps(State2, Providers, ProjectApps),
rebar_hooks:run_all_hooks(Cwd, post, ?PROVIDER, Providers, State),
{ok, rebar_state:project_apps(State, ProjectApps1)}. {ok, rebar_state:project_apps(State, ProjectApps1)}.
@ -53,10 +56,10 @@ do(State) ->
format_error(Reason) -> format_error(Reason) ->
io_lib:format("~p", [Reason]). io_lib:format("~p", [Reason]).
build_apps(State, Apps) ->
[build_app(State, AppInfo) || AppInfo <- Apps].
build_apps(State, Providers, Apps) ->
[build_app(State, Providers, AppInfo) || AppInfo <- Apps].
build_app(State, AppInfo) ->
build_app(State, Providers, AppInfo) ->
AppDir = rebar_app_info:dir(AppInfo), AppDir = rebar_app_info:dir(AppInfo),
OutDir = rebar_app_info:out_dir(AppInfo), OutDir = rebar_app_info:out_dir(AppInfo),
@ -71,9 +74,10 @@ build_app(State, AppInfo) ->
end, end,
%% Legacy hook support %% Legacy hook support
rebar_hooks:run_compile_hooks(AppDir, pre_hooks, compile, S),
rebar_hooks:run_all_hooks(AppDir, pre, ?PROVIDER, Providers, S),
AppInfo1 = compile(S, AppInfo), AppInfo1 = compile(S, AppInfo),
rebar_hooks:run_compile_hooks(AppDir, post_hooks, compile, S),
rebar_hooks:run_all_hooks(AppDir, post, ?PROVIDER, Providers, S),
true = code:add_patha(rebar_app_info:ebin_dir(AppInfo1)), true = code:add_patha(rebar_app_info:ebin_dir(AppInfo1)),
AppInfo1. AppInfo1.

+ 3
- 3
src/rebar_prv_deps.erl View File

@ -77,7 +77,7 @@ display_dep(_State, {Name, _Vsn, Source, _Opts}) when is_tuple(Source) ->
display_dep(State, {Name, Source={pkg, _, Vsn}, Level}) when is_integer(Level) -> display_dep(State, {Name, Source={pkg, _, Vsn}, Level}) when is_integer(Level) ->
DepsDir = rebar_dir:deps_dir(State), DepsDir = rebar_dir:deps_dir(State),
AppDir = filename:join([DepsDir, ec_cnv:to_binary(Name)]), AppDir = filename:join([DepsDir, ec_cnv:to_binary(Name)]),
NeedsUpdate = case rebar_fetch:needs_update(AppDir, Source) of
NeedsUpdate = case rebar_fetch:needs_update(AppDir, Source, State) of
true -> "*"; true -> "*";
false -> "" false -> ""
end, end,
@ -85,7 +85,7 @@ display_dep(State, {Name, Source={pkg, _, Vsn}, Level}) when is_integer(Level) -
display_dep(State, {Name, Source, Level}) when is_tuple(Source), is_integer(Level), element(1, Source) =:= git -> display_dep(State, {Name, Source, Level}) when is_tuple(Source), is_integer(Level), element(1, Source) =:= git ->
DepsDir = rebar_dir:deps_dir(State), DepsDir = rebar_dir:deps_dir(State),
AppDir = filename:join([DepsDir, ec_cnv:to_binary(Name)]), AppDir = filename:join([DepsDir, ec_cnv:to_binary(Name)]),
NeedsUpdate = case rebar_fetch:needs_update(AppDir, Source) of
NeedsUpdate = case rebar_fetch:needs_update(AppDir, Source, State) of
true -> "*"; true -> "*";
false -> "" false -> ""
end, end,
@ -93,7 +93,7 @@ display_dep(State, {Name, Source, Level}) when is_tuple(Source), is_integer(Leve
display_dep(State, {Name, Source, Level}) when is_tuple(Source), is_integer(Level) -> display_dep(State, {Name, Source, Level}) when is_tuple(Source), is_integer(Level) ->
DepsDir = rebar_dir:deps_dir(State), DepsDir = rebar_dir:deps_dir(State),
AppDir = filename:join([DepsDir, ec_cnv:to_binary(Name)]), AppDir = filename:join([DepsDir, ec_cnv:to_binary(Name)]),
NeedsUpdate = case rebar_fetch:needs_update(AppDir, Source) of
NeedsUpdate = case rebar_fetch:needs_update(AppDir, Source, State) of
true -> "*"; true -> "*";
false -> "" false -> ""
end, end,

+ 12
- 3
src/rebar_prv_eunit.erl View File

@ -37,9 +37,19 @@ init(State) ->
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. -spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) -> do(State) ->
?INFO("Performing EUnit tests...", []), ?INFO("Performing EUnit tests...", []),
%% Run eunit provider prehooks
Providers = rebar_state:providers(State),
Cwd = rebar_dir:get_cwd(),
rebar_hooks:run_all_hooks(Cwd, pre, ?PROVIDER, Providers, State),
case prepare_tests(State) of case prepare_tests(State) of
{ok, Tests} -> do_tests(State, Tests);
Error -> Error
{ok, Tests} ->
{ok, State1} = do_tests(State, Tests),
%% Run eunit provider posthooks
rebar_hooks:run_all_hooks(Cwd, post, ?PROVIDER, Providers, State1),
{ok, State1};
Error ->
Error
end. end.
do_tests(State, Tests) -> do_tests(State, Tests) ->
@ -250,4 +260,3 @@ help(app) -> "List of application test suites to run";
help(cover) -> "Generate cover data"; help(cover) -> "Generate cover data";
help(suite) -> "List of test suites to run"; help(suite) -> "List of test suites to run";
help(verbose) -> "Verbose output". help(verbose) -> "Verbose output".

+ 9
- 6
src/rebar_prv_install_deps.erl View File

@ -336,13 +336,13 @@ handle_upgrade(AppInfo, SrcDeps, PkgDeps, SrcApps, Level, State, Locks) ->
handle_dep(AppInfo, SrcDeps, PkgDeps, SrcApps, Level, State, Locks) -> handle_dep(AppInfo, SrcDeps, PkgDeps, SrcApps, Level, State, Locks) ->
DepsDir = rebar_dir:deps_dir(State), DepsDir = rebar_dir:deps_dir(State),
{AppInfo1, NewSrcDeps, NewPkgDeps, NewLocks} =
{AppInfo1, NewSrcDeps, NewPkgDeps, NewLocks, State1} =
handle_dep(State, DepsDir, AppInfo, Locks, Level), handle_dep(State, DepsDir, AppInfo, Locks, Level),
AppInfo2 = rebar_app_info:dep_level(AppInfo1, Level), AppInfo2 = rebar_app_info:dep_level(AppInfo1, Level),
{NewSrcDeps ++ SrcDeps {NewSrcDeps ++ SrcDeps
,NewPkgDeps++PkgDeps ,NewPkgDeps++PkgDeps
,[AppInfo2 | SrcApps] ,[AppInfo2 | SrcApps]
,State
,State1
,NewLocks}. ,NewLocks}.
-spec handle_dep(rebar_state:t(), file:filename_all(), rebar_app_info:t(), list(), integer()) -> -spec handle_dep(rebar_state:t(), file:filename_all(), rebar_app_info:t(), list(), integer()) ->
@ -359,13 +359,16 @@ handle_dep(State, DepsDir, AppInfo, Locks, Level) ->
S3 = rebar_state:apply_overrides(S2, Name), S3 = rebar_state:apply_overrides(S2, Name),
AppInfo1 = rebar_app_info:state(AppInfo, S3), AppInfo1 = rebar_app_info:state(AppInfo, S3),
%% Dep may have plugins to install. Find and install here.
State1 = rebar_plugins:handle_plugins(rebar_state:get(S3, plugins, []), State),
Deps = rebar_state:get(S3, deps, []), Deps = rebar_state:get(S3, deps, []),
%% Upgrade lock level to be the level the dep will have in this dep tree %% Upgrade lock level to be the level the dep will have in this dep tree
NewLocks = [{DepName, Source, LockLevel+Level} || NewLocks = [{DepName, Source, LockLevel+Level} ||
{DepName, Source, LockLevel} <- rebar_state:get(S3, {locks, default}, [])], {DepName, Source, LockLevel} <- rebar_state:get(S3, {locks, default}, [])],
AppInfo2 = rebar_app_info:deps(AppInfo1, rebar_state:deps_names(Deps)), AppInfo2 = rebar_app_info:deps(AppInfo1, rebar_state:deps_names(Deps)),
{SrcDeps, PkgDeps} = parse_deps(DepsDir, Deps, S3, Locks, Level), {SrcDeps, PkgDeps} = parse_deps(DepsDir, Deps, S3, Locks, Level),
{AppInfo2, SrcDeps, PkgDeps, Locks++NewLocks}.
{AppInfo2, SrcDeps, PkgDeps, Locks++NewLocks, State1}.
-spec maybe_fetch(rebar_app_info:t(), boolean() | {true, binary(), integer()}, -spec maybe_fetch(rebar_app_info:t(), boolean() | {true, binary(), integer()},
sets:set(binary()), rebar_state:t()) -> boolean(). sets:set(binary()), rebar_state:t()) -> boolean().
@ -507,12 +510,12 @@ fetch_app(AppInfo, AppDir, State) ->
Result Result
end. end.
maybe_upgrade(AppInfo, AppDir, false, _State) ->
maybe_upgrade(AppInfo, AppDir, false, State) ->
Source = rebar_app_info:source(AppInfo), Source = rebar_app_info:source(AppInfo),
rebar_fetch:needs_update(AppDir, Source);
rebar_fetch:needs_update(AppDir, Source, State);
maybe_upgrade(AppInfo, AppDir, true, State) -> maybe_upgrade(AppInfo, AppDir, true, State) ->
Source = rebar_app_info:source(AppInfo), Source = rebar_app_info:source(AppInfo),
case rebar_fetch:needs_update(AppDir, Source) of
case rebar_fetch:needs_update(AppDir, Source, State) of
true -> true ->
?INFO("Updating ~s", [rebar_app_info:name(AppInfo)]), ?INFO("Updating ~s", [rebar_app_info:name(AppInfo)]),
case rebar_fetch:download_source(AppDir, Source, State) of case rebar_fetch:download_source(AppDir, Source, State) of

+ 1
- 1
src/rebar_prv_lock.erl View File

@ -37,7 +37,7 @@ do(State) ->
%% If source is tuple it is a source dep %% If source is tuple it is a source dep
%% e.g. {git, "git://github.com/ninenines/cowboy.git", "master"} %% e.g. {git, "git://github.com/ninenines/cowboy.git", "master"}
{rebar_app_info:name(Dep) {rebar_app_info:name(Dep)
,rebar_fetch:lock_source(Dir, Source)
,rebar_fetch:lock_source(Dir, Source, State)
,rebar_app_info:dep_level(Dep)} ,rebar_app_info:dep_level(Dep)}
end || Dep <- AllDeps, not(rebar_app_info:is_checkout(Dep))], end || Dep <- AllDeps, not(rebar_app_info:is_checkout(Dep))],
Dir = rebar_state:dir(State), Dir = rebar_state:dir(State),

+ 23
- 47
src/rebar_state.erl View File

@ -30,6 +30,7 @@
overrides/1, overrides/2, overrides/1, overrides/2,
apply_overrides/2, apply_overrides/2,
resources/1, resources/2, add_resource/2,
providers/1, providers/2, add_provider/2]). providers/1, providers/2, add_provider/2]).
-include("rebar.hrl"). -include("rebar.hrl").
@ -51,6 +52,7 @@
all_deps = [] :: [rebar_app_info:t()], all_deps = [] :: [rebar_app_info:t()],
overrides = [], overrides = [],
resources = [],
providers = []}). providers = []}).
-export_type([t/0]). -export_type([t/0]).
@ -296,6 +298,18 @@ namespace(#state_t{namespace=Namespace}) ->
namespace(State=#state_t{}, Namespace) -> namespace(State=#state_t{}, Namespace) ->
State#state_t{namespace=Namespace}. State#state_t{namespace=Namespace}.
-spec resources(t()) -> rebar_resource:resource().
resources(#state_t{resources=Resources}) ->
Resources.
-spec resources(t(), [rebar_resource:resource()]) -> t().
resources(State, NewResources) ->
State#state_t{resources=NewResources}.
-spec add_resource(t(), rebar_resource:resource()) -> t().
add_resource(State=#state_t{resources=Resources}, Resource) ->
State#state_t{resources=[Resource | Resources]}.
providers(#state_t{providers=Providers}) -> providers(#state_t{providers=Providers}) ->
Providers. Providers.
@ -308,62 +322,25 @@ add_provider(State=#state_t{providers=Providers}, Provider) ->
create_logic_providers(ProviderModules, State0) -> create_logic_providers(ProviderModules, State0) ->
try try
State1 = lists:foldl(fun(ProviderMod, StateAcc) ->
case providers:new(ProviderMod, StateAcc) of
{error, Reason} ->
?ERROR(Reason++"~n", []),
StateAcc;
{ok, StateAcc1} ->
StateAcc1
end
end, State0, ProviderModules),
apply_hooks(State1)
lists:foldl(fun(ProviderMod, StateAcc) ->
case providers:new(ProviderMod, StateAcc) of
{error, Reason} ->
?ERROR(Reason++"~n", []),
StateAcc;
{ok, StateAcc1} ->
StateAcc1
end
end, State0, ProviderModules)
catch catch
C:T -> C:T ->
?DEBUG("~p: ~p ~p", [C, T, erlang:get_stacktrace()]), ?DEBUG("~p: ~p ~p", [C, T, erlang:get_stacktrace()]),
throw({error, "Failed creating providers. Run with DEBUG=1 for stacktrace."}) throw({error, "Failed creating providers. Run with DEBUG=1 for stacktrace."})
end. end.
apply_hooks(State0) ->
try
Hooks = rebar_state:get(State0, provider_hooks, []),
PreHooks = proplists:get_value(pre, Hooks, []),
PostHooks = proplists:get_value(post, Hooks, []),
State1 = lists:foldl(fun({Target, Hook}, StateAcc) ->
prepend_hook(StateAcc, Target, Hook)
end, State0, PreHooks),
lists:foldl(fun({Target, Hook}, StateAcc) ->
append_hook(StateAcc, Target, Hook)
end, State1, PostHooks)
catch
C:T ->
?DEBUG("~p: ~p ~p", [C, T, erlang:get_stacktrace()]),
throw({error, "Failed parsing provider hooks. Run with DEBUG=1 for stacktrace."})
end.
%% =================================================================== %% ===================================================================
%% Internal functions %% Internal functions
%% =================================================================== %% ===================================================================
prepend_hook(State=#state_t{providers=Providers}, Target, Hook) ->
State#state_t{providers=add_hook(pre, Providers, Target, Hook)}.
append_hook(State=#state_t{providers=Providers}, Target, Hook) ->
State#state_t{providers=add_hook(post, Providers, Target, Hook)}.
add_hook(Which, Providers, Target, Hook) ->
Provider = providers:get_provider(Target, Providers),
Hooks = providers:hooks(Provider),
NewHooks = add_hook(Which, Hooks, Hook),
NewProvider = providers:hooks(Provider, NewHooks),
[NewProvider | lists:delete(Provider, Providers)].
add_hook(pre, {PreHooks, PostHooks}, Hook) ->
{[Hook | PreHooks], PostHooks};
add_hook(post, {PreHooks, PostHooks}, Hook) ->
{PreHooks, [Hook | PostHooks]}.
%% Sort the list in proplist-order, meaning that `{a,b}' and `{a,c}' %% Sort the list in proplist-order, meaning that `{a,b}' and `{a,c}'
%% both compare as usual, and `a' and `b' do the same, but `a' and `{a,b}' will %% both compare as usual, and `a' and `b' do the same, but `a' and `{a,b}' will
%% compare based on the first element of the key, and in order. So the following %% compare based on the first element of the key, and in order. So the following
@ -425,4 +402,3 @@ umerge([], Olds, Merged, CmpMerged, Cmp) when CmpMerged == Cmp ->
lists:reverse(Olds, Merged); lists:reverse(Olds, Merged);
umerge([], Olds, Merged, _CmpMerged, Cmp) -> umerge([], Olds, Merged, _CmpMerged, Cmp) ->
lists:reverse(Olds, [Cmp | Merged]). lists:reverse(Olds, [Cmp | Merged]).

+ 2
- 1
test/mock_git_resource.erl View File

@ -99,6 +99,7 @@ mock_vsn(Opts) ->
%% into a `rebar.config' file to describe dependencies. %% into a `rebar.config' file to describe dependencies.
mock_download(Opts) -> mock_download(Opts) ->
Deps = proplists:get_value(deps, Opts, []), Deps = proplists:get_value(deps, Opts, []),
Config = proplists:get_value(config, Opts, []),
Default = proplists:get_value(default_vsn, Opts, "0.0.0"), Default = proplists:get_value(default_vsn, Opts, "0.0.0"),
Overrides = proplists:get_value(override_vsn, Opts, []), Overrides = proplists:get_value(override_vsn, Opts, []),
meck:expect( meck:expect(
@ -112,7 +113,7 @@ mock_download(Opts) ->
Dir, App, Vsn, Dir, App, Vsn,
[kernel, stdlib] ++ [element(1,D) || D <- AppDeps] [kernel, stdlib] ++ [element(1,D) || D <- AppDeps]
), ),
rebar_test_utils:create_config(Dir, [{deps, AppDeps}]),
rebar_test_utils:create_config(Dir, [{deps, AppDeps}]++Config),
{ok, 'WHATEVER'} {ok, 'WHATEVER'}
end). end).

+ 34
- 2
test/rebar_compile_SUITE.erl View File

@ -15,7 +15,8 @@
dont_recompile_when_opts_dont_change/1, dont_recompile_when_opts_dont_change/1,
dont_recompile_yrl_or_xrl/1, dont_recompile_yrl_or_xrl/1,
deps_in_path/1, deps_in_path/1,
checkout_priority/1]).
checkout_priority/1,
compile_plugins/1]).
-include_lib("common_test/include/ct.hrl"). -include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl"). -include_lib("eunit/include/eunit.hrl").
@ -41,7 +42,7 @@ all() ->
build_checkout_apps, build_checkout_deps, build_checkout_apps, build_checkout_deps,
build_all_srcdirs, build_all_srcdirs,
recompile_when_opts_change, dont_recompile_when_opts_dont_change, recompile_when_opts_change, dont_recompile_when_opts_dont_change,
dont_recompile_yrl_or_xrl, deps_in_path, checkout_priority].
dont_recompile_yrl_or_xrl, deps_in_path, checkout_priority, compile_plugins].
build_basic_app(Config) -> build_basic_app(Config) ->
AppDir = ?config(apps, Config), AppDir = ?config(apps, Config),
@ -332,3 +333,34 @@ checkout_priority(Config) ->
?assertEqual(Vsn2, proplists:get_value(vsn, DepProps)), ?assertEqual(Vsn2, proplists:get_value(vsn, DepProps)),
?assertEqual(Vsn2, proplists:get_value(vsn, PkgProps)). ?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),
PluginsDir = filename:join([?config(base_dir, Config), "default", "plugins"]),
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_"),
mock_git_resource:mock([{config, [{plugins, [
{list_to_atom(PluginName), Vsn}
]}]}]),
mock_pkg_resource:mock([
{pkgdeps, [{{iolist_to_binary(PluginName), iolist_to_binary(Vsn)}, []}]}
]),
RConfFile =
rebar_test_utils:create_config(AppDir,
[{deps, [
{list_to_atom(DepName), {git, "http://site.com/user/"++DepName++".git", {tag, Vsn}}}
]}]),
{ok, RConf} = file:consult(RConfFile),
%% Build with deps.
rebar_test_utils:run_and_check(
Config, RConf, ["compile"],
{ok, [{app, Name}, {plugin, PluginName}, {dep, DepName}]}
).

+ 6
- 2
test/rebar_resource_SUITE.erl View File

@ -12,7 +12,10 @@ groups() ->
{hg, [], [{group, all}]}]. {hg, [], [{group, all}]}].
init_per_group(all, Config) -> init_per_group(all, Config) ->
Config;
State = rebar_state:resources(rebar_state:new(), [{git, rebar_git_resource},
{pkg, rebar_pkg_resource},
{hg, rebar_hg_resource}]),
[{state, State} | Config];
init_per_group(Name, Config) -> init_per_group(Name, Config) ->
[{type, Name}, [{type, Name},
{resource, {Name, "https://example.org/user/app", "vsn"}} | Config]. {resource, {Name, "https://example.org/user/app", "vsn"}} | Config].
@ -33,4 +36,5 @@ end_per_testcase(_, Config) ->
change_type_upgrade(Config) -> change_type_upgrade(Config) ->
?assert(rebar_fetch:needs_update(?config(path, Config), ?assert(rebar_fetch:needs_update(?config(path, Config),
?config(resource, Config))).
?config(resource, Config),
?config(state, Config))).

+ 15
- 0
test/rebar_test_utils.erl View File

@ -158,6 +158,7 @@ top_level_deps([{{Name, Vsn, Ref}, _} | Deps]) ->
%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%
check_results(AppDir, Expected) -> check_results(AppDir, Expected) ->
BuildDirs = filelib:wildcard(filename:join([AppDir, "_build", "*", "lib"])), BuildDirs = filelib:wildcard(filename:join([AppDir, "_build", "*", "lib"])),
PluginDirs = filelib:wildcard(filename:join([AppDir, "_build", "*", "plugins"])),
CheckoutsDir = filename:join([AppDir, "_checkouts"]), CheckoutsDir = filename:join([AppDir, "_checkouts"]),
LockFile = filename:join([AppDir, "rebar.lock"]), LockFile = filename:join([AppDir, "rebar.lock"]),
Locks = lists:flatten(rebar_config:consult_file(LockFile)), Locks = lists:flatten(rebar_config:consult_file(LockFile)),
@ -172,6 +173,8 @@ check_results(AppDir, Expected) ->
DepsNames = [{ec_cnv:to_list(rebar_app_info:name(App)), App} || App <- Deps], DepsNames = [{ec_cnv:to_list(rebar_app_info:name(App)), App} || App <- Deps],
Checkouts = rebar_app_discover:find_apps([CheckoutsDir], all), Checkouts = rebar_app_discover:find_apps([CheckoutsDir], all),
CheckoutsNames = [{ec_cnv:to_list(rebar_app_info:name(App)), App} || App <- Checkouts], CheckoutsNames = [{ec_cnv:to_list(rebar_app_info:name(App)), App} || App <- Checkouts],
Plugins = rebar_app_discover:find_apps(PluginDirs, all),
PluginsNames = [{ec_cnv:to_list(rebar_app_info:name(App)), App} || App <- Plugins],
lists:foreach( lists:foreach(
fun({app, Name}) -> fun({app, Name}) ->
@ -213,6 +216,18 @@ check_results(AppDir, Expected) ->
?assertEqual(iolist_to_binary(Vsn), ?assertEqual(iolist_to_binary(Vsn),
iolist_to_binary(rebar_app_info:original_vsn(App))) iolist_to_binary(rebar_app_info:original_vsn(App)))
end end
; ({plugin, Name}) ->
ct:pal("Name: ~p", [Name]),
?assertNotEqual(false, lists:keyfind(Name, 1, PluginsNames))
; ({plugin, Name, Vsn}) ->
ct:pal("Name: ~p, Vsn: ~p", [Name, Vsn]),
case lists:keyfind(Name, 1, PluginsNames) of
false ->
error({dep_not_found, Name});
{Name, App} ->
?assertEqual(iolist_to_binary(Vsn),
iolist_to_binary(rebar_app_info:original_vsn(App)))
end
; ({lock, Name}) -> ; ({lock, Name}) ->
ct:pal("Name: ~p", [Name]), ct:pal("Name: ~p", [Name]),
?assertNotEqual(false, lists:keyfind(iolist_to_binary(Name), 1, Locks)) ?assertNotEqual(false, lists:keyfind(iolist_to_binary(Name), 1, Locks))

Loading…
Cancel
Save