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.

154 line
6.7 KiB

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. PreBuiltPaths = [rebar_app_info:ebin_dir(A) || A <- Apps] -- ToBuild,
  82. code:add_pathsa(PreBuiltPaths),
  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. AllPluginEbins = filelib:wildcard(filename:join([rebar_dir:plugins_dir(State), "*", "ebin"])),
  89. CodePaths = PreBuiltPaths++(AllPluginEbins--ToBuild),
  90. code:add_pathsa(NewCodePaths++CodePaths),
  91. %% Store plugin code paths so we can remove them when compiling project apps
  92. State4 = rebar_state:update_code_paths(State3, all_plugin_deps, PreBuiltPaths++NewCodePaths),
  93. {plugin_providers(Plugin), State4}
  94. catch
  95. ?WITH_STACKTRACE(C,T,S)
  96. ?DEBUG("~p ~p ~p", [C, T, S]),
  97. ?WARN("Plugin ~p not available. It will not be used.", [Plugin]),
  98. {[], State}
  99. end.
  100. build_plugin(AppInfo, Apps, State) ->
  101. Providers = rebar_state:providers(State),
  102. %Providers1 = rebar_state:providers(rebar_app_info:state(AppInfo)),
  103. %rebar_app_info:state_or_new(State, AppInfo)
  104. S = rebar_state:all_deps(State, Apps),
  105. S1 = rebar_state:set(S, deps_dir, ?DEFAULT_PLUGINS_DIR),
  106. rebar_prv_compile:compile(S1, Providers, AppInfo).
  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. plugin_providers(Plugin) when is_atom(Plugin) ->
  114. validate_plugin(Plugin).
  115. validate_plugin(Plugin) ->
  116. _ = application:load(Plugin),
  117. case application:get_env(Plugin, providers) of
  118. {ok, Providers} ->
  119. Providers;
  120. undefined ->
  121. Exports = Plugin:module_info(exports),
  122. case lists:member({init,1}, Exports) of
  123. false ->
  124. ?WARN("Plugin ~p does not export init/1. It will not be used.", [Plugin]),
  125. [];
  126. true ->
  127. [Plugin]
  128. end
  129. end.