瀏覽代碼

Merge pull request #2257 from tsloughter/relx-4

initial relx 4.0 support
pull/2262/head
Tristan Sloughter 5 年之前
committed by GitHub
父節點
當前提交
9076a483cf
沒有發現已知的金鑰在資料庫的簽署中 GPG 金鑰 ID: 4AEE18F83AFDEB23
共有 11 個檔案被更改,包括 171 行新增107 行删除
  1. +1
    -1
      .cirrus.yml
  2. +4
    -1
      rebar.config
  3. +6
    -16
      rebar.lock
  4. +5
    -5
      src/rebar_app_discover.erl
  5. +53
    -22
      src/rebar_app_info.erl
  6. +3
    -2
      src/rebar_prv_release.erl
  7. +2
    -2
      src/rebar_prv_relup.erl
  8. +2
    -2
      src/rebar_prv_tar.erl
  9. +93
    -46
      src/rebar_relx.erl
  10. +1
    -5
      test/rebar_release_SUITE.erl
  11. +1
    -5
      test/rebar_test_utils.erl

+ 1
- 1
.cirrus.yml 查看文件

@ -2,11 +2,11 @@ test_task:
use_compute_credits: true
container:
matrix:
- image: erlang:23
- image: erlang:22
- image: erlang:21
- image: erlang:20
- image: erlang:19
- image: erlang:18
test_script: |
./bootstrap
./rebar3 ct

+ 4
- 1
rebar.config 查看文件

