Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

404 rindas
14 KiB

pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 8 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 9 gadiem
pirms 9 gadiem
pirms 9 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
  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(_) ->
  5. application:start(crypto),
  6. application:start(asn1),
  7. application:start(public_key),
  8. application:start(ssl),
  9. inets:start(),
  10. inets:start(httpc, [{profile, rebar}]),
  11. set_httpc_options(),
  12. %% Fetch and build deps required to build rebar3
  13. BaseDeps = [{providers, []}
  14. ,{getopt, []}
  15. ,{cf, []}
  16. ,{erlware_commons, ["ec_dictionary.erl", "ec_vsn.erl"]}
  17. ,{certifi, []}],
  18. Deps = get_deps(),
  19. [fetch_and_compile(Dep, Deps) || Dep <- BaseDeps],
  20. %% Build rebar3 modules with compile:file
  21. bootstrap_rebar3(),
  22. %% Build rebar.app from rebar.app.src
  23. {ok, App} = rebar_app_info:new(rebar, "3.2.0", filename:absname("_build/default/lib/rebar/")),
  24. rebar_otp_app:compile(rebar_state:new(), App),
  25. %% Because we are compiling files that are loaded already we want to silence
  26. %% not_purged errors in rebar_erlc_compiler:opts_changed/1
  27. error_logger:tty(false),
  28. setup_env(),
  29. os:putenv("REBAR_PROFILE", "bootstrap"),
  30. RegistryFile = default_registry_file(),
  31. case filelib:is_file(RegistryFile) of
  32. true ->
  33. ok;
  34. false ->
  35. rebar3:run(["update"])
  36. end,
  37. {ok, State} = rebar3:run(["compile"]),
  38. reset_env(),
  39. os:putenv("REBAR_PROFILE", ""),
  40. DepsPaths = rebar_state:code_paths(State, all_deps),
  41. code:add_pathsa(DepsPaths),
  42. rebar3:run(["clean", "-a"]),
  43. rebar3:run(["escriptize"]),
  44. %% Done with compile, can turn back on error logger
  45. error_logger:tty(true),
  46. %% Finally, update executable perms for our script on *nix,
  47. %% or write out script files on win32.
  48. ec_file:copy("_build/default/bin/rebar3", "./rebar3"),
  49. case os:type() of
  50. {unix,_} ->
  51. [] = os:cmd("chmod u+x rebar3"),
  52. ok;
  53. {win32,_} ->
  54. write_windows_scripts(),
  55. ok;
  56. _ ->
  57. ok
  58. end.
  59. default_registry_file() ->
  60. {ok, [[Home]]} = init:get_argument(home),
  61. CacheDir = filename:join([Home, ".cache", "rebar3"]),
  62. filename:join([CacheDir, "hex", "default", "registry"]).
  63. fetch_and_compile({Name, ErlFirstFiles}, Deps) ->
  64. case lists:keyfind(Name, 1, Deps) of
  65. {Name, Vsn} ->
  66. ok = fetch({pkg, atom_to_binary(Name, utf8), list_to_binary(Vsn)}, Name);
  67. {Name, _, Source} ->
  68. ok = fetch(Source, Name)
  69. end,
  70. %% Hack: erlware_commons depends on a .script file to check if it is being built with
  71. %% rebar2 or rebar3. But since rebar3 isn't built yet it can't get the vsn with get_key.
  72. %% So we simply make sure that file is deleted before compiling
  73. file:delete("_build/default/lib/erlware_commons/rebar.config.script"),
  74. compile(Name, ErlFirstFiles).
  75. fetch({pkg, Name, Vsn}, App) ->
  76. Dir = filename:join([filename:absname("_build/default/lib/"), App]),
  77. case filelib:is_dir(Dir) of
  78. false ->
  79. CDN = "https://repo.hex.pm/tarballs",
  80. Package = binary_to_list(<<Name/binary, "-", Vsn/binary, ".tar">>),
  81. Url = string:join([CDN, Package], "/"),
  82. case request(Url) of
  83. {ok, Binary} ->
  84. {ok, Contents} = extract(Binary),
  85. ok = erl_tar:extract({binary, Contents}, [{cwd, Dir}, compressed]);
  86. _ ->
  87. io:format("Error: Unable to fetch package ~p ~p~n", [Name, Vsn])
  88. end;
  89. true ->
  90. io:format("Dependency ~s already exists~n", [Name])
  91. end.
  92. extract(Binary) ->
  93. {ok, Files} = erl_tar:extract({binary, Binary}, [memory]),
  94. {"contents.tar.gz", Contents} = lists:keyfind("contents.tar.gz", 1, Files),
  95. {ok, Contents}.
  96. request(Url) ->
  97. case httpc:request(get, {Url, []},
  98. [{relaxed, true}],
  99. [{body_format, binary}],
  100. rebar) of
  101. {ok, {{_Version, 200, _Reason}, _Headers, Body}} ->
  102. {ok, Body};
  103. Error ->
  104. Error
  105. end.
  106. get_rebar_config() ->
  107. {ok, [[Home]]} = init:get_argument(home),
  108. ConfDir = filename:join(Home, ".config/rebar3"),
  109. case file:consult(filename:join(ConfDir, "rebar.config")) of
  110. {ok, Config} ->
  111. Config;
  112. _ ->
  113. []
  114. end.
  115. get_http_vars(Scheme) ->
  116. OS = case os:getenv(atom_to_list(Scheme)) of
  117. Str when is_list(Str) -> Str;
  118. _ -> []
  119. end,
  120. proplists:get_value(Scheme, get_rebar_config(), OS).
  121. set_httpc_options() ->
  122. set_httpc_options(https_proxy, get_http_vars(https_proxy)),
  123. set_httpc_options(proxy, get_http_vars(http_proxy)).
  124. set_httpc_options(_, []) ->
  125. ok;
  126. set_httpc_options(Scheme, Proxy) ->
  127. {ok, {_, _, Host, Port, _, _}} = http_uri:parse(Proxy),
  128. httpc:set_options([{Scheme, {{Host, Port}, []}}], rebar).
  129. compile(App, FirstFiles) ->
  130. Dir = filename:join(filename:absname("_build/default/lib/"), App),
  131. filelib:ensure_dir(filename:join([Dir, "ebin", "dummy.beam"])),
  132. code:add_path(filename:join(Dir, "ebin")),
  133. FirstFilesPaths = [filename:join([Dir, "src", Module]) || Module <- FirstFiles],
  134. Sources = FirstFilesPaths ++ filelib:wildcard(filename:join([Dir, "src", "*.erl"])),
  135. [compile_file(X, [{i, filename:join(Dir, "include")}
  136. ,debug_info
  137. ,{outdir, filename:join(Dir, "ebin")}
  138. ,return | additional_defines()]) || X <- Sources].
  139. compile_file(File, Opts) ->
  140. case compile:file(File, Opts) of
  141. {ok, _Mod} ->
  142. ok;
  143. {ok, _Mod, []} ->
  144. ok;
  145. {ok, _Mod, Ws} ->
  146. io:format("~s~n", [format_warnings(File, Ws)]),
  147. halt(1);
  148. {error, Es, Ws} ->
  149. io:format("~s ~s~n", [format_errors(File, Es), format_warnings(File, Ws)]),
  150. halt(1)
  151. end.
  152. bootstrap_rebar3() ->
  153. filelib:ensure_dir("_build/default/lib/rebar/ebin/dummy.beam"),
  154. code:add_path("_build/default/lib/rebar/ebin/"),
  155. ok = symlink_or_copy(filename:absname("src"),
  156. filename:absname("_build/default/lib/rebar/src")),
  157. Sources = ["src/rebar_resource.erl" | filelib:wildcard("src/*.erl")],
  158. [compile_file(X, [{outdir, "_build/default/lib/rebar/ebin/"}
  159. ,return | additional_defines()]) || X <- Sources],
  160. code:add_patha(filename:absname("_build/default/lib/rebar/ebin")).
  161. %%rebar.hrl
  162. -define(FMT(Str, Args), lists:flatten(io_lib:format(Str, Args))).
  163. %%/rebar.hrl
  164. %%rebar_file_utils
  165. symlink_or_copy(Source, Target) ->
  166. Link = case os:type() of
  167. {win32, _} ->
  168. Source;
  169. _ ->
  170. make_relative_path(Source, Target)
  171. end,
  172. case file:make_symlink(Link, Target) of
  173. ok ->
  174. ok;
  175. {error, eexist} ->
  176. ok;
  177. {error, _} ->
  178. cp_r([Source], Target)
  179. end.
  180. make_relative_path(Source, Target) ->
  181. do_make_relative_path(filename:split(Source), filename:split(Target)).
  182. do_make_relative_path([H|T1], [H|T2]) ->
  183. do_make_relative_path(T1, T2);
  184. do_make_relative_path(Source, Target) ->
  185. Base = lists:duplicate(max(length(Target) - 1, 0), ".."),
  186. filename:join(Base ++ Source).
  187. cp_r([], _Dest) ->
  188. ok;
  189. cp_r(Sources, Dest) ->
  190. case os:type() of
  191. {unix, _} ->
  192. EscSources = [escape_path(Src) || Src <- Sources],
  193. SourceStr = string:join(EscSources, " "),
  194. os:cmd(?FMT("cp -R ~s \"~s\"", [SourceStr, Dest])),
  195. ok;
  196. {win32, _} ->
  197. lists:foreach(fun(Src) -> ok = cp_r_win32(Src,Dest) end, Sources),
  198. ok
  199. end.
  200. xcopy_win32(Source,Dest)->
  201. R = os:cmd(?FMT("xcopy \"~s\" \"~s\" /q /y /e 2> nul",
  202. [filename:nativename(Source), filename:nativename(Dest)])),
  203. case length(R) > 0 of
  204. %% when xcopy fails, stdout is empty and and error message is printed
  205. %% to stderr (which is redirected to nul)
  206. true -> ok;
  207. false ->
  208. {error, lists:flatten(
  209. io_lib:format("Failed to xcopy from ~s to ~s~n",
  210. [Source, Dest]))}
  211. end.
  212. cp_r_win32({true, SourceDir}, {true, DestDir}) ->
  213. %% from directory to directory
  214. SourceBase = filename:basename(SourceDir),
  215. ok = case file:make_dir(filename:join(DestDir, SourceBase)) of
  216. {error, eexist} -> ok;
  217. Other -> Other
  218. end,
  219. ok = xcopy_win32(SourceDir, filename:join(DestDir, SourceBase));
  220. cp_r_win32({false, Source} = S,{true, DestDir}) ->
  221. %% from file to directory
  222. cp_r_win32(S, {false, filename:join(DestDir, filename:basename(Source))});
  223. cp_r_win32({false, Source},{false, Dest}) ->
  224. %% from file to file
  225. {ok,_} = file:copy(Source, Dest),
  226. ok;
  227. cp_r_win32({true, SourceDir}, {false, DestDir}) ->
  228. case filelib:is_regular(DestDir) of
  229. true ->
  230. %% From directory to file? This shouldn't happen
  231. {error, lists:flatten(
  232. io_lib:format("Cannot copy dir (~p) to file (~p)\n",
  233. [SourceDir, DestDir]))};
  234. false ->
  235. %% Specifying a target directory that doesn't currently exist.
  236. %% So let's attempt to create this directory
  237. case filelib:ensure_dir(filename:join(DestDir, "dummy")) of
  238. ok ->
  239. ok = xcopy_win32(SourceDir, DestDir);
  240. {error, Reason} ->
  241. {error, lists:flatten(
  242. io_lib:format("Unable to create dir ~p: ~p\n",
  243. [DestDir, Reason]))}
  244. end
  245. end;
  246. cp_r_win32(Source,Dest) ->
  247. Dst = {filelib:is_dir(Dest), Dest},
  248. lists:foreach(fun(Src) ->
  249. ok = cp_r_win32({filelib:is_dir(Src), Src}, Dst)
  250. end, filelib:wildcard(Source)),
  251. ok.
  252. escape_path(Str) ->
  253. re:replace(Str, "([ ()?])", "\\\\&", [global, {return, list}]).
  254. %%/rebar_file_utils
  255. setup_env() ->
  256. %% We don't need or want relx providers loaded yet
  257. application:load(rebar),
  258. {ok, Providers} = application:get_env(rebar, providers),
  259. Providers1 = Providers -- [rebar_prv_release,
  260. rebar_prv_relup,
  261. rebar_prv_tar],
  262. application:set_env(rebar, providers, Providers1).
  263. reset_env() ->
  264. %% Reset the env so we get all providers
  265. application:unset_env(rebar, providers),
  266. application:unload(rebar),
  267. application:load(rebar).
  268. write_windows_scripts() ->
  269. CmdScript=
  270. "@echo off\r\n"
  271. "setlocal\r\n"
  272. "set rebarscript=%~f0\r\n"
  273. "escript.exe \"%rebarscript:.cmd=%\" %*\r\n",
  274. ok = file:write_file("rebar3.cmd", CmdScript).
  275. get_deps() ->
  276. case file:consult("rebar.lock") of
  277. {ok, [[]]} ->
  278. %% Something went wrong in a previous build, lock file shouldn't be empty
  279. io:format("Empty list in lock file, deleting rebar.lock~n"),
  280. ok = file:delete("rebar.lock"),
  281. {ok, Config} = file:consult("rebar.config"),
  282. proplists:get_value(deps, Config);
  283. {ok, [Deps]} ->
  284. [{binary_to_atom(Name, utf8), "", Source} || {Name, Source, _Level} <- Deps];
  285. _ ->
  286. {ok, Config} = file:consult("rebar.config"),
  287. proplists:get_value(deps, Config)
  288. end.
  289. format_errors(Source, Errors) ->
  290. format_errors(Source, "", Errors).
  291. format_warnings(Source, Warnings) ->
  292. format_warnings(Source, Warnings, []).
  293. format_warnings(Source, Warnings, Opts) ->
  294. Prefix = case lists:member(warnings_as_errors, Opts) of
  295. true -> "";
  296. false -> "Warning: "
  297. end,
  298. format_errors(Source, Prefix, Warnings).
  299. format_errors(_MainSource, Extra, Errors) ->
  300. [begin
  301. [format_error(Source, Extra, Desc) || Desc <- Descs]
  302. end
  303. || {Source, Descs} <- Errors].
  304. format_error(AbsSource, Extra, {{Line, Column}, Mod, Desc}) ->
  305. ErrorDesc = Mod:format_error(Desc),
  306. io_lib:format("~s:~w:~w: ~s~s~n", [AbsSource, Line, Column, Extra, ErrorDesc]);
  307. format_error(AbsSource, Extra, {Line, Mod, Desc}) ->
  308. ErrorDesc = Mod:format_error(Desc),
  309. io_lib:format("~s:~w: ~s~s~n", [AbsSource, Line, Extra, ErrorDesc]);
  310. format_error(AbsSource, Extra, {Mod, Desc}) ->
  311. ErrorDesc = Mod:format_error(Desc),
  312. io_lib:format("~s: ~s~s~n", [AbsSource, Extra, ErrorDesc]).
  313. additional_defines() ->
  314. [{d, D} || {Re, D} <- [{"^[0-9]+", namespaced_types}, {"^R1[4|5]", deprecated_crypto}, {"^((1[8|9])|2)", rand_module}], is_otp_release(Re)].
  315. is_otp_release(ArchRegex) ->
  316. case re:run(otp_release(), ArchRegex, [{capture, none}]) of
  317. match ->
  318. true;
  319. nomatch ->
  320. false
  321. end.
  322. otp_release() ->
  323. otp_release1(erlang:system_info(otp_release)).
  324. %% If OTP <= R16, otp_release is already what we want.
  325. otp_release1([$R,N|_]=Rel) when is_integer(N) ->
  326. Rel;
  327. %% If OTP >= 17.x, erlang:system_info(otp_release) returns just the
  328. %% major version number, we have to read the full version from
  329. %% a file. See http://www.erlang.org/doc/system_principles/versions.html
  330. %% Read vsn string from the 'OTP_VERSION' file and return as list without
  331. %% the "\n".
  332. otp_release1(Rel) ->
  333. File = filename:join([code:root_dir(), "releases", Rel, "OTP_VERSION"]),
  334. case file:read_file(File) of
  335. {error, _} ->
  336. Rel;
  337. {ok, Vsn} ->
  338. %% It's fine to rely on the binary module here because we can
  339. %% be sure that it's available when the otp_release string does
  340. %% not begin with $R.
  341. Size = byte_size(Vsn),
  342. %% The shortest vsn string consists of at least two digits
  343. %% followed by "\n". Therefore, it's safe to assume Size >= 3.
  344. case binary:part(Vsn, {Size, -3}) of
  345. <<"**\n">> ->
  346. %% The OTP documentation mentions that a system patched
  347. %% using the otp_patch_apply tool available to licensed
  348. %% customers will leave a '**' suffix in the version as a
  349. %% flag saying the system consists of application versions
  350. %% from multiple OTP versions. We ignore this flag and
  351. %% drop the suffix, given for all intents and purposes, we
  352. %% cannot obtain relevant information from it as far as
  353. %% tooling is concerned.
  354. binary:bin_to_list(Vsn, {0, Size - 3});
  355. _ ->
  356. binary:bin_to_list(Vsn, {0, Size - 1})
  357. end
  358. end.