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.

167 line
7.2 KiB

10 年之前
10 年之前
10 年之前
10 年之前
10 年之前
10 年之前
10 年之前
10 年之前
10 年之前
  1. %% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
  2. %% ex: ts=4 sw=4 et
  3. -module(rebar_plugins).
  4. -export([project_plugins_install/1
  5. ,top_level_install/1
  6. ,project_apps_install/1
  7. ,install/2
  8. ,handle_plugins/3
  9. ,handle_plugins/4]).
  10. -include("rebar.hrl").
  11. %% ===================================================================
  12. %% Public API
  13. %% ===================================================================
  14. -spec project_plugins_install(rebar_state:t()) -> rebar_state:t().
  15. project_plugins_install(State) ->
  16. Profiles = rebar_state:current_profiles(State),
  17. State1 = rebar_state:allow_provider_overrides(State, true),
  18. State2 = lists:foldl(fun(Profile, StateAcc) ->
  19. Plugins = rebar_state:get(State, {project_plugins, Profile}, []),
  20. handle_plugins(Profile, Plugins, StateAcc)
  21. end, State1, Profiles),
  22. rebar_state:allow_provider_overrides(State2, false).
  23. -spec top_level_install(rebar_state:t()) -> rebar_state:t().
  24. top_level_install(State) ->
  25. Profiles = rebar_state:current_profiles(State),
  26. lists:foldl(fun(Profile, StateAcc) ->
  27. Plugins = rebar_state:get(State, {plugins, Profile}, []),
  28. handle_plugins(Profile, Plugins, StateAcc)
  29. end, State, Profiles).
  30. -spec project_apps_install(rebar_state:t()) -> rebar_state:t().
  31. project_apps_install(State) ->
  32. Profiles = rebar_state:current_profiles(State),
  33. ProjectApps = rebar_state:project_apps(State),
  34. lists:foldl(fun(Profile, StateAcc) ->
  35. StateAcc1 = case Profile of
  36. default ->
  37. %% default profile top level plugins
  38. %% are installed in run_aux
  39. StateAcc;
  40. _ ->
  41. Plugins = rebar_state:get(State, {plugins, Profile}, []),
  42. handle_plugins(Profile, Plugins, StateAcc)
  43. end,
  44. lists:foldl(fun(AppInfo, StateAcc2) ->
  45. Plugins2 = rebar_app_info:get(AppInfo, {plugins, Profile}, []),
  46. handle_plugins(Profile, Plugins2, StateAcc2)
  47. end, StateAcc1, ProjectApps)
  48. end, State, Profiles).
  49. -spec install(rebar_state:t(), rebar_app_info:t()) -> rebar_state:t().
  50. install(State, AppInfo) ->
  51. Profiles = rebar_state:current_profiles(State),
  52. %% don't lose the overrides of the dep we are processing plugins for
  53. Overrides = rebar_app_info:get(AppInfo, overrides, []),
  54. StateOverrides = rebar_state:get(State, overrides, []),
  55. AllOverrides = Overrides ++ StateOverrides,
  56. State1 = rebar_state:set(State, overrides, AllOverrides),
  57. State2 = lists:foldl(fun(Profile, StateAcc) ->
  58. Plugins = rebar_app_info:get(AppInfo, {plugins, Profile}, []),
  59. Plugins1 = filter_existing_plugins(Plugins, StateAcc),
  60. handle_plugins(Profile, Plugins1, StateAcc)
  61. end, State1, Profiles),
  62. %% Reset the overrides after processing the dep
  63. rebar_state:set(State2, overrides, StateOverrides).
  64. filter_existing_plugins(Plugins, State) ->
  65. PluginNames = lists:zip(Plugins, rebar_state:deps_names(Plugins)),
  66. AllPlugins = rebar_state:all_plugin_deps(State),
  67. lists:filtermap(fun({Plugin, PluginName}) ->
  68. case rebar_app_utils:find(PluginName, AllPlugins) of
  69. {ok, _} ->
  70. false;
  71. _ ->
  72. {true, Plugin}
  73. end
  74. end, PluginNames).
  75. handle_plugins(Profile, Plugins, State) ->
  76. handle_plugins(Profile, Plugins, State, false).
  77. handle_plugins(Profile, Plugins, State, Upgrade) ->
  78. %% Set deps dir to plugins dir so apps are installed there
  79. Locks = rebar_state:lock(State),
  80. DepsDir = rebar_state:get(State, deps_dir, ?DEFAULT_DEPS_DIR),
  81. State1 = rebar_state:set(State, deps_dir, ?DEFAULT_PLUGINS_DIR),
  82. %% Install each plugin individually so if one fails to install it doesn't effect the others
  83. {_PluginProviders, State2} =
  84. lists:foldl(fun(Plugin, {PluginAcc, StateAcc}) ->
  85. {NewPlugins, NewState} = handle_plugin(Profile, Plugin, StateAcc, Upgrade),
  86. NewState1 = rebar_state:create_logic_providers(NewPlugins, NewState),
  87. {PluginAcc++NewPlugins, NewState1}
  88. end, {[], State1}, Plugins),
  89. %% reset deps dir
  90. State3 = rebar_state:set(State2, deps_dir, DepsDir),
  91. rebar_state:lock(State3, Locks).
  92. handle_plugin(Profile, Plugin, State, Upgrade) ->
  93. try
  94. {Apps, State2} = rebar_prv_install_deps:handle_deps_as_profile(Profile, State, [Plugin], Upgrade),
  95. {no_cycle, Sorted} = rebar_prv_install_deps:find_cycles(Apps),
  96. ToBuild = rebar_prv_install_deps:cull_compile(Sorted, []),
  97. %% Add already built plugin deps to the code path
  98. PreBuiltPaths = [rebar_app_info:ebin_dir(A) || A <- Apps] -- ToBuild,
  99. code:add_pathsa(PreBuiltPaths),
  100. %% Build plugin and its deps
  101. [build_plugin(AppInfo, Apps, State2) || AppInfo <- ToBuild],
  102. %% Add newly built deps and plugin to code path
  103. State3 = rebar_state:update_all_plugin_deps(State2, Apps),
  104. NewCodePaths = [rebar_app_info:ebin_dir(A) || A <- ToBuild],
  105. %% Store plugin code paths so we can remove them when compiling project apps
  106. State4 = rebar_state:update_code_paths(State3, all_plugin_deps, PreBuiltPaths++NewCodePaths),
  107. rebar_paths:set_paths([plugins], State4),
  108. {plugin_providers(Plugin), State4}
  109. catch
  110. ?WITH_STACKTRACE(C,T,S)
  111. ?DEBUG("~p ~p ~p", [C, T, S]),
  112. ?WARN("Plugin ~p not available. It will not be used.", [Plugin]),
  113. {[], State}
  114. end.
  115. build_plugin(AppInfo, Apps, State) ->
  116. Providers = rebar_state:providers(State),
  117. S = rebar_state:all_deps(State, Apps),
  118. S1 = rebar_state:set(S, deps_dir, ?DEFAULT_PLUGINS_DIR),
  119. rebar_prv_compile:compile(S1, Providers, AppInfo).
  120. plugin_providers({Plugin, _, _, _}) when is_atom(Plugin) ->
  121. validate_plugin(Plugin);
  122. plugin_providers({Plugin, _, _}) when is_atom(Plugin) ->
  123. validate_plugin(Plugin);
  124. plugin_providers({Plugin, _}) when is_atom(Plugin) ->
  125. validate_plugin(Plugin);
  126. plugin_providers(Plugin) when is_atom(Plugin) ->
  127. validate_plugin(Plugin).
  128. validate_plugin(Plugin) ->
  129. _ = application:load(Plugin),
  130. case application:get_env(Plugin, providers) of
  131. {ok, Providers} ->
  132. Providers;
  133. undefined ->
  134. Exports = Plugin:module_info(exports),
  135. case lists:member({init,1}, Exports) of
  136. false ->
  137. ?WARN("Plugin ~p does not export init/1. It will not be used.", [Plugin]),
  138. [];
  139. true ->
  140. [Plugin]
  141. end
  142. end.