@ -8,7 +8,8 @@
{providers, "1.8.1"},
{getopt, "1.0.1"},
{bbmustache, "1.8.0"},
{relx, "3.33.0"},
%% {relx, "3.33.0"},
{relx, {git, "https://github.com/erlware/relx.git", {branch, "4.0.0"}}},
{cf, "0.2.2"},
{cth_readable, "1.4.8"},
{eunit_formatters, "0.5.0"}]}.
@ -29,6 +30,8 @@
{escript_incl_extra, [{"relx/priv/templates/*", "_build/default/lib/"},
{"rebar/priv/templates/*", "_build/default/lib/"}]}.
{overrides, [{add, relx, [{erl_opts, [{d, 'RLX_LOG', rebar_log}]}]}]}.
{erl_opts, [{platform_define, "^(19|2)", rand_only},
{platform_define, "^18", no_maps_update_with},
{platform_define, "^2", unicode_str},

+ 6
- 16
rebar.lock 查看文件

@ -1,4 +1,4 @@
{"1.2.0",
{"1.1.0",
[{<<"bbmustache">>,{pkg,<<"bbmustache">>,<<"1.8.0">>},0},
{<<"certifi">>,{pkg,<<"certifi">>,<<"2.5.1">>},0},
{<<"cf">>,{pkg,<<"cf">>,<<"0.2.2">>},0},
@ -8,7 +8,10 @@
{<<"getopt">>,{pkg,<<"getopt">>,<<"1.0.1">>},0},
{<<"parse_trans">>,{pkg,<<"parse_trans">>,<<"3.3.0">>},0},
{<<"providers">>,{pkg,<<"providers">>,<<"1.8.1">>},0},
{<<"relx">>,{pkg,<<"relx">>,<<"3.33.0">>},0},
{<<"relx">>,
{git,"https://github.com/erlware/relx.git",
{ref,"ad25111b7349c633fbec30f26c1ad03361d6b806"}},
0},
{<<"ssl_verify_fun">>,{pkg,<<"ssl_verify_fun">>,<<"1.1.5">>},0}]}.
[
{pkg_hash,[
@ -21,18 +24,5 @@
{<<"getopt">>, <<"C73A9FA687B217F2FF79F68A3B637711BB1936E712B521D8CE466B29CBF7808A">>},
{<<"parse_trans">>, <<"09765507A3C7590A784615CFD421D101AEC25098D50B89D7AA1D66646BC571C1">>},
{<<"providers">>, <<"70B4197869514344A8A60E2B2A4EF41CA03DEF43CFB1712ECF076A0F3C62F083">>},
{<<"relx">>, <<"AFC019320BB69881718576B3E4E1EB548C1FA3270717BA66A78004C98A77CD17">>},
{<<"ssl_verify_fun">>, <<"6EAF7AD16CB568BB01753DBBD7A95FF8B91C7979482B95F38443FE2C8852A79B">>}]},
{pkg_hash_ext,[
{<<"bbmustache">>, <<"190EA2206128BDFABF5D9200B8DF97F6511D9C62953655828E28C2BC79161252">>},
{<<"certifi">>, <<"805ABD97539CAF89EC6D4732C91E62BA9DA0CDA51AC462380BBD28EE697A8C42">>},
{<<"cf">>, <<"48283B3019BC7FAD56E7B23028A5DA4D3E6CD598A553AB2A99A2153BF5F19B21">>},
{<<"cth_readable">>, <<"46C3BB14DF581DC7A9DC0CB9E8C755BFF596665FB9A23148DD76E3A200804E90">>},
{<<"erlware_commons">>, <<"7AADA93F368D0A0430122E39931B7FB4AC9E94DBF043CDC980AD4330FD9CD166">>},
{<<"eunit_formatters">>, <<"D6C8BA213424944E6E05BBC097C32001CDD0ABE3925D02454F229B20D68763C9">>},
{<<"getopt">>, <<"53E1AB83B9CEB65C9672D3E7A35B8092E9BDC9B3EE80721471A161C10C59959C">>},
{<<"parse_trans">>, <<"17EF63ABDE837AD30680EA7F857DD9E7CED9476CDD7B0394432AF4BFC241B960">>},
{<<"providers">>, <<"E45745ADE9C476A9A469EA0840E418AB19360DC44F01A233304E118A44486BA0">>},
{<<"relx">>, <<"6E0456139FC70BADE0C45FF8A8197C5E879A57FD792F771FC632B94C5AEC1EAC">>},
{<<"ssl_verify_fun">>, <<"13104D7897E38ED7F044C4DE953A6C28597D1C952075EB2E328BC6D6F2BFC496">>}]}
{<<"ssl_verify_fun">>, <<"6EAF7AD16CB568BB01753DBBD7A95FF8B91C7979482B95F38443FE2C8852A79B">>}]}
].

+ 5
- 5
src/rebar_app_discover.erl 查看文件

@ -362,16 +362,16 @@ create_app_info(AppInfo, AppDir, AppFile) ->
rebar_app_info:original_vsn(
rebar_app_info:dir(AppInfo, AppDir), AppVsn), AppName),
AppInfo2 = rebar_app_info:applications(
rebar_app_info:app_details(AppInfo1, AppDetails),
IncludedApplications++Applications),
Valid = case rebar_app_utils:validate_application_info(AppInfo2) =:= true
andalso rebar_app_info:has_all_artifacts(AppInfo2) =:= true of
rebar_app_info:app_details(AppInfo1, AppDetails), Applications),
AppInfo3 = rebar_app_info:included_applications(AppInfo2, IncludedApplications),
Valid = case rebar_app_utils:validate_application_info(AppInfo3) =:= true
andalso rebar_app_info:has_all_artifacts(AppInfo3) =:= true of
true ->
true;
_ ->
false
end,
rebar_app_info:dir(rebar_app_info:valid(AppInfo2, Valid), AppDir);
rebar_app_info:dir(rebar_app_info:valid(AppInfo3, Valid), AppDir);
_Invalid ->
throw({error, {?MODULE, {cannot_read_app_file, AppFile}}})
catch

+ 53
- 22
src/rebar_app_info.erl 查看文件

