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.

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