25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

445 lines
18 KiB

support for hex v2, multiple repository fetching, private organizations (#1884) * update to hex_core for hex-v2 repo support (#1865) * update to hex_core for hex-v2 repo support This patch adds only single repo hex-v2 support through hex_core. Packages no longer filtered out by buildtool metadata and the package index is updated per-package instead of fetched as one large ets dump. * tell travis to also build hex_core branch * support list of repos for hex packages (#1866) * support list of repos for hex packages repos are defined under the hex key in rebar configs. They can be defined at the top level of a project or globally, but not in profiles and the repos configured in dependencies are also ignored. Searching for packages involves first checking for a match in the local repo index cache, in the order repos are defined. If not found each repo is checked through the hex api for any known versions of the package and the first repo with a version that fits the constraint is used. * add {repos, replace, []} for overriding the global & default repos * add hex auth handling for repos (#1874) auth token are kept in a hex.config file that is modified by the rebar3 hex plugin. Repo names that have a : separating a parent and child are considered organizations. The parent repo's auth will be included with the child. So an organization named hexpm:rebar3_test will include any hexpm auth tokens found in the rebar3_test organization's configuration. * move packages to top level of of hexpm cache dir (#1876) * move packages to top level of of hexpm cache dir * append organization name to parent's repo_url when parsing repos * only eval config scripts and apply overrides once per app (#1879) * only eval config scripts and apply overrides once per app * move new resource behaviour to rebar_resource_v2 and keep v1 * cleanup use of rebar_resource module and unused functions * cleanup error messages and unused code * when discovering apps support mix packages as unbuilt apps (#1882) * use hex_core tarball unpacking support in pkg resource (#1883) * use hex_core tarball unpacking support in pkg resource * ignore etag if package doesn't exist and delete if checksum fails * add back tests for bad package checksums * improve bad registry checksum error message
6 년 전
support for hex v2, multiple repository fetching, private organizations (#1884) * update to hex_core for hex-v2 repo support (#1865) * update to hex_core for hex-v2 repo support This patch adds only single repo hex-v2 support through hex_core. Packages no longer filtered out by buildtool metadata and the package index is updated per-package instead of fetched as one large ets dump. * tell travis to also build hex_core branch * support list of repos for hex packages (#1866) * support list of repos for hex packages repos are defined under the hex key in rebar configs. They can be defined at the top level of a project or globally, but not in profiles and the repos configured in dependencies are also ignored. Searching for packages involves first checking for a match in the local repo index cache, in the order repos are defined. If not found each repo is checked through the hex api for any known versions of the package and the first repo with a version that fits the constraint is used. * add {repos, replace, []} for overriding the global & default repos * add hex auth handling for repos (#1874) auth token are kept in a hex.config file that is modified by the rebar3 hex plugin. Repo names that have a : separating a parent and child are considered organizations. The parent repo's auth will be included with the child. So an organization named hexpm:rebar3_test will include any hexpm auth tokens found in the rebar3_test organization's configuration. * move packages to top level of of hexpm cache dir (#1876) * move packages to top level of of hexpm cache dir * append organization name to parent's repo_url when parsing repos * only eval config scripts and apply overrides once per app (#1879) * only eval config scripts and apply overrides once per app * move new resource behaviour to rebar_resource_v2 and keep v1 * cleanup use of rebar_resource module and unused functions * cleanup error messages and unused code * when discovering apps support mix packages as unbuilt apps (#1882) * use hex_core tarball unpacking support in pkg resource (#1883) * use hex_core tarball unpacking support in pkg resource * ignore etag if package doesn't exist and delete if checksum fails * add back tests for bad package checksums * improve bad registry checksum error message
6 년 전
support for hex v2, multiple repository fetching, private organizations (#1884) * update to hex_core for hex-v2 repo support (#1865) * update to hex_core for hex-v2 repo support This patch adds only single repo hex-v2 support through hex_core. Packages no longer filtered out by buildtool metadata and the package index is updated per-package instead of fetched as one large ets dump. * tell travis to also build hex_core branch * support list of repos for hex packages (#1866) * support list of repos for hex packages repos are defined under the hex key in rebar configs. They can be defined at the top level of a project or globally, but not in profiles and the repos configured in dependencies are also ignored. Searching for packages involves first checking for a match in the local repo index cache, in the order repos are defined. If not found each repo is checked through the hex api for any known versions of the package and the first repo with a version that fits the constraint is used. * add {repos, replace, []} for overriding the global & default repos * add hex auth handling for repos (#1874) auth token are kept in a hex.config file that is modified by the rebar3 hex plugin. Repo names that have a : separating a parent and child are considered organizations. The parent repo's auth will be included with the child. So an organization named hexpm:rebar3_test will include any hexpm auth tokens found in the rebar3_test organization's configuration. * move packages to top level of of hexpm cache dir (#1876) * move packages to top level of of hexpm cache dir * append organization name to parent's repo_url when parsing repos * only eval config scripts and apply overrides once per app (#1879) * only eval config scripts and apply overrides once per app * move new resource behaviour to rebar_resource_v2 and keep v1 * cleanup use of rebar_resource module and unused functions * cleanup error messages and unused code * when discovering apps support mix packages as unbuilt apps (#1882) * use hex_core tarball unpacking support in pkg resource (#1883) * use hex_core tarball unpacking support in pkg resource * ignore etag if package doesn't exist and delete if checksum fails * add back tests for bad package checksums * improve bad registry checksum error message
6 년 전
support for hex v2, multiple repository fetching, private organizations (#1884) * update to hex_core for hex-v2 repo support (#1865) * update to hex_core for hex-v2 repo support This patch adds only single repo hex-v2 support through hex_core. Packages no longer filtered out by buildtool metadata and the package index is updated per-package instead of fetched as one large ets dump. * tell travis to also build hex_core branch * support list of repos for hex packages (#1866) * support list of repos for hex packages repos are defined under the hex key in rebar configs. They can be defined at the top level of a project or globally, but not in profiles and the repos configured in dependencies are also ignored. Searching for packages involves first checking for a match in the local repo index cache, in the order repos are defined. If not found each repo is checked through the hex api for any known versions of the package and the first repo with a version that fits the constraint is used. * add {repos, replace, []} for overriding the global & default repos * add hex auth handling for repos (#1874) auth token are kept in a hex.config file that is modified by the rebar3 hex plugin. Repo names that have a : separating a parent and child are considered organizations. The parent repo's auth will be included with the child. So an organization named hexpm:rebar3_test will include any hexpm auth tokens found in the rebar3_test organization's configuration. * move packages to top level of of hexpm cache dir (#1876) * move packages to top level of of hexpm cache dir * append organization name to parent's repo_url when parsing repos * only eval config scripts and apply overrides once per app (#1879) * only eval config scripts and apply overrides once per app * move new resource behaviour to rebar_resource_v2 and keep v1 * cleanup use of rebar_resource module and unused functions * cleanup error messages and unused code * when discovering apps support mix packages as unbuilt apps (#1882) * use hex_core tarball unpacking support in pkg resource (#1883) * use hex_core tarball unpacking support in pkg resource * ignore etag if package doesn't exist and delete if checksum fails * add back tests for bad package checksums * improve bad registry checksum error message
6 년 전
support for hex v2, multiple repository fetching, private organizations (#1884) * update to hex_core for hex-v2 repo support (#1865) * update to hex_core for hex-v2 repo support This patch adds only single repo hex-v2 support through hex_core. Packages no longer filtered out by buildtool metadata and the package index is updated per-package instead of fetched as one large ets dump. * tell travis to also build hex_core branch * support list of repos for hex packages (#1866) * support list of repos for hex packages repos are defined under the hex key in rebar configs. They can be defined at the top level of a project or globally, but not in profiles and the repos configured in dependencies are also ignored. Searching for packages involves first checking for a match in the local repo index cache, in the order repos are defined. If not found each repo is checked through the hex api for any known versions of the package and the first repo with a version that fits the constraint is used. * add {repos, replace, []} for overriding the global & default repos * add hex auth handling for repos (#1874) auth token are kept in a hex.config file that is modified by the rebar3 hex plugin. Repo names that have a : separating a parent and child are considered organizations. The parent repo's auth will be included with the child. So an organization named hexpm:rebar3_test will include any hexpm auth tokens found in the rebar3_test organization's configuration. * move packages to top level of of hexpm cache dir (#1876) * move packages to top level of of hexpm cache dir * append organization name to parent's repo_url when parsing repos * only eval config scripts and apply overrides once per app (#1879) * only eval config scripts and apply overrides once per app * move new resource behaviour to rebar_resource_v2 and keep v1 * cleanup use of rebar_resource module and unused functions * cleanup error messages and unused code * when discovering apps support mix packages as unbuilt apps (#1882) * use hex_core tarball unpacking support in pkg resource (#1883) * use hex_core tarball unpacking support in pkg resource * ignore etag if package doesn't exist and delete if checksum fails * add back tests for bad package checksums * improve bad registry checksum error message
6 년 전
support for hex v2, multiple repository fetching, private organizations (#1884) * update to hex_core for hex-v2 repo support (#1865) * update to hex_core for hex-v2 repo support This patch adds only single repo hex-v2 support through hex_core. Packages no longer filtered out by buildtool metadata and the package index is updated per-package instead of fetched as one large ets dump. * tell travis to also build hex_core branch * support list of repos for hex packages (#1866) * support list of repos for hex packages repos are defined under the hex key in rebar configs. They can be defined at the top level of a project or globally, but not in profiles and the repos configured in dependencies are also ignored. Searching for packages involves first checking for a match in the local repo index cache, in the order repos are defined. If not found each repo is checked through the hex api for any known versions of the package and the first repo with a version that fits the constraint is used. * add {repos, replace, []} for overriding the global & default repos * add hex auth handling for repos (#1874) auth token are kept in a hex.config file that is modified by the rebar3 hex plugin. Repo names that have a : separating a parent and child are considered organizations. The parent repo's auth will be included with the child. So an organization named hexpm:rebar3_test will include any hexpm auth tokens found in the rebar3_test organization's configuration. * move packages to top level of of hexpm cache dir (#1876) * move packages to top level of of hexpm cache dir * append organization name to parent's repo_url when parsing repos * only eval config scripts and apply overrides once per app (#1879) * only eval config scripts and apply overrides once per app * move new resource behaviour to rebar_resource_v2 and keep v1 * cleanup use of rebar_resource module and unused functions * cleanup error messages and unused code * when discovering apps support mix packages as unbuilt apps (#1882) * use hex_core tarball unpacking support in pkg resource (#1883) * use hex_core tarball unpacking support in pkg resource * ignore etag if package doesn't exist and delete if checksum fails * add back tests for bad package checksums * improve bad registry checksum error message
6 년 전
  1. %% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
  2. %% ex: ts=4 sw=4 et
  3. %% -------------------------------------------------------------------
  4. %%
  5. %% rebar: Erlang Build Tools
  6. %%
  7. %% Copyright (c) 2009 Dave Smith (dizzyd@dizzyd.com)
  8. %%
  9. %% Permission is hereby granted, free of charge, to any person obtaining a copy
  10. %% of this software and associated documentation files (the "Software"), to deal
  11. %% in the Software without restriction, including without limitation the rights
  12. %% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. %% copies of the Software, and to permit persons to whom the Software is
  14. %% furnished to do so, subject to the following conditions:
  15. %%
  16. %% The above copyright notice and this permission notice shall be included in
  17. %% all copies or substantial portions of the Software.
  18. %%
  19. %% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. %% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. %% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22. %% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. %% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24. %% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25. %% THE SOFTWARE.
  26. %% -------------------------------------------------------------------
  27. %%
  28. %% @doc Main module for rebar3. Supports two interfaces; one for escripts,
  29. %% and one for usage as a library (although rebar3 makes a lot of
  30. %% assumptions about its environment, making it a bit tricky to use as
  31. %% a lib).
  32. %%
  33. %% This module's job is mostly to set up the root environment for rebar3
  34. %% and handle global options (mostly all from the ENV) and make them
  35. %% accessible to the rest of the run.
  36. %% @end
  37. -module(rebar3).
  38. -export([main/0,
  39. main/1,
  40. run/1,
  41. run/2,
  42. global_option_spec_list/0,
  43. init_config/0,
  44. set_options/2,
  45. parse_args/1,
  46. version/0,
  47. log_level/0]).
  48. -include("rebar.hrl").
  49. %% ====================================================================
  50. %% Public API
  51. %% ====================================================================
  52. %% @doc For running with:
  53. %% erl +sbtu +A1 -noinput -mode minimal -boot start_clean -s rebar3 main -extra "$@"
  54. -spec main() -> no_return().
  55. main() ->
  56. List = init:get_plain_arguments(),
  57. main(List).
  58. %% @doc escript Entry point
  59. -spec main(list()) -> no_return().
  60. main(Args) ->
  61. try run(Args) of
  62. {ok, _State} ->
  63. erlang:halt(0);
  64. Error ->
  65. handle_error(Error, [])
  66. catch
  67. ?WITH_STACKTRACE(_,Error,Stacktrace)
  68. handle_error(Error, Stacktrace)
  69. end.
  70. %% @doc Erlang-API entry point
  71. -spec run(rebar_state:t(), [string()]) -> {ok, rebar_state:t()} | {error, term()}.
  72. run(BaseState, Commands) ->
  73. start_and_load_apps(api),
  74. BaseState1 = rebar_state:set(BaseState, task, Commands),
  75. BaseState2 = rebar_state:set(BaseState1, caller, api),
  76. Verbosity = log_level(),
  77. ok = rebar_log:init(api, Verbosity),
  78. run_aux(BaseState2, Commands).
  79. %% ====================================================================
  80. %% Internal functions
  81. %% ====================================================================
  82. %% @private sets up the rebar3 environment based on the command line
  83. %% arguments passed, if they have any relevance; used to translate
  84. %% from the escript call-site into a common one with the library
  85. %% usage.
  86. -spec run([any(), ...]) -> {ok, rebar_state:t()} | {error, term()}.
  87. run(RawArgs) ->
  88. start_and_load_apps(command_line),
  89. BaseState = init_config(),
  90. BaseState1 = rebar_state:set(BaseState, caller, command_line),
  91. case erlang:system_info(version) of
  92. "6.1" ->
  93. ?WARN("Due to a filelib bug in Erlang 17.1 it is recommended"
  94. "you update to a newer release.", []);
  95. _ ->
  96. ok
  97. end,
  98. {BaseState2, _Args1} = set_options(BaseState1, {[], []}),
  99. run_aux(BaseState2, RawArgs).
  100. %% @private Junction point between the CLI and library entry points.
  101. %% From here on the module's role is a shared path here to finish
  102. %% up setting the environment for the run.
  103. -spec run_aux(rebar_state:t(), [string()]) ->
  104. {ok, rebar_state:t()} | {error, term()}.
  105. run_aux(State, RawArgs) ->
  106. io:setopts([{encoding, unicode}]),
  107. %% Profile override; can only support one profile
  108. State1 = case os:getenv("REBAR_PROFILE") of
  109. false ->
  110. State;
  111. "" ->
  112. State;
  113. Profile ->
  114. rebar_state:apply_profiles(State, [list_to_atom(Profile)])
  115. end,
  116. rebar_utils:check_min_otp_version(rebar_state:get(State1, minimum_otp_vsn, undefined)),
  117. rebar_utils:check_blacklisted_otp_versions(rebar_state:get(State1, blacklisted_otp_vsns, undefined)),
  118. %% Change the default hex CDN
  119. State2 = case os:getenv("HEX_CDN") of
  120. false ->
  121. State1;
  122. CDN ->
  123. rebar_state:set(State1, rebar_packages_cdn, CDN)
  124. end,
  125. Compilers = application:get_env(rebar, compilers, []),
  126. State0 = rebar_state:compilers(State2, Compilers),
  127. %% TODO: this means use of REBAR_PROFILE=profile will replace the repos with
  128. %% the repos defined in the profile. But it will not work with `as profile`.
  129. %% Maybe it shouldn't work with either to be consistent?
  130. Resources = application:get_env(rebar, resources, []),
  131. State2_ = rebar_state:create_resources(Resources, State0),
  132. %% bootstrap test profile
  133. State3 = rebar_state:add_to_profile(State2_, test, test_state(State1)),
  134. %% Process each command, resetting any state between each one
  135. BaseDir = rebar_state:get(State, base_dir, ?DEFAULT_BASE_DIR),
  136. State4 = rebar_state:set(State3, base_dir,
  137. filename:join(filename:absname(rebar_state:dir(State3)), BaseDir)),
  138. {ok, Providers} = application:get_env(rebar, providers),
  139. %% Providers can modify profiles stored in opts, so set default after initializing providers
  140. State5 = rebar_state:create_logic_providers(Providers, State4),
  141. %% Initializing project_plugins which can override default providers
  142. State6 = rebar_plugins:project_plugins_install(State5),
  143. State7 = rebar_plugins:top_level_install(State6),
  144. State8 = case os:getenv("REBAR_CACHE_DIR") of
  145. false ->
  146. State7;
  147. ConfigFile ->
  148. rebar_state:set(State7, global_rebar_dir, ConfigFile)
  149. end,
  150. State9 = rebar_state:default(State8, rebar_state:opts(State8)),
  151. {Task, Args} = parse_args(RawArgs),
  152. State10 = rebar_state:code_paths(State9, default, code:get_path()),
  153. case rebar_core:init_command(rebar_state:command_args(State10, Args), Task) of
  154. {ok, State11} ->
  155. case rebar_state:get(State11, caller, command_line) of
  156. api ->
  157. rebar_paths:unset_paths([deps, plugins], State11),
  158. {ok, State11};
  159. _ ->
  160. {ok, State11}
  161. end;
  162. Other ->
  163. Other
  164. end.
  165. %% @doc set up base configuration having to do with verbosity, where
  166. %% to find config files, and so on, and return an internal rebar3 state term.
  167. -spec init_config() -> rebar_state:t().
  168. init_config() ->
  169. rebar_utils:set_httpc_options(),
  170. %% Initialize logging system
  171. Verbosity = log_level(),
  172. ok = rebar_log:init(command_line, Verbosity),
  173. Config = rebar_config:consult_root(),
  174. Config1 = rebar_config:merge_locks(Config, rebar_config:consult_lock_file(?LOCK_FILE)),
  175. %% If $HOME/.config/rebar3/rebar.config exists load and use as global config
  176. GlobalConfigFile = rebar_dir:global_config(),
  177. State = case filelib:is_regular(GlobalConfigFile) of
  178. true ->
  179. ?DEBUG("Load global config file ~ts", [GlobalConfigFile]),
  180. try state_from_global_config(Config1, GlobalConfigFile)
  181. catch
  182. _:_ ->
  183. ?WARN("Global config ~ts exists but can not be read. Ignoring global config values.", [GlobalConfigFile]),
  184. rebar_state:new(Config1)
  185. end;
  186. false ->
  187. rebar_state:new(Config1)
  188. end,
  189. %% Determine the location of the rebar executable; important for pulling
  190. %% resources out of the escript
  191. State1 = try
  192. ScriptName = filename:absname(escript:script_name()),
  193. %% Running with 'erl -s rebar3 main' still sets a name for some reason
  194. %% so verify it is a real file
  195. case filelib:is_regular(ScriptName) of
  196. true ->
  197. rebar_state:escript_path(State, ScriptName);
  198. false ->
  199. State
  200. end
  201. catch
  202. _:_ ->
  203. State
  204. end,
  205. %% TODO: Do we need this still? I think it may still be used.
  206. %% Initialize vsn cache
  207. rebar_state:set(State1, vsn_cache, dict:new()).
  208. %% @doc Parse basic rebar3 arguments to find the top-level task
  209. %% to be run; this parsing is only partial from the point of view that
  210. %% runs done with arguments like `as $PROFILE do $TASK' will just
  211. %% return `as', which is then in charge of doing a more dynamic
  212. %% dispatch.
  213. %% If no arguments are given, the `help' task is returned.
  214. %% If special arguments like `-h' or `-v' are translated to `help'
  215. %% and `version' tasks.
  216. %% The unparsed parts of arguments are returned in:
  217. %% `{Task, Rest}'.
  218. -spec parse_args([string()]) -> {atom(), [string()]}.
  219. parse_args([]) ->
  220. parse_args(["help"]);
  221. parse_args([H | Rest]) when H =:= "-h"
  222. ; H =:= "--help" ->
  223. parse_args(["help" | Rest]);
  224. parse_args([H | Rest]) when H =:= "-v"
  225. ; H =:= "--version" ->
  226. parse_args(["version" | Rest]);
  227. parse_args([Task | RawRest]) ->
  228. {list_to_atom(Task), RawRest}.
  229. %% @private actually not too sure what this does anymore.
  230. -spec set_options(rebar_state:t(),{[any()],[any()]}) -> {rebar_state:t(),[any()]}.
  231. set_options(State, {Options, NonOptArgs}) ->
  232. GlobalDefines = proplists:get_all_values(defines, Options),
  233. State1 = rebar_state:set(State, defines, GlobalDefines),
  234. %% Set global variables based on getopt options
  235. State2 = set_global_flag(State1, Options, force),
  236. Task = proplists:get_value(task, Options, "help"),
  237. {rebar_state:set(State2, task, Task), NonOptArgs}.
  238. %% @doc get log level based on getopt options and ENV
  239. -spec log_level() -> integer().
  240. log_level() ->
  241. case os:getenv("QUIET") of
  242. Q when Q == false; Q == "" ->
  243. DefaultLevel = rebar_log:default_level(),
  244. case os:getenv("DEBUG") of
  245. D when D == false; D == "" ->
  246. DefaultLevel;
  247. _ ->
  248. DefaultLevel + 3
  249. end;
  250. _ ->
  251. rebar_log:error_level()
  252. end.
  253. %% @doc show version information
  254. -spec version() -> ok.
  255. version() ->
  256. {ok, Vsn} = application:get_key(rebar, vsn),
  257. ?CONSOLE("rebar ~ts on Erlang/OTP ~ts Erts ~ts",
  258. [Vsn, erlang:system_info(otp_release), erlang:system_info(version)]).
  259. %% @private set global flag based on getopt option boolean value
  260. %% TODO: Actually make it 'global'
  261. -spec set_global_flag(rebar_state:t(), list(), term()) -> rebar_state:t().
  262. set_global_flag(State, Options, Flag) ->
  263. Value = case proplists:get_bool(Flag, Options) of
  264. true ->
  265. "1";
  266. false ->
  267. "0"
  268. end,
  269. rebar_state:set(State, Flag, Value).
  270. %% @doc options accepted via getopt
  271. -spec global_option_spec_list() -> [{atom(), char(), string(), atom(), string()}, ...].
  272. global_option_spec_list() ->
  273. [
  274. %% {Name, ShortOpt, LongOpt, ArgSpec, HelpMsg}
  275. {help, $h, "help", undefined, "Print this help."},
  276. {version, $v, "version", undefined, "Show version information."},
  277. {task, undefined, undefined, string, "Task to run."}
  278. ].
  279. %% @private translate unhandled errors and internal return codes into proper
  280. %% erroneous program exits.
  281. -spec handle_error(term(), term()) -> no_return().
  282. handle_error(rebar_abort, _) ->
  283. erlang:halt(1);
  284. handle_error({error, rebar_abort}, _) ->
  285. erlang:halt(1);
  286. handle_error({error, {Module, Reason}}, Stacktrace) ->
  287. case code:which(Module) of
  288. non_existing ->
  289. ?CRASHDUMP("~p: ~p~n~p~n~n", [Module, Reason, Stacktrace]),
  290. ?ERROR("Uncaught error in rebar_core. Run with DEBUG=1 to stacktrace or consult rebar3.crashdump", []),
  291. ?DEBUG("Uncaught error: ~p ~p", [Module, Reason]),
  292. ?INFO("When submitting a bug report, please include the output of `rebar3 report \"your command\"`", []);
  293. _ ->
  294. ?ERROR("~ts", [Module:format_error(Reason)])
  295. end,
  296. erlang:halt(1);
  297. handle_error({error, Error}, _) when is_list(Error) ->
  298. ?ERROR("~ts", [Error]),
  299. erlang:halt(1);
  300. handle_error(Error, StackTrace) ->
  301. %% Nothing should percolate up from rebar_core;
  302. %% Dump this error to console
  303. ?CRASHDUMP("Error: ~p~n~p~n~n", [Error, StackTrace]),
  304. ?ERROR("Uncaught error in rebar_core. Run with DEBUG=1 to see stacktrace or consult rebar3.crashdump", []),
  305. ?DEBUG("Uncaught error: ~p", [Error]),
  306. case StackTrace of
  307. [] -> ok;
  308. Trace ->
  309. ?DEBUG("Stack trace to the error location:~n~p", [Trace])
  310. end,
  311. ?INFO("When submitting a bug report, please include the output of `rebar3 report \"your command\"`", []),
  312. erlang:halt(1).
  313. %% @private Boot Erlang dependencies; problem is that escripts don't auto-boot
  314. %% stuff the way releases do and we have to do it by hand.
  315. %% This also lets us detect and show nicer errors when a critical lib is
  316. %% not supported
  317. -spec start_and_load_apps(command_line|api) -> term().
  318. start_and_load_apps(Caller) ->
  319. _ = application:load(rebar),
  320. %% Make sure crypto is running
  321. ensure_running(crypto, Caller),
  322. ensure_running(asn1, Caller),
  323. ensure_running(public_key, Caller),
  324. ensure_running(ssl, Caller),
  325. ensure_running(inets, Caller),
  326. inets:start(httpc, [{profile, rebar}]).
  327. %% @doc Make sure a required app is running, or display an error message
  328. %% and abort if there's a problem.
  329. -spec ensure_running(atom(), command_line|api) -> ok | no_return().
  330. ensure_running(App, Caller) ->
  331. case application:start(App) of
  332. ok -> ok;
  333. {error, {already_started, App}} -> ok;
  334. {error, Reason} ->
  335. %% These errors keep rebar3's own configuration to be loaded,
  336. %% which disables the log level and causes a failure without
  337. %% showing the error message. Bypass this entirely by overriding
  338. %% the default value (which allows logging to take place)
  339. %% and shut things down manually.
  340. Log = ec_cmd_log:new(warn, Caller),
  341. ec_cmd_log:error(Log, "Rebar dependency ~p could not be loaded "
  342. "for reason ~p~n", [App, Reason]),
  343. throw(rebar_abort)
  344. end.
  345. -spec state_from_global_config([term()], file:filename()) -> rebar_state:t().
  346. state_from_global_config(Config, GlobalConfigFile) ->
  347. GlobalConfigTerms = rebar_config:consult_file(GlobalConfigFile),
  348. GlobalConfig = rebar_state:new(GlobalConfigTerms),
  349. %% We don't want to worry about global plugin install state effecting later
  350. %% usage. So we throw away the global profile state used for plugin install.
  351. GlobalConfigThrowAway0 = rebar_state:current_profiles(GlobalConfig, [global]),
  352. Resources = application:get_env(rebar, resources, []),
  353. GlobalConfigThrowAway = rebar_state:create_resources(Resources, GlobalConfigThrowAway0),
  354. Compilers = application:get_env(rebar, compilers, []),
  355. GlobalConfigThrowAway1 = rebar_state:compilers(GlobalConfigThrowAway, Compilers),
  356. GlobalState = case rebar_state:get(GlobalConfigThrowAway1, plugins, []) of
  357. [] ->
  358. GlobalConfigThrowAway1;
  359. GlobalPluginsToInstall ->
  360. rebar_plugins:handle_plugins(global,
  361. GlobalPluginsToInstall,
  362. GlobalConfigThrowAway1)
  363. end,
  364. GlobalPlugins = rebar_state:providers(GlobalState),
  365. GlobalConfig2 = rebar_state:set(GlobalConfig, plugins, []),
  366. GlobalConfig3 = rebar_state:set(GlobalConfig2, {plugins, global},
  367. rebar_state:get(GlobalConfigThrowAway1, plugins, [])),
  368. rebar_state:providers(rebar_state:new(GlobalConfig3, Config), GlobalPlugins).
  369. -spec test_state(rebar_state:t()) -> [{'extra_src_dirs',[string()]} | {'erl_opts',[any()]}].
  370. test_state(State) ->
  371. %% Fetch the test profile's erl_opts only
  372. Opts = rebar_state:opts(State),
  373. Profiles = rebar_opts:get(Opts, profiles, []),
  374. ProfileOpts = proplists:get_value(test, Profiles, []),
  375. ErlOpts = proplists:get_value(erl_opts, ProfileOpts, []),
  376. TestOpts = safe_define_test_macro(ErlOpts),
  377. [{extra_src_dirs, ["test"]}, {erl_opts, TestOpts}].
  378. -spec safe_define_test_macro([any()]) -> [any()] | [{'d',atom()} | any()].
  379. safe_define_test_macro(Opts) ->
  380. %% defining a compile macro twice results in an exception so
  381. %% make sure 'TEST' is only defined once
  382. case test_defined(Opts) of
  383. true -> Opts;
  384. false -> [{d, 'TEST'}|Opts]
  385. end.
  386. -spec test_defined([{d, atom()} | {d, atom(), term()} | term()]) -> boolean().
  387. test_defined([{d, 'TEST'}|_]) -> true;
  388. test_defined([{d, 'TEST', true}|_]) -> true;
  389. test_defined([_|Rest]) -> test_defined(Rest);
  390. test_defined([]) -> false.