Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

355 rader
12 KiB

10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
  1. -module(rebar_state).
  2. -export([new/0, new/1, new/2, new/3,
  3. get/2, get/3, set/3,
  4. opts/1, opts/2,
  5. default/1, default/2,
  6. escript_path/1, escript_path/2,
  7. lock/1, lock/2,
  8. current_profiles/1,
  9. command_args/1, command_args/2,
  10. command_parsed_args/1, command_parsed_args/2,
  11. add_to_profile/3, apply_profiles/2,
  12. dir/1, dir/2,
  13. create_logic_providers/2,
  14. project_apps/1, project_apps/2,
  15. deps_to_build/1, deps_to_build/2,
  16. all_deps/1, all_deps/2,
  17. namespace/1, namespace/2,
  18. deps_names/1,
  19. overrides/1, overrides/2,
  20. apply_overrides/2,
  21. packages/1, packages/2,
  22. resources/1, resources/2, add_resource/2,
  23. providers/1, providers/2, add_provider/2]).
  24. -include("rebar.hrl").
  25. -record(state_t, {dir :: file:name(),
  26. opts = dict:new() :: rebar_dict(),
  27. default = dict:new() :: rebar_dict(),
  28. escript_path :: undefined | file:filename_all(),
  29. lock = [],
  30. current_profiles = [default] :: [atom()],
  31. namespace = undefined :: atom(),
  32. command_args = [],
  33. command_parsed_args = [],
  34. project_apps = [] :: [rebar_app_info:t()],
  35. deps_to_build = [] :: [rebar_app_info:t()],
  36. all_deps = [] :: [rebar_app_info:t()],
  37. packages = undefined :: {rebar_dict(), rebar_digraph()} | undefined,
  38. overrides = [],
  39. resources = [],
  40. providers = []}).
  41. -export_type([t/0]).
  42. -type t() :: record(state_t).
  43. -spec new() -> t().
  44. new() ->
  45. #state_t{dir = rebar_dir:get_cwd()}.
  46. -spec new(list()) -> t().
  47. new(Config) when is_list(Config) ->
  48. Deps = proplists:get_value(deps, Config, []),
  49. Opts = dict:from_list([{{deps, default}, Deps} | Config]),
  50. #state_t { dir = rebar_dir:get_cwd(),
  51. default = Opts,
  52. opts = Opts }.
  53. -spec new(t() | atom(), list()) -> t().
  54. new(Profile, Config) when is_atom(Profile)
  55. , is_list(Config) ->
  56. Deps = proplists:get_value(deps, Config, []),
  57. Opts = dict:from_list([{{deps, default}, Deps} | Config]),
  58. #state_t { dir = rebar_dir:get_cwd(),
  59. current_profiles = [Profile],
  60. default = Opts,
  61. opts = Opts };
  62. new(ParentState=#state_t{}, Config) ->
  63. %% Load terms from rebar.config, if it exists
  64. Dir = rebar_dir:get_cwd(),
  65. new(ParentState, Config, Dir).
  66. -spec new(t(), list(), file:name()) -> t().
  67. new(ParentState, Config, Dir) ->
  68. Opts = ParentState#state_t.opts,
  69. LocalOpts = case rebar_config:consult_file(filename:join(Dir, ?LOCK_FILE)) of
  70. [D] ->
  71. %% We want the top level deps only from the lock file.
  72. %% This ensures deterministic overrides for configs.
  73. Deps = [X || X <- D, element(3, X) =:= 0],
  74. dict:from_list([{{locks, default}, D}, {{deps, default}, Deps} | Config]);
  75. _ ->
  76. D = proplists:get_value(deps, Config, []),
  77. dict:from_list([{{deps, default}, D} | Config])
  78. end,
  79. NewOpts = merge_opts(LocalOpts, Opts),
  80. ParentState#state_t{dir=Dir
  81. ,opts=NewOpts
  82. ,default=NewOpts}.
  83. get(State, Key) ->
  84. {ok, Value} = dict:find(Key, State#state_t.opts),
  85. Value.
  86. get(State, Key, Default) ->
  87. case dict:find(Key, State#state_t.opts) of
  88. {ok, Value} ->
  89. Value;
  90. error ->
  91. Default
  92. end.
  93. -spec set(t(), any(), any()) -> t().
  94. set(State=#state_t{opts=Opts}, Key, Value) ->
  95. State#state_t{ opts = dict:store(Key, Value, Opts) }.
  96. default(#state_t{default=Opts}) ->
  97. Opts.
  98. default(State, Opts) ->
  99. State#state_t{default=Opts}.
  100. opts(#state_t{opts=Opts}) ->
  101. Opts.
  102. opts(State, Opts) ->
  103. State#state_t{opts=Opts}.
  104. current_profiles(#state_t{current_profiles=Profiles}) ->
  105. Profiles.
  106. lock(#state_t{lock=Lock}) ->
  107. Lock.
  108. lock(State=#state_t{}, Apps) when is_list(Apps) ->
  109. State#state_t{lock=Apps};
  110. lock(State=#state_t{lock=Lock}, App) ->
  111. State#state_t{lock=[App | Lock]}.
  112. escript_path(#state_t{escript_path=EscriptPath}) ->
  113. EscriptPath.
  114. escript_path(State, EscriptPath) ->
  115. State#state_t{escript_path=EscriptPath}.
  116. command_args(#state_t{command_args=CmdArgs}) ->
  117. CmdArgs.
  118. command_args(State, CmdArgs) ->
  119. State#state_t{command_args=CmdArgs}.
  120. command_parsed_args(#state_t{command_parsed_args=CmdArgs}) ->
  121. CmdArgs.
  122. command_parsed_args(State, CmdArgs) ->
  123. State#state_t{command_parsed_args=CmdArgs}.
  124. apply_overrides(State=#state_t{overrides=Overrides}, AppName) ->
  125. Name = binary_to_atom(AppName, utf8),
  126. %% Inefficient. We want the order we get here though.
  127. State1 = lists:foldl(fun({override, O}, StateAcc) ->
  128. lists:foldl(fun({Key, Value}, StateAcc1) ->
  129. rebar_state:set(StateAcc1, Key, Value)
  130. end, StateAcc, O);
  131. (_, StateAcc) ->
  132. StateAcc
  133. end, State, Overrides),
  134. State2 = lists:foldl(fun({override, N, O}, StateAcc) when N =:= Name ->
  135. lists:foldl(fun({Key, Value}, StateAcc1) ->
  136. rebar_state:set(StateAcc1, Key, Value)
  137. end, StateAcc, O);
  138. (_, StateAcc) ->
  139. StateAcc
  140. end, State1, Overrides),
  141. lists:foldl(fun({add, N, O}, StateAcc) when N =:= Name ->
  142. lists:foldl(fun({Key, Value}, StateAcc1) ->
  143. OldValue = rebar_state:get(StateAcc1, Key, []),
  144. rebar_state:set(StateAcc1, Key, Value++OldValue)
  145. end, StateAcc, O);
  146. (_, StateAcc) ->
  147. StateAcc
  148. end, State2, Overrides).
  149. add_to_profile(State, Profile, KVs) when is_atom(Profile), is_list(KVs) ->
  150. Profiles = rebar_state:get(State, profiles, []),
  151. ProfileOpts = dict:from_list(proplists:get_value(Profile, Profiles, [])),
  152. NewOpts = merge_opts(Profile, dict:from_list(KVs), ProfileOpts),
  153. NewProfiles = [{Profile, dict:to_list(NewOpts)}|lists:keydelete(Profile, 1, Profiles)],
  154. rebar_state:set(State, profiles, NewProfiles).
  155. apply_profiles(State, Profile) when not is_list(Profile) ->
  156. apply_profiles(State, [Profile]);
  157. apply_profiles(State, [default]) ->
  158. State;
  159. apply_profiles(State=#state_t{opts=Opts, current_profiles=CurrentProfiles}, Profiles) ->
  160. ConfigProfiles = rebar_state:get(State, profiles, []),
  161. {Profiles1, NewOpts} =
  162. lists:foldl(fun(default, {ProfilesAcc, OptsAcc}) ->
  163. {ProfilesAcc, OptsAcc};
  164. (Profile, {ProfilesAcc, OptsAcc}) ->
  165. ProfileOpts = dict:from_list(proplists:get_value(Profile, ConfigProfiles, [])),
  166. {[Profile]++ProfilesAcc, merge_opts(Profile, ProfileOpts, OptsAcc)}
  167. end, {[], Opts}, Profiles),
  168. State#state_t{current_profiles=CurrentProfiles++Profiles1, opts=NewOpts}.
  169. merge_opts(Profile, NewOpts, OldOpts) ->
  170. Opts = merge_opts(NewOpts, OldOpts),
  171. case dict:find(deps, NewOpts) of
  172. {ok, Value} ->
  173. dict:store({deps, Profile}, Value, Opts);
  174. error ->
  175. Opts
  176. end.
  177. merge_opts(NewOpts, OldOpts) ->
  178. dict:merge(fun(deps, NewValue, _OldValue) ->
  179. NewValue;
  180. ({deps, _}, NewValue, _OldValue) ->
  181. NewValue;
  182. (profiles, NewValue, OldValue) ->
  183. dict:to_list(merge_opts(dict:from_list(NewValue), dict:from_list(OldValue)));
  184. (_Key, NewValue, OldValue) when is_list(NewValue) ->
  185. case io_lib:printable_list(NewValue) of
  186. true when NewValue =:= [] ->
  187. case io_lib:printable_list(OldValue) of
  188. true ->
  189. NewValue;
  190. false ->
  191. OldValue
  192. end;
  193. true ->
  194. NewValue;
  195. false ->
  196. rebar_utils:tup_umerge(rebar_utils:tup_sort(NewValue)
  197. ,rebar_utils:tup_sort(OldValue))
  198. end;
  199. (_Key, NewValue, _OldValue) ->
  200. NewValue
  201. end, NewOpts, OldOpts).
  202. dir(#state_t{dir=Dir}) ->
  203. Dir.
  204. dir(State=#state_t{}, Dir) ->
  205. State#state_t{dir=filename:absname(Dir)}.
  206. deps_names(Deps) when is_list(Deps) ->
  207. lists:map(fun(Dep) when is_tuple(Dep) ->
  208. ec_cnv:to_binary(element(1, Dep));
  209. (Dep) when is_atom(Dep) ->
  210. ec_cnv:to_binary(Dep)
  211. end, Deps);
  212. deps_names(State) ->
  213. Deps = rebar_state:get(State, deps, []),
  214. deps_names(Deps).
  215. overrides(#state_t{overrides=Overrides}) ->
  216. Overrides.
  217. overrides(State=#state_t{}, Overrides) ->
  218. State#state_t{overrides=Overrides}.
  219. project_apps(#state_t{project_apps=Apps}) ->
  220. Apps.
  221. project_apps(State=#state_t{}, NewApps) when is_list(NewApps) ->
  222. State#state_t{project_apps=NewApps};
  223. project_apps(State=#state_t{project_apps=Apps}, App) ->
  224. State#state_t{project_apps=lists:keystore(rebar_app_info:name(App), 2, Apps, App)}.
  225. deps_to_build(#state_t{deps_to_build=Apps}) ->
  226. Apps.
  227. deps_to_build(State=#state_t{deps_to_build=Apps}, NewApps) when is_list(NewApps) ->
  228. State#state_t{deps_to_build=Apps++NewApps};
  229. deps_to_build(State=#state_t{deps_to_build=Apps}, App) ->
  230. State#state_t{deps_to_build=lists:keystore(rebar_app_info:name(App), 2, Apps, App)}.
  231. all_deps(#state_t{all_deps=Apps}) ->
  232. Apps.
  233. all_deps(State=#state_t{}, NewApps) ->
  234. State#state_t{all_deps=NewApps}.
  235. namespace(#state_t{namespace=Namespace}) ->
  236. Namespace.
  237. namespace(State=#state_t{}, Namespace) ->
  238. State#state_t{namespace=Namespace}.
  239. packages(State=#state_t{packages=undefined}) ->
  240. rebar_packages:get_packages(State);
  241. packages(#state_t{packages=Packages}) ->
  242. Packages.
  243. packages(State, Packages) ->
  244. State#state_t{packages=Packages}.
  245. -spec resources(t()) -> rebar_resource:resource().
  246. resources(#state_t{resources=Resources}) ->
  247. Resources.
  248. -spec resources(t(), [rebar_resource:resource()]) -> t().
  249. resources(State, NewResources) ->
  250. State#state_t{resources=NewResources}.
  251. -spec add_resource(t(), rebar_resource:resource()) -> t().
  252. add_resource(State=#state_t{resources=Resources}, Resource) ->
  253. State#state_t{resources=[Resource | Resources]}.
  254. providers(#state_t{providers=Providers}) ->
  255. Providers.
  256. providers(State, NewProviders) ->
  257. State#state_t{providers=NewProviders}.
  258. -spec add_provider(t(), providers:t()) -> t().
  259. add_provider(State=#state_t{providers=Providers}, Provider) ->
  260. State#state_t{providers=[Provider | Providers]}.
  261. create_logic_providers(ProviderModules, State0) ->
  262. try
  263. lists:foldl(fun(ProviderMod, StateAcc) ->
  264. case providers:new(ProviderMod, StateAcc) of
  265. {error, Reason} ->
  266. ?ERROR(Reason++"~n", []),
  267. StateAcc;
  268. {ok, StateAcc1} ->
  269. StateAcc1
  270. end
  271. end, State0, ProviderModules)
  272. catch
  273. C:T ->
  274. ?DEBUG("~p: ~p ~p", [C, T, erlang:get_stacktrace()]),
  275. throw({error, "Failed creating providers. Run with DEBUG=1 for stacktrace."})
  276. end.
  277. %% ===================================================================
  278. %% Internal functions
  279. %% ===================================================================