aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTristan Sloughter <[email protected]>2014-05-09 08:45:24 -0500
committerTristan Sloughter <[email protected]>2014-05-14 17:30:57 -0500
commitdd55959854069553b40f2bc2f2f7c5c7fc7c5a94 (patch)
tree967afbea1f132b9a962ea00f90b9680bc1f1e185
parent7d3626779ce5716055b31eed76feb81a9fcb2210 (diff)
downloadrelx-dd55959854069553b40f2bc2f2f7c5c7fc7c5a94.tar.gz
relx-dd55959854069553b40f2bc2f2f7c5c7fc7c5a94.tar.bz2
relx-dd55959854069553b40f2bc2f2f7c5c7fc7c5a94.zip
refactor tar and relup commands to own providers
-rw-r--r--src/relx.erl4
-rw-r--r--src/rlx_prv_archive.erl116
-rw-r--r--src/rlx_prv_assembler.erl267
-rw-r--r--src/rlx_prv_config.erl5
-rw-r--r--src/rlx_prv_discover.erl2
-rw-r--r--src/rlx_prv_relup.erl154
-rw-r--r--src/rlx_state.erl34
-rw-r--r--src/rlx_util.erl35
-rw-r--r--test/rlx_command_SUITE.erl2
-rw-r--r--test/rlx_release_SUITE.erl9
10 files changed, 355 insertions, 273 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) ->
diff --git a/test/rlx_command_SUITE.erl b/test/rlx_command_SUITE.erl
index e26e0ad..c34ed88 100644
--- a/test/rlx_command_SUITE.erl
+++ b/test/rlx_command_SUITE.erl
@@ -65,7 +65,7 @@ normal_passing_case(Config) ->
{ok, State2} = rlx_provider:do(ConfigProvider, State1),
?assertMatch([Lib1, Lib2],
rlx_state:lib_dirs(State2)),
- ?assertMatch(Outdir, rlx_state:output_dir(State2)),
+ ?assertMatch(Outdir, rlx_state:base_output_dir(State2)),
?assertMatch([{app1,{{33,33},{[],[<<"build4">>]}},lte},
{app2,
diff --git a/test/rlx_release_SUITE.erl b/test/rlx_release_SUITE.erl
index 0382a26..6f067dc 100644
--- a/test/rlx_release_SUITE.erl
+++ b/test/rlx_release_SUITE.erl
@@ -222,7 +222,6 @@ make_scriptless_release(Config) ->
?assert(lists:member({goal_app_2, "0.0.1"}, AppSpecs)),
?assert(lists:member({lib_dep_1, "0.0.1", load}, AppSpecs)).
-
make_overridden_release(Config) ->
DataDir = proplists:get_value(data_dir, Config),
OverrideDir1 = filename:join([DataDir, create_random_name("override_dir_")]),
@@ -565,10 +564,10 @@ overlay_release(Config) ->
?assert(lists:member({goal_app_2, "0.0.1"}, AppSpecs)),
?assert(lists:member({lib_dep_1, "0.0.1", load}, AppSpecs)),
- ?assert(ec_file:exists(filename:join(OutputDir, "fooo"))),
- ?assert(ec_file:exists(filename:join([OutputDir, "foodir", "vars1.config"]))),
- ?assert(ec_file:exists(filename:join([OutputDir, "yahoo", "vars1.config"]))),
- ?assert(ec_file:exists(filename:join([OutputDir, SecondTestDir, TestDir, TestFile]))),
+ ?assert(ec_file:exists(filename:join([OutputDir, "foo", "fooo"]))),
+ ?assert(ec_file:exists(filename:join([OutputDir, "foo", "foodir", "vars1.config"]))),
+ ?assert(ec_file:exists(filename:join([OutputDir, "foo", "yahoo", "vars1.config"]))),
+ ?assert(ec_file:exists(filename:join([OutputDir, "foo", SecondTestDir, TestDir, TestFile]))),
TemplateData = case file:consult(filename:join([OutputDir, "foo", "test_template_resolved"])) of
{ok, Details} ->