@ -6,6 +6,7 @@
new/3,
new/4,
new/5,
app_to_map/1,
update_opts/3,
update_opts/2,
update_opts_deps/2,
@ -27,6 +28,8 @@
priv_dir/1,
applications/1,
applications/2,
included_applications/1,
included_applications/2,
profiles/1,
profiles/2,
deps/1,
@ -76,28 +79,29 @@
-type project_type() :: rebar3 | mix | undefined.
-record(app_info_t, {name :: binary() | undefined,
app_file_src :: file:filename_all() | undefined,
app_file_src_script:: file:filename_all() | undefined,
app_file :: file:filename_all() | undefined,
original_vsn :: binary() | undefined,
parent=root :: binary() | root,
app_details=[] :: list(),
applications=[] :: list(),
deps=[] :: list(),
profiles=[default] :: [atom()],
default=dict:new() :: rebar_dict(),
opts=dict:new() :: rebar_dict(),
dep_level=0 :: integer(),
dir :: file:name(),
out_dir :: file:name(),
ebin_dir :: file:name(),
source :: string() | tuple() | checkout | undefined,
is_lock=false :: boolean(),
is_checkout=false :: boolean(),
valid :: boolean() | undefined,
project_type :: project_type(),
is_available=false :: boolean()}).
-record(app_info_t, {name :: binary() | undefined,
app_file_src :: file:filename_all() | undefined,
app_file_src_script :: file:filename_all() | undefined,
app_file :: file:filename_all() | undefined,
original_vsn :: binary() | undefined,
parent=root :: binary() | root,
app_details=[] :: list(),
applications=[] :: list(),
included_applications=[] :: [atom()],
deps=[] :: list(),
profiles=[default] :: [atom()],
default=dict:new() :: rebar_dict(),
opts=dict:new() :: rebar_dict(),
dep_level=0 :: integer(),
dir :: file:name(),
out_dir :: file:name(),
ebin_dir :: file:name(),
source :: string() | tuple() | checkout | undefined,
is_lock=false :: boolean(),
is_checkout=false :: boolean(),
valid :: boolean() | undefined,
project_type :: project_type(),
is_available=false :: boolean()}).
%%============================================================================
%% types
@ -159,6 +163,22 @@ new(Parent, AppName, Vsn, Dir, Deps) ->
ebin_dir=filename:join(rebar_utils:to_list(Dir), "ebin"),
deps=Deps}}.
app_to_map(#app_info_t{name=Name,
original_vsn=Vsn,
applications=Applications,
included_applications=IncludedApplications,
out_dir=OutDir,
ebin_dir=EbinDir}) ->
%% TODO: call rlx_app_info to create map
#{name => ec_cnv:to_atom(Name),
vsn => Vsn,
applications => Applications,
included_applications => IncludedApplications,
dir => OutDir,
out_dir => OutDir,
ebin_dir => EbinDir,
link => false}.
%% @doc update the opts based on the contents of a config
%% file for the app
-spec update_opts(t(), rebar_dict(), [any()]) -> t().
@ -406,6 +426,17 @@ applications(#app_info_t{applications=Applications}) ->
applications(AppInfo=#app_info_t{}, Applications) ->
AppInfo#app_info_t{applications=Applications}.
%% @doc returns the list of included_applications the app depends on.
-spec included_applications(t()) -> list().
included_applications(#app_info_t{included_applications=Applications}) ->
Applications.
%% @doc sets the list of applications the app depends on.
%% Should be obtained from the app file.
-spec included_applications(t(), list()) -> t().
included_applications(AppInfo=#app_info_t{}, Applications) ->
AppInfo#app_info_t{included_applications=Applications}.
%% @doc returns the list of active profiles
-spec profiles(t()) -> list().
profiles(#app_info_t{profiles=Profiles}) ->

+ 3
- 2
src/rebar_prv_release.erl 查看文件

@ -9,6 +9,7 @@
do/1,
format_error/1]).
-include_lib("providers/include/providers.hrl").
-include("rebar.hrl").
-define(PROVIDER, release).
@ -27,12 +28,12 @@ init(State) ->
{example, "rebar3 release"},
{short_desc, "Build release of project."},
{desc, "Build release of project."},
{opts, relx:opt_spec_list()}])),
{opts, rebar_relx:opt_spec_list()}])),
{ok, State1}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) ->
rebar_relx:do(rlx_prv_release, "release", ?PROVIDER, State).
rebar_relx:do(?PROVIDER, State).
-spec format_error(any()) -> iolist().
format_error(Reason) ->

+ 2
- 2
src/rebar_prv_relup.erl 查看文件

@ -27,13 +27,13 @@ init(State) ->
{example, "rebar3 relup"},
{short_desc, "Create relup of releases."},
{desc, "Create relup of releases."},
{opts, relx:opt_spec_list()}]),
{opts, rebar_relx:opt_spec_list()}]),
State1 = rebar_state:add_provider(State, Provider),
{ok, State1}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) ->
rebar_relx:do(rlx_prv_release, "relup", ?PROVIDER, State).
rebar_relx:do(?PROVIDER, State).
-spec format_error(any()) -> iolist().
format_error(Reason) ->

+ 2
- 2
src/rebar_prv_tar.erl 查看文件

@ -27,12 +27,12 @@ init(State) ->
{example, "rebar3 tar"},
{short_desc, "Tar archive of release built of project."},
{desc, "Tar archive of release built of project."},
{opts, relx:opt_spec_list()}])),
{opts, rebar_relx:opt_spec_list()}])),
{ok, State1}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) ->
rebar_relx:do(rlx_prv_release, "tar", ?PROVIDER, State).
rebar_relx:do(?PROVIDER, State).
-spec format_error(any()) -> iolist().
format_error(Reason) ->

+ 93
- 46
src/rebar_relx.erl 查看文件

@ -3,71 +3,76 @@
-module(rebar_relx).
-export([do/4,
-export([do/2,
opt_spec_list/0,
format_error/1]).
-ifdef(TEST).
-export([merge_overlays/1]).
-endif.
-include_lib("providers/include/providers.hrl").
-include("rebar.hrl").
%% ===================================================================
%% Public API
%% ===================================================================
-spec do(atom(), string(), atom(), rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(Module, Command, Provider, State) ->
%% We set the color mode for relx as a application env
application:set_env(relx, color_intensity, rebar_log:intensity()),
LogLevel = rebar_log:get_level(),
Options = rebar_state:command_args(State),
DepsDir = rebar_dir:deps_dir(State),
ProjectAppDirs = lists:delete(".", ?DEFAULT_PROJECT_APP_DIRS),
LibDirs = rebar_utils:filtermap(fun ec_file:exists/1,
[rebar_dir:checkouts_dir(State), DepsDir | ProjectAppDirs]),
OutputDir = filename:join(rebar_dir:base_dir(State), ?DEFAULT_RELEASE_DIR),
-spec do(atom(), rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(Provider, State) ->
{Opts, _} = rebar_state:command_parsed_args(State),
Release = case proplists:get_value(relname, Opts, undefined) of
undefined ->
undefined;
R ->
case proplists:get_value(relvsn, Opts, undefined) of
undefined ->
list_to_atom(R);
RelVsn ->
{list_to_atom(R), RelVsn}
end
end,
%% TODO: read in ./relx.config if it exists or --config value
RelxConfig = rebar_state:get(State, relx, []),
ProfileString = rebar_dir:profile_dir_name(State),
AllOptions = rebar_string:join([Command | Options], " "),
Cwd = rebar_state:dir(State),
Providers = rebar_state:providers(State),
RebarOpts = rebar_state:opts(State),
ExtraOverlays = [{profile_string, ProfileString}],
ErlOpts = rebar_opts:erl_opts(RebarOpts),
DefaultOutputDir = filename:join(rebar_dir:base_dir(State), ?DEFAULT_RELEASE_DIR),
RelxConfig1 = [output_dir(DefaultOutputDir, Opts),
{overlay_vars_values, ExtraOverlays},
{overlay_vars, [{base_dir, rebar_dir:base_dir(State)}]}
| merge_overlays(RelxConfig)],
{ok, RelxState} = rlx_config:to_state(RelxConfig1),
Providers = rebar_state:providers(State),
Cwd = rebar_state:dir(State),
rebar_hooks:run_project_and_app_hooks(Cwd, pre, Provider, Providers, State),
try
case rebar_state:get(State, relx, []) of
[] ->
relx:main([{lib_dirs, LibDirs}
,{caller, api}
,{log_level, LogLevel}
,{api_caller_overlays, ExtraOverlays}
| output_dir(OutputDir, Options)] ++ ErlOpts, AllOptions);
Config ->
Config1 = [{overlay_vars, [{base_dir, rebar_dir:base_dir(State)}]}
| merge_overlays(Config)],
relx:main([{lib_dirs, LibDirs}
,{config, Config1}
,{caller, api}
,{log_level, LogLevel}
,{api_caller_overlays, ExtraOverlays}
| output_dir(OutputDir, Options)] ++ ErlOpts, AllOptions)
end,
rebar_hooks:run_project_and_app_hooks(Cwd, post, Provider, Providers, State),
{ok, State}
catch
throw:T ->
{error, {Module, T}}
end.
case Provider of
release ->
relx:build_release(Release, all_apps(State), RelxState);
tar ->
relx:build_tar(Release, all_apps(State), RelxState);
relup ->
ToVsn = proplists:get_value(relvsn, Opts, undefined),
UpFromVsn = proplists:get_value(upfrom, Opts, undefined),
relx:build_relup(Release, ToVsn, UpFromVsn, RelxState)
end,
rebar_hooks:run_project_and_app_hooks(Cwd, post, Provider, Providers, State),
{ok, State}.
-spec format_error(any()) -> iolist().
format_error(Reason) ->
io_lib:format("~p", [Reason]).
format_error(Error) ->
io_lib:format("~p", [Error]).
%% Don't override output_dir if the user passed one on the command line
output_dir(OutputDir, Options) ->
[{output_dir, OutputDir} || not(lists:member("-o", Options))
andalso not(lists:member("--output-dir", Options))].
output_dir(DefaultOutputDir, Options) ->
{output_dir, proplists:get_value(output_dir, Options, DefaultOutputDir)}.
merge_overlays(Config) ->
{Overlays, Others} =
@ -77,3 +82,45 @@ merge_overlays(Config) ->
%% Have profile overlay entries come before others to match how profiles work elsewhere
NewOverlay = lists:flatmap(fun({overlay, Overlay}) -> Overlay end, lists:reverse(Overlays)),
[{overlay, NewOverlay} | Others].
%%
%% Returns a map of all apps that are part of the rebar3 project.
%% This means the project apps and dependencies but not OTP libraries.
-spec all_apps(rebar_state:t()) -> #{atom() => rlx_app_info:t()}.
all_apps(State) ->
lists:foldl(fun(AppInfo, Acc) ->
Acc#{binary_to_atom(rebar_app_info:name(AppInfo), utf8)
=> rebar_app_info:app_to_map(AppInfo)}
end, #{}, rebar_state:project_apps(State) ++ rebar_state:all_deps(State)).
%%
-spec opt_spec_list() -> [getopt:option_spec()].
opt_spec_list() ->
[{relname, $n, "relname", string,
"Specify the name for the release that will be generated"},
{relvsn, $v, "relvsn", string, "Specify the version for the release"},
{upfrom, $u, "upfrom", string,
"Only valid with relup target, specify the release to upgrade from"},
{output_dir, $o, "output-dir", string,
"The output directory for the release. This is `./` by default."},
{help, $h, "help", undefined,
"Print usage"},
{lib_dir, $l, "lib-dir", string,
"Additional dir that should be searched for OTP Apps"},
{log_level, $V, "verbose", {integer, 2},
"Verbosity level, maybe between 0 and 3"},
{dev_mode, $d, "dev-mode", boolean,
"Symlink the applications and configuration into the release instead of copying"},
{include_erts, $i, "include-erts", string,
"If true include a copy of erts used to build with, if a path include erts at that path. If false, do not include erts"},
{override, $a, "override", string,
"Provide an app name and a directory to override in the form <appname>:<app directory>"},
{config, $c, "config", {string, ""}, "The path to a config file"},
{overlay_vars, undefined, "overlay_vars", string, "Path to a file of overlay variables"},
{vm_args, undefined, "vm_args", string, "Path to a file to use for vm.args"},
{sys_config, undefined, "sys_config", string, "Path to a file to use for sys.config"},
{system_libs, undefined, "system_libs", string, "Boolean or path to dir of Erlang system libs"},
{version, undefined, "version", undefined, "Print relx version"},
{root_dir, $r, "root", string, "The project root directory"}].

+ 1
- 5
test/rebar_release_SUITE.erl 查看文件

@ -190,11 +190,7 @@ user_output_dir(Config) ->
{ok, []}
),
RelxState = rlx_state:new("", [], []),
RelxState1 = rlx_state:base_output_dir(RelxState, ReleaseDir),
{ok, RelxState2} = rlx_prv_app_discover:do(RelxState1),
{ok, RelxState3} = rlx_prv_rel_discover:do(RelxState2),
rlx_state:get_realized_release(RelxState3, list_to_atom(Name), Vsn).
?assertNotMatch([], filelib:wildcard(filename:join([ReleaseDir, Name, "releases", Vsn, "*"]))).
profile_overlays(Config) ->
AppDir = ?config(apps, Config),

+ 1
- 5
test/rebar_test_utils.erl 查看文件

@ -392,10 +392,6 @@ check_results(AppDir, Expected, ProfileRun) ->
try
file:set_cwd(AppDir),
[ReleaseDir] = filelib:wildcard(filename:join([AppDir, "_build", "*", "rel"])),
RelxState = rlx_state:new("", [], []),
RelxState1 = rlx_state:base_output_dir(RelxState, ReleaseDir),
{ok, RelxState2} = rlx_prv_app_discover:do(RelxState1),
{ok, RelxState3} = rlx_prv_rel_discover:do(RelxState2),
LibDir = filename:join([ReleaseDir, Name, "lib"]),
{ok, RelLibs} = rebar_utils:list_dir(LibDir),
@ -407,7 +403,7 @@ check_results(AppDir, Expected, ProfileRun) ->
?assertEqual(ExpectedDevMode, DevMode),
%% throws not_found if it doesn't exist
rlx_state:get_realized_release(RelxState3, Name, Vsn)
ok
catch
_ ->
ct:fail(release_not_found)

Loading…
取消
儲存