您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

355 行
12 KiB

  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. %% ===================================================================