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.

243 lines
7.8 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. -module(rebar_state).
  2. -export([new/0, new/1, new/2, new/3,
  3. get/2, get/3, set/3,
  4. opts/1,
  5. default/1, default/2,
  6. lock/1, lock/2,
  7. current_profile/1,
  8. current_profile/2,
  9. command_args/1, command_args/2,
  10. command_parsed_args/1, command_parsed_args/2,
  11. apply_profile/2,
  12. dir/1, dir/2,
  13. create_logic_providers/2,
  14. project_apps/1, project_apps/2,
  15. all_deps/1, all_deps/2,
  16. deps_names/1,
  17. prepend_hook/3, append_hook/3, hooks/2,
  18. providers/1, providers/2, add_provider/2]).
  19. -include("rebar.hrl").
  20. -record(state_t, {dir :: file:name(),
  21. opts = dict:new() :: rebar_dict(),
  22. default = dict:new() :: rebar_dict(),
  23. lock = [],
  24. current_profile = default :: atom(),
  25. command_args = [],
  26. command_parsed_args = [],
  27. project_apps = [] :: [rebar_app_into:t()],
  28. all_deps = [] :: [rebar_app_into:t()],
  29. providers = []}).
  30. -export_type([t/0]).
  31. -type t() :: record(state_t).
  32. -spec new() -> t().
  33. new() ->
  34. #state_t{dir = rebar_utils:get_cwd()}.
  35. -spec new(list()) -> t().
  36. new(Config) when is_list(Config) ->
  37. Opts = dict:from_list(Config),
  38. #state_t { dir = rebar_utils:get_cwd(),
  39. default = Opts,
  40. opts = Opts }.
  41. -spec new(t() | atom(), list()) -> t().
  42. new(Profile, Config) when is_atom(Profile)
  43. , is_list(Config) ->
  44. Opts = dict:from_list(Config),
  45. #state_t { dir = rebar_utils:get_cwd(),
  46. current_profile = Profile,
  47. default = Opts,
  48. opts = Opts };
  49. new(ParentState=#state_t{}, Config) ->
  50. %% Load terms from rebar.config, if it exists
  51. Dir = rebar_utils:get_cwd(),
  52. new(ParentState, Config, Dir).
  53. -spec new(t(), list(), file:name()) -> t().
  54. new(ParentState, Config, Dir) ->
  55. Opts = ParentState#state_t.opts,
  56. LocalOpts = case rebar_config:consult_file(?LOCK_FILE) of
  57. [D] ->
  58. dict:from_list([{locks, D} | Config]);
  59. _ ->
  60. dict:from_list(Config)
  61. end,
  62. NewOpts = dict:merge(fun(_Key, Value1, _Value2) ->
  63. Value1
  64. end, LocalOpts, Opts),
  65. ProviderModules = [],
  66. create_logic_providers(ProviderModules
  67. ,ParentState#state_t{dir=Dir
  68. ,opts=NewOpts
  69. ,default=NewOpts}).
  70. get(State, Key) ->
  71. {ok, Value} = dict:find(Key, State#state_t.opts),
  72. Value.
  73. get(State, Key, Default) ->
  74. case dict:find(Key, State#state_t.opts) of
  75. {ok, Value} ->
  76. Value;
  77. error ->
  78. Default
  79. end.
  80. -spec set(t(), any(), any()) -> t().
  81. set(State=#state_t{opts=Opts}, Key, Value) ->
  82. State#state_t{ opts = dict:store(Key, Value, Opts) }.
  83. default(#state_t{default=Opts}) ->
  84. Opts.
  85. default(State, Opts) ->
  86. State#state_t{default=Opts}.
  87. opts(#state_t{opts=Opts}) ->
  88. Opts.
  89. current_profile(#state_t{current_profile=Profile}) ->
  90. Profile.
  91. current_profile(State, Profile) ->
  92. apply_profile(State#state_t{current_profile=Profile}, Profile).
  93. lock(#state_t{lock=Lock}) ->
  94. Lock.
  95. lock(State=#state_t{lock=Lock}, App) ->
  96. State#state_t{lock=[App | Lock]}.
  97. command_args(#state_t{command_args=CmdArgs}) ->
  98. CmdArgs.
  99. command_args(State, CmdArgs) ->
  100. State#state_t{command_args=CmdArgs}.
  101. command_parsed_args(#state_t{command_parsed_args=CmdArgs}) ->
  102. CmdArgs.
  103. command_parsed_args(State, CmdArgs) ->
  104. State#state_t{command_parsed_args=CmdArgs}.
  105. %% Only apply profiles to the default profile
  106. apply_profile(State=#state_t{default=Opts}, Profile) ->
  107. ConfigProfiles = rebar_state:get(State, profiles, []),
  108. Deps = rebar_state:get(State, deps, []),
  109. Opts1 = dict:store({deps, default}, Deps, dict:erase(deps, Opts)),
  110. ProfileOpts = dict:from_list(proplists:get_value(Profile, ConfigProfiles, [])),
  111. State#state_t{opts=merge_opts(Profile, ProfileOpts, Opts1)}.
  112. merge_opts(Profile, Opts1, Opts2) ->
  113. dict:fold(fun(deps, Value, OptsAcc) ->
  114. dict:store({deps, Profile}, Value, OptsAcc);
  115. (Key, Value, OptsAcc) ->
  116. case dict:fetch(Key, Opts2) of
  117. OldValue when is_list(OldValue) ->
  118. case io_lib:printable_list(Value) of
  119. true ->
  120. dict:store(Key, Value, OptsAcc);
  121. false ->
  122. dict:store(Key, lists:keymerge(1, lists:keysort(1, OldValue), lists:keysort(1, Value)), OptsAcc)
  123. end;
  124. _ ->
  125. dict:store(Key, Value, OptsAcc)
  126. end
  127. end, Opts2, Opts1).
  128. dir(#state_t{dir=Dir}) ->
  129. Dir.
  130. dir(State=#state_t{}, Dir) ->
  131. State#state_t{dir=filename:absname(Dir)}.
  132. deps_names(Deps) when is_list(Deps) ->
  133. lists:map(fun(Dep) when is_tuple(Dep) ->
  134. ec_cnv:to_binary(element(1, Dep));
  135. (Dep) when is_atom(Dep) ->
  136. ec_cnv:to_binary(Dep)
  137. end, Deps);
  138. deps_names(State) ->
  139. Deps = rebar_state:get(State, deps, []),
  140. deps_names(Deps).
  141. project_apps(#state_t{project_apps=Apps}) ->
  142. Apps.
  143. project_apps(State=#state_t{}, NewApps) when is_list(NewApps) ->
  144. State#state_t{project_apps=NewApps};
  145. project_apps(State=#state_t{project_apps=Apps}, App) ->
  146. State#state_t{project_apps=lists:keystore(rebar_app_info:name(App), 2, Apps, App)}.
  147. all_deps(#state_t{all_deps=Apps}) ->
  148. Apps.
  149. all_deps(State=#state_t{}, NewApps) ->
  150. State#state_t{all_deps=NewApps}.
  151. providers(#state_t{providers=Providers}) ->
  152. Providers.
  153. providers(State, NewProviders) ->
  154. State#state_t{providers=NewProviders}.
  155. -spec add_provider(t(), providers:t()) -> t().
  156. add_provider(State=#state_t{providers=Providers}, Provider) ->
  157. State#state_t{providers=[Provider | Providers]}.
  158. create_logic_providers(ProviderModules, State0) ->
  159. lists:foldl(fun(ProviderMod, Acc) ->
  160. case providers:new(ProviderMod, Acc) of
  161. {error, Reason} ->
  162. ?ERROR(Reason++"~n", []),
  163. Acc;
  164. {ok, State1} ->
  165. State1
  166. end
  167. end, State0, ProviderModules).
  168. prepend_hook(State=#state_t{providers=Providers}, Target, Hook) ->
  169. State#state_t{providers=add_hook(pre, Providers, Target, Hook)}.
  170. append_hook(State=#state_t{providers=Providers}, Target, Hook) ->
  171. State#state_t{providers=add_hook(post, Providers, Target, Hook)}.
  172. -spec hooks(t(), atom()) -> {[providers:t()], [providers:t()]}.
  173. hooks(_State=#state_t{providers=Providers}, Target) ->
  174. Provider = providers:get_provider(Target, Providers),
  175. providers:hooks(Provider).
  176. %% ===================================================================
  177. %% Internal functions
  178. %% ===================================================================
  179. add_hook(Which, Providers, Target, Hook) ->
  180. Provider = providers:get_provider(Target, Providers),
  181. Hooks = providers:hooks(Provider),
  182. NewHooks = add_hook(Which, Hooks, Hook),
  183. NewProvider = providers:hooks(Provider, NewHooks),
  184. [NewProvider | lists:delete(Provider, Providers)].
  185. add_hook(pre, {PreHooks, PostHooks}, Hook) ->
  186. {[Hook | PreHooks], PostHooks};
  187. add_hook(post, {PreHooks, PostHooks}, Hook) ->
  188. {PreHooks, [Hook | PostHooks]}.