diff options
author | Tristan Sloughter <[email protected]> | 2014-05-09 08:45:24 -0500 |
---|---|---|
committer | Tristan Sloughter <[email protected]> | 2014-05-14 17:30:57 -0500 |
commit | dd55959854069553b40f2bc2f2f7c5c7fc7c5a94 (patch) | |
tree | 967afbea1f132b9a962ea00f90b9680bc1f1e185 /src | |
parent | 7d3626779ce5716055b31eed76feb81a9fcb2210 (diff) | |
download | relx-dd55959854069553b40f2bc2f2f7c5c7fc7c5a94.tar.gz relx-dd55959854069553b40f2bc2f2f7c5c7fc7c5a94.tar.bz2 relx-dd55959854069553b40f2bc2f2f7c5c7fc7c5a94.zip |
refactor tar and relup commands to own providers
Diffstat (limited to 'src')
-rw-r--r-- | src/relx.erl | 4 | ||||
-rw-r--r-- | src/rlx_prv_archive.erl | 116 | ||||
-rw-r--r-- | src/rlx_prv_assembler.erl | 267 | ||||
-rw-r--r-- | src/rlx_prv_config.erl | 5 | ||||
-rw-r--r-- | src/rlx_prv_discover.erl | 2 | ||||
-rw-r--r-- | src/rlx_prv_relup.erl | 154 | ||||
-rw-r--r-- | src/rlx_state.erl | 34 | ||||
-rw-r--r-- | src/rlx_util.erl | 35 |
8 files changed, 350 insertions, 267 deletions
diff --git a/src/relx.erl b/src/relx.erl index 79eeae2..769668a 100644 --- a/src/relx.erl +++ b/src/relx.erl @@ -118,7 +118,7 @@ do(RootDir, RelName, RelVsn, Goals, LibDirs, LogLevel, OutputDir, Configs) -> -spec do(file:name(), atom(), string(), [goal()], [file:name()], ec_cmd_log:log_level(), [file:name()], [{atom(), file:name()}], file:name() | undefined) -> ok | error() | {ok, rlx_state:t()}. -do(RootDir, RelName, RelVsn, Goals, LibDirs, LogLevel, OutputDir, Overrides, Config) -> +do(RootDir, RelName, RelVsn, Goals, LibDirs, LogLevel, OutputDir, Overrides, Config) -> do([{relname, RelName}, {relvsn, RelVsn}, {goals, Goals}, @@ -258,7 +258,7 @@ handle_output(_State, command_line, _) -> handle_output(_State, api, Result) -> Result. -run_providers(ConfigProvider, Providers, State0) -> +run_providers(ConfigProvider, Providers, State0) -> case Providers of [ConfigProvider | Rest] -> %% IF the config provider is still the first provider do not run it diff --git a/src/rlx_prv_archive.erl b/src/rlx_prv_archive.erl new file mode 100644 index 0000000..3ad06b4 --- /dev/null +++ b/src/rlx_prv_archive.erl @@ -0,0 +1,116 @@ +%% -*- erlang-indent-level: 4; indent-tabs-mode: nil; fill-column: 80 -*- +%%% Copyright 2014 Erlware, LLC. All Rights Reserved. +%%% +%%% This file is provided to you under the Apache License, +%%% Version 2.0 (the "License"); you may not use this file +%%% except in compliance with the License. You may obtain +%%% a copy of the License at +%%% +%%% http://www.apache.org/licenses/LICENSE-2.0 +%%% +%%% Unless required by applicable law or agreed to in writing, +%%% software distributed under the License is distributed on an +%%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +%%% KIND, either express or implied. See the License for the +%%% specific language governing permissions and limitations +%%% under the License. +%%%--------------------------------------------------------------------------- +%%% @author Tristan Sloughter <[email protected]> +%%% @copyright (C) 2014 Erlware, LLC. +%%% +%%% @doc Given a complete built release this provider assembles that release +%%% into a release directory. +-module(rlx_prv_archive). + +-behaviour(rlx_provider). + +-export([init/1, + do/1, + format_error/1]). + +-include("relx.hrl"). + +%%============================================================================ +%% API +%%============================================================================ +-spec init(rlx_state:t()) -> {ok, rlx_state:t()}. +init(State) -> + {ok, State}. + +-spec do(rlx_state:t()) -> {ok, rlx_state:t()} | relx:error(). +do(State) -> + {RelName, RelVsn} = rlx_state:default_configured_release(State), + Release = rlx_state:get_realized_release(State, RelName, RelVsn), + OutputDir = rlx_state:output_dir(State), + make_tar(State, Release, OutputDir). + +format_error({tar_unknown_generation_error, Module, Vsn}) -> + io_lib:format("Tarball generation error of ~s ~s", + [Module, Vsn]); +format_error({tar_generation_warn, Module, Warnings}) -> + io_lib:format("Tarball generation warnings for ~p : ~p", + [Module, Warnings]); +format_error({tar_generation_error, Module, Errors}) -> + io_lib:format("Tarball generation error for ~p reason ~p", + [Module, Errors]). + +make_tar(State, Release, OutputDir) -> + Name = atom_to_list(rlx_release:name(Release)), + Vsn = rlx_release:vsn(Release), + ErtsVersion = rlx_release:erts(Release), + Opts = [{path, [filename:join([OutputDir, "lib", "*", "ebin"])]}, + {outdir, OutputDir} | + case rlx_state:get(State, include_erts, true) of + true -> + Prefix = code:root_dir(), + ErtsDir = filename:join([Prefix]), + [{erts, ErtsDir}]; + false -> + []; + Prefix -> + ErtsDir = filename:join([Prefix]), + [{erts, ErtsDir}] + end], + case systools:make_tar(filename:join([OutputDir, "releases", Vsn, Name]), + Opts) of + ok -> + TempDir = ec_file:insecure_mkdtemp(), + try + update_tar(State, TempDir, OutputDir, Name, Vsn, ErtsVersion) + catch + E:R -> + ec_file:remove(TempDir, [recursive]), + ?RLX_ERROR({tar_generation_error, E, R}) + end; + {ok, Module, Warnings} -> + ?RLX_ERROR({tar_generation_warn, Module, Warnings}); + error -> + ?RLX_ERROR({tar_unknown_generation_error, Name, Vsn}); + {error, Module, Errors} -> + ?RLX_ERROR({tar_generation_error, Module, Errors}) + end. + +update_tar(State, TempDir, OutputDir, Name, Vsn, ErtsVersion) -> + TarFile = filename:join(OutputDir, Name++"-"++Vsn++".tar.gz"), + file:rename(filename:join(OutputDir, Name++".tar.gz"), TarFile), + erl_tar:extract(TarFile, [{cwd, TempDir}, compressed]), + ok = + erl_tar:create(TarFile, + [{"lib", filename:join(TempDir, "lib")}, + {"releases", filename:join(TempDir, "releases")}, + {filename:join(["releases", "RELEASES"]), + filename:join([OutputDir, "releases", "RELEASES"])}, + {filename:join(["releases", Vsn, "vm.args"]), + filename:join([OutputDir, "releases", Vsn, "vm.args"])}, + {"bin", filename:join([OutputDir, "bin"])} | + case rlx_state:get(State, include_erts, true) of + false -> + []; + _ -> + [{"erts-"++ErtsVersion, filename:join(OutputDir, "erts-"++ErtsVersion)}] + end], [compressed]), + ec_cmd_log:info(rlx_state:log(State), + "tarball ~s successfully created!~n", [TarFile]), + ec_file:remove(TempDir, [recursive]), + {ok, State}. + diff --git a/src/rlx_prv_assembler.erl b/src/rlx_prv_assembler.erl index 1afd18d..827b4c1 100644 --- a/src/rlx_prv_assembler.erl +++ b/src/rlx_prv_assembler.erl @@ -40,49 +40,21 @@ init(State) -> %% @doc recursively dig down into the library directories specified in the state %% looking for OTP Applications -spec do(rlx_state:t()) -> {ok, rlx_state:t()} | relx:error(). -do(State) -> +do(State) -> print_dev_mode(State), {RelName, RelVsn} = rlx_state:default_configured_release(State), Release = rlx_state:get_realized_release(State, RelName, RelVsn), - OutputDir = rlx_state:output_dir(State), + OutputDir = rlx_state:output_dir(State), case create_output_dir(OutputDir) of ok -> case rlx_release:realized(Release) of - true -> - run_actions(State, Release, OutputDir); + true -> + copy_app_directories_to_output(State, Release, OutputDir); false -> ?RLX_ERROR({unresolved_release, RelName, RelVsn}) end; Error -> - Error - end. - -do(release, State, Release, OutputDir) -> - copy_app_directories_to_output(State, Release, OutputDir); -do(relup, State, Release, _OutputDir) -> - RelName = rlx_release:name(Release), - RelVsn = rlx_release:vsn(Release), - Release0 = rlx_state:get_realized_release(State, RelName, RelVsn), - make_relup(State, Release0); -do(tar, State, Release, OutputDir) -> - make_tar(State, Release, OutputDir). - -run_actions(State, Release, OutputDir) -> - run_actions(State, Release, OutputDir, rlx_state:actions(State), [release, relup, tar]). - -run_actions(State, _Release, _OutputDir, _Actions, []) -> - {ok, State}; -run_actions(State, Release, OutputDir, Actions, [H | T]) -> - case lists:member(H, Actions) of - true -> - case do(H, State, Release, OutputDir) of - {ok, NewState} -> - run_actions(NewState, Release, OutputDir, Actions, T); - Error -> - Error - end; - false -> - run_actions(State, Release, OutputDir, Actions, T) + Error end. -spec format_error(ErrorDetail::term()) -> iolist(). @@ -109,37 +81,10 @@ format_error({unable_to_create_output_dir, OutputDir}) -> format_error({release_script_generation_error, Module, Errors}) -> ["Errors generating release \n", rlx_util:indent(2), Module:format_error(Errors)]; -format_error({relup_generation_error, CurrentName, UpFromName}) -> - io_lib:format("Unknown internal release error generating the relup from ~s to ~s", - [UpFromName, CurrentName]); -format_error({relup_generation_warning, Module, Warnings}) -> - ["Warnings generating relup \s", - rlx_util:indent(2), Module:format_warning(Warnings)]; -format_error({no_upfrom_release_found, undefined}) -> - io_lib:format("No earlier release for relup found", []); -format_error({no_upfrom_release_found, Vsn}) -> - io_lib:format("Upfrom release version (~s) for relup not found", [Vsn]); -format_error({relup_script_generation_error, - {relup_script_generation_error, systools_relup, - {missing_sasl, _}}}) -> - "Unfortunately, due to requirements in systools, you need to have the sasl application " - "in both the current release and the release to upgrade from."; -format_error({relup_script_generation_error, Module, Errors}) -> - ["Errors generating relup \n", - rlx_util:indent(2), Module:format_error(Errors)]; format_error({unable_to_make_symlink, AppDir, TargetDir, Reason}) -> io_lib:format("Unable to symlink directory ~s to ~s because \n~s~s", [AppDir, TargetDir, rlx_util:indent(2), - file:format_error(Reason)]); -format_error({tar_unknown_generation_error, Module, Vsn}) -> - io_lib:format("Tarball generation error of ~s ~s", - [Module, Vsn]); -format_error({tar_generation_warn, Module, Warnings}) -> - io_lib:format("Tarball generation warnings for ~p : ~p", - [Module, Warnings]); -format_error({tar_generation_error, Module, Errors}) -> - io_lib:format("Tarball generation error for ~p reason ~p", - [Module, Errors]). + file:format_error(Reason)]). %%%=================================================================== %%% Internal Functions @@ -174,13 +119,13 @@ copy_app_directories_to_output(State, Release, OutputDir) -> IncludeSrc = rlx_state:include_src(State), Apps = prepare_applications(State, rlx_release:application_details(Release)), Result = lists:filter(fun({error, _}) -> - true; - (_) -> - false - end, - lists:flatten(ec_plists:map(fun(App) -> - copy_app(LibDir, App, IncludeSrc) - end, Apps))), + true; + (_) -> + false + end, + lists:flatten(ec_plists:map(fun(App) -> + copy_app(LibDir, App, IncludeSrc) + end, Apps))), case Result of [E | _] -> E; @@ -274,7 +219,7 @@ copy_dir(AppDir, TargetDir, SubDir) -> create_release_info(State0, Release0, OutputDir) -> RelName = atom_to_list(rlx_release:name(Release0)), - ReleaseDir = release_output_dir(State0, Release0), + ReleaseDir = rlx_util:release_output_dir(State0, Release0), ReleaseFile = filename:join([ReleaseDir, RelName ++ ".rel"]), ok = ec_file:mkdir_p(ReleaseDir), Release1 = rlx_release:relfile(Release0, ReleaseFile), @@ -287,7 +232,6 @@ create_release_info(State0, Release0, OutputDir) -> E end. - write_bin_file(State, Release, OutputDir, RelDir) -> RelName = erlang:atom_to_list(rlx_release:name(Release)), RelVsn = rlx_release:vsn(Release), @@ -466,12 +410,12 @@ include_erts(State, Release, OutputDir, RelDir) -> -spec make_boot_script(rlx_state:t(), rlx_release:t(), file:name(), file:name()) -> {ok, rlx_state:t()} | relx:error(). make_boot_script(State, Release, OutputDir, RelDir) -> - Options = [{path, [RelDir | get_code_paths(Release, OutputDir)]}, + Options = [{path, [RelDir | rlx_util:get_code_paths(Release, OutputDir)]}, {outdir, RelDir}, no_module_tests, silent], Name = erlang:atom_to_list(rlx_release:name(Release)), ReleaseFile = filename:join([RelDir, Name ++ ".rel"]), - case make_script(Options, + case rlx_util:make_script(Options, fun(CorrectedOptions) -> systools:make_script(Name, CorrectedOptions) end) of @@ -493,95 +437,6 @@ make_boot_script(State, Release, OutputDir, RelDir) -> ?RLX_ERROR({release_script_generation_error, Module, Error}) end. --spec make_script([term()], - fun(([term()]) -> Res)) -> Res. -make_script(Options, RunFun) -> - %% Erts 5.9 introduced a non backwards compatible option to - %% erlang this takes that into account - Erts = erlang:system_info(version), - case ec_semver:gte(Erts, "5.9") of - true -> - RunFun([no_warn_sasl | Options]); - _ -> - RunFun(Options) - end. - -make_relup(State, Release) -> - Vsn = rlx_state:upfrom(State), - UpFrom = - case Vsn of - undefined -> - get_last_release(State, Release); - Vsn -> - get_up_release(State, Release, Vsn) - end, - case UpFrom of - undefined -> - ?RLX_ERROR({no_upfrom_release_found, Vsn}); - _ -> - make_upfrom_script(State, Release, UpFrom) - end. - -make_tar(State, Release, OutputDir) -> - Name = atom_to_list(rlx_release:name(Release)), - Vsn = rlx_release:vsn(Release), - ErtsVersion = rlx_release:erts(Release), - Opts = [{path, [filename:join([OutputDir, "lib", "*", "ebin"])]}, - {outdir, OutputDir} | - case rlx_state:get(State, include_erts, true) of - true -> - Prefix = code:root_dir(), - ErtsDir = filename:join([Prefix]), - [{erts, ErtsDir}]; - false -> - []; - Prefix -> - ErtsDir = filename:join([Prefix]), - [{erts, ErtsDir}] - end], - case systools:make_tar(filename:join([OutputDir, "releases", Vsn, Name]), - Opts) of - ok -> - TempDir = ec_file:insecure_mkdtemp(), - try - update_tar(State, TempDir, OutputDir, Name, Vsn, ErtsVersion) - catch - E:R -> - ec_file:remove(TempDir, [recursive]), - ?RLX_ERROR({tar_generation_error, E, R}) - end; - {ok, Module, Warnings} -> - ?RLX_ERROR({tar_generation_warn, Module, Warnings}); - error -> - ?RLX_ERROR({tar_unknown_generation_error, Name, Vsn}); - {error, Module, Errors} -> - ?RLX_ERROR({tar_generation_error, Module, Errors}) - end. - -update_tar(State, TempDir, OutputDir, Name, Vsn, ErtsVersion) -> - TarFile = filename:join(OutputDir, Name++"-"++Vsn++".tar.gz"), - file:rename(filename:join(OutputDir, Name++".tar.gz"), TarFile), - erl_tar:extract(TarFile, [{cwd, TempDir}, compressed]), - ok = - erl_tar:create(TarFile, - [{"lib", filename:join(TempDir, "lib")}, - {"releases", filename:join(TempDir, "releases")}, - {filename:join(["releases", "RELEASES"]), - filename:join([OutputDir, "releases", "RELEASES"])}, - {filename:join(["releases", Vsn, "vm.args"]), - filename:join([OutputDir, "releases", Vsn, "vm.args"])}, - {"bin", filename:join([OutputDir, "bin"])} | - case rlx_state:get(State, include_erts, true) of - false -> - []; - _ -> - [{"erts-"++ErtsVersion, filename:join(OutputDir, "erts-"++ErtsVersion)}] - end], [compressed]), - ec_cmd_log:info(rlx_state:log(State), - "tarball ~s successfully created!~n", [TarFile]), - ec_file:remove(TempDir, [recursive]), - {ok, State}. - create_RELEASES(OutputDir, ReleaseFile) -> {ok, OldCWD} = file:get_cwd(), file:set_cwd(OutputDir), @@ -591,96 +446,6 @@ create_RELEASES(OutputDir, ReleaseFile) -> []), file:set_cwd(OldCWD). -make_upfrom_script(State, Release, UpFrom) -> - OutputDir = rlx_state:output_dir(State), - Options = [{outdir, OutputDir}, - {path, get_code_paths(Release, OutputDir) ++ - get_code_paths(UpFrom, OutputDir)}, - silent], - CurrentRel = strip_rel(rlx_release:relfile(Release)), - UpFromRel = strip_rel(rlx_release:relfile(UpFrom)), - ec_cmd_log:debug(rlx_state:log(State), - "systools:make_relup(~p, ~p, ~p, ~p)", - [CurrentRel, UpFromRel, UpFromRel, Options]), - case make_script(Options, - fun(CorrectOptions) -> - systools:make_relup(CurrentRel, [UpFromRel], [UpFromRel], CorrectOptions) - end) of - ok -> - ec_cmd_log:error(rlx_state:log(State), - "relup from ~s to ~s successfully created!", - [UpFromRel, CurrentRel]), - {ok, State}; - error -> - ?RLX_ERROR({relup_script_generation_error, CurrentRel, UpFromRel}); - {ok, RelUp, _, []} -> - ec_cmd_log:error(rlx_state:log(State), - "relup successfully created!"), - write_relup_file(State, Release, RelUp), - {ok, State}; - {ok,_, Module,Warnings} -> - ?RLX_ERROR({relup_script_generation_warn, Module, Warnings}); - {error,Module,Errors} -> - ?RLX_ERROR({relup_script_generation_error, Module, Errors}) - end. - -write_relup_file(State, Release, Relup) -> - OutDir = release_output_dir(State, Release), - RelupFile = filename:join(OutDir, "relup"), - ok = ec_file:write_term(RelupFile, Relup). - -strip_rel(Name) -> - rlx_util:to_string(filename:join(filename:dirname(Name), - filename:basename(Name, ".rel"))). - -get_up_release(State, Release, Vsn) -> - Name = rlx_release:name(Release), - try - ec_dictionary:get({Name, Vsn}, rlx_state:realized_releases(State)) - catch - throw:not_found -> - undefined - end. - -get_last_release(State, Release) -> - Releases0 = [Rel || {{_, _}, Rel} <- ec_dictionary:to_list(rlx_state:realized_releases(State))], - Releases1 = lists:sort(fun(R1, R2) -> - ec_semver:lte(rlx_release:vsn(R1), - rlx_release:vsn(R2)) - end, Releases0), - Res = lists:foldl(fun(_Rel, R = {found, _}) -> - R; - (Rel, Prev) -> - case rlx_release:vsn(Rel) == rlx_release:vsn(Release) of - true -> - {found, Prev}; - false -> - Rel - end - end, undefined, Releases1), - case Res of - {found, R} -> - R; - Else -> - Else - end. - --spec release_output_dir(rlx_state:t(), rlx_release:t()) -> string(). -release_output_dir(State, Release) -> - OutputDir = rlx_state:output_dir(State), - filename:join([OutputDir, - "releases", - rlx_release:vsn(Release)]). - -%% @doc Generates the correct set of code paths for the system. --spec get_code_paths(rlx_release:t(), file:name()) -> [file:name()]. -get_code_paths(Release, OutDir) -> - LibDir = filename:join(OutDir, "lib"), - [filename:join([LibDir, - erlang:atom_to_list(rlx_app_info:name(App)) ++ "-" ++ - rlx_app_info:original_vsn(App), "ebin"]) || - App <- rlx_release:application_details(Release)]. - unless_exists_write_default(Path, File) -> case ec_file:exists(Path) of true -> diff --git a/src/rlx_prv_config.erl b/src/rlx_prv_config.erl index dd7dc70..c795334 100644 --- a/src/rlx_prv_config.erl +++ b/src/rlx_prv_config.erl @@ -137,11 +137,6 @@ load_terms({system_libs, SystemLibs}, {ok, State}) -> system_libs, SystemLibs), {ok, State2}; -load_terms({overlay_vars, OverlayVars}, {ok, State}) -> - State2 = rlx_state:put(State, - overlay_vars, - list_of_overlay_vars_files(OverlayVars)), - {ok, State2}; load_terms({lib_dirs, Dirs}, {ok, State}) -> State2 = rlx_state:add_lib_dirs(State, diff --git a/src/rlx_prv_discover.erl b/src/rlx_prv_discover.erl index 5d09619..21e5687 100644 --- a/src/rlx_prv_discover.erl +++ b/src/rlx_prv_discover.erl @@ -128,7 +128,7 @@ add_release_output_dir(State) -> true -> []; false -> - Output = erlang:iolist_to_binary(rlx_state:output_dir(State)), + Output = erlang:iolist_to_binary(rlx_state:base_output_dir(State)), case ec_file:exists(erlang:binary_to_list(Output)) of true -> Output; diff --git a/src/rlx_prv_relup.erl b/src/rlx_prv_relup.erl new file mode 100644 index 0000000..241d45b --- /dev/null +++ b/src/rlx_prv_relup.erl @@ -0,0 +1,154 @@ +%% -*- erlang-indent-level: 4; indent-tabs-mode: nil; fill-column: 80 -*- +%%% Copyright 2014 Erlware, LLC. All Rights Reserved. +%%% +%%% This file is provided to you under the Apache License, +%%% Version 2.0 (the "License"); you may not use this file +%%% except in compliance with the License. You may obtain +%%% a copy of the License at +%%% +%%% http://www.apache.org/licenses/LICENSE-2.0 +%%% +%%% Unless required by applicable law or agreed to in writing, +%%% software distributed under the License is distributed on an +%%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +%%% KIND, either express or implied. See the License for the +%%% specific language governing permissions and limitations +%%% under the License. +%%%--------------------------------------------------------------------------- +%%% @author Tristan Sloughter <[email protected]> +%%% @copyright (C) 2014 Erlware, LLC. +%%% +%%% @doc Given a complete built release this provider assembles that release +%%% into a release directory. +-module(rlx_prv_relup). + +-behaviour(rlx_provider). + +-export([init/1, + do/1, + format_error/1]). + +-include("relx.hrl"). + +%%============================================================================ +%% API +%%============================================================================ +-spec init(rlx_state:t()) -> {ok, rlx_state:t()}. +init(State) -> + {ok, State}. + +-spec do(rlx_state:t()) -> {ok, rlx_state:t()} | relx:error(). +do(State) -> + {RelName, RelVsn} = rlx_state:default_configured_release(State), + Release0 = rlx_state:get_realized_release(State, RelName, RelVsn), + make_relup(State, Release0). + +format_error({relup_generation_error, CurrentName, UpFromName}) -> + io_lib:format("Unknown internal release error generating the relup from ~s to ~s", + [UpFromName, CurrentName]); +format_error({relup_generation_warning, Module, Warnings}) -> + ["Warnings generating relup \s", + rlx_util:indent(2), Module:format_warning(Warnings)]; +format_error({no_upfrom_release_found, undefined}) -> + io_lib:format("No earlier release for relup found", []); +format_error({no_upfrom_release_found, Vsn}) -> + io_lib:format("Upfrom release version (~s) for relup not found", [Vsn]); +format_error({relup_script_generation_error, + {relup_script_generation_error, systools_relup, + {missing_sasl, _}}}) -> + "Unfortunately, due to requirements in systools, you need to have the sasl application " + "in both the current release and the release to upgrade from."; +format_error({relup_script_generation_error, Module, Errors}) -> + ["Errors generating relup \n", + rlx_util:indent(2), Module:format_error(Errors)]. + +make_relup(State, Release) -> + Vsn = rlx_state:upfrom(State), + UpFrom = + case Vsn of + undefined -> + get_last_release(State, Release); + Vsn -> + get_up_release(State, Release, Vsn) + end, + case UpFrom of + undefined -> + ?RLX_ERROR({no_upfrom_release_found, Vsn}); + _ -> + make_upfrom_script(State, Release, UpFrom) + end. + +get_last_release(State, Release) -> + Releases0 = [Rel || {{_, _}, Rel} <- ec_dictionary:to_list(rlx_state:realized_releases(State))], + Releases1 = lists:sort(fun(R1, R2) -> + ec_semver:lte(rlx_release:vsn(R1), + rlx_release:vsn(R2)) + end, Releases0), + Res = lists:foldl(fun(_Rel, R = {found, _}) -> + R; + (Rel, Prev) -> + case rlx_release:vsn(Rel) == rlx_release:vsn(Release) of + true -> + {found, Prev}; + false -> + Rel + end + end, undefined, Releases1), + case Res of + {found, R} -> + R; + Else -> + Else + end. + +get_up_release(State, Release, Vsn) -> + Name = rlx_release:name(Release), + try + ec_dictionary:get({Name, Vsn}, rlx_state:realized_releases(State)) + catch + throw:not_found -> + undefined + end. + +make_upfrom_script(State, Release, UpFrom) -> + OutputDir = rlx_state:output_dir(State), + Options = [{outdir, OutputDir}, + {path, rlx_util:get_code_paths(Release, OutputDir) ++ + rlx_util:get_code_paths(UpFrom, OutputDir)}, + silent], + CurrentRel = strip_rel(rlx_release:relfile(Release)), + UpFromRel = strip_rel(rlx_release:relfile(UpFrom)), + ec_cmd_log:debug(rlx_state:log(State), + "systools:make_relup(~p, ~p, ~p, ~p)", + [CurrentRel, UpFromRel, UpFromRel, Options]), + case rlx_util:make_script(Options, + fun(CorrectOptions) -> + systools:make_relup(CurrentRel, [UpFromRel], [UpFromRel], CorrectOptions) + end) of + ok -> + ec_cmd_log:error(rlx_state:log(State), + "relup from ~s to ~s successfully created!", + [UpFromRel, CurrentRel]), + {ok, State}; + error -> + ?RLX_ERROR({relup_script_generation_error, CurrentRel, UpFromRel}); + {ok, RelUp, _, []} -> + ec_cmd_log:error(rlx_state:log(State), + "relup successfully created!"), + write_relup_file(State, Release, RelUp), + {ok, State}; + {ok,_, Module,Warnings} -> + ?RLX_ERROR({relup_script_generation_warn, Module, Warnings}); + {error,Module,Errors} -> + ?RLX_ERROR({relup_script_generation_error, Module, Errors}) + end. + +write_relup_file(State, Release, Relup) -> + OutDir = rlx_util:release_output_dir(State, Release), + RelupFile = filename:join(OutDir, "relup"), + ok = ec_file:write_term(RelupFile, Relup). + +strip_rel(Name) -> + rlx_util:to_string(filename:join(filename:dirname(Name), + filename:basename(Name, ".rel"))). + diff --git a/src/rlx_state.erl b/src/rlx_state.erl index c84be78..d212dcf 100644 --- a/src/rlx_state.erl +++ b/src/rlx_state.erl @@ -135,8 +135,7 @@ new(Config, CommandLineConfig, Targets) {ok, Root} = file:get_cwd(), Caller = proplists:get_value(caller, CommandLineConfig, api), - Log = proplists:get_value(log, CommandLineConfig, ec_cmd_log:new(error, Caller)), - + Log = proplists:get_value(log, CommandLineConfig, ec_cmd_log:new(error, Caller)), State0 = #state_t{log=Log, config_file=Config, cli_args=CommandLineConfig, @@ -148,7 +147,7 @@ new(Config, CommandLineConfig, Targets) default_configured_release=undefined, configured_releases=ec_dictionary:new(ec_dict), realized_releases=ec_dictionary:new(ec_dict), - config_values=ec_dictionary:new(ec_dict)}, + config_values=ec_dictionary:new(ec_dict)}, State1 = rlx_state:put(State0, default_libs, true), State2 = rlx_state:put(State1, system_libs, undefined), State3 = rlx_state:put(State2, overlay_vars, []), @@ -404,10 +403,31 @@ create_logic_providers(State0) -> {ConfigProvider, {ok, State1}} = rlx_provider:new(rlx_prv_config, State0), {DiscoveryProvider, {ok, State2}} = rlx_provider:new(rlx_prv_discover, State1), {ReleaseProvider, {ok, State3}} = rlx_provider:new(rlx_prv_release, State2), - {OverlayProvider, {ok, State4}} = rlx_provider:new(rlx_prv_overlay, State3), - {AssemblerProvider, {ok, State5}} = rlx_provider:new(rlx_prv_assembler, State4), + {OverlayProvider, {ok, State4}} = rlx_provider:new(rlx_prv_overlay, State3), + {ActionProviders, State5} = add_providers([release, relup, tar], State4), State5#state_t{providers=[ConfigProvider, DiscoveryProvider, - ReleaseProvider, OverlayProvider, AssemblerProvider]}. + ReleaseProvider, OverlayProvider | ActionProviders]}. + +add_providers(Actions, State) -> + add_providers(Actions, [], State). + +add_providers([], Providers, State) -> + {lists:reverse(Providers), State}; +add_providers([Action | T], Providers, State) -> + case lists:member(Action, actions(State)) of + true -> + {Provider, {ok, State1}} = new_provider(Action, State), + add_providers(T, [Provider | Providers], State1); + false -> + add_providers(T, Providers, State) + end. + +new_provider(release, State) -> + rlx_provider:new(rlx_prv_assembler, State); +new_provider(relup, State) -> + rlx_provider:new(rlx_prv_relup, State); +new_provider(tar, State) -> + rlx_provider:new(rlx_prv_archive, State). %%%=================================================================== %%% Test Functions @@ -418,7 +438,7 @@ create_logic_providers(State0) -> new_test() -> LogState = ec_cmd_log:new(error), - RCLState = new(LogState, [], [release]), + RCLState = new("", [{log, LogState}], [release]), ?assertMatch(LogState, log(RCLState)). -endif. diff --git a/src/rlx_util.erl b/src/rlx_util.erl index 48e2ee1..9c4dcc2 100644 --- a/src/rlx_util.erl +++ b/src/rlx_util.erl @@ -21,7 +21,10 @@ %%% @doc Trivial utility file to help handle common tasks -module(rlx_util). --export([mkdir_p/1, +-export([get_code_paths/2, + release_output_dir/2, + make_script/2, + mkdir_p/1, to_binary/1, to_string/1, to_atom/1, @@ -40,6 +43,36 @@ %%============================================================================ %% API %%============================================================================ + +%% @doc Generates the correct set of code paths for the system. +-spec get_code_paths(rlx_release:t(), file:name()) -> [file:name()]. +get_code_paths(Release, OutDir) -> + LibDir = filename:join(OutDir, "lib"), + [filename:join([LibDir, + erlang:atom_to_list(rlx_app_info:name(App)) ++ "-" ++ + rlx_app_info:original_vsn(App), "ebin"]) || + App <- rlx_release:application_details(Release)]. + +-spec release_output_dir(rlx_state:t(), rlx_release:t()) -> string(). +release_output_dir(State, Release) -> + OutputDir = rlx_state:output_dir(State), + filename:join([OutputDir, + "releases", + rlx_release:vsn(Release)]). + +-spec make_script([term()], + fun(([term()]) -> Res)) -> Res. +make_script(Options, RunFun) -> + %% Erts 5.9 introduced a non backwards compatible option to + %% erlang this takes that into account + Erts = erlang:system_info(version), + case ec_semver:gte(Erts, "5.9") of + true -> + RunFun([no_warn_sasl | Options]); + _ -> + RunFun(Options) + end. + %% @doc Makes a directory including parent dirs if they are missing. -spec mkdir_p(string()) -> ok | {error, Reason::file:posix()}. mkdir_p(Path) -> |