You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

135 lines
6.2 KiB

  1. -module(rebar_hooks).
  2. -export([run_all_hooks/5
  3. ,run_all_hooks/6
  4. ,format_error/1]).
  5. -include("rebar.hrl").
  6. -include_lib("providers/include/providers.hrl").
  7. -spec run_all_hooks(file:filename_all(), pre | post,
  8. atom() | {atom(), atom()} | string(),
  9. [providers:t()], rebar_app_info:t(), rebar_state:t()) -> rebar_app_info:t().
  10. run_all_hooks(Dir, Type, Command, Providers, AppInfo, State) ->
  11. State1 = rebar_state:current_app(State, AppInfo),
  12. State2 = run_provider_hooks(Dir, Type, Command, Providers, rebar_app_info:opts(AppInfo), State1),
  13. run_hooks(Dir, Type, Command, rebar_app_info:opts(AppInfo), State1),
  14. rebar_state:current_app(State2).
  15. run_all_hooks(Dir, Type, Command, Providers, State) ->
  16. run_provider_hooks(Dir, Type, Command, Providers, rebar_state:opts(State), State),
  17. run_hooks(Dir, Type, Command, rebar_state:opts(State), State).
  18. run_provider_hooks(Dir, Type, Command, Providers, Opts, State) ->
  19. case rebar_opts:get(Opts, provider_hooks, []) of
  20. [] ->
  21. State;
  22. AllHooks ->
  23. TypeHooks = proplists:get_value(Type, AllHooks, []),
  24. run_provider_hooks_(Dir, Type, Command, Providers, TypeHooks, rebar_state:opts(State, Opts))
  25. end.
  26. run_provider_hooks_(_Dir, _Type, _Command, _Providers, [], State) ->
  27. State;
  28. run_provider_hooks_(Dir, Type, Command, Providers, TypeHooks, State) ->
  29. PluginDepsPaths = rebar_state:code_paths(State, all_plugin_deps),
  30. code:add_pathsa(PluginDepsPaths),
  31. Providers1 = rebar_state:providers(State),
  32. State1 = rebar_state:providers(rebar_state:dir(State, Dir), Providers++Providers1),
  33. HookProviders = proplists:get_all_values(Command, TypeHooks),
  34. case rebar_core:do(HookProviders, State1) of
  35. {error, ProviderName} ->
  36. ?DEBUG(format_error({bad_provider, Type, Command, ProviderName}), []),
  37. throw(?PRV_ERROR({bad_provider, Type, Command, ProviderName}));
  38. {ok, State2} ->
  39. rebar_utils:remove_from_code_path(PluginDepsPaths),
  40. State2
  41. end.
  42. format_error({bad_provider, Type, Command, {Name, Namespace}}) ->
  43. io_lib:format("Unable to run ~s hooks for '~p', command '~p' in namespace '~p' not found.", [Type, Command, Namespace, Name]);
  44. format_error({bad_provider, Type, Command, Name}) ->
  45. io_lib:format("Unable to run ~s hooks for '~p', command '~p' not found.", [Type, Command, Name]).
  46. %% @doc The following environment variables are exported when running
  47. %% a hook (absolute paths):
  48. %%
  49. %% REBAR_DEPS_DIR = rebar_dir:deps_dir/1
  50. %% REBAR_BUILD_DIR = rebar_dir:base_dir/1
  51. %% REBAR_ROOT_DIR = rebar_dir:root_dir/1
  52. %% REBAR_CHECKOUTS_DIR = rebar_dir:checkouts_dir/1
  53. %% REBAR_PLUGINS_DIR = rebar_dir:plugins_dir/1
  54. %% REBAR_GLOBAL_CONFIG_DIR = rebar_dir:global_config_dir/1
  55. %% REBAR_GLOBAL_CACHE_DIR = rebar_dir:global_cache_dir/1
  56. %% REBAR_TEMPLATE_DIR = rebar_dir:template_dir/1
  57. %% REBAR_APP_DIRS = rebar_dir:lib_dirs/1
  58. %% REBAR_SRC_DIRS = rebar_dir:src_dirs/1
  59. %%
  60. %% autoconf compatible variables
  61. %% (see: http://www.gnu.org/software/autoconf/manual/autoconf.html#Erlang-Libraries):
  62. %% ERLANG_ERTS_VER = erlang:system_info(version)
  63. %% ERLANG_ROOT_DIR = code:root_dir/0
  64. %% ERLANG_LIB_DIR_erl_interface = code:lib_dir(erl_interface)
  65. %% ERLANG_LIB_VER_erl_interface = version part of path returned by code:lib_dir(erl_interface)
  66. %% ERL = ERLANG_ROOT_DIR/bin/erl
  67. %% ERLC = ERLANG_ROOT_DIR/bin/erl
  68. %%
  69. run_hooks(Dir, pre, Command, Opts, State) ->
  70. run_hooks(Dir, pre_hooks, Command, Opts, State);
  71. run_hooks(Dir, post, Command, Opts, State) ->
  72. run_hooks(Dir, post_hooks, Command, Opts, State);
  73. run_hooks(Dir, Type, Command, Opts, State) ->
  74. case rebar_opts:get(Opts, Type, []) of
  75. [] ->
  76. ok;
  77. Hooks ->
  78. Env = create_env(State, Opts),
  79. lists:foreach(fun({_, C, _}=Hook) when C =:= Command ->
  80. apply_hook(Dir, Env, Hook);
  81. ({C, _}=Hook) when C =:= Command ->
  82. apply_hook(Dir, Env, Hook);
  83. (_) ->
  84. continue
  85. end, Hooks)
  86. end.
  87. apply_hook(Dir, Env, {Arch, Command, Hook}) ->
  88. case rebar_utils:is_arch(Arch) of
  89. true ->
  90. apply_hook(Dir, Env, {Command, Hook});
  91. false ->
  92. ok
  93. end;
  94. apply_hook(Dir, Env, {Command, Hook}) ->
  95. Msg = lists:flatten(io_lib:format("Hook for ~p failed!~n", [Command])),
  96. rebar_utils:sh(Hook, [use_stdout, {cd, Dir}, {env, Env}, {abort_on_error, Msg}]).
  97. create_env(State, Opts) ->
  98. BaseDir = rebar_dir:base_dir(State),
  99. [
  100. {"REBAR_DEPS_DIR", filename:absname(rebar_dir:deps_dir(State))},
  101. {"REBAR_BUILD_DIR", filename:absname(rebar_dir:base_dir(State))},
  102. {"REBAR_ROOT_DIR", filename:absname(rebar_dir:root_dir(State))},
  103. {"REBAR_CHECKOUTS_DIR", filename:absname(rebar_dir:checkouts_dir(State))},
  104. {"REBAR_PLUGINS_DIR", filename:absname(rebar_dir:plugins_dir(State))},
  105. {"REBAR_GLOBAL_CONFIG_DIR", filename:absname(rebar_dir:global_config_dir(State))},
  106. {"REBAR_GLOBAL_CACHE_DIR", filename:absname(rebar_dir:global_cache_dir(Opts))},
  107. {"REBAR_TEMPLATE_DIR", filename:absname(rebar_dir:template_dir(State))},
  108. {"REBAR_APP_DIRS", join_dirs(BaseDir, rebar_dir:lib_dirs(State))},
  109. {"REBAR_SRC_DIRS", join_dirs(BaseDir, rebar_dir:all_src_dirs(Opts))},
  110. {"ERLANG_ERTS_VER", erlang:system_info(version)},
  111. {"ERLANG_ROOT_DIR", code:root_dir()},
  112. {"ERLANG_LIB_DIR_erl_interface", code:lib_dir(erl_interface)},
  113. {"ERLANG_LIB_VER_erl_interface", re_version(code:lib_dir(erl_interface))},
  114. {"ERL", filename:join([code:root_dir(), "bin", "erl"])},
  115. {"ERLC", filename:join([code:root_dir(), "bin", "erlc"])}
  116. ].
  117. join_dirs(BaseDir, Dirs) ->
  118. string:join([ filename:join(BaseDir, Dir) || Dir <- Dirs ], ":").
  119. re_version(Path) ->
  120. case re:run(Path, "^.*-(?<VER>[^/-]*)$", [{capture, [1], list}]) of
  121. nomatch -> "";
  122. {match, [Ver]} -> Ver
  123. end.