Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

152 рядки
6.5 KiB

10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
9 роки тому
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. Plugins = rebar_state:get(State, {plugins, Profile}, []),
  36. StateAcc1 = handle_plugins(Profile, Plugins, StateAcc),
  37. lists:foldl(fun(AppInfo, StateAcc2) ->
  38. C = rebar_config:consult(rebar_app_info:dir(AppInfo)),
  39. AppInfo0 = rebar_app_info:update_opts(AppInfo, rebar_app_info:opts(AppInfo), C),
  40. Plugins2 = rebar_app_info:get(AppInfo0, {plugins, Profile}, []),
  41. handle_plugins(Profile, Plugins2, StateAcc2)
  42. end, StateAcc1, ProjectApps)
  43. end, State, Profiles).
  44. -spec install(rebar_state:t(), rebar_app_info:t()) -> rebar_state:t().
  45. install(State, AppInfo) ->
  46. Profiles = rebar_state:current_profiles(State),
  47. %% don't lose the overrides of the dep we are processing plugins for
  48. Overrides = rebar_app_info:get(AppInfo, overrides, []),
  49. StateOverrides = rebar_state:get(State, overrides, []),
  50. AllOverrides = Overrides ++ StateOverrides,
  51. State1 = rebar_state:set(State, overrides, AllOverrides),
  52. State2 = lists:foldl(fun(Profile, StateAcc) ->
  53. Plugins = rebar_app_info:get(AppInfo, {plugins, Profile}, []),
  54. handle_plugins(Profile, Plugins, StateAcc)
  55. end, State1, Profiles),
  56. %% Reset the overrides after processing the dep
  57. rebar_state:set(State2, overrides, StateOverrides).
  58. handle_plugins(Profile, Plugins, State) ->
  59. handle_plugins(Profile, Plugins, State, false).
  60. handle_plugins(Profile, Plugins, State, Upgrade) ->
  61. %% Set deps dir to plugins dir so apps are installed there
  62. Locks = rebar_state:lock(State),
  63. DepsDir = rebar_state:get(State, deps_dir, ?DEFAULT_DEPS_DIR),
  64. State1 = rebar_state:set(State, deps_dir, ?DEFAULT_PLUGINS_DIR),
  65. %% Install each plugin individually so if one fails to install it doesn't effect the others
  66. {_PluginProviders, State2} =
  67. lists:foldl(fun(Plugin, {PluginAcc, StateAcc}) ->
  68. {NewPlugins, NewState} = handle_plugin(Profile, Plugin, StateAcc, Upgrade),
  69. NewState1 = rebar_state:create_logic_providers(NewPlugins, NewState),
  70. {PluginAcc++NewPlugins, NewState1}
  71. end, {[], State1}, Plugins),
  72. %% reset deps dir
  73. State3 = rebar_state:set(State2, deps_dir, DepsDir),
  74. rebar_state:lock(State3, Locks).
  75. handle_plugin(Profile, Plugin, State, Upgrade) ->
  76. try
  77. {Apps, State2} = rebar_prv_install_deps:handle_deps_as_profile(Profile, State, [Plugin], Upgrade),
  78. {no_cycle, Sorted} = rebar_prv_install_deps:find_cycles(Apps),
  79. ToBuild = rebar_prv_install_deps:cull_compile(Sorted, []),
  80. %% Add already built plugin deps to the code path
  81. CodePaths = [rebar_app_info:ebin_dir(A) || A <- Apps -- ToBuild],
  82. code:add_pathsa(CodePaths),
  83. %% Build plugin and its deps
  84. [build_plugin(AppInfo, Apps, State2) || AppInfo <- ToBuild],
  85. %% Add newly built deps and plugin to code path
  86. State3 = rebar_state:update_all_plugin_deps(State2, Apps),
  87. NewCodePaths = [rebar_app_info:ebin_dir(A) || A <- ToBuild],
  88. code:add_pathsa(CodePaths),
  89. %% Store plugin code paths so we can remove them when compiling project apps
  90. State4 = rebar_state:update_code_paths(State3, all_plugin_deps, CodePaths++NewCodePaths),
  91. {plugin_providers(Plugin), State4}
  92. catch
  93. C:T ->
  94. ?DEBUG("~p ~p ~p", [C, T, erlang:get_stacktrace()]),
  95. ?WARN("Plugin ~p not available. It will not be used.", [Plugin]),
  96. {[], State}
  97. end.
  98. build_plugin(AppInfo, Apps, State) ->
  99. Providers = rebar_state:providers(State),
  100. %Providers1 = rebar_state:providers(rebar_app_info:state(AppInfo)),
  101. %rebar_app_info:state_or_new(State, AppInfo)
  102. S = rebar_state:all_deps(State, Apps),
  103. S1 = rebar_state:set(S, deps_dir, ?DEFAULT_PLUGINS_DIR),
  104. rebar_prv_compile:compile(S1, Providers, AppInfo).
  105. plugin_providers({Plugin, _, _, _}) when is_atom(Plugin) ->
  106. validate_plugin(Plugin);
  107. plugin_providers({Plugin, _, _}) when is_atom(Plugin) ->
  108. validate_plugin(Plugin);
  109. plugin_providers({Plugin, _}) when is_atom(Plugin) ->
  110. validate_plugin(Plugin);
  111. plugin_providers(Plugin) when is_atom(Plugin) ->
  112. validate_plugin(Plugin).
  113. validate_plugin(Plugin) ->
  114. _ = application:load(Plugin),
  115. case application:get_env(Plugin, providers) of
  116. {ok, Providers} ->
  117. Providers;
  118. undefined ->
  119. Exports = Plugin:module_info(exports),
  120. case lists:member({init,1}, Exports) of
  121. false ->
  122. ?WARN("Plugin ~p does not export init/1. It will not be used.", [Plugin]),
  123. [];
  124. true ->
  125. [Plugin]
  126. end
  127. end.