Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

463 строки
18 KiB

10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
9 лет назад
9 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
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 лет назад
10 лет назад
10 лет назад
10 лет назад
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 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
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 лет назад
Fix directory recursion in compiler This patch contains two behaviour changes and reasserts other behaviours that now line things up with user and documentation expectations: 1. The src directories remain recursive. We turned it on by accident at some point in the past and now people rely on it, so we're stuck with it. However a new test ensures that the feature can be turned off on-demand as documented on the website. 2. The test directories are no longer recursive by default. The fix is done by properly fixing how rebar3.erl does its feature injection by mandating the default value there. I'm somewhat nervous that this change could negatively impact some users and older compiler module versions, but if users stick to the rebar_dir interface, everything should keep working transparently. 3. The test directories' configuration is no longer silently dropped. Due to how rebar3.erl injected test state without looking for what the user may have specified, multiple extra_src_dirs entries existed at once and were run; one with the recursion set to true and one with whatever the user specified. If the user disabled recursion of the "test" extra_src_dir, then the injected value still ran it once... 4. The handling of extra files in the compiler module is fixed to actually use the rebar_dir interface properly, and reinjects non-default directory recursion settings into the swapped options for the shimmed extra apps. Not doing this annotation step resulted in the write for swapped opts to actually drop the configured recursion value and make everything recursive all the time. A single new test actually validates all of that behaviour and seems to work fine.
5 лет назад
  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. %% Maybe change the default hex CDN
  119. HexCDN = case os:getenv("HEX_CDN") of
  120. false -> ?DEFAULT_CDN;
  121. CDN -> CDN
  122. end,
  123. State2 = rebar_state:set(State1, rebar_packages_cdn, HexCDN),
  124. Compilers = application:get_env(rebar, compilers, []),
  125. State0 = rebar_state:compilers(State2, Compilers),
  126. %% TODO: this means use of REBAR_PROFILE=profile will replace the repos with
  127. %% the repos defined in the profile. But it will not work with `as profile`.
  128. %% Maybe it shouldn't work with either to be consistent?
  129. Resources = application:get_env(rebar, resources, []),
  130. State2_ = rebar_state:create_resources(Resources, State0),
  131. %% bootstrap test profile
  132. State3 = rebar_state:add_to_profile(State2_, test, test_state(State1)),
  133. BaseDir = case os:getenv("REBAR_BASE_DIR") of
  134. D when D =:= false orelse D =:= "" ->
  135. rebar_state:get(State, base_dir, ?DEFAULT_BASE_DIR);
  136. Dir ->
  137. Dir
  138. end,
  139. State4 = rebar_state:set(State3, base_dir,
  140. filename:join(filename:absname(rebar_state:dir(State3)), BaseDir)),
  141. {ok, Providers} = application:get_env(rebar, providers),
  142. %% Providers can modify profiles stored in opts, so set default after initializing providers
  143. State5 = rebar_state:create_logic_providers(Providers, State4),
  144. %% Initializing project_plugins which can override default providers
  145. State6 = rebar_plugins:project_plugins_install(State5),
  146. State7 = rebar_plugins:top_level_install(State6),
  147. State8 = case os:getenv("REBAR_CACHE_DIR") of
  148. false ->
  149. State7;
  150. ConfigFile ->
  151. rebar_state:set(State7, global_rebar_dir, ConfigFile)
  152. end,
  153. State9 = rebar_state:default(State8, rebar_state:opts(State8)),
  154. {Task, Args} = parse_args(RawArgs),
  155. State10 = rebar_state:code_paths(State9, default, code:get_path()),
  156. case rebar_core:init_command(rebar_state:command_args(State10, Args), Task) of
  157. {ok, State11} ->
  158. case rebar_state:get(State11, caller, command_line) of
  159. api ->
  160. rebar_paths:unset_paths([deps, plugins], State11),
  161. {ok, State11};
  162. _ ->
  163. {ok, State11}
  164. end;
  165. Other ->
  166. Other
  167. end.
  168. %% @doc set up base configuration having to do with verbosity, where
  169. %% to find config files, and so on, and return an internal rebar3 state term.
  170. -spec init_config() -> rebar_state:t().
  171. init_config() ->
  172. rebar_utils:set_httpc_options(),
  173. %% Initialize logging system
  174. Verbosity = log_level(),
  175. ok = rebar_log:init(command_line, Verbosity),
  176. Config = rebar_config:consult_root(),
  177. Config1 = rebar_config:merge_locks(Config, rebar_config:consult_lock_file(?LOCK_FILE)),
  178. %% If $HOME/.config/rebar3/rebar.config exists load and use as global config
  179. GlobalConfigFile = rebar_dir:global_config(),
  180. State = case filelib:is_regular(GlobalConfigFile) of
  181. true ->
  182. ?DEBUG("Load global config file ~ts", [GlobalConfigFile]),
  183. try state_from_global_config(Config1, GlobalConfigFile)
  184. catch
  185. _:_ ->
  186. ?WARN("Global config ~ts exists but can not be read. Ignoring global config values.", [GlobalConfigFile]),
  187. rebar_state:new(Config1)
  188. end;
  189. false ->
  190. rebar_state:new(Config1)
  191. end,
  192. %% Determine the location of the rebar executable; important for pulling
  193. %% resources out of the escript
  194. State1 = try
  195. ScriptName = filename:absname(escript:script_name()),
  196. %% Running with 'erl -s rebar3 main' still sets a name for some reason
  197. %% so verify it is a real file
  198. case filelib:is_regular(ScriptName) of
  199. true ->
  200. rebar_state:escript_path(State, ScriptName);
  201. false ->
  202. State
  203. end
  204. catch
  205. _:_ ->
  206. State
  207. end,
  208. %% TODO: Do we need this still? I think it may still be used.
  209. %% Initialize vsn cache
  210. rebar_state:set(State1, vsn_cache, dict:new()).
  211. %% @doc Parse basic rebar3 arguments to find the top-level task
  212. %% to be run; this parsing is only partial from the point of view that
  213. %% runs done with arguments like `as $PROFILE do $TASK' will just
  214. %% return `as', which is then in charge of doing a more dynamic
  215. %% dispatch.
  216. %% If no arguments are given, the `help' task is returned.
  217. %% If special arguments like `-h' or `-v' are translated to `help'
  218. %% and `version' tasks.
  219. %% The unparsed parts of arguments are returned in:
  220. %% `{Task, Rest}'.
  221. -spec parse_args([string()]) -> {atom(), [string()]}.
  222. parse_args([]) ->
  223. parse_args(["help"]);
  224. parse_args([H | Rest]) when H =:= "-h"
  225. ; H =:= "--help" ->
  226. parse_args(["help" | Rest]);
  227. parse_args([H | Rest]) when H =:= "-v"
  228. ; H =:= "--version" ->
  229. parse_args(["version" | Rest]);
  230. parse_args([Task | RawRest]) ->
  231. {list_to_atom(Task), RawRest}.
  232. %% @private actually not too sure what this does anymore.
  233. -spec set_options(rebar_state:t(),{[any()],[any()]}) -> {rebar_state:t(),[any()]}.
  234. set_options(State, {Options, NonOptArgs}) ->
  235. GlobalDefines = proplists:get_all_values(defines, Options),
  236. State1 = rebar_state:set(State, defines, GlobalDefines),
  237. %% Set global variables based on getopt options
  238. State2 = set_global_flag(State1, Options, force),
  239. Task = proplists:get_value(task, Options, "help"),
  240. {rebar_state:set(State2, task, Task), NonOptArgs}.
  241. %% @doc get log level based on getopt options and ENV
  242. -spec log_level() -> integer().
  243. log_level() ->
  244. case os:getenv("QUIET") of
  245. Q when Q == false; Q == "" ->
  246. case os:getenv("DIAGNOSTIC") of
  247. Di when Di == false; Di == "" ->
  248. case os:getenv("DEBUG") of
  249. D when D == false; D == "" ->
  250. rebar_log:default_level();
  251. _ ->
  252. rebar_log:debug_level()
  253. end;
  254. _ ->
  255. rebar_log:diagnostic_level()
  256. end;
  257. _ ->
  258. rebar_log:error_level()
  259. end.
  260. %% @doc show version information
  261. -spec version() -> ok.
  262. version() ->
  263. {ok, Vsn} = application:get_key(rebar, vsn),
  264. ?CONSOLE("rebar ~ts on Erlang/OTP ~ts Erts ~ts",
  265. [Vsn, erlang:system_info(otp_release), erlang:system_info(version)]).
  266. %% @private set global flag based on getopt option boolean value
  267. %% TODO: Actually make it 'global'
  268. -spec set_global_flag(rebar_state:t(), list(), term()) -> rebar_state:t().
  269. set_global_flag(State, Options, Flag) ->
  270. Value = case proplists:get_bool(Flag, Options) of
  271. true ->
  272. "1";
  273. false ->
  274. "0"
  275. end,
  276. rebar_state:set(State, Flag, Value).
  277. %% @doc options accepted via getopt
  278. -spec global_option_spec_list() -> [{atom(), char(), string(), atom(), string()}, ...].
  279. global_option_spec_list() ->
  280. [
  281. %% {Name, ShortOpt, LongOpt, ArgSpec, HelpMsg}
  282. {help, $h, "help", undefined, "Print this help."},
  283. {version, $v, "version", undefined, "Show version information."},
  284. {task, undefined, undefined, string, "Task to run."}
  285. ].
  286. %% @private translate unhandled errors and internal return codes into proper
  287. %% erroneous program exits.
  288. -spec handle_error(term(), term()) -> no_return().
  289. handle_error(rebar_abort, _) ->
  290. erlang:halt(1);
  291. handle_error({error, rebar_abort}, _) ->
  292. erlang:halt(1);
  293. handle_error({error, {Module, Reason}}, Stacktrace) ->
  294. case code:which(Module) of
  295. non_existing ->
  296. ?CRASHDUMP("~p: ~p~n~p~n~n", [Module, Reason, Stacktrace]),
  297. ?ERROR("Uncaught error in rebar_core. Run with DIAGNOSTIC=1 to stacktrace or consult rebar3.crashdump", []),
  298. ?DEBUG("Uncaught error: ~p ~p", [Module, Reason]),
  299. ?INFO("When submitting a bug report, please include the output of `rebar3 report \"your command\"`", []);
  300. _ ->
  301. ?ERROR("~ts", [Module:format_error(Reason)])
  302. end,
  303. erlang:halt(1);
  304. handle_error({error, Error}, _) when is_list(Error) ->
  305. ?ERROR("~ts", [Error]),
  306. erlang:halt(1);
  307. handle_error(Error, StackTrace) ->
  308. %% Nothing should percolate up from rebar_core;
  309. %% Dump this error to console
  310. ?CRASHDUMP("Error: ~p~n~p~n~n", [Error, StackTrace]),
  311. ?ERROR("Uncaught error in rebar_core. Run with DIAGNOSTIC=1 to see stacktrace or consult rebar3.crashdump", []),
  312. ?DEBUG("Uncaught error: ~p", [Error]),
  313. case StackTrace of
  314. [] -> ok;
  315. Trace ->
  316. ?DEBUG("Stack trace to the error location:~n~p", [Trace])
  317. end,
  318. ?INFO("When submitting a bug report, please include the output of `rebar3 report \"your command\"`", []),
  319. erlang:halt(1).
  320. %% @private Boot Erlang dependencies; problem is that escripts don't auto-boot
  321. %% stuff the way releases do and we have to do it by hand.
  322. %% This also lets us detect and show nicer errors when a critical lib is
  323. %% not supported
  324. -spec start_and_load_apps(command_line|api) -> term().
  325. start_and_load_apps(Caller) ->
  326. _ = application:load(rebar),
  327. %% Make sure crypto is running
  328. ensure_running(crypto, Caller),
  329. ensure_running(asn1, Caller),
  330. ensure_running(public_key, Caller),
  331. ensure_running(ssl, Caller),
  332. ensure_running(inets, Caller),
  333. inets:start(httpc, [{profile, rebar}]).
  334. %% @doc Make sure a required app is running, or display an error message
  335. %% and abort if there's a problem.
  336. -spec ensure_running(atom(), command_line|api) -> ok | no_return().
  337. ensure_running(App, Caller) ->
  338. case application:start(App) of
  339. ok -> ok;
  340. {error, {already_started, App}} -> ok;
  341. {error, Reason} ->
  342. %% These errors keep rebar3's own configuration to be loaded,
  343. %% which disables the log level and causes a failure without
  344. %% showing the error message. Bypass this entirely by overriding
  345. %% the default value (which allows logging to take place)
  346. %% and shut things down manually.
  347. Log = ec_cmd_log:new(warn, Caller),
  348. ec_cmd_log:error(Log, "Rebar dependency ~p could not be loaded "
  349. "for reason ~p~n", [App, Reason]),
  350. throw(rebar_abort)
  351. end.
  352. -spec state_from_global_config([term()], file:filename()) -> rebar_state:t().
  353. state_from_global_config(Config, GlobalConfigFile) ->
  354. GlobalConfigTerms = rebar_config:consult_file(GlobalConfigFile),
  355. GlobalConfig = rebar_state:new(GlobalConfigTerms),
  356. %% We don't want to worry about global plugin install state effecting later
  357. %% usage. So we throw away the global profile state used for plugin install.
  358. GlobalConfigThrowAway0 = rebar_state:current_profiles(GlobalConfig, [global]),
  359. Resources = application:get_env(rebar, resources, []),
  360. GlobalConfigThrowAway = rebar_state:create_resources(Resources, GlobalConfigThrowAway0),
  361. Compilers = application:get_env(rebar, compilers, []),
  362. GlobalConfigThrowAway1 = rebar_state:compilers(GlobalConfigThrowAway, Compilers),
  363. GlobalState = case rebar_state:get(GlobalConfigThrowAway1, plugins, []) of
  364. [] ->
  365. GlobalConfigThrowAway1;
  366. GlobalPluginsToInstall ->
  367. rebar_plugins:handle_plugins(global,
  368. GlobalPluginsToInstall,
  369. GlobalConfigThrowAway1)
  370. end,
  371. GlobalPlugins = rebar_state:providers(GlobalState),
  372. GlobalConfig2 = rebar_state:set(GlobalConfig, plugins, []),
  373. GlobalConfig3 = rebar_state:set(GlobalConfig2, {plugins, global},
  374. rebar_state:get(GlobalConfigThrowAway1, plugins, [])),
  375. rebar_state:providers(rebar_state:new(GlobalConfig3, Config), GlobalPlugins).
  376. -spec test_state(rebar_state:t()) -> [{'extra_src_dirs',[string()]} | {'erl_opts',[any()]}].
  377. test_state(State) ->
  378. %% Fetch the test profile's erl_opts only
  379. Opts = rebar_state:opts(State),
  380. Profiles = rebar_opts:get(Opts, profiles, []),
  381. ProfileOpts = proplists:get_value(test, Profiles, []),
  382. ErlOpts = proplists:get_value(erl_opts, ProfileOpts, []),
  383. TestOpts = safe_define_test_macro(ErlOpts),
  384. %% Only define the test directory if it wasn't set by the user already,
  385. %% otherwise our definition may clash with theirs
  386. Extras = rebar_opts:get(Opts, extra_src_dirs, []),
  387. ExtrasTest = proplists:get_value(extra_src_dirs, ProfileOpts, []),
  388. IsDefined = lists:any(fun({"test", _}) -> true
  389. ; ("test") -> true
  390. ; (_) -> false
  391. end, Extras ++ ExtrasTest),
  392. case IsDefined of
  393. true -> [];
  394. false -> [{extra_src_dirs, [{"test", [{recursive, false}]}]}]
  395. end ++ [{erl_opts, TestOpts}].
  396. -spec safe_define_test_macro([any()]) -> [any()] | [{'d',atom()} | any()].
  397. safe_define_test_macro(Opts) ->
  398. %% defining a compile macro twice results in an exception so
  399. %% make sure 'TEST' is only defined once
  400. case test_defined(Opts) of
  401. true -> Opts;
  402. false -> [{d, 'TEST'}|Opts]
  403. end.
  404. -spec test_defined([{d, atom()} | {d, atom(), term()} | term()]) -> boolean().
  405. test_defined([{d, 'TEST'}|_]) -> true;
  406. test_defined([{d, 'TEST', true}|_]) -> true;
  407. test_defined([_|Rest]) -> test_defined(Rest);
  408. test_defined([]) -> false.