aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/relx.erl4
-rw-r--r--src/rlx_cmd_args.erl253
-rw-r--r--src/rlx_prv_archive.erl116
-rw-r--r--src/rlx_prv_assembler.erl267
-rw-r--r--src/rlx_prv_config.erl51
-rw-r--r--src/rlx_prv_discover.erl2
-rw-r--r--src/rlx_prv_relup.erl154
-rw-r--r--src/rlx_state.erl127
-rw-r--r--src/rlx_util.erl35
-rw-r--r--test/rlx_command_SUITE.erl12
-rw-r--r--test/rlx_depsolver_tester.erl1
-rw-r--r--test/rlx_discover_SUITE.erl7
-rw-r--r--test/rlx_release_SUITE.erl7
13 files changed, 583 insertions, 453 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_cmd_args.erl b/src/rlx_cmd_args.erl
index da8f3a0..9233db9 100644
--- a/src/rlx_cmd_args.erl
+++ b/src/rlx_cmd_args.erl
@@ -33,16 +33,16 @@
{ok, {rlx_state:t(), [string()]}} |
relx:error().
args2state(Opts, Targets) ->
- RelName = rlx_util:to_atom(proplists:get_value(relname, Opts, undefined)),
- RelVsn = proplists:get_value(relvsn, Opts, undefined),
case convert_targets(Targets) of
{ok, AtomizedTargets} ->
- case create_log(Opts, [{relname, RelName},
- {relvsn, RelVsn}]) of
+ case run_creates(Opts) of
Error = {error, _} ->
Error;
{ok, CommandLineConfig} ->
- handle_config(Opts, AtomizedTargets, CommandLineConfig)
+ RelName = rlx_util:to_atom(proplists:get_value(relname, Opts, undefined)),
+ RelVsn = proplists:get_value(relvsn, Opts, undefined),
+ handle_config(Opts, AtomizedTargets,
+ [{default_release, {RelName, RelVsn}} | CommandLineConfig])
end;
Error ->
Error
@@ -95,7 +95,7 @@ handle_config(Opts, Targets, CommandLineConfig) ->
Error = {error, _} ->
Error;
{ok, Config} ->
- {ok, rlx_state:new([{config, Config} | CommandLineConfig], Targets)}
+ {ok, rlx_state:new(Config, CommandLineConfig, Targets)}
end.
-spec convert_targets([string()]) -> {ok, release | relup} | relx:error().
@@ -131,40 +131,137 @@ validate_config(Config) ->
?RLX_ERROR({invalid_config_file, Config})
end.
--spec create_log([getopt:option()], rlx_state:cmd_args()) ->
- {ok, rlx_state:cmd_args()} | relx:error().
-create_log(Opts, Acc) ->
+run_creates(Opts) ->
+ try
+ Conf = lists:flatten(lists:foldl(fun(X, Acc) ->
+ [create(X, Opts) | Acc]
+ end, [], proplists:get_keys(Opts))),
+ {ok, Conf}
+ catch
+ throw:E ->
+ E
+ end.
+
+create(log_level, Opts) ->
LogLevel = proplists:get_value(log_level, Opts, 0),
if
LogLevel >= 0, LogLevel =< 3 ->
- create_goals(Opts, [{log, ec_cmd_log:new(LogLevel, command_line)} | Acc]);
+ {log, ec_cmd_log:new(LogLevel, command_line)};
true ->
- ?RLX_ERROR({invalid_log_level, LogLevel})
- end.
-
--spec create_goals([getopt:option()], rlx_state:cmd_args()) ->
- {ok, rlx_state:cmd_args()} | relx:error().
-create_goals(Opts, Acc) ->
+ throw(?RLX_ERROR({invalid_log_level, LogLevel}))
+ end;
+create(goal, Opts) ->
Goals = proplists:get_value(goals, Opts, []) ++
proplists:get_all_values(goal, Opts),
case convert_goals(Goals, []) of
Error={error, _} ->
- Error;
+ throw(Error);
{ok, Specs} ->
- create_overrides(Opts, [{goals, Specs} | Acc])
- end.
-
--spec create_overrides([getopt:option()], rlx_state:cmd_args()) ->
- {ok, rlx_state:cmd_args()} | relx:error().
-create_overrides(Opts, Acc) ->
+ {goals, Specs}
+ end;
+create(goals, Opts) ->
+ Goals = proplists:get_value(goals, Opts, []) ++
+ proplists:get_all_values(goal, Opts),
+ case convert_goals(Goals, []) of
+ Error={error, _} ->
+ throw(Error);
+ {ok, Specs} ->
+ {goals, Specs}
+ end;
+create(overrides, Opts) ->
Overrides = proplists:get_all_values(override, Opts) ++
proplists:get_value(overrides, Opts, []),
case convert_overrides(Overrides, []) of
{ok, Overrides} ->
- create_output_dir(Opts, [{overrides, Overrides} | Acc]);
+ {overrides, Overrides};
Error ->
- Error
- end.
+ throw(Error)
+ end;
+create(output_dir, Opts) ->
+ OutputDir = proplists:get_value(output_dir, Opts, "./_rel"),
+ {output_dir, filename:absname(OutputDir)};
+create(lib_dir, Opts) ->
+ Dirs = proplists:get_all_values(lib_dir, Opts) ++
+ proplists:get_value(lib_dirs, Opts, []),
+ ExpDirs = rlx_util:wildcard_paths(Dirs),
+ case check_lib_dirs(ExpDirs) of
+ Error = {error, _} ->
+ throw(Error);
+ ok ->
+ LibDirs = [rlx_util:to_binary(Dir) || Dir <- ExpDirs],
+ {lib_dirs, LibDirs}
+ end;
+create(lib_dirs, Opts) ->
+ Dirs = proplists:get_all_values(lib_dir, Opts) ++
+ proplists:get_value(lib_dirs, Opts, []),
+ ExpDirs = rlx_util:wildcard_paths(Dirs),
+ case check_lib_dirs(ExpDirs) of
+ Error = {error, _} ->
+ throw(Error);
+ ok ->
+ LibDirs = [rlx_util:to_binary(Dir) || Dir <- ExpDirs],
+ {lib_dirs, LibDirs}
+ end;
+create(root_dir, Opts) ->
+ Dir = proplists:get_value(root_dir, Opts, undefined),
+ case Dir of
+ undefined ->
+ {ok, Cwd} = file:get_cwd(),
+ {root_dir, Cwd};
+ _ ->
+ {root_dir, filename:absname(Dir)}
+ end;
+create(default_libs, Opts) ->
+ Def = proplists:get_value(default_libs, Opts, true),
+ {default_libs, Def};
+create(overlay_vars, Opts)->
+ OverlayVars = proplists:get_all_values(overlay_vars, Opts),
+ {overlay_vars, OverlayVars};
+create(sys_config, Opts) ->
+ SysConfig = proplists:get_value(sys_config, Opts, undefined),
+ {sys_config, SysConfig};
+create(system_libs, Opts) ->
+ SystemLibs = proplists:get_value(system_libs, Opts, undefined),
+ {system_libs, SystemLibs};
+create(upfrom, Opts) ->
+ case proplists:get_value(upfrom, Opts, undefined) of
+ undefined ->
+ [];
+ UpFrom ->
+ {upfrom, UpFrom}
+ end;
+create(caller, Opts) ->
+ case proplists:get_value(caller, Opts, api) of
+ "command_line" ->
+ {caller, command_line};
+ "commandline" ->
+ {caller, command_line};
+ "api" ->
+ {caller, api};
+ api ->
+ {caller, api};
+ commandline ->
+ {caller, command_line};
+ command_line ->
+ {caller, command_line};
+ Caller ->
+ ?RLX_ERROR({invalid_caller, Caller})
+ end;
+create(paths, Opts) ->
+ Dirs = proplists:get_all_values(path, Opts) ++
+ proplists:get_value(paths, Opts, []),
+ case check_lib_dirs(Dirs) of
+ Error = {error, _} ->
+ throw(Error);
+ ok ->
+ code:add_pathsa([filename:absname(Path) || Path <- Dirs]),
+ []
+ end;
+create(dev_mode, Opts) ->
+ DevMode = proplists:get_value(dev_mode, Opts, false),
+ {dev_mode, DevMode};
+create(_, _) ->
+ [].
-spec convert_overrides([{atom(), string() | binary()} |
string() | binary()], [{atom(), string() | binary()}]) ->
@@ -212,110 +309,6 @@ parse_goal(RawSpec, Rest, Acc) ->
?RLX_ERROR({failed_to_parse, RawSpec})
end.
--spec create_output_dir([getopt:option()], rlx_state:cmd_args()) ->
- {ok, rlx_state:cmd_args()} | relx:error().
-create_output_dir(Opts, Acc) ->
- OutputDir = proplists:get_value(output_dir, Opts, "./_rel"),
- create_lib_dirs(Opts, [{output_dir, filename:absname(OutputDir)} | Acc]).
-
--spec create_lib_dirs([getopt:option()], rlx_state:cmd_args()) ->
- {ok, rlx_state:cmd_args()} | relx:error().
-create_lib_dirs(Opts, Acc) ->
- Dirs = proplists:get_all_values(lib_dir, Opts) ++
- proplists:get_value(lib_dirs, Opts, []),
- ExpDirs = rlx_util:wildcard_paths(Dirs),
- case check_lib_dirs(ExpDirs) of
- Error = {error, _} ->
- Error;
- ok ->
- create_root_dir(Opts, [{lib_dirs, ExpDirs} | Acc])
- end.
-
--spec create_root_dir([getopt:option()], rlx_state:cmd_args()) ->
- {ok, rlx_state:cmd_args()} | relx:error().
-create_root_dir(Opts, Acc) ->
- Dir = proplists:get_value(root_dir, Opts, undefined),
- case Dir of
- undefined ->
- {ok, Cwd} = file:get_cwd(),
- create_disable_default_libs(Opts, [{root_dir, Cwd} | Acc]);
- _ ->
- create_disable_default_libs(Opts, [{root_dir, Dir} | Acc])
- end.
-
--spec create_disable_default_libs([getopt:option()], rlx_state:cmd_args()) ->
- {ok, rlx_state:cmd_args()} | relx:error().
-create_disable_default_libs(Opts, Acc) ->
- Def = proplists:get_value(default_libs, Opts, true),
- create_overlay_vars(Opts, [{default_libs, Def} | Acc]).
-
--spec create_overlay_vars([getopt:option()], rlx_state:cmd_args()) ->
- {ok, rlx_state:cmd_args()} | relx:error().
-create_overlay_vars(Opts, Acc) ->
- OverlayVars = proplists:get_all_values(overlay_vars, Opts),
- create_sys_config(Opts, [{overlay_vars, OverlayVars} | Acc]).
-
--spec create_sys_config([getopt:option()], rlx_state:cmd_args()) ->
- {ok, rlx_state:cmd_args()} | relx:error().
-create_sys_config(Opts, Acc) ->
- SysConfig = proplists:get_value(sys_config, Opts, undefined),
- create_system_libs(Opts, [{sys_config, SysConfig} | Acc]).
-
--spec create_system_libs([getopt:option()], rlx_state:cmd_args()) ->
- {ok, rlx_state:cmd_args()} | relx:error().
-create_system_libs(Opts, Acc) ->
- SystemLibs = proplists:get_value(system_libs, Opts, undefined),
- create_upfrom(Opts, [{system_libs, SystemLibs} | Acc]).
-
--spec create_upfrom([getopt:option()], rlx_state:cmd_args()) ->
- {ok, rlx_state:cmd_args()} | relx:error().
-create_upfrom(Opts, Acc) ->
- case proplists:get_value(upfrom, Opts, undefined) of
- undefined ->
- create_caller(Opts, Acc);
- UpFrom ->
- create_caller(Opts, [{upfrom, UpFrom} | Acc])
- end.
-
--spec create_caller([getopt:option()], rlx_state:cmd_args()) ->
- {ok, rlx_state:cmd_args()} | relx:error().
-create_caller(Opts, Acc) ->
- case proplists:get_value(caller, Opts, api) of
- "command_line" ->
- create_paths(Opts, [{caller, command_line} | Acc]);
- "commandline" ->
- create_paths(Opts, [{caller, command_line} | Acc]);
- "api" ->
- create_paths(Opts, [{caller, api} | Acc]);
- api ->
- create_paths(Opts, [{caller, api} | Acc]);
- commandline ->
- create_paths(Opts, [{caller, command_line} | Acc]);
- command_line ->
- create_paths(Opts, [{caller, command_line} | Acc]);
- Caller ->
- ?RLX_ERROR({invalid_caller, Caller})
- end.
-
--spec create_paths([getopt:option()], rlx_state:cmd_args()) ->
- {ok, rlx_state:cmd_args()} | relx:error().
-create_paths(Opts, Acc) ->
- Dirs = proplists:get_all_values(path, Opts) ++
- proplists:get_value(paths, Opts, []),
- case check_lib_dirs(Dirs) of
- Error = {error, _} ->
- Error;
- ok ->
- code:add_pathsa([filename:absname(Path) || Path <- Dirs]),
- create_dev_mode(Opts, Acc)
- end.
-
--spec create_dev_mode([getopt:option()], rlx_state:cmd_args()) ->
- {ok, rlx_state:cmd_args()} | relx:error().
-create_dev_mode(Opts, Acc) ->
- DevMode = proplists:get_value(dev_mode, Opts, false),
- {ok, [{dev_mode, DevMode} | Acc]}.
-
-spec check_lib_dirs([string()]) -> ok | relx:error().
check_lib_dirs([]) ->
ok;
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 47d96aa..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 9efd8a0..c795334 100644
--- a/src/rlx_prv_config.erl
+++ b/src/rlx_prv_config.erl
@@ -114,23 +114,29 @@ load_config(ConfigFile, State) ->
{error, Reason} ->
?RLX_ERROR({consult, ConfigFile, Reason});
{ok, Terms} ->
- lists:foldl(fun load_terms/2, {ok, State}, Terms)
+ CliTerms = rlx_state:cli_args(State),
+ lists:foldl(fun load_terms/2, {ok, State}, merge_configs(CliTerms, Terms))
end,
ok = file:set_cwd(CurrentCwd),
Result.
-spec load_terms(term(), {ok, rlx_state:t()} | relx:error()) ->
{ok, rlx_state:t()} | relx:error().
-load_terms({default_release, RelName, RelVsn}, {ok, State}) ->
- case rlx_state:default_configured_release(State) of
- {undefined, undefined} ->
- {ok, rlx_state:default_configured_release(State, RelName, RelVsn)};
- _ ->
- {ok, State}
- end;
+load_terms({default_release, {RelName, RelVsn}}, {ok, State}) ->
+ {ok, rlx_state:default_configured_release(State, RelName, RelVsn)};
load_terms({paths, Paths}, {ok, State}) ->
code:add_pathsa([filename:absname(Path) || Path <- Paths]),
{ok, State};
+load_terms({default_libs, DefaultLibs}, {ok, State}) ->
+ State2 = rlx_state:put(State,
+ default_libs,
+ DefaultLibs),
+ {ok, State2};
+load_terms({system_libs, SystemLibs}, {ok, State}) ->
+ State2 = rlx_state:put(State,
+ system_libs,
+ SystemLibs),
+ {ok, State2};
load_terms({lib_dirs, Dirs}, {ok, State}) ->
State2 =
rlx_state:add_lib_dirs(State,
@@ -159,6 +165,10 @@ load_terms({overrides, Overrides0}, {ok, State0}) ->
{ok, rlx_state:overrides(State0, Overrides0)};
load_terms({dev_mode, DevMode}, {ok, State0}) ->
{ok, rlx_state:dev_mode(State0, DevMode)};
+load_terms({goals, Goals}, {ok, State0}) ->
+ {ok, rlx_state:goals(State0, Goals)};
+load_terms({upfrom, UpFrom}, {ok, State0}) ->
+ {ok, rlx_state:upfrom(State0, UpFrom)};
load_terms({include_src, IncludeSrc}, {ok, State0}) ->
{ok, rlx_state:include_src(State0, IncludeSrc)};
load_terms({release, {RelName, Vsn, {extend, RelName2}}, Applications}, {ok, State0}) ->
@@ -199,6 +209,8 @@ load_terms({sys_config, SysConfig}, {ok, State}) ->
_ ->
{ok, State}
end;
+load_terms({root_dir, Root}, {ok, State}) ->
+ {ok, rlx_state:root_dir(State, filename:absname(Root))};
load_terms({output_dir, OutputDir}, {ok, State}) ->
{ok, rlx_state:base_output_dir(State, filename:absname(OutputDir))};
load_terms({overlay_vars, OverlayVars}, {ok, State}) ->
@@ -232,3 +244,26 @@ list_of_overlay_vars_files([H | _]=FileNames) when erlang:is_list(H) ->
FileNames;
list_of_overlay_vars_files(FileName) when is_list(FileName) ->
[FileName].
+
+merge_configs([], ConfigTerms) ->
+ ConfigTerms;
+merge_configs([{_Key, undefined} | CliTerms], ConfigTerms) ->
+ merge_configs(CliTerms, ConfigTerms);
+merge_configs([{_Key, []} | CliTerms], ConfigTerms) ->
+ merge_configs(CliTerms, ConfigTerms);
+merge_configs([{Key, Value} | CliTerms], ConfigTerms) ->
+ case Key of
+ X when X =:= lib_dirs
+ ; X =:= goals
+ ; X =:= overlay_vars
+ ; X =:= overrides ->
+ case lists:keyfind(Key, 1, ConfigTerms) of
+ {Key, Value2} ->
+ MergedValue = lists:umerge([Value, Value2]),
+ merge_configs(CliTerms, lists:keyreplace(Key, 1, ConfigTerms, {Key, MergedValue}));
+ false ->
+ merge_configs(CliTerms, [{Key, Value} | ConfigTerms])
+ end;
+ _ ->
+ merge_configs(CliTerms, [{Key, Value} | ConfigTerms])
+ end.
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 5b488c8..d212dcf 100644
--- a/src/rlx_state.erl
+++ b/src/rlx_state.erl
@@ -24,6 +24,7 @@
-module(rlx_state).
-export([new/2,
+ new/3,
log/1,
actions/1,
output_dir/1,
@@ -36,8 +37,11 @@
skip_apps/1,
skip_apps/2,
goals/1,
+ goals/2,
config_file/1,
config_file/2,
+ cli_args/1,
+ cli_args/2,
providers/1,
providers/2,
vm_args/1,
@@ -68,6 +72,7 @@
include_src/1,
include_src/2,
upfrom/1,
+ upfrom/2,
format/1,
format/2]).
@@ -84,13 +89,14 @@
output_dir :: file:name(),
lib_dirs=[] :: [file:name()],
config_file=[] :: file:filename() | undefined,
+ cli_args=[] :: proplists:proplist(),
goals=[] :: [rlx_depsolver:constraint()],
providers=[] :: [rlx_provider:t()],
available_apps=[] :: [rlx_app_info:t()],
- default_configured_release :: {rlx_release:name(), rlx_release:vsn()},
+ default_configured_release :: {rlx_release:name(), rlx_release:vsn()} | undefined,
vm_args :: file:filename() | undefined,
sys_config :: file:filename() | undefined,
- overrides :: [{AppName::atom(), Directory::file:filename()}],
+ overrides=[] :: [{AppName::atom(), Directory::file:filename()}],
skip_apps=[] :: [AppName::atom()],
configured_releases :: releases(),
realized_releases :: releases(),
@@ -116,45 +122,36 @@
%%============================================================================
%% API
%%============================================================================
-%% @doc Create a new 'log level' for the system
--spec new(proplists:proplist(), undefined | [atom()]) -> t().
-new(PropList, undefined) ->
- new(PropList, [release]);
-new(PropList, Targets)
- when erlang:is_list(PropList),
+-spec new(string(), undefined | [atom()]) -> t().
+new(Config, Targets) ->
+ new(Config, [], Targets).
+
+-spec new(string(), proplists:proplist(), undefined | [atom()]) -> t().
+new(Config, CommandLineConfig, undefined) ->
+ new(Config, CommandLineConfig, [release]);
+new(Config, CommandLineConfig, Targets)
+ when erlang:is_list(CommandLineConfig),
erlang:is_list(Targets) ->
{ok, Root} = file:get_cwd(),
- Caller = proplists:get_value(caller, PropList, api),
- State0 =
- #state_t{log = proplists:get_value(log, PropList, ec_cmd_log:new(error, Caller)),
- output_dir=proplists:get_value(output_dir, PropList, ""),
- lib_dirs=[to_binary(Dir) || Dir <- proplists:get_value(lib_dirs, PropList, [])],
- config_file=proplists:get_value(config, PropList, undefined),
- sys_config=proplists:get_value(sys_config, PropList, undefined),
- dev_mode = proplists:get_value(dev_mode, PropList),
- actions = Targets,
- caller = Caller,
- goals=proplists:get_value(goals, PropList, []),
- providers = [],
- configured_releases=ec_dictionary:new(ec_dict),
- realized_releases=ec_dictionary:new(ec_dict),
- config_values=ec_dictionary:new(ec_dict),
- overrides = proplists:get_value(overrides, PropList, []),
- root_dir = filename:absname(proplists:get_value(root_dir, PropList, Root)),
- upfrom = proplists:get_value(upfrom, PropList, undefined),
- default_configured_release={proplists:get_value(relname, PropList, undefined),
- proplists:get_value(relvsn, PropList, undefined)}},
- State1 = rlx_state:put(create_logic_providers(State0),
- default_libs,
- proplists:get_value(default_libs, PropList, true)),
-
- State2 = rlx_state:put(create_logic_providers(State1),
- system_libs,
- proplists:get_value(system_libs, PropList, undefined)),
-
- rlx_state:put(create_logic_providers(State2),
- overlay_vars,
- proplists:get_value(overlay_vars, PropList, [])).
+
+ Caller = proplists:get_value(caller, CommandLineConfig, api),
+ Log = proplists:get_value(log, CommandLineConfig, ec_cmd_log:new(error, Caller)),
+ State0 = #state_t{log=Log,
+ config_file=Config,
+ cli_args=CommandLineConfig,
+ actions=Targets,
+ caller=Caller,
+ root_dir=Root,
+ output_dir=filename:join(Root, "_rel"),
+ providers=[],
+ 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)},
+ State1 = rlx_state:put(State0, default_libs, true),
+ State2 = rlx_state:put(State1, system_libs, undefined),
+ State3 = rlx_state:put(State2, overlay_vars, []),
+ create_logic_providers(State3).
%% @doc the actions targeted for this system
-spec actions(t()) -> [action()].
@@ -210,6 +207,10 @@ add_lib_dirs(State=#state_t{lib_dirs=LibDir}, Dirs) ->
goals(#state_t{goals=TS}) ->
TS.
+-spec goals(t(), [rlx_depsolver:constraint()]) -> t().
+goals(State, Goals) ->
+ State#state_t{goals=Goals}.
+
-spec config_file(t()) -> file:filename() | undefined.
config_file(#state_t{config_file=ConfigFiles}) ->
ConfigFiles.
@@ -218,6 +219,14 @@ config_file(#state_t{config_file=ConfigFiles}) ->
config_file(State, ConfigFiles) ->
State#state_t{config_file=ConfigFiles}.
+-spec cli_args(t()) -> proplists:proplist().
+cli_args(#state_t{cli_args=CliArgs}) ->
+ CliArgs.
+
+-spec cli_args(t(), proplists:proplist()) -> t().
+cli_args(State, CliArgs) ->
+ State#state_t{cli_args=CliArgs}.
+
-spec providers(t()) -> [rlx_provider:t()].
providers(#state_t{providers=Providers}) ->
Providers.
@@ -356,6 +365,10 @@ include_src(S, IncludeSrc) ->
upfrom(#state_t{upfrom=UpFrom}) ->
UpFrom.
+-spec upfrom(t(), string() | binary() | undefined) -> t().
+upfrom(State, UpFrom) ->
+ State#state_t{upfrom=UpFrom}.
+
-spec format(t()) -> iolist().
format(Mod) ->
format(Mod, 0).
@@ -390,17 +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]}.
-
-to_binary(Dir)
- when erlang:is_list(Dir) ->
- erlang:list_to_binary(Dir);
-to_binary(Dir)
- when erlang:is_binary(Dir) ->
- Dir.
+ 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
@@ -411,7 +438,7 @@ to_binary(Dir)
new_test() ->
LogState = ec_cmd_log:new(error),
- RCLState = new([{log, 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 2e1ef1d..c34ed88 100644
--- a/test/rlx_command_SUITE.erl
+++ b/test/rlx_command_SUITE.erl
@@ -61,15 +61,17 @@ normal_passing_case(Config) ->
"-n", RelName, "-v", RelVsn, "-o", Outdir],
{ok, {Opts, Targets}} = getopt:parse(relx:opt_spec_list(), CmdLine),
{ok, State} = rlx_cmd_args:args2state(Opts, Targets),
+ {ConfigProvider, {ok, State1}} = rlx_provider:new(rlx_prv_config, State),
+ {ok, State2} = rlx_provider:do(ConfigProvider, State1),
?assertMatch([Lib1, Lib2],
- rlx_state:lib_dirs(State)),
- ?assertMatch(Outdir, rlx_state:base_output_dir(State)),
+ rlx_state:lib_dirs(State2)),
+ ?assertMatch(Outdir, rlx_state:base_output_dir(State2)),
?assertMatch([{app1,{{33,33},{[],[<<"build4">>]}},lte},
{app2,
{{33,22},{[],[]}},
{{45,22},{[],[<<"build">>,21]}}, between}],
- rlx_state:goals(State)).
+ rlx_state:goals(State2)).
lib_expansion_case(Config) ->
DataDir = proplists:get_value(data_dir, Config),
@@ -81,8 +83,10 @@ lib_expansion_case(Config) ->
CmdLine = ["-l", filename:join(DataDir, "*")],
{ok, {Opts, Targets}} = getopt:parse(relx:opt_spec_list(), CmdLine),
{ok, State} = rlx_cmd_args:args2state(Opts, Targets),
+ {ConfigProvider, {ok, State1}} = rlx_provider:new(rlx_prv_config, State),
+ {ok, State2} = rlx_provider:do(ConfigProvider, State1),
?assertMatch([Lib1, Lib2],
- rlx_state:lib_dirs(State)).
+ rlx_state:lib_dirs(State2)).
lib_fail_case(Config) ->
DataDir = proplists:get_value(data_dir, Config),
diff --git a/test/rlx_depsolver_tester.erl b/test/rlx_depsolver_tester.erl
index 2dddf76..b441a1e 100644
--- a/test/rlx_depsolver_tester.erl
+++ b/test/rlx_depsolver_tester.erl
@@ -365,7 +365,6 @@ fix_rebar_brokenness(Filename) ->
true ->
Alt2;
false ->
- io:format("~p~n", [Alt2]),
erlang:throw(unable_to_find_data_files)
end
end.
diff --git a/test/rlx_discover_SUITE.erl b/test/rlx_discover_SUITE.erl
index 8ea95c4..7e7015c 100644
--- a/test/rlx_discover_SUITE.erl
+++ b/test/rlx_discover_SUITE.erl
@@ -48,10 +48,12 @@ init_per_testcase(_, Config) ->
LibDir2 = filename:join([DataDir, create_random_name("lib_dir2_")]),
ok = rlx_util:mkdir_p(LibDir1),
ok = rlx_util:mkdir_p(LibDir2),
- State = rlx_state:new([{lib_dirs, [LibDir1, LibDir2]}], [release]),
+ State = rlx_state:new([], [{lib_dirs, [LibDir1, LibDir2]}], [release]),
+ {ConfigProvider, {ok, State1}} = rlx_provider:new(rlx_prv_config, State),
+ {ok, State2} = rlx_provider:do(ConfigProvider, State1),
[{lib1, LibDir1},
{lib2, LibDir2},
- {state, State} | Config].
+ {state, State2} | Config].
all() ->
@@ -78,6 +80,7 @@ normal_case(Config) ->
default_libs, false),
{DiscoverProvider, {ok, State1}} = rlx_provider:new(rlx_prv_discover, State0),
{ok, State2} = rlx_provider:do(DiscoverProvider, State1),
+
lists:foreach(fun(App) ->
?assertMatch(true, lists:member(App, rlx_state:available_apps(State2)))
end, Apps1),
diff --git a/test/rlx_release_SUITE.erl b/test/rlx_release_SUITE.erl
index 730e1d1..6f067dc 100644
--- a/test/rlx_release_SUITE.erl
+++ b/test/rlx_release_SUITE.erl
@@ -60,9 +60,11 @@ init_per_testcase(_, Config) ->
DataDir = proplists:get_value(data_dir, Config),
LibDir1 = filename:join([DataDir, create_random_name("lib_dir1_")]),
ok = rlx_util:mkdir_p(LibDir1),
- State = rlx_state:new([{lib_dirs, [LibDir1]}], [release]),
+ State = rlx_state:new([], [{lib_dirs, [LibDir1]}], [release]),
+ {ConfigProvider, {ok, State1}} = rlx_provider:new(rlx_prv_config, State),
+ {ok, State2} = rlx_provider:do(ConfigProvider, State1),
[{lib1, LibDir1},
- {state, State} | Config].
+ {state, State2} | Config].
all() ->
[make_release, make_extend_release, make_scriptless_release,
@@ -220,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_")]),