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.

220 regels
8.1 KiB

10 jaren geleden
10 jaren geleden
10 jaren geleden
10 jaren geleden
10 jaren geleden
10 jaren geleden
10 jaren geleden
10 jaren geleden
10 jaren geleden
10 jaren geleden
10 jaren geleden
  1. #!/usr/bin/env escript
  2. %% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
  3. %% ex: ft=erlang ts=4 sw=4 et
  4. main(_Args) ->
  5. %% Fetch and build deps required to build rebar3
  6. BaseDeps = [{providers, []}
  7. ,{getopt, []}
  8. ,{erlware_commons, ["ec_dictionary.erl", "ec_vsn.erl"]}],
  9. Deps = get_deps(),
  10. [fetch_and_compile(Dep, Deps) || Dep <- BaseDeps],
  11. %% Build rebar3 modules with compile:file
  12. bootstrap_rebar3(),
  13. %% Build rebar.app from rebar.app.src
  14. {ok, App} = rebar_app_info:new(rebar, "3.0.0", filename:absname("_build/default/lib/rebar/")),
  15. rebar_otp_app:compile(rebar_state:new(), App),
  16. %% Because we are compiling files that are loaded already we want to silence
  17. %% not_purged errors in rebar_erlc_compiler:opts_changed/1
  18. error_logger:tty(false),
  19. setup_env(),
  20. os:putenv("REBAR_PROFILE", "bootstrap"),
  21. {ok, State} = rebar3:run(["compile"]),
  22. reset_env(),
  23. os:putenv("REBAR_PROFILE", ""),
  24. %% Build erlydtl files (a hook on compile in the default profile) and escript file
  25. DepsPaths = rebar_state:code_paths(State, all_deps),
  26. code:add_pathsa(DepsPaths),
  27. rebar3:run(["clean", "-a"]),
  28. rebar3:run(["escriptize"]),
  29. %% Done with compile, can turn back on error logger
  30. error_logger:tty(true),
  31. %% Finally, update executable perms for our script on *nix,
  32. %% or write out script files on win32.
  33. ec_file:copy("_build/default/bin/rebar3", "./rebar3"),
  34. case os:type() of
  35. {unix,_} ->
  36. [] = os:cmd("chmod u+x rebar3"),
  37. ok;
  38. {win32,_} ->
  39. write_windows_scripts(),
  40. ok;
  41. _ ->
  42. ok
  43. end.
  44. fetch_and_compile({Name, ErlFirstFiles}, Deps) ->
  45. {Name, _, Repo} = lists:keyfind(Name, 1, Deps),
  46. ok = fetch(Repo, Name),
  47. compile(Name, ErlFirstFiles).
  48. fetch({git, Url, Source}, App) ->
  49. Dir = filename:join([filename:absname("_build/default/lib/"), App]),
  50. case filelib:is_dir(Dir) of
  51. true ->
  52. true = code:add_path(filename:join(Dir, "ebin")),
  53. ok;
  54. false ->
  55. fetch_source(Dir, Url, Source),
  56. ok
  57. end.
  58. fetch_source(Dir, Url, {ref, Ref}) ->
  59. ok = filelib:ensure_dir(Dir),
  60. os:cmd(io_lib:format("git clone ~s ~s", [Url, Dir])),
  61. {ok, Cwd} = file:get_cwd(),
  62. file:set_cwd(Dir),
  63. os:cmd(io_lib:format("git checkout -q ~s", [Ref])),
  64. file:set_cwd(Cwd);
  65. fetch_source(Dir, Url, {_, Branch}) ->
  66. ok = filelib:ensure_dir(Dir),
  67. os:cmd(io_lib:format("git clone ~s ~s -b ~s --single-branch",
  68. [Url, Dir, Branch])).
  69. compile(App, FirstFiles) ->
  70. Dir = filename:join(filename:absname("_build/default/lib/"), App),
  71. filelib:ensure_dir(filename:join([Dir, "ebin", "dummy.beam"])),
  72. code:add_path(filename:join(Dir, "ebin")),
  73. FirstFilesPaths = [filename:join([Dir, "src", Module]) || Module <- FirstFiles],
  74. Sources = FirstFilesPaths ++ filelib:wildcard(filename:join([Dir, "src", "*.erl"])),
  75. [compile_file(X, [{i, filename:join(Dir, "include")}
  76. ,{outdir, filename:join(Dir, "ebin")}
  77. ,return | additional_defines()]) || X <- Sources].
  78. compile_file(File, Opts) ->
  79. case compile:file(File, Opts) of
  80. {ok, _Mod} ->
  81. ok;
  82. {ok, _Mod, []} ->
  83. ok;
  84. {ok, _Mod, Ws} ->
  85. io:format("~s~n", [format_warnings(File, Ws)]),
  86. halt(1);
  87. {error, Es, Ws} ->
  88. io:format("~s ~s~n", [format_errors(File, Es), format_warnings(File, Ws)]),
  89. halt(1)
  90. end.
  91. bootstrap_rebar3() ->
  92. filelib:ensure_dir("_build/default/lib/rebar/ebin/dummy.beam"),
  93. code:add_path("_build/default/lib/rebar/ebin/"),
  94. file:make_symlink(filename:absname("src"), filename:absname("_build/default/lib/rebar/src")),
  95. Sources = ["src/rebar_resource.erl" | filelib:wildcard("src/*.erl")],
  96. [compile_file(X, [{outdir, "_build/default/lib/rebar/ebin/"}
  97. ,return | additional_defines()]) || X <- Sources],
  98. code:add_patha(filename:absname("_build/default/lib/rebar/ebin")).
  99. setup_env() ->
  100. %% We don't need or want erlydtl or relx providers loaded yet
  101. application:load(rebar),
  102. {ok, Providers} = application:get_env(rebar, providers),
  103. Providers1 = Providers -- [rebar_prv_erlydtl_compiler,
  104. rebar_prv_release,
  105. rebar_prv_tar],
  106. application:set_env(rebar, providers, Providers1).
  107. reset_env() ->
  108. %% Reset the env so we get all providers and can build erlydtl files
  109. application:unset_env(rebar, providers),
  110. application:unload(rebar),
  111. application:load(rebar).
  112. write_windows_scripts() ->
  113. CmdScript=
  114. "@echo off\r\n"
  115. "setlocal\r\n"
  116. "set rebarscript=%~f0\r\n"
  117. "escript.exe \"%rebarscript:.cmd=%\" %*\r\n",
  118. ok = file:write_file("rebar3.cmd", CmdScript).
  119. get_deps() ->
  120. case file:consult("rebar.lock") of
  121. {ok, [Deps]} ->
  122. [{binary_to_atom(Name, utf8), "", Source} || {Name, Source, _Level} <- Deps];
  123. _ ->
  124. {ok, Config} = file:consult("rebar.config"),
  125. proplists:get_value(deps, Config)
  126. end.
  127. format_errors(Source, Errors) ->
  128. format_errors(Source, "", Errors).
  129. format_warnings(Source, Warnings) ->
  130. format_warnings(Source, Warnings, []).
  131. format_warnings(Source, Warnings, Opts) ->
  132. Prefix = case lists:member(warnings_as_errors, Opts) of
  133. true -> "";
  134. false -> "Warning: "
  135. end,
  136. format_errors(Source, Prefix, Warnings).
  137. format_errors(_MainSource, Extra, Errors) ->
  138. [begin
  139. [format_error(Source, Extra, Desc) || Desc <- Descs]
  140. end
  141. || {Source, Descs} <- Errors].
  142. format_error(AbsSource, Extra, {{Line, Column}, Mod, Desc}) ->
  143. ErrorDesc = Mod:format_error(Desc),
  144. io_lib:format("~s:~w:~w: ~s~s~n", [AbsSource, Line, Column, Extra, ErrorDesc]);
  145. format_error(AbsSource, Extra, {Line, Mod, Desc}) ->
  146. ErrorDesc = Mod:format_error(Desc),
  147. io_lib:format("~s:~w: ~s~s~n", [AbsSource, Line, Extra, ErrorDesc]);
  148. format_error(AbsSource, Extra, {Mod, Desc}) ->
  149. ErrorDesc = Mod:format_error(Desc),
  150. io_lib:format("~s: ~s~s~n", [AbsSource, Extra, ErrorDesc]).
  151. additional_defines() ->
  152. [{d, D} || {Re, D} <- [{"^[0-9]+", namespaced_types}, {"^R1[4|5]", deprecated_crypto}], is_otp_release(Re)].
  153. is_otp_release(ArchRegex) ->
  154. case re:run(otp_release(), ArchRegex, [{capture, none}]) of
  155. match ->
  156. true;
  157. nomatch ->
  158. false
  159. end.
  160. otp_release() ->
  161. otp_release1(erlang:system_info(otp_release)).
  162. %% If OTP <= R16, otp_release is already what we want.
  163. otp_release1([$R,N|_]=Rel) when is_integer(N) ->
  164. Rel;
  165. %% If OTP >= 17.x, erlang:system_info(otp_release) returns just the
  166. %% major version number, we have to read the full version from
  167. %% a file. See http://www.erlang.org/doc/system_principles/versions.html
  168. %% Read vsn string from the 'OTP_VERSION' file and return as list without
  169. %% the "\n".
  170. otp_release1(Rel) ->
  171. File = filename:join([code:root_dir(), "releases", Rel, "OTP_VERSION"]),
  172. {ok, Vsn} = file:read_file(File),
  173. %% It's fine to rely on the binary module here because we can
  174. %% be sure that it's available when the otp_release string does
  175. %% not begin with $R.
  176. Size = byte_size(Vsn),
  177. %% The shortest vsn string consists of at least two digits
  178. %% followed by "\n". Therefore, it's safe to assume Size >= 3.
  179. case binary:part(Vsn, {Size, -3}) of
  180. <<"**\n">> ->
  181. %% The OTP documentation mentions that a system patched
  182. %% using the otp_patch_apply tool available to licensed
  183. %% customers will leave a '**' suffix in the version as a
  184. %% flag saying the system consists of application versions
  185. %% from multiple OTP versions. We ignore this flag and
  186. %% drop the suffix, given for all intents and purposes, we
  187. %% cannot obtain relevant information from it as far as
  188. %% tooling is concerned.
  189. binary:bin_to_list(Vsn, {0, Size - 3});
  190. _ ->
  191. binary:bin_to_list(Vsn, {0, Size - 1})
  192. end.