Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

167 строки
7.2 KiB

10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
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.