aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile3
-rw-r--r--README.md4
-rwxr-xr-xpriv/templates/bin.dtl10
-rw-r--r--priv/templates/extended_bin.dtl129
-rw-r--r--priv/templates/install_upgrade_escript.dtl32
-rw-r--r--priv/templates/nodetool.dtl2
-rw-r--r--rebar.config4
-rw-r--r--src/relx.erl27
-rw-r--r--src/rlx_app_discovery.erl49
-rw-r--r--src/rlx_cmd_args.erl38
-rw-r--r--src/rlx_config.erl64
-rw-r--r--src/rlx_prv_app_discover.erl (renamed from src/rlx_prv_discover.erl)67
-rw-r--r--src/rlx_prv_archive.erl56
-rw-r--r--src/rlx_prv_assembler.erl121
-rw-r--r--src/rlx_prv_overlay.erl118
-rw-r--r--src/rlx_prv_rel_discover.erl92
-rw-r--r--src/rlx_prv_release.erl120
-rw-r--r--src/rlx_prv_relup.erl25
-rw-r--r--src/rlx_rel_discovery.erl4
-rw-r--r--src/rlx_release.erl14
-rw-r--r--src/rlx_state.erl28
-rw-r--r--src/rlx_topo.erl6
-rw-r--r--test/rlx_archive_SUITE.erl132
-rw-r--r--test/rlx_discover_SUITE.erl18
-rw-r--r--test/rlx_release_SUITE.erl628
-rw-r--r--test/rlx_test_utils.erl98
26 files changed, 1181 insertions, 708 deletions
diff --git a/Makefile b/Makefile
index ad4b5d6..43f0d7e 100644
--- a/Makefile
+++ b/Makefile
@@ -101,7 +101,8 @@ ct: compile clean-common-test-data
-logdir $(CURDIR)/logs \
-dir $(CURDIR)/test/ \
-cover cover.spec \
- -suite rlx_command_SUITE rlx_discover_SUITE -suite rlx_release_SUITE
+ -suite rlx_command_SUITE rlx_discover_SUITE -suite rlx_release_SUITE \
+ -suite rlx_archive_SUITE
test: compile dialyzer eunit ct
diff --git a/README.md b/README.md
index 9e7217c..672290f 100644
--- a/README.md
+++ b/README.md
@@ -67,13 +67,13 @@ Options
| Short | Long | Type | Default | Description |
|:-----:|:------------:|:-------:|:------:|------------------------------------------------------------------------------------------- |
| -r | --root | string | ./ | Sets the root of the project |
-| -n | --name | string | | Name for the release that will be generated |
+| -n | --relname | string | | Name for the release that will be generated |
| -v | --relvsn | string | | Version for the release |
| -g | --goal | string | | A goal for the system. These are usually the OTP apps that are part of the release |
| -u | --upfrom | string | | The release to upgrade from. Only valid with relup target |
| -o | --output-dir | string | ./ | The output directory for the release |
| -l | --lib-dir | string | | Additional dirs to search for OTP apps |
-| | --system_libs | string | | Path to a Erlang system libs to use |
+| | --system_libs | boolean/string | true | If true include a copy of system libs used to build with, if a path include system libs at that path. If false, do not include system libs |
| -p | --path | string | | Additional dirs to add to Erlang code path |
| | --default-libs | boolean | true | Whether to use the default system added lib dirs (means you must add them all manually) |
| -V | --verbose | integer | 2 | The verbosity level between 0 and 3 |
diff --git a/priv/templates/bin.dtl b/priv/templates/bin.dtl
index bb83434..3398d63 100755
--- a/priv/templates/bin.dtl
+++ b/priv/templates/bin.dtl
@@ -17,12 +17,11 @@ find_erts_dir() {
ROOTDIR="$RELEASE_ROOT_DIR"
else
local erl="$(which erl)"
- code="io:format(\"~s\", [code:root_dir()]), halt()."
- local erl_root="$("$erl" -noshell -eval "$code")"
+ code="io:format(\"~s\", [code:root_dir()])."
+ local erl_root="$("$erl" -noshell -eval "$code" -s init stop)"
ERTS_DIR="$erl_root/erts-$ERTS_VSN"
ROOTDIR="$erl_root"
fi
-
}
find_sys_config() {
@@ -47,7 +46,8 @@ export BINDIR="$ERTS_DIR/bin"
export EMU="beam"
export PROGNAME="erl"
export LD_LIBRARY_PATH="$ERTS_DIR/lib:$LD_LIBRARY_PATH"
-
+ERTS_LIB_DIR="$ERTS_DIR/../lib"
+[ -f "$REL_DIR/$REL_NAME.boot" ] && BOOTFILE="$REL_NAME" || BOOTFILE=start
cd "$ROOTDIR"
# Save extra arguments
@@ -57,7 +57,7 @@ ARGS="$@"
set -- "$ERL_OPTS"
[ "$SYS_CONFIG" ] && set -- "$@" -config "$SYS_CONFIG"
[ "$VM_ARGS" ] && set -- "$@" -args_file "$VM_ARGS"
-set -- "$@" -boot "$REL_DIR/$REL_NAME" "$ARGS"
+set -- "$@" -boot_var ERTS_LIB_DIR "$ERTS_LIB_DIR" -boot "$REL_DIR/$BOOTFILE" "$ARGS"
# Boot the release
$BINDIR/erlexec $@
diff --git a/priv/templates/extended_bin.dtl b/priv/templates/extended_bin.dtl
index ec4a8f3..ffff615 100644
--- a/priv/templates/extended_bin.dtl
+++ b/priv/templates/extended_bin.dtl
@@ -7,6 +7,7 @@ RELEASE_ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
REL_NAME="{{ rel_name }}"
REL_VSN="{{ rel_vsn }}"
ERTS_VSN="{{ erts_vsn }}"
+CODE_LOADING_MODE="${CODE_LOADING_MODE:-embedded}"
REL_DIR="$RELEASE_ROOT_DIR/releases/$REL_VSN"
ERL_OPTS="{{ erl_opts }}"
RUNNER_LOG_DIR="${RUNNER_LOG_DIR:-$RELEASE_ROOT_DIR/log}"
@@ -25,6 +26,18 @@ find_erts_dir() {
fi
}
+# Get node pid
+relx_get_pid() {
+ if output="$(relx_nodetool rpcterms os getpid)"
+ then
+ echo "$output" | sed -e 's/"//g'
+ return 0
+ else
+ echo "$output"
+ return 1
+ fi
+}
+
# Connect to a remote node
relx_rem_sh() {
# Generate a unique id used to allow multiple remsh to the same node
@@ -36,6 +49,7 @@ relx_rem_sh() {
# Setup remote shell command to control node
exec "$BINDIR/erl" "$NAME_TYPE" "$id" -remsh "$NAME" -boot start_clean \
+ -boot_var ERTS_LIB_DIR "$ERTS_LIB_DIR" \
-setcookie "$COOKIE" -kernel net_ticktime $TICKTIME
}
@@ -59,6 +73,7 @@ relx_escript() {
"$ERTS_DIR/bin/escript" "$ROOTDIR/$scriptpath" $@
}
+
# Output a start command for the last argument of run_erl
relx_start_command() {
printf "exec \"%s\" \"%s\"" "$RELEASE_ROOT_DIR/bin/$REL_NAME" \
@@ -84,17 +99,17 @@ fi
# Make sure log directory exists
mkdir -p "$RUNNER_LOG_DIR"
-if [ -z "$CONFIG_PATH" ]; then
+if [ -z "$RELX_CONFIG_PATH" ]; then
if [ -f "$USE_DIR/sys.config" ]; then
- CONFIG_PATH="$USE_DIR/sys.config"
+ RELX_CONFIG_PATH="$USE_DIR/sys.config"
else
- CONFIG_PATH="$REL_DIR/sys.config"
+ RELX_CONFIG_PATH="$REL_DIR/sys.config"
fi
fi
if [ $RELX_REPLACE_OS_VARS ]; then
- awk '{while(match($0,"[$]{[^}]*}")) {var=substr($0,RSTART+2,RLENGTH -3);gsub("[$]{"var"}",ENVIRON[var])}}1' < $CONFIG_PATH > $CONFIG_PATH.2.config
- CONFIG_PATH=$CONFIG_PATH.2.config
+ awk '{while(match($0,"[$]{[^}]*}")) {var=substr($0,RSTART+2,RLENGTH -3);gsub("[$]{"var"}",ENVIRON[var])}}1' < $RELX_CONFIG_PATH > $RELX_CONFIG_PATH.2.config
+ RELX_CONFIG_PATH=$RELX_CONFIG_PATH.2.config
fi
# Extract the target node name from node.args
@@ -117,7 +132,14 @@ case $NAME in
;;
*)
# Add @hostname
- NAME=$NAME@`hostname -f`
+ case $NAME_TYPE in
+ -sname)
+ NAME=$NAME@`hostname -s`
+ ;;
+ -name)
+ NAME=$NAME@`hostname -f`
+ ;;
+ esac
;;
esac
@@ -139,6 +161,7 @@ export BINDIR="$ERTS_DIR/bin"
export EMU="beam"
export PROGNAME="erl"
export LD_LIBRARY_PATH="$ERTS_DIR/lib:$LD_LIBRARY_PATH"
+ERTS_LIB_DIR="$ERTS_DIR/../lib"
cd "$ROOTDIR"
@@ -184,24 +207,9 @@ case "$1" in
stop)
# Wait for the node to completely stop...
- case $(uname -s) in
- Linux|Darwin|FreeBSD|DragonFly|NetBSD|OpenBSD)
- # PID COMMAND
- PID=$(ps ax -o pid= -o command=|
- grep "$RELEASE_ROOT_DIR/.*/[b]eam"|awk '{print $1}')
- ;;
- SunOS)
- # PID COMMAND
- PID=$(ps -ef -o pid= -o args=|
- grep "$RELEASE_ROOT_DIR/.*/[b]eam"|awk '{print $1}')
- ;;
- CYGWIN*)
- # UID PID PPID TTY STIME COMMAND
- PID=$(ps -efw|grep "$RELEASE_ROOT_DIR/.*/[b]eam"|awk '{print $2}')
- ;;
- esac
+ PID="$(relx_get_pid)"
if ! relx_nodetool "stop"; then
- exit $?
+ exit 1
fi
while $(kill -0 "$PID" 2>/dev/null);
do
@@ -212,37 +220,43 @@ case "$1" in
restart)
## Restart the VM without exiting the process
if ! relx_nodetool "restart"; then
- exit $?
+ exit 1
fi
;;
reboot)
## Restart the VM completely (uses heart to restart it)
if ! relx_nodetool "reboot"; then
- exit $?
+ exit 1
+ fi
+ ;;
+
+ pid)
+ ## Get the VM's pid
+ if ! relx_get_pid; then
+ exit 1
fi
;;
ping)
## See if the VM is alive
if ! relx_nodetool "ping"; then
- exit $?
+ exit 1
fi
;;
escript)
## Run an escript under the node's environment
if ! relx_escript $@; then
- exit $?
+ exit 1
fi
;;
attach)
# Make sure a node IS running
if ! relx_nodetool "ping" > /dev/null; then
- ES="$?"
echo "Node is not running!"
- exit $ES
+ exit 1
fi
shift
@@ -252,9 +266,8 @@ case "$1" in
remote_console)
# Make sure a node IS running
if ! relx_nodetool "ping" > /dev/null; then
- ES="$?"
echo "Node is not running!"
- exit $ES
+ exit 1
fi
shift
@@ -271,13 +284,30 @@ case "$1" in
# Make sure a node IS running
if ! relx_nodetool "ping" > /dev/null; then
- ES="$?"
echo "Node is not running!"
- exit $ES
+ exit 1
fi
exec "$BINDIR/escript" "$ROOTDIR/bin/install_upgrade.escript" \
- "$REL_NAME" "$NAME" "$COOKIE" "$2"
+ "install" "$REL_NAME" "$NAME" "$COOKIE" "$2"
+ ;;
+
+ unpack)
+ if [ -z "$2" ]; then
+ echo "Missing package argument"
+ echo "Usage: $REL_NAME $1 {package base name}"
+ echo "NOTE {package base name} MUST NOT include the .tar.gz suffix"
+ exit 1
+ fi
+
+ # Make sure a node IS running
+ if ! relx_nodetool "ping" > /dev/null; then
+ echo "Node is not running!"
+ exit 1
+ fi
+
+ exec "$BINDIR/escript" "$ROOTDIR/bin/install_upgrade.escript" \
+ "unpack" "$REL_NAME" "$NAME" "$COOKIE" "$2"
;;
console|console_clean|console_boot)
@@ -314,7 +344,8 @@ case "$1" in
# Build an array of arguments to pass to exec later on
# Build it here because this command will be used for logging.
set -- "$BINDIR/erlexec" -boot "$BOOTFILE" \
- -env ERL_LIBS "$REL_DIR/lib" -config "$CONFIG_PATH" \
+ -boot_var ERTS_LIB_DIR "$ERTS_LIB_DIR" \
+ -env ERL_LIBS "$REL_DIR/lib" -config "$RELX_CONFIG_PATH" \
-args_file "$VMARGS_PATH"
# Dump environment info for logging purposes
@@ -349,7 +380,8 @@ case "$1" in
# Build an array of arguments to pass to exec later on
# Build it here because this command will be used for logging.
set -- "$BINDIR/erlexec" $FOREGROUNDOPTIONS \
- -boot "$REL_DIR/$BOOTFILE" -mode embedded -config "$CONFIG_PATH" \
+ -boot "$REL_DIR/$BOOTFILE" -mode "$CODE_LOADING_MODE" -config "$RELX_CONFIG_PATH" \
+ -boot_var ERTS_LIB_DIR "$ERTS_LIB_DIR" \
-args_file "$VMARGS_PATH"
# Dump environment info for logging purposes
@@ -359,8 +391,31 @@ case "$1" in
# Start the VM
exec "$@" -- ${1+$ARGS}
;;
+ rpc)
+ # Make sure a node IS running
+ if ! relx_nodetool "ping" > /dev/null; then
+ echo "Node is not running!"
+ exit 1
+ fi
+
+ shift
+
+ relx_nodetool rpc $@
+ ;;
+ rpcterms)
+ # Make sure a node IS running
+ if ! relx_nodetool "ping" > /dev/null; then
+ echo "Node is not running!"
+ exit 1
+ fi
+
+ shift
+
+ relx_nodetool rpcterms $@
+ ;;
+
*)
- echo "Usage: $REL_NAME {start|start_boot <file>|foreground|stop|restart|reboot|ping|console|console_clean|console_boot <file>|attach|remote_console|upgrade|escript}"
+ echo "Usage: $REL_NAME {start|start_boot <file>|foreground|stop|restart|reboot|pid|ping|console|console_clean|console_boot <file>|attach|remote_console|upgrade|escript|rpc|rpcterms}"
exit 1
;;
esac
diff --git a/priv/templates/install_upgrade_escript.dtl b/priv/templates/install_upgrade_escript.dtl
index dce2e11..3fb9d04 100644
--- a/priv/templates/install_upgrade_escript.dtl
+++ b/priv/templates/install_upgrade_escript.dtl
@@ -6,8 +6,36 @@
-define(TIMEOUT, 300000).
-define(INFO(Fmt,Args), io:format(Fmt,Args)).
-%% Upgrades, to a new tar.gz release
-main([RelName, NodeName, Cookie, VersionArg]) ->
+%% Unpack or upgrade to a new tar.gz release
+main(["unpack", RelName, NodeName, Cookie, VersionArg]) ->
+ TargetNode = start_distribution(NodeName, Cookie),
+ WhichReleases = which_releases(TargetNode),
+ Version = parse_version(VersionArg),
+ case proplists:get_value(Version, WhichReleases) of
+ undefined ->
+ %% not installed, so unpack tarball:
+ ?INFO("Release ~s not found, attempting to unpack releases/~s/~s.tar.gz~n",[Version,Version,RelName]),
+ ReleasePackage = Version ++ "/" ++ RelName,
+ case rpc:call(TargetNode, release_handler, unpack_release,
+ [ReleasePackage], ?TIMEOUT) of
+ {ok, Vsn} ->
+ ?INFO("Unpacked successfully: ~p~n", [Vsn]);
+ {error, UnpackReason} ->
+ print_existing_versions(TargetNode),
+ ?INFO("Unpack failed: ~p~n",[UnpackReason]),
+ erlang:halt(2)
+ end;
+ old ->
+ %% no need to unpack, has been installed previously
+ ?INFO("Release ~s is marked old, switching to it.~n",[Version]);
+ unpacked ->
+ ?INFO("Release ~s is already unpacked, now installing.~n",[Version]);
+ current ->
+ ?INFO("Release ~s is already installed and current. Making permanent.~n",[Version]);
+ permanent ->
+ ?INFO("Release ~s is already installed, and set permanent.~n",[Version])
+ end;
+main(["install", RelName, NodeName, Cookie, VersionArg]) ->
TargetNode = start_distribution(NodeName, Cookie),
WhichReleases = which_releases(TargetNode),
Version = parse_version(VersionArg),
diff --git a/priv/templates/nodetool.dtl b/priv/templates/nodetool.dtl
index 2f46395..dee14b4 100644
--- a/priv/templates/nodetool.dtl
+++ b/priv/templates/nodetool.dtl
@@ -44,7 +44,7 @@ main(Args) ->
end;
["rpcterms", Module, Function | ArgsAsString] ->
case rpc:call(TargetNode, list_to_atom(Module), list_to_atom(Function),
- consult(ArgsAsString), 60000) of
+ consult(lists:flatten(ArgsAsString)), 60000) of
{badrpc, Reason} ->
io:format("RPC to ~p failed: ~p\n", [TargetNode, Reason]),
halt(1);
diff --git a/rebar.config b/rebar.config
index ca9894b..b67d1f8 100644
--- a/rebar.config
+++ b/rebar.config
@@ -10,7 +10,7 @@
{branch, "master"}}},
{providers, ".*",
{git, "https://github.com/tsloughter/providers.git",
- {branch, "master"}}},
+ {tag, "v1.0.0"}}},
{erlydtl, ".*",
{git, "https://github.com/erlydtl/erlydtl.git",
{tag, "0.9.0"}}},
@@ -40,3 +40,5 @@
{compiler_options, [report, return, debug_info]}]}.
{escript_incl_apps,
[getopt, erlware_commons, erlydtl, providers]}.
+{escript_emu_args, "%%! +sbtu +A0 -noinput\n"}.
+
diff --git a/src/relx.erl b/src/relx.erl
index 25f3220..eb3b969 100644
--- a/src/relx.erl
+++ b/src/relx.erl
@@ -26,7 +26,7 @@
do/7,
do/8,
do/9,
- format_error/2,
+ format_error/1,
opt_spec_list/0]).
-export_type([error/0]).
@@ -216,18 +216,18 @@ opt_spec_list() ->
{version, undefined, "version", undefined, "Print relx version"},
{root_dir, $r, "root", string, "The project root directory"}].
--spec format_error(Reason::term(), rlx_state:t()) -> string().
-format_error({invalid_return_value, Provider, Value}, _) ->
+-spec format_error(Reason::term()) -> string().
+format_error({invalid_return_value, Provider, Value}) ->
io_lib:format(lists:flatten([providers:format(Provider), " returned an invalid value ",
io_lib:format("~p", [Value])]), []);
-format_error({opt_parse, {invalid_option, Opt}}, _) ->
+format_error({opt_parse, {invalid_option, Opt}}) ->
io_lib:format("invalid option ~s~n", [Opt]);
-format_error({opt_parse, Arg}, _) ->
+format_error({opt_parse, Arg}) ->
io_lib:format("~p~n", [Arg]);
-format_error({error, {relx, Reason}}, State) ->
- format_error(Reason, State);
-format_error({error, {Module, Reason}}, State) ->
- io_lib:format("~s~n", [Module:format_error(Reason, State)]).
+format_error({error, {relx, Reason}}) ->
+ format_error(Reason);
+format_error({error, {Module, Reason}}) ->
+ io_lib:format("~s~n", [Module:format_error(Reason)]).
%%============================================================================
%% internal api
@@ -298,19 +298,20 @@ run_provider(_ProviderName, Error) ->
-spec usage() -> ok.
usage() ->
- getopt:usage(opt_spec_list(), "relx", "[*release-specification-file*]").
+ getopt:usage(opt_spec_list(), "relx", "[<task>]"),
+ io:format("Several tasks are available:~n~nrelease\t\tCreate release.~nrelup\t\tGenerate a release upgrade.~ntar\t\tCreate tarball archive of a release.~n~n").
-spec report_error(rlx_state:t(), error()) -> none() | error().
report_error(State, Error) ->
case Error of
{error, {relx, {opt_parse, _}}} ->
- io:format(standard_error, format_error(Error, State), []),
+ io:format(standard_error, format_error(Error), []),
usage();
{error, {rlx_cmd_args, _}} ->
- io:format(standard_error, format_error(Error, State), []),
+ io:format(standard_error, format_error(Error), []),
usage();
_ ->
- io:format(standard_error, format_error(Error, State), [])
+ io:format(standard_error, format_error(Error), [])
end,
case rlx_state:caller(State) of
command_line ->
diff --git a/src/rlx_app_discovery.erl b/src/rlx_app_discovery.erl
index 2c5714b..3d58185 100644
--- a/src/rlx_app_discovery.erl
+++ b/src/rlx_app_discovery.erl
@@ -25,7 +25,7 @@
-module(rlx_app_discovery).
-export([do/2,
- format_error/2]).
+ format_error/1]).
-include("relx.hrl").
@@ -44,10 +44,10 @@ do(State, LibDirs) ->
end),
resolve_app_metadata(State, LibDirs).
--spec format_error([ErrorDetail::term()], rlx_state:t()) -> iolist().
-format_error(ErrorDetails, State)
+-spec format_error([ErrorDetail::term()]) -> iolist().
+format_error(ErrorDetails)
when erlang:is_list(ErrorDetails) ->
- [[format_detail(ErrorDetail, State), "\n"] || ErrorDetail <- ErrorDetails].
+ [[format_detail(ErrorDetail), "\n"] || ErrorDetail <- ErrorDetails].
%%%===================================================================
%%% Internal Functions
@@ -85,10 +85,10 @@ get_app_metadata(State, LibDirs) ->
{ok, _} = AppMeta ->
[AppMeta|Acc];
{warning, W} ->
- ec_cmd_log:warn(rlx_state:log(State), format_detail(W, State)),
+ ec_cmd_log:warn(rlx_state:log(State), format_detail(W)),
Acc;
{error, E} ->
- ec_cmd_log:error(rlx_state:log(State), format_detail(E, State)),
+ ec_cmd_log:error(rlx_state:log(State), format_detail(E)),
Acc;
_ ->
Acc
@@ -111,15 +111,17 @@ resolve_app_metadata(State, LibDirs) ->
{error, _} ->
true;
{warning, W} ->
- ec_cmd_log:warn(rlx_state:log(State), format_detail(W, State)),
+ ec_cmd_log:warn(rlx_state:log(State), format_detail(W)),
false;
_ ->
false
end] of
[] ->
SkipApps = rlx_state:skip_apps(State),
- AppMeta1 = [App || {ok, App} <- setup_overrides(State, AppMeta0),
- not lists:keymember(rlx_app_info:name(App), 1, SkipApps)],
+ ExcludeApps = rlx_state:exclude_apps(State),
+ AppMeta1 = [rm_exclude_apps(App, ExcludeApps) ||
+ {ok, App} <- setup_overrides(State, AppMeta0),
+ not lists:keymember(rlx_app_info:name(App), 1, SkipApps++ExcludeApps)],
ec_cmd_log:debug(rlx_state:log(State),
fun() ->
["Resolved the following OTP Applications from the system: \n",
@@ -129,6 +131,11 @@ resolve_app_metadata(State, LibDirs) ->
Errors ->
?RLX_ERROR(Errors)
end.
+%% Apps listed in {exclude_apps, [...]} must be removed from applications lists
+rm_exclude_apps(App, ExcludeApps) ->
+ ActiveApps = lists:subtract(rlx_app_info:active_deps(App), ExcludeApps),
+ LibraryApps = lists:subtract(rlx_app_info:library_deps(App), ExcludeApps),
+ rlx_app_info:library_deps(rlx_app_info:active_deps(App, ActiveApps), LibraryApps).
app_name({warning, _}) ->
undefined;
@@ -155,30 +162,30 @@ resolve_override(AppName, FileName0) ->
{ok, rlx_app_info:link(App, true)}
end.
--spec format_detail(ErrorDetail::term(), rlx_state:t()) -> iolist().
-format_detail({missing_beam_file, Module, BeamFile}, _) ->
+-spec format_detail(ErrorDetail::term()) -> iolist().
+format_detail({missing_beam_file, Module, BeamFile}) ->
io_lib:format("Missing beam file ~p ~p", [Module, BeamFile]);
-format_detail({error, {invalid_override, AppName, FileName}}, _) ->
+format_detail({error, {invalid_override, AppName, FileName}}) ->
io_lib:format("Override {~p, ~p} is not a valid OTP App. Perhaps you forgot to build it?",
[AppName, FileName]);
-format_detail({accessing, File, eaccess}, _) ->
+format_detail({accessing, File, eaccess}) ->
io_lib:format("permission denied accessing file ~s", [File]);
-format_detail({accessing, File, Type}, _) ->
+format_detail({accessing, File, Type}) ->
io_lib:format("error (~p) accessing file ~s", [Type, File]);
-format_detail({no_beam_files, EbinDir}, _) ->
+format_detail({no_beam_files, EbinDir}) ->
io_lib:format("no beam files found in directory ~s", [EbinDir]);
-format_detail({not_a_directory, EbinDir}, _) ->
+format_detail({not_a_directory, EbinDir}) ->
io_lib:format("~s is not a directory when it should be a directory", [EbinDir]);
-format_detail({unable_to_load_app, AppDir, _}, _) ->
+format_detail({unable_to_load_app, AppDir, _}) ->
io_lib:format("Unable to load the application metadata from ~s", [AppDir]);
-format_detail({invalid_app_file, File}, _) ->
+format_detail({invalid_app_file, File}) ->
io_lib:format("Application metadata file exists but is malformed: ~s",
[File]);
-format_detail({unversioned_app, AppDir, _AppName}, _) ->
+format_detail({unversioned_app, AppDir, _AppName}) ->
io_lib:format("Application metadata exists but version is not available: ~s",
[AppDir]);
-format_detail({app_info_error, {Module, Detail}}, State) ->
- Module:format_error(Detail, State).
+format_detail({app_info_error, {Module, Detail}}) ->
+ Module:format_error(Detail).
-spec discover_dir([file:name()], directory | file) ->
{ok, rlx_app_info:t()} | {error, Reason::term()}.
diff --git a/src/rlx_cmd_args.erl b/src/rlx_cmd_args.erl
index a47c2ee..2039b43 100644
--- a/src/rlx_cmd_args.erl
+++ b/src/rlx_cmd_args.erl
@@ -22,7 +22,7 @@
-module(rlx_cmd_args).
-export([args2state/2,
- format_error/2]).
+ format_error/1]).
-include("relx.hrl").
@@ -48,10 +48,10 @@ args2state(Opts, Targets) ->
Error
end.
--spec format_error(Reason::term(), rlx_state:t()) -> iolist().
-format_error({invalid_targets, Targets}, _) ->
+-spec format_error(Reason::term()) -> iolist().
+format_error({invalid_targets, Targets}) ->
io_lib:format("One config must be specified! not ~p~n", [Targets]);
-format_error({invalid_option_arg, Arg}, _) ->
+format_error({invalid_option_arg, Arg}) ->
case Arg of
{goals, Goal} ->
io_lib:format("Invalid Goal argument -g ~p~n", [Goal]);
@@ -68,20 +68,20 @@ format_error({invalid_option_arg, Arg}, _) ->
{path, Path} ->
io_lib:format("Invalid code path argument -n ~p~n", [Path])
end;
-format_error({invalid_config_file, Config}, _) ->
+format_error({invalid_config_file, Config}) ->
io_lib:format("Invalid configuration file specified: ~p", [Config]);
-format_error({invalid_caller, Caller}, _) ->
+format_error({invalid_caller, Caller}) ->
io_lib:format("Invalid caller specified: ~s", [Caller]);
-format_error({failed_to_parse, Spec}, _) ->
+format_error({failed_to_parse, Spec}) ->
io_lib:format("Unable to parse spec ~s", [Spec]);
-format_error({failed_to_parse_override, QA}, _) ->
+format_error({failed_to_parse_override, QA}) ->
io_lib:format("Failed to parse app override ~s", [QA]);
-format_error({not_directory, Dir}, _) ->
+format_error({not_directory, Dir}) ->
io_lib:format("Library directory does not exist: ~s", [Dir]);
-format_error({invalid_log_level, LogLevel}, _) ->
+format_error({invalid_log_level, LogLevel}) ->
io_lib:format("Invalid log level specified -V ~p, log level must be in the"
" range 0..3", [LogLevel]);
-format_error({invalid_target, Target}, _) ->
+format_error({invalid_target, Target}) ->
io_lib:format("Invalid action specified: ~s", [Target]).
%%%===================================================================
@@ -102,7 +102,7 @@ handle_config(Opts, Targets, CommandLineConfig) ->
end
end.
--spec convert_targets([string()]) -> {ok, release | relup} | relx:error().
+-spec convert_targets([string()]) -> {ok, [rlx_state:action()]} | relx:error().
convert_targets(Targets) ->
convert_targets(Targets, []).
@@ -111,7 +111,7 @@ convert_targets(Targets) ->
convert_targets([], []) ->
{ok, [release]};
convert_targets([], Acc) ->
- {ok, Acc};
+ {ok, lists:reverse(Acc)};
convert_targets(["release" | T], Acc) ->
convert_targets(T, [release | Acc]);
convert_targets(["relup" | T], Acc) ->
@@ -244,8 +244,16 @@ create(vm_args, Opts) ->
VmArgs = proplists:get_value(vm_args, Opts, undefined),
{vm_args, VmArgs};
create(system_libs, Opts) ->
- SystemLibs = proplists:get_value(system_libs, Opts, undefined),
- {system_libs, SystemLibs};
+ case proplists:get_value(system_libs, Opts, true) of
+ SystemLibs when SystemLibs =:= true
+ ; SystemLibs =:= "true" ->
+ {system_libs, true};
+ SystemLibs when SystemLibs =:= false
+ ; SystemLibs =:= "false" ->
+ {system_libs, false};
+ SystemLibsDir when is_list(SystemLibsDir) ->
+ {system_libs, SystemLibsDir}
+ end;
create(upfrom, Opts) ->
case proplists:get_value(upfrom, Opts, undefined) of
undefined ->
diff --git a/src/rlx_config.erl b/src/rlx_config.erl
index c838c18..df08342 100644
--- a/src/rlx_config.erl
+++ b/src/rlx_config.erl
@@ -97,25 +97,50 @@ parent_dir([_H], Acc) ->
parent_dir([H | T], Acc) ->
parent_dir(T, [H | Acc]).
+-spec config_script_file(file:filename(), rlx_state:t()) -> file:filename().
+config_script_file(ConfigFile, _State) ->
+ ConfigFile ++ ".script".
+
+bs(Vars) ->
+ lists:foldl(fun({K,V}, Bs) ->
+ erl_eval:add_binding(K, V, Bs)
+ end, erl_eval:new_bindings(), Vars).
+
+-spec apply_config_script(proplists:proplist(), file:filename()) ->
+ proplists:proplist().
+apply_config_script(ConfigData, ConfigScriptFile) ->
+ {ok, Config} = file:script(ConfigScriptFile, bs([{'CONFIG', ConfigData},
+ {'SCRIPT', ConfigScriptFile}])),
+ Config.
+
-spec load_config(file:filename() | proplists:proplist(), rlx_state:t()) ->
{ok, rlx_state:t()} | relx:error().
load_config(ConfigFile, State) ->
{ok, CurrentCwd} = file:get_cwd(),
- case filelib:is_regular(ConfigFile) of
- true ->
- ok = file:set_cwd(filename:dirname(ConfigFile)),
- Result = case file:consult(ConfigFile) of
- {error, Reason} ->
- ?RLX_ERROR({consult, ConfigFile, Reason});
- {ok, 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;
- false ->
- CliTerms = rlx_state:cli_args(State),
- lists:foldl(fun load_terms/2, {ok, State}, merge_configs(CliTerms, ConfigFile))
+ CliTerms = rlx_state:cli_args(State),
+ Config0 = case filelib:is_regular(ConfigFile) of
+ true ->
+ ok = file:set_cwd(filename:dirname(ConfigFile)),
+ Result = case file:consult(ConfigFile) of
+ {error, Reason} ->
+ ?RLX_ERROR({consult, ConfigFile, Reason});
+ {ok, Terms} -> merge_configs(CliTerms, Terms)
+ end,
+ ok = file:set_cwd(CurrentCwd),
+ Result;
+ false -> merge_configs(CliTerms, ConfigFile)
+ end,
+ % we now take the merged config and try to apply a config script to it,
+ % get a new config as a result
+ case Config0 of
+ {error, _} = Error -> Error;
+ _ ->
+ ConfigScriptFile = config_script_file(ConfigFile, State),
+ Config1 = case filelib:is_regular(ConfigScriptFile) of
+ false -> Config0;
+ true -> apply_config_script(Config0, ConfigScriptFile)
+ end,
+ lists:foldl(fun load_terms/2, {ok, State}, Config1)
end.
-spec load_terms(term(), {ok, rlx_state:t()} | relx:error()) ->
@@ -131,11 +156,6 @@ load_terms({default_libs, DefaultLibs}, {ok, 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,
@@ -162,6 +182,10 @@ load_terms({add_providers, Providers0}, {ok, State0}) ->
end;
load_terms({skip_apps, SkipApps0}, {ok, State0}) ->
{ok, rlx_state:skip_apps(State0, SkipApps0)};
+load_terms({exclude_apps, ExcludeApps0}, {ok, State0}) ->
+ {ok, rlx_state:exclude_apps(State0, ExcludeApps0)};
+load_terms({debug_info, DebugInfo}, {ok, State0}) ->
+ {ok, rlx_state:debug_info(State0, DebugInfo)};
load_terms({overrides, Overrides0}, {ok, State0}) ->
{ok, rlx_state:overrides(State0, Overrides0)};
load_terms({dev_mode, DevMode}, {ok, State0}) ->
diff --git a/src/rlx_prv_discover.erl b/src/rlx_prv_app_discover.erl
index 41e3993..eb40f38 100644
--- a/src/rlx_prv_discover.erl
+++ b/src/rlx_prv_app_discover.erl
@@ -22,16 +22,17 @@
%%% Lib Dirs looking for all OTP Applications that are available. When it finds
%%% those OTP Applications it loads the information about them and adds them to
%%% the state of available apps. This implements the provider behaviour.
--module(rlx_prv_discover).
+-module(rlx_prv_app_discover).
+
-behaviour(provider).
-export([init/1,
do/1,
- format_error/2]).
+ format_error/1]).
-include("relx.hrl").
--define(PROVIDER, discover).
+-define(PROVIDER, app_discover).
-define(DEPS, []).
%%============================================================================
@@ -42,48 +43,31 @@
init(State) ->
State1 = rlx_state:add_provider(State, providers:create([{name, ?PROVIDER},
{module, ?MODULE},
- {bare, false},
- {deps, ?DEPS},
- {example, "build"},
- {short_desc, ""},
- {desc, ""},
- {opts, []}])),
+ {deps, ?DEPS}])),
{ok, State1}.
%% @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(State0) ->
- LibDirs = get_lib_dirs(State0),
+ LibDirs = dedup(get_lib_dirs(State0)),
case rlx_app_discovery:do(State0, LibDirs) of
{ok, AppMeta} ->
- case rlx_rel_discovery:do(State0, LibDirs, AppMeta) of
- {ok, Releases} ->
- State1 = rlx_state:available_apps(State0, AppMeta),
- {ok, rlx_state:realized_releases(State1, lists:foldl(fun add/2,
- ec_dictionary:new(ec_dict),
- Releases))};
- Error ->
- Error
- end;
+ State1 = rlx_state:available_apps(State0, AppMeta),
+ {ok, State1};
Error ->
Error
end.
%% @doc this is here to comply with the signature. However, we do not actually
%% produce any errors and so simply return an empty string.
--spec format_error(any(), rlx_state:t()) -> iolist().
-format_error(_, _) ->
+-spec format_error(any()) -> iolist().
+format_error(_) ->
"".
%%%===================================================================
%%% Internal Functions
%%%===================================================================
-%% @doc only add the release if its not documented in the system
-add(Rel, Dict) ->
- RelName = rlx_release:name(Rel),
- RelVsn = rlx_release:vsn(Rel),
- ec_dictionary:add({RelName, RelVsn}, Rel, Dict).
get_lib_dirs(State) ->
LibDirs0 = rlx_state:lib_dirs(State),
@@ -91,10 +75,17 @@ get_lib_dirs(State) ->
false ->
LibDirs0;
true ->
+ Output = erlang:iolist_to_binary(rlx_state:base_output_dir(State)),
+ OutputDir = case ec_file:exists(binary_to_list(Output)) of
+ true ->
+ Output;
+ false ->
+ []
+ end,
lists:flatten([LibDirs0,
add_common_project_dirs(State),
add_system_lib_dir(State),
- add_release_output_dir(State)])
+ OutputDir])
end.
-spec add_common_project_dirs(rlx_state:t()) -> [file:name()].
@@ -124,8 +115,8 @@ add_common_project_dirs(State) ->
-spec add_system_lib_dir(rlx_state:t()) -> [file:name()].
add_system_lib_dir(State) ->
ExcludeSystem = rlx_state:get(State, discover_exclude_system, false),
- case rlx_state:get(State, system_libs, undefined) of
- undefined ->
+ case rlx_state:get(State, system_libs, true) of
+ Atom when is_atom(Atom) ->
case ExcludeSystem of
true ->
[];
@@ -136,16 +127,8 @@ add_system_lib_dir(State) ->
erlang:iolist_to_binary(SystemLibs)
end.
-add_release_output_dir(State) ->
- case rlx_state:get(State, disable_discover_release_output, false) of
- true ->
- [];
- false ->
- Output = erlang:iolist_to_binary(rlx_state:base_output_dir(State)),
- case ec_file:exists(erlang:binary_to_list(Output)) of
- true ->
- Output;
- false ->
- []
- end
- end.
+%% Order matters so this slow dedup needs to be used
+dedup([]) ->
+ [];
+dedup([H|T]) ->
+ [H | [X || X <- dedup(T), X /= H]].
diff --git a/src/rlx_prv_archive.erl b/src/rlx_prv_archive.erl
index e4cd18f..62cc37c 100644
--- a/src/rlx_prv_archive.erl
+++ b/src/rlx_prv_archive.erl
@@ -26,7 +26,7 @@
-export([init/1,
do/1,
- format_error/2]).
+ format_error/1]).
-include("relx.hrl").
@@ -41,12 +41,7 @@
init(State) ->
State1 = rlx_state:add_provider(State, providers:create([{name, ?PROVIDER},
{module, ?MODULE},
- {bare, false},
- {deps, ?DEPS},
- {example, "tar"},
- {short_desc, ""},
- {desc, ""},
- {opts, []}])),
+ {deps, ?DEPS}])),
{ok, State1}.
@@ -57,13 +52,13 @@ do(State) ->
OutputDir = rlx_state:output_dir(State),
make_tar(State, Release, OutputDir).
-format_error({tar_unknown_generation_error, Module, Vsn}, _) ->
+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}, _) ->
+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}, _) ->
+format_error({tar_generation_error, Module, Errors}) ->
io_lib:format("Tarball generation error for ~p reason ~p",
[Module, Errors]).
@@ -72,7 +67,7 @@ make_tar(State, Release, OutputDir) ->
Vsn = rlx_release:vsn(Release),
ErtsVersion = rlx_release:erts(Release),
Opts = [{path, [filename:join([OutputDir, "lib", "*", "ebin"])]},
- {outdir, OutputDir} |
+ {outdir, OutputDir} |
case rlx_state:get(State, include_erts, true) of
true ->
Prefix = code:root_dir(),
@@ -104,14 +99,18 @@ make_tar(State, Release, OutputDir) ->
end.
update_tar(State, TempDir, OutputDir, Name, Vsn, ErtsVersion) ->
+ IncludeErts = rlx_state:get(State, include_erts, true),
+ SystemLibs = rlx_state:get(State, system_libs, true),
+ {RelName, RelVsn} = rlx_state:default_configured_release(State),
+ Release = rlx_state:get_realized_release(State, RelName, RelVsn),
TarFile = filename:join(OutputDir, Name++"-"++Vsn++".tar.gz"),
file:rename(filename:join(OutputDir, Name++".tar.gz"), TarFile),
erl_tar:extract(TarFile, [{cwd, TempDir}, compressed]),
- OverlayFiles = overlay_files(rlx_state:get(State, overlay, undefined), OutputDir),
+ OverlayVars = rlx_prv_overlay:generate_overlay_vars(State, Release),
+ OverlayFiles = overlay_files(OverlayVars, rlx_state:get(State, overlay, undefined), OutputDir),
ok =
erl_tar:create(TarFile,
- [{"lib", filename:join(TempDir, "lib")},
- {"releases", filename:join(TempDir, "releases")},
+ [{"releases", filename:join(TempDir, "releases")},
{filename:join(["releases", "start_erl.data"]),
filename:join([OutputDir, "releases", "start_erl.data"])},
{filename:join(["releases", "RELEASES"]),
@@ -119,21 +118,36 @@ update_tar(State, TempDir, OutputDir, Name, Vsn, ErtsVersion) ->
{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
+ case IncludeErts of
false ->
- [];
+ %% Remove system libs from tarball
+ case SystemLibs of
+ false ->
+ Libs = filelib:wildcard("*", filename:join(TempDir, "lib")),
+ AllSystemLibs = filelib:wildcard("*", code:lib_dir()),
+ [{filename:join("lib", LibDir), filename:join([TempDir, "lib", LibDir])} ||
+ LibDir <- lists:subtract(Libs, AllSystemLibs)];
+ _ ->
+ [{"lib", filename:join(TempDir, "lib")}]
+ end;
_ ->
- [{"erts-"++ErtsVersion, filename:join(OutputDir, "erts-"++ErtsVersion)}]
+ [{"lib", filename:join(TempDir, "lib")},
+ {"erts-"++ErtsVersion, filename:join(OutputDir, "erts-"++ErtsVersion)}]
end]++OverlayFiles, [compressed]),
ec_cmd_log:info(rlx_state:log(State),
- "tarball ~s successfully created!~n", [TarFile]),
+ "tarball ~s successfully created!~n", [TarFile]),
ec_file:remove(TempDir, [recursive]),
{ok, State}.
-overlay_files(undefined, _) ->
+overlay_files(_, undefined, _) ->
[];
-overlay_files(Overlay, OutputDir) ->
- [{to(O), filename:join(OutputDir, to(O))} || O <- Overlay, filter(O)].
+overlay_files(OverlayVars, Overlay, OutputDir) ->
+ [begin
+ To = to(O),
+ ToTemplateName = rlx_prv_overlay:make_template_name("rlx_template_to_template", To),
+ File = rlx_prv_overlay:render_string(OverlayVars, To, ToTemplateName),
+ {ec_cnv:to_list(File), ec_cnv:to_list(filename:join(OutputDir, File))}
+ end || O <- Overlay, filter(O)].
to({copy, _, To}) ->
To;
diff --git a/src/rlx_prv_assembler.erl b/src/rlx_prv_assembler.erl
index c535485..60cef76 100644
--- a/src/rlx_prv_assembler.erl
+++ b/src/rlx_prv_assembler.erl
@@ -26,7 +26,7 @@
-export([init/1,
do/1,
- format_error/2]).
+ format_error/1]).
-include("relx.hrl").
@@ -40,12 +40,7 @@
init(State) ->
State1 = rlx_state:add_provider(State, providers:create([{name, ?PROVIDER},
{module, ?MODULE},
- {bare, false},
- {deps, ?DEPS},
- {example, "release"},
- {short_desc, ""},
- {desc, ""},
- {opts, []}])),
+ {deps, ?DEPS}])),
{ok, State1}.
%% @doc recursively dig down into the library directories specified in the state
@@ -60,7 +55,23 @@ do(State) ->
ok ->
case rlx_release:realized(Release) of
true ->
- copy_app_directories_to_output(State, Release, OutputDir);
+ case copy_app_directories_to_output(State, Release, OutputDir) of
+ {ok, State1} ->
+ case rlx_state:debug_info(State1) =:= strip
+ andalso rlx_state:dev_mode(State1) =:= false of
+ true ->
+ case beam_lib:strip_release(OutputDir) of
+ {ok, _} ->
+ {ok, State1};
+ {error, _, Reason} ->
+ ?RLX_ERROR({strip_release, Reason})
+ end;
+ false ->
+ {ok, State1}
+ end;
+ E ->
+ E
+ end;
false ->
?RLX_ERROR({unresolved_release, RelName, RelVsn})
end;
@@ -68,34 +79,37 @@ do(State) ->
Error
end.
--spec format_error(ErrorDetail::term(), rlx_state:t()) -> iolist().
-format_error({unresolved_release, RelName, RelVsn}, _) ->
+-spec format_error(ErrorDetail::term()) -> iolist().
+format_error({unresolved_release, RelName, RelVsn}) ->
io_lib:format("The release has not been resolved ~p-~s", [RelName, RelVsn]);
-format_error({ec_file_error, AppDir, TargetDir, E}, _) ->
+format_error({ec_file_error, AppDir, TargetDir, E}) ->
io_lib:format("Unable to copy OTP App from ~s to ~s due to ~p",
[AppDir, TargetDir, E]);
-format_error({config_does_not_exist, Path}, _) ->
+format_error({config_does_not_exist, Path}) ->
io_lib:format("The config file specified for this release (~s) does not exist!",
[Path]);
-format_error({specified_erts_does_not_exist, ErtsVersion}, _) ->
+format_error({specified_erts_does_not_exist, ErtsVersion}) ->
io_lib:format("Specified version of erts (~s) does not exist",
[ErtsVersion]);
-format_error({release_script_generation_error, RelFile}, _) ->
+format_error({release_script_generation_error, RelFile}) ->
io_lib:format("Unknown internal release error generating the release file to ~s",
[RelFile]);
-format_error({release_script_generation_warning, Module, Warnings}, _) ->
+format_error({release_script_generation_warning, Module, Warnings}) ->
["Warnings generating release \s",
rlx_util:indent(2), Module:format_warning(Warnings)];
-format_error({unable_to_create_output_dir, OutputDir}, _) ->
+format_error({unable_to_create_output_dir, OutputDir}) ->
io_lib:format("Unable to create output directory (possible permissions issue): ~s",
[OutputDir]);
-format_error({release_script_generation_error, Module, Errors}, State) ->
+format_error({release_script_generation_error, Module, Errors}) ->
["Errors generating release \n",
- rlx_util:indent(2), Module:format_error(Errors, State)];
-format_error({unable_to_make_symlink, AppDir, TargetDir, Reason}, _) ->
+ 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)]).
+ file:format_error(Reason)]);
+format_error({strip_release, Reason}) ->
+ io_lib:format("Stripping debug info from release beam files failed becuase ~s",
+ [beam_lib:format_error(Reason)]).
%%%===================================================================
%%% Internal Functions
@@ -128,6 +142,7 @@ copy_app_directories_to_output(State, Release, OutputDir) ->
LibDir = filename:join([OutputDir, "lib"]),
ok = ec_file:mkdir_p(LibDir),
IncludeSrc = rlx_state:include_src(State),
+ IncludeErts = rlx_state:get(State, include_erts, true),
Apps = prepare_applications(State, rlx_release:application_details(Release)),
Result = lists:filter(fun({error, _}) ->
true;
@@ -135,7 +150,7 @@ copy_app_directories_to_output(State, Release, OutputDir) ->
false
end,
lists:flatten(ec_plists:map(fun(App) ->
- copy_app(LibDir, App, IncludeSrc)
+ copy_app(LibDir, App, IncludeSrc, IncludeErts)
end, Apps))),
case Result of
[E | _] ->
@@ -152,7 +167,7 @@ prepare_applications(State, Apps) ->
Apps
end.
-copy_app(LibDir, App, IncludeSrc) ->
+copy_app(LibDir, App, IncludeSrc, IncludeErts) ->
AppName = erlang:atom_to_list(rlx_app_info:name(App)),
AppVsn = rlx_app_info:original_vsn(App),
AppDir = rlx_app_info:dir(App),
@@ -163,16 +178,69 @@ copy_app(LibDir, App, IncludeSrc) ->
%% a release dir
ok;
true ->
- copy_app(App, AppDir, TargetDir, IncludeSrc)
+ case IncludeErts of
+ false ->
+ case is_erts_lib(AppDir) of
+ true ->
+ [];
+ false ->
+ copy_app_(App, AppDir, TargetDir, IncludeSrc)
+ end;
+ _ ->
+ copy_app_(App, AppDir, TargetDir, IncludeSrc)
+ end
end.
-copy_app(App, AppDir, TargetDir, IncludeSrc) ->
+is_erts_lib(Dir) ->
+ lists:prefix(filename:split(list_to_binary(code:lib_dir())), filename:split(Dir)).
+
+copy_app_(App, AppDir, TargetDir, IncludeSrc) ->
remove_symlink_or_directory(TargetDir),
case rlx_app_info:link(App) of
true ->
- link_directory(AppDir, TargetDir);
+ link_directory(AppDir, TargetDir),
+ rewrite_app_file(App, AppDir);
false ->
- copy_directory(AppDir, TargetDir, IncludeSrc)
+ copy_directory(AppDir, TargetDir, IncludeSrc),
+ rewrite_app_file(App, TargetDir)
+ end.
+
+%% If excluded apps exist in this App's applications list we must write a new .app
+rewrite_app_file(App, TargetDir) ->
+ Name = rlx_app_info:name(App),
+ ActiveDeps = rlx_app_info:active_deps(App),
+ IncludedDeps = rlx_app_info:library_deps(App),
+ AppFile = filename:join([TargetDir, "ebin", ec_cnv:to_list(Name) ++ ".app"]),
+
+ {ok, [{application, AppName, AppData}]} = file:consult(AppFile),
+ OldActiveDeps = proplists:get_value(applications, AppData, []),
+ OldIncludedDeps = proplists:get_value(included_applications, AppData, []),
+
+ case {OldActiveDeps, OldIncludedDeps} of
+ {ActiveDeps, IncludedDeps} ->
+ ok;
+ _ ->
+ AppData1 = lists:keyreplace(applications
+ ,1
+ ,AppData
+ ,{applications, ActiveDeps}),
+ AppData2 = lists:keyreplace(included_applications
+ ,1
+ ,AppData1
+ ,{included_applications, IncludedDeps}),
+ Spec = io_lib:format("~p.\n", [{application, AppName, AppData2}]),
+ write_file_if_contents_differ(AppFile, Spec)
+ end.
+
+write_file_if_contents_differ(Filename, Bytes) ->
+ ToWrite = iolist_to_binary(Bytes),
+ case file:read_file(Filename) of
+ {ok, ToWrite} ->
+ ok;
+ {ok, _} ->
+ file:write_file(Filename, ToWrite);
+ {error, _} ->
+ file:write_file(Filename, ToWrite)
end.
remove_symlink_or_directory(TargetDir) ->
@@ -424,6 +492,7 @@ include_erts(State, Release, OutputDir, RelDir) ->
make_boot_script(State, Release, OutputDir, RelDir) ->
Options = [{path, [RelDir | rlx_util:get_code_paths(Release, OutputDir)]},
{outdir, RelDir},
+ {variables, [{"ERTS_LIB_DIR", code:lib_dir()}]},
no_module_tests, silent],
Name = erlang:atom_to_list(rlx_release:name(Release)),
ReleaseFile = filename:join([RelDir, Name ++ ".rel"]),
diff --git a/src/rlx_prv_overlay.erl b/src/rlx_prv_overlay.erl
index 6df142b..cdce915 100644
--- a/src/rlx_prv_overlay.erl
+++ b/src/rlx_prv_overlay.erl
@@ -26,7 +26,11 @@
-export([init/1,
do/1,
- format_error/2]).
+ format_error/1]).
+
+-export([generate_overlay_vars/2,
+ make_template_name/2,
+ render_string/3]).
-define(DIRECTORY_RE, ".*(\/|\\\\)$").
@@ -45,12 +49,7 @@
init(State) ->
State1 = rlx_state:add_provider(State, providers:create([{name, ?PROVIDER},
{module, ?MODULE},
- {bare, false},
- {deps, ?DEPS},
- {example, "overlay"},
- {short_desc, ""},
- {desc, ""},
- {opts, []}])),
+ {deps, ?DEPS}])),
{ok, State1}.
%% @doc recursively dig down into the library directories specified in the state
@@ -61,45 +60,50 @@ do(State) ->
Release = rlx_state:get_realized_release(State, RelName, RelVsn),
case rlx_release:realized(Release) of
true ->
- generate_overlay_vars(State, Release);
+ case generate_overlay_vars(State, Release) of
+ {error, Reason} ->
+ {error, Reason};
+ OverlayVars ->
+ do_overlay(State, OverlayVars)
+ end;
false ->
?RLX_ERROR({unresolved_release, RelName, RelVsn})
end.
--spec format_error(ErrorDetail::term(), rlx_state:t()) -> iolist().
-format_error({unresolved_release, RelName, RelVsn}, _) ->
+-spec format_error(ErrorDetail::term()) -> iolist().
+format_error({unresolved_release, RelName, RelVsn}) ->
io_lib:format("The release has not been resolved ~p-~s", [RelName, RelVsn]);
-format_error({ec_file_error, AppDir, TargetDir, E}, _) ->
+format_error({ec_file_error, AppDir, TargetDir, E}) ->
io_lib:format("Unable to copy OTP App from ~s to ~s due to ~p",
[AppDir, TargetDir, E]);
-format_error({unable_to_read_varsfile, FileName, Reason}, _) ->
+format_error({unable_to_read_varsfile, FileName, Reason}) ->
io_lib:format("Unable to read vars file (~s) for overlay due to: ~p",
[FileName, Reason]);
-format_error({overlay_failed, Errors}, State) ->
- [[format_error(rlx_util:error_reason(Error), State), "\n"] || Error <- Errors];
-format_error({dir_render_failed, Dir, Error}, _) ->
+format_error({overlay_failed, Errors}) ->
+ [[format_error(rlx_util:error_reason(Error)), "\n"] || Error <- Errors];
+format_error({dir_render_failed, Dir, Error}) ->
io_lib:format("rendering mkdir path failed ~s with ~p",
[Dir, Error]);
-format_error({unable_to_make_symlink, AppDir, TargetDir, Reason}, _) ->
+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({copy_failed, FromFile, ToFile, Err}, _) ->
+format_error({copy_failed, FromFile, ToFile, Err}) ->
io_lib:format("Unable to copy from ~s to ~s because of ~p",
[FromFile, ToFile, Err]);
-format_error({unable_to_write, ToFile, Reason}, _) ->
+format_error({unable_to_write, ToFile, Reason}) ->
io_lib:format("Unable to write to ~s because ~p",
[ToFile, Reason]);
-format_error({unable_to_enclosing_dir, ToFile, Reason}, _) ->
+format_error({unable_to_enclosing_dir, ToFile, Reason}) ->
io_lib:format("Unable to create enclosing directory for ~s because ~p",
[ToFile, Reason]);
-format_error({unable_to_render_template, FromFile, Reason}, _) ->
+format_error({unable_to_render_template, FromFile, Reason}) ->
io_lib:format("Unable to render template ~s because ~p",
[FromFile, Reason]);
-format_error({unable_to_compile_template, FromFile, Reason}, State) ->
+format_error({unable_to_compile_template, FromFile, Reason}) ->
io_lib:format("Unable to compile template ~s because \n~s",
- [FromFile, [format_errors(F, Es, State) || {F, Es} <- Reason]]);
-format_error({unable_to_make_dir, Absolute, Error}, _) ->
+ [FromFile, [format_errors(F, Es) || {F, Es} <- Reason]]);
+format_error({unable_to_make_dir, Absolute, Error}) ->
io_lib:format("Unable to make directory ~s because ~p",
[Absolute, Error]).
@@ -107,39 +111,39 @@ format_error({unable_to_make_dir, Absolute, Error}, _) ->
%%% Internal Functions
%%%===================================================================
-format_errors(File, [{none, Mod, E}|Es], State) ->
+format_errors(File, [{none, Mod, E}|Es]) ->
[io_lib:format("~s~s: ~ts~n",
[rlx_util:indent(2), File,
- Mod:format_error(E, State)])
- |format_errors(File, Es, State)];
-format_errors(File, [{{Line, Col}, Mod, E}|Es], State) ->
+ Mod:format_error(E)])
+ |format_errors(File, Es)];
+format_errors(File, [{{Line, Col}, Mod, E}|Es]) ->
[io_lib:format("~s~s:~w:~w: ~ts~n",
[rlx_util:indent(2), File, Line, Col,
- Mod:format_error(E, State)])
- |format_errors(File, Es, State)];
-format_errors(File, [{Line, Mod, E}|Es], State) ->
+ Mod:format_error(E)])
+ |format_errors(File, Es)];
+format_errors(File, [{Line, Mod, E}|Es]) ->
[io_lib:format("~s~s:~w: ~ts~n",
[rlx_util:indent(2), File, Line,
- Mod:format_error(E, State)])
- |format_errors(File, Es, State)];
-format_errors(_, [], _State) -> [].
+ Mod:format_error(E)])
+ |format_errors(File, Es)];
+format_errors(_, []) -> [].
-spec generate_overlay_vars(rlx_state:t(), rlx_release:t()) ->
- {ok, rlx_state:t()} | relx:error().
+ proplists:proplist() | relx:error().
generate_overlay_vars(State, Release) ->
StateVars = generate_state_vars(State),
ReleaseVars = generate_release_vars(Release),
get_overlay_vars_from_file(State, StateVars ++ ReleaseVars).
-spec get_overlay_vars_from_file(rlx_state:t(), proplists:proplist()) ->
- {ok, rlx_state:t()} | relx:error().
+ proplists:proplist() | relx:error().
get_overlay_vars_from_file(State, OverlayVars) ->
case rlx_state:get(State, overlay_vars, undefined) of
undefined ->
- do_overlay(State, OverlayVars);
+ OverlayVars;
[] ->
- do_overlay(State, OverlayVars);
+ OverlayVars;
[H | _]=FileNames when is_list(H) ->
read_overlay_vars(State, OverlayVars, FileNames);
FileName when is_list(FileName) ->
@@ -147,16 +151,31 @@ get_overlay_vars_from_file(State, OverlayVars) ->
end.
-spec read_overlay_vars(rlx_state:t(), proplists:proplist(), [file:name()]) ->
- {ok, rlx_state:t()} | relx:error().
+ proplists:proplist() | relx:error().
read_overlay_vars(State, OverlayVars, FileNames) ->
Terms = merge_overlay_vars(State, FileNames),
case render_overlay_vars(OverlayVars, Terms, []) of
{ok, NewTerms} ->
- do_overlay(State, OverlayVars ++ NewTerms);
+ OverlayVars ++ NewTerms;
Error ->
Error
end.
+-spec check_overlay_inclusion(rlx_state:t(), string(), proplists:proplist()) ->
+ proplists:proplist().
+check_overlay_inclusion(State, RelativeRoot, Terms) ->
+ check_overlay_inclusion(State, RelativeRoot, Terms, []).
+
+-spec check_overlay_inclusion(rlx_state:t(), string(), proplists:proplist(), proplists:proplist()) ->
+ proplists:proplist().
+check_overlay_inclusion(State, RelativeRoot, [File|T], Terms) when is_list(File) ->
+ IncludedTerms = merge_overlay_vars(State, [filename:join(RelativeRoot, File)]),
+ check_overlay_inclusion(State, RelativeRoot, T, Terms ++ IncludedTerms);
+check_overlay_inclusion(State, RelativeRoot, [Tuple|T], Terms) ->
+ check_overlay_inclusion(State, RelativeRoot, T, Terms ++ [Tuple]);
+check_overlay_inclusion(_State, _RelativeRoot, [], Terms) ->
+ Terms.
+
-spec merge_overlay_vars(rlx_state:t(), [file:name()]) ->
proplists:proplist().
merge_overlay_vars(State, FileNames) ->
@@ -165,10 +184,14 @@ merge_overlay_vars(State, FileNames) ->
RelativePath = filename:join(RelativeRoot, erlang:iolist_to_binary(FileName)),
case file:consult(RelativePath) of
{ok, Terms} ->
- lists:ukeymerge(1, lists:ukeysort(1, Terms), Acc);
+ % the location of the included overlay files will be relative
+ %% to the current one being read
+ OverlayRelativeRoot = filename:dirname(FileName),
+ NewTerms = check_overlay_inclusion(State, OverlayRelativeRoot, Terms),
+ lists:ukeymerge(1, lists:ukeysort(1, NewTerms), Acc);
{error, Reason} ->
ec_cmd_log:warn(rlx_state:log(State),
- format_error({unable_to_read_varsfile, FileName, Reason}, State)),
+ format_error({unable_to_read_varsfile, FileName, Reason})),
Acc
end
end, [], FileNames).
@@ -431,6 +454,19 @@ write_template(OverlayVars, FromFile, ToFile) ->
Error
end.
+render_string(OverlayVars, Data, TemplateName) ->
+ case erlydtl:compile(erlang:iolist_to_binary(Data), TemplateName, ?ERLYDTL_COMPILE_OPTS) of
+ {ok, TemplateName} ->
+ case render(TemplateName, OverlayVars) of
+ {ok, IoList} ->
+ erlang:iolist_to_binary(IoList);
+ {error, Error} ->
+ ?RLX_ERROR({render_failed, Data, Error})
+ end;
+ {error, Reason, _Warnings} ->
+ ?RLX_ERROR({unable_to_compile_template, Data, Reason})
+ end.
+
-spec file_render_do(proplists:proplist(), iolist(), module(),
fun((term()) -> {ok, rlx_state:t()} | relx:error())) ->
{ok, rlx_state:t()} | relx:error().
diff --git a/src/rlx_prv_rel_discover.erl b/src/rlx_prv_rel_discover.erl
new file mode 100644
index 0000000..4224e75
--- /dev/null
+++ b/src/rlx_prv_rel_discover.erl
@@ -0,0 +1,92 @@
+%% -*- erlang-indent-level: 4; indent-tabs-mode: nil; fill-column: 80 -*-
+%%% Copyright 2012 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 Eric Merritt <[email protected]>
+%%% @copyright (C) 2012 Erlware, LLC.
+%%%
+-module(rlx_prv_rel_discover).
+-behaviour(provider).
+
+-export([init/1,
+ do/1,
+ format_error/1]).
+
+-include("relx.hrl").
+
+-define(PROVIDER, rel_discover).
+-define(DEPS, [app_discover]).
+
+%%============================================================================
+%% API
+%%============================================================================
+
+-spec init(rlx_state:t()) -> {ok, rlx_state:t()}.
+init(State) ->
+ State1 = rlx_state:add_provider(State, providers:create([{name, ?PROVIDER},
+ {module, ?MODULE},
+ {deps, ?DEPS}])),
+ {ok, State1}.
+
+-spec do(rlx_state:t()) -> {ok, rlx_state:t()} | relx:error().
+do(State0) ->
+ LibDirs = get_lib_dirs(State0),
+ AppMeta = rlx_state:available_apps(State0),
+ case rlx_rel_discovery:do(State0, LibDirs, AppMeta) of
+ {ok, Releases} ->
+ {ok, rlx_state:realized_releases(State0, lists:foldl(fun add/2,
+ ec_dictionary:new(ec_dict),
+ Releases))};
+ Error ->
+ Error
+ end.
+
+-spec format_error(any()) -> iolist().
+format_error(_) ->
+ "".
+
+%%%===================================================================
+%%% Internal Functions
+%%%===================================================================
+%% @doc only add the release if its not documented in the system
+add(Rel, Dict) ->
+ RelName = rlx_release:name(Rel),
+ RelVsn = rlx_release:vsn(Rel),
+ ec_dictionary:add({RelName, RelVsn}, Rel, Dict).
+
+get_lib_dirs(State) ->
+ LibDirs0 = rlx_state:lib_dirs(State),
+ case rlx_state:get(State, default_libs, true) of
+ false ->
+ LibDirs0;
+ true ->
+ lists:flatten([LibDirs0,
+ add_release_output_dir(State)])
+ end.
+
+add_release_output_dir(State) ->
+ case rlx_state:get(State, disable_discover_release_output, false) of
+ true ->
+ [];
+ false ->
+ Output = erlang:iolist_to_binary(rlx_state:base_output_dir(State)),
+ case ec_file:exists(erlang:binary_to_list(Output)) of
+ true ->
+ Output;
+ false ->
+ []
+ end
+ end.
diff --git a/src/rlx_prv_release.erl b/src/rlx_prv_release.erl
index bd5acc4..bd58434 100644
--- a/src/rlx_prv_release.erl
+++ b/src/rlx_prv_release.erl
@@ -18,22 +18,18 @@
%%% @author Eric Merritt <[email protected]>
%%% @copyright (C) 2012 Erlware, LLC.
%%%
-%%% @doc This provider uses the lib_dir setting of the state. It searches the
-%%% Lib Dirs looking for all OTP Applications that are available. When it finds
-%%% those OTP Applications it loads the information about them and adds them to
-%%% the state of available apps. This implements the provider behaviour.
-module(rlx_prv_release).
-behaviour(provider).
-export([init/1,
do/1,
- format_error/2]).
+ format_error/1]).
-include("relx.hrl").
-define(PROVIDER, resolve_release).
--define(DEPS, [discover]).
+-define(DEPS, [app_discover]).
%%============================================================================
%% API
@@ -43,12 +39,7 @@
init(State) ->
State1 = rlx_state:add_provider(State, providers:create([{name, ?PROVIDER},
{module, ?MODULE},
- {bare, false},
- {deps, ?DEPS},
- {example, ""},
- {short_desc, ""},
- {desc, ""},
- {opts, []}])),
+ {deps, ?DEPS}])),
{ok, State1}.
%% @doc recursively dig down into the library directories specified in the state
@@ -58,26 +49,31 @@ do(State) ->
DepGraph = create_dep_graph(State),
find_default_release(State, DepGraph).
--spec format_error(ErrorDetail::term(), rlx_state:t()) -> iolist().
-format_error(no_goals_specified, _) ->
+-spec format_error(ErrorDetail::term()) -> iolist().
+format_error(no_goals_specified) ->
"No goals specified for this release ~n";
-format_error({no_release_name, Vsn}, _) ->
+format_error({release_erts_error, Dir}) ->
+ io_lib:format("Unable to find erts in ~s~n", [Dir]);
+format_error({no_release_name, Vsn}) ->
io_lib:format("A target release version was specified (~s) but no name", [Vsn]);
-format_error({invalid_release_info, Info}, _) ->
+format_error({invalid_release_info, Info}) ->
io_lib:format("Target release information is in an invalid format ~p", [Info]);
-format_error({multiple_release_names, RelA, RelB}, _) ->
+format_error({multiple_release_names, RelA, RelB}) ->
io_lib:format("No default release name was specified and there are multiple "
- "releases in the config: ~s, ~s",
- [RelA, RelB]);
-format_error(no_releases_in_system, _) ->
+ "releases in the config: ~s, ~s",
+ [RelA, RelB]);
+format_error(no_releases_in_system) ->
"No releases have been specified in the system!";
-format_error({no_releases_for, RelName}, _) ->
+format_error({no_releases_for, RelName}) ->
io_lib:format("No releases exist in the system for ~s!", [RelName]);
-format_error({release_not_found, {RelName, RelVsn}}, _) ->
+format_error({release_not_found, {RelName, RelVsn}}) ->
io_lib:format("No releases exist in the system for ~p:~s!", [RelName, RelVsn]);
-format_error({failed_solve, Error}, _) ->
+format_error({failed_solve, Error}) ->
io_lib:format("Failed to solve release:\n ~s",
- [rlx_depsolver:format_error({error, Error})]).
+ [rlx_depsolver:format_error({error, Error})]);
+format_error({release_error, Error}) ->
+ io_lib:format("Failed to resolve release:\n ~p~n", [Error]).
+
%%%===================================================================
%%% Internal Functions
@@ -92,28 +88,30 @@ create_dep_graph(State) ->
Deps = rlx_app_info:active_deps(App) ++
rlx_app_info:library_deps(App),
rlx_depsolver:add_package_version(Graph1,
- AppName,
- AppVsn,
- Deps)
+ AppName,
+ AppVsn,
+ Deps)
end, Graph0, Apps).
-spec find_default_release(rlx_state:t(), rlx_depsolver:t()) ->
{ok, rlx_state:t()} | relx:error().
find_default_release(State, DepGraph) ->
- try rlx_state:default_configured_release(State) of
- {undefined, undefined} ->
- resolve_default_release(State, DepGraph);
- {RelName, undefined} ->
- resolve_default_version(State, DepGraph, RelName);
- {undefined, Vsn} ->
- ?RLX_ERROR({no_release_name, Vsn});
- {RelName, RelVsn} ->
- solve_release(State, DepGraph, RelName, RelVsn);
- undefined ->
- ?RLX_ERROR(no_releases_in_system)
+ try
+ case rlx_state:default_configured_release(State) of
+ {undefined, undefined} ->
+ resolve_default_release(State, DepGraph);
+ {RelName, undefined} ->
+ resolve_default_version(State, DepGraph, RelName);
+ {undefined, Vsn} ->
+ ?RLX_ERROR({no_release_name, Vsn});
+ {RelName, RelVsn} ->
+ solve_release(State, DepGraph, RelName, RelVsn);
+ undefined ->
+ ?RLX_ERROR(no_releases_in_system)
+ end
catch
- {multiple_release_names, _, _}=Error ->
+ throw:{multiple_release_names, _, _}=Error ->
?RLX_ERROR(Error)
end.
@@ -156,8 +154,8 @@ release_sort({{RelA, _}, _}, {{RelB, _}, _}) ->
solve_release(State0, DepGraph, RelName, RelVsn) ->
ec_cmd_log:debug(rlx_state:log(State0),
- "Solving Release ~p-~s~n",
- [RelName, RelVsn]),
+ "Solving Release ~p-~s~n",
+ [RelName, RelVsn]),
try
Release =
case get_realized_release(State0, RelName, RelVsn) of
@@ -184,20 +182,32 @@ solve_release(State0, DepGraph, RelName, RelVsn) ->
end.
set_resolved(State, Release0, Pkgs) ->
- case rlx_release:realize(Release0, Pkgs, rlx_state:available_apps(State)) of
- {ok, Release1} ->
- ec_cmd_log:info(rlx_state:log(State),
- "Resolved ~p-~s~n",
- [rlx_release:name(Release1),
- rlx_release:vsn(Release1)]),
- ec_cmd_log:debug(rlx_state:log(State),
- fun() ->
- rlx_release:format(0, Release1)
- end),
- {ok, rlx_state:add_realized_release(State, Release1)};
- {error, E} ->
- ?RLX_ERROR({release_error, E})
- end.
+ case rlx_release:realize(Release0, Pkgs, rlx_state:available_apps(State)) of
+ {ok, Release1} ->
+ ec_cmd_log:info(rlx_state:log(State),
+ "Resolved ~p-~s~n",
+ [rlx_release:name(Release1),
+ rlx_release:vsn(Release1)]),
+ ec_cmd_log:debug(rlx_state:log(State),
+ fun() ->
+ rlx_release:format(0, Release1)
+ end),
+ case rlx_state:get(State, include_erts, undefined) of
+ IncludeErts when is_atom(IncludeErts) ->
+ {ok, rlx_state:add_realized_release(State, Release1)};
+ ErtsDir ->
+ try
+ [Erts | _] = filelib:wildcard(filename:join(ErtsDir, "erts-*")),
+ [_, ErtsVsn] = string:tokens(filename:basename(Erts), "-"),
+ {ok, rlx_state:add_realized_release(State, rlx_release:erts(Release1, ErtsVsn))}
+ catch
+ _:_ ->
+ ?RLX_ERROR({release_erts_error, ErtsDir})
+ end
+ end;
+ {error, E} ->
+ ?RLX_ERROR({release_error, E})
+ end.
get_realized_release(State, RelName, RelVsn) ->
try
diff --git a/src/rlx_prv_relup.erl b/src/rlx_prv_relup.erl
index df6f831..6bf5d56 100644
--- a/src/rlx_prv_relup.erl
+++ b/src/rlx_prv_relup.erl
@@ -26,12 +26,12 @@
-export([init/1,
do/1,
- format_error/2]).
+ format_error/1]).
-include("relx.hrl").
-define(PROVIDER, relup).
--define(DEPS, [release]).
+-define(DEPS, [rel_discover, release]).
%%============================================================================
%% API
@@ -41,12 +41,7 @@
init(State) ->
State1 = rlx_state:add_provider(State, providers:create([{name, ?PROVIDER},
{module, ?MODULE},
- {bare, false},
- {deps, ?DEPS},
- {example, "relup"},
- {short_desc, "Builds release upgrade for latest and last release."},
- {desc, ""},
- {opts, []}])),
+ {deps, ?DEPS}])),
{ok, State1}.
-spec do(rlx_state:t()) -> {ok, rlx_state:t()} | relx:error().
@@ -55,24 +50,24 @@ do(State) ->
Release0 = rlx_state:get_realized_release(State, RelName, RelVsn),
make_relup(State, Release0).
-format_error({relup_generation_error, CurrentName, UpFromName}, _) ->
+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}, _) ->
+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}, _) ->
+format_error({no_upfrom_release_found, undefined}) ->
io_lib:format("No earlier release for relup found", []);
-format_error({no_upfrom_release_found, Vsn}, _) ->
+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, _}}}, _) ->
+ {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}, State) ->
+format_error({relup_script_generation_error, Module, Errors}) ->
["Errors generating relup \n",
- rlx_util:indent(2), Module:format_error(Errors, State)].
+ rlx_util:indent(2), Module:format_error(Errors)].
make_relup(State, Release) ->
Vsn = rlx_state:upfrom(State),
diff --git a/src/rlx_rel_discovery.erl b/src/rlx_rel_discovery.erl
index b7c15bc..1cfdc87 100644
--- a/src/rlx_rel_discovery.erl
+++ b/src/rlx_rel_discovery.erl
@@ -18,10 +18,6 @@
%%% @author Eric Merritt <[email protected]>
%%% @copyright (C) 2012 Erlware, LLC.
%%%
-%%% @doc This provider uses the lib_dir setting of the state. It searches the
-%%% Lib Dirs looking for all OTP Applications that are available. When it finds
-%%% those OTP Applications it loads the information about them and adds them to
-%%% the state of available apps. This implements the provider behaviour.
-module(rlx_rel_discovery).
-export([do/3,
diff --git a/src/rlx_release.erl b/src/rlx_release.erl
index 7b82119..1d333bf 100644
--- a/src/rlx_release.erl
+++ b/src/rlx_release.erl
@@ -41,7 +41,7 @@
canonical_name/1,
format/1,
format/2,
- format_error/2]).
+ format_error/1]).
-export_type([t/0,
name/0,
@@ -217,14 +217,14 @@ format_goal({Constraint, AppType, AppInc}) ->
format_goal(Constraint) ->
rlx_depsolver:format_constraint(Constraint).
--spec format_error(Reason::term(), rlx_state:t()) -> iolist().
-format_error({topo_error, E}, State) ->
- rlx_topo:format_error(E, State);
-format_error({failed_to_parse, Con}, _) ->
+-spec format_error(Reason::term()) -> iolist().
+format_error({topo_error, E}) ->
+ rlx_topo:format_error(E);
+format_error({failed_to_parse, Con}) ->
io_lib:format("Failed to parse constraint ~p", [Con]);
-format_error({invalid_constraint, _, Con}, _) ->
+format_error({invalid_constraint, _, Con}) ->
io_lib:format("Invalid constraint specified ~p", [Con]);
-format_error({not_realized, Name, Vsn}, _) ->
+format_error({not_realized, Name, Vsn}) ->
io_lib:format("Unable to produce metadata release: ~p-~s has not been realized",
[Name, Vsn]).
diff --git a/src/rlx_state.erl b/src/rlx_state.erl
index 550a44a..3bd818a 100644
--- a/src/rlx_state.erl
+++ b/src/rlx_state.erl
@@ -36,6 +36,10 @@
overrides/2,
skip_apps/1,
skip_apps/2,
+ exclude_apps/1,
+ exclude_apps/2,
+ debug_info/1,
+ debug_info/2,
goals/1,
goals/2,
config_file/1,
@@ -102,6 +106,8 @@
sys_config :: file:filename() | undefined,
overrides=[] :: [{AppName::atom(), Directory::file:filename()}],
skip_apps=[] :: [AppName::atom()],
+ exclude_apps=[] :: [AppName::atom()],
+ debug_info=keep :: keep | strip,
configured_releases :: releases(),
realized_releases :: releases(),
dev_mode=false :: boolean(),
@@ -154,7 +160,7 @@ new(Config, CommandLineConfig, Targets)
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),
+ State2 = rlx_state:put(State1, system_libs, true),
State3 = rlx_state:put(State2, overlay_vars, []),
create_logic_providers(State3).
@@ -183,6 +189,23 @@ skip_apps(#state_t{skip_apps=Apps}) ->
skip_apps(State, SkipApps) ->
State#state_t{skip_apps=SkipApps}.
+-spec exclude_apps(t()) -> [AppName::atom()].
+exclude_apps(#state_t{exclude_apps=Apps}) ->
+ Apps.
+
+%% @doc the application overrides for the system
+-spec exclude_apps(t(), [AppName::atom()]) -> t().
+exclude_apps(State, SkipApps) ->
+ State#state_t{exclude_apps=SkipApps}.
+
+-spec debug_info(t()) -> keep | strip.
+debug_info(#state_t{debug_info=DebugInfo}) ->
+ DebugInfo.
+
+-spec debug_info(t(), keep | strip) -> t().
+debug_info(State, DebugInfo) ->
+ State#state_t{debug_info=DebugInfo}.
+
%% @doc get the current log state for the system
-spec log(t()) -> ec_cmd_log:t().
log(#state_t{log=LogState}) ->
@@ -438,7 +461,8 @@ add_hook(post, {PreHooks, PostHooks}, Hook) ->
-spec create_logic_providers(t()) -> t() | relx:error().
create_logic_providers(State) ->
- create_all(State, [rlx_prv_discover,
+ create_all(State, [rlx_prv_app_discover,
+ rlx_prv_rel_discover,
rlx_prv_overlay,
rlx_prv_release,
rlx_prv_assembler,
diff --git a/src/rlx_topo.erl b/src/rlx_topo.erl
index 1d5de7e..d24f227 100644
--- a/src/rlx_topo.erl
+++ b/src/rlx_topo.erl
@@ -34,7 +34,7 @@
-export([sort/1,
sort_apps/1,
- format_error/2]).
+ format_error/1]).
-include("relx.hrl").
@@ -72,8 +72,8 @@ sort(Pairs) ->
iterate(Pairs, [], all(Pairs)).
%% @doc nicely format the error from the sort.
--spec format_error(Reason::term(), rlx_state:t()) -> iolist().
-format_error({cycle, Pairs}, _) ->
+-spec format_error(Reason::term()) -> iolist().
+format_error({cycle, Pairs}) ->
["Cycle detected in dependency graph, this must be resolved "
"before we can continue:\n",
case Pairs of
diff --git a/test/rlx_archive_SUITE.erl b/test/rlx_archive_SUITE.erl
new file mode 100644
index 0000000..27cf94a
--- /dev/null
+++ b/test/rlx_archive_SUITE.erl
@@ -0,0 +1,132 @@
+%%% @author Tristan Sloughter <[email protected]>
+%%% @copyright (C) 2015, Tristan Sloughter
+-module(rlx_archive_SUITE).
+
+-export([suite/0,
+ init_per_suite/1,
+ end_per_suite/1,
+ init_per_testcase/2,
+ all/0,
+ basic_tar/1,
+ exclude_erts/1]).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("eunit/include/eunit.hrl").
+-include_lib("kernel/include/file.hrl").
+
+suite() ->
+ [{timetrap, {seconds, 30}}].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_testcase(_, Config) ->
+ DataDir = proplists:get_value(data_dir, Config),
+ LibDir1 = filename:join([DataDir, rlx_test_utils:create_random_name("lib_dir1_")]),
+ ok = rlx_util:mkdir_p(LibDir1),
+ State = rlx_state:new([], [{lib_dirs, [LibDir1]}], [release]),
+ {ok, State1} = rlx_config:do(State),
+ [{lib1, LibDir1},
+ {state, State1} | Config].
+
+all() ->
+ [basic_tar, exclude_erts].
+
+basic_tar(Config) ->
+ LibDir1 = proplists:get_value(lib1, Config),
+ [(fun({Name, Vsn}) ->
+ rlx_test_utils:create_app(LibDir1, Name, Vsn, [kernel, stdlib], [])
+ end)(App)
+ ||
+ App <-
+ [{rlx_test_utils:create_random_name("lib_app1_"), rlx_test_utils:create_random_vsn()}
+ || _ <- lists:seq(1, 100)]],
+
+ rlx_test_utils:create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []),
+ rlx_test_utils:create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []),
+ rlx_test_utils:create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []),
+ rlx_test_utils:create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]),
+ rlx_test_utils:create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []),
+
+ ConfigFile = filename:join([LibDir1, "relx.config"]),
+ rlx_test_utils:write_config(ConfigFile,
+ [{release, {foo, "0.0.1"},
+ [goal_app_1,
+ goal_app_2]}]),
+ OutputDir = filename:join([proplists:get_value(data_dir, Config),
+ rlx_test_utils:create_random_name("relx-output")]),
+ {ok, State} = relx:do([{relname, foo},
+ {relvsn, "0.0.1"},
+ {goals, []},
+ {lib_dirs, [LibDir1]},
+ {log_level, 3},
+ {output_dir, OutputDir},
+ {config, ConfigFile}], ["release", "tar"]),
+
+ [{{foo, "0.0.1"}, Release}] = ec_dictionary:to_list(rlx_state:realized_releases(State)),
+ AppSpecs = rlx_release:applications(Release),
+ ?assert(lists:keymember(stdlib, 1, AppSpecs)),
+ ?assert(lists:keymember(kernel, 1, AppSpecs)),
+ ?assert(lists:member({non_goal_1, "0.0.1"}, AppSpecs)),
+ ?assert(lists:member({non_goal_2, "0.0.1"}, AppSpecs)),
+ ?assert(lists:member({goal_app_1, "0.0.1"}, AppSpecs)),
+ ?assert(lists:member({goal_app_2, "0.0.1"}, AppSpecs)),
+ ?assert(lists:member({lib_dep_1, "0.0.1", load}, AppSpecs)),
+
+ TarFile = filename:join([OutputDir, "foo", "foo-0.0.1.tar.gz"]),
+ {ok, Files} = erl_tar:table(TarFile, [compressed]),
+ ?assert(lists:any(fun(X) -> re:run(X, "lib/stdlib-.*/ebin/.*") =/= nomatch end, Files)),
+ ?assert(lists:any(fun(X) -> re:run(X, "lib/kernel-.*/ebin/.*") =/= nomatch end, Files)),
+ ?assert(filelib:is_regular(TarFile)).
+
+exclude_erts(Config) ->
+ LibDir1 = proplists:get_value(lib1, Config),
+ [(fun({Name, Vsn}) ->
+ rlx_test_utils:create_app(LibDir1, Name, Vsn, [kernel, stdlib], [])
+ end)(App)
+ ||
+ App <-
+ [{rlx_test_utils:create_random_name("lib_app1_"), rlx_test_utils:create_random_vsn()}
+ || _ <- lists:seq(1, 100)]],
+
+ rlx_test_utils:create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []),
+ rlx_test_utils:create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []),
+ rlx_test_utils:create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []),
+ rlx_test_utils:create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]),
+ rlx_test_utils:create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []),
+
+ ConfigFile = filename:join([LibDir1, "relx.config"]),
+ rlx_test_utils:write_config(ConfigFile,
+ [{release, {foo, "0.0.1"},
+ [goal_app_1,
+ goal_app_2]}]),
+ OutputDir = filename:join([proplists:get_value(data_dir, Config),
+ rlx_test_utils:create_random_name("relx-output")]),
+ {ok, State} = relx:do([{relname, foo},
+ {relvsn, "0.0.1"},
+ {goals, []},
+ {lib_dirs, [LibDir1]},
+ {log_level, 3},
+ {output_dir, OutputDir},
+ {config, ConfigFile},
+ {include_erts, false},
+ {system_libs, false}], ["release", "tar"]),
+
+ [{{foo, "0.0.1"}, Release}] = ec_dictionary:to_list(rlx_state:realized_releases(State)),
+ AppSpecs = rlx_release:applications(Release),
+ ?assert(lists:keymember(stdlib, 1, AppSpecs)),
+ ?assert(lists:keymember(kernel, 1, AppSpecs)),
+ ?assert(lists:member({non_goal_1, "0.0.1"}, AppSpecs)),
+ ?assert(lists:member({non_goal_2, "0.0.1"}, AppSpecs)),
+ ?assert(lists:member({goal_app_1, "0.0.1"}, AppSpecs)),
+ ?assert(lists:member({goal_app_2, "0.0.1"}, AppSpecs)),
+ ?assert(lists:member({lib_dep_1, "0.0.1", load}, AppSpecs)),
+
+ TarFile = filename:join([OutputDir, "foo", "foo-0.0.1.tar.gz"]),
+ {ok, Files} = erl_tar:table(TarFile, [compressed]),
+ ?assert(lists:all(fun(X) -> re:run(X, "lib/stdlib-.*/ebin/.*") =:= nomatch end, Files)),
+ ?assert(lists:all(fun(X) -> re:run(X, "lib/kernel-.*/ebin/.*") =:= nomatch end, Files)),
+ ?assert(filelib:is_regular(TarFile)).
diff --git a/test/rlx_discover_SUITE.erl b/test/rlx_discover_SUITE.erl
index 2db8e4d..4a3b817 100644
--- a/test/rlx_discover_SUITE.erl
+++ b/test/rlx_discover_SUITE.erl
@@ -77,8 +77,8 @@ normal_case(Config) ->
|| _ <- lists:seq(1, 100)]],
State0 = rlx_state:put(proplists:get_value(state, Config),
default_libs, false),
- {ok, State1} = providers:new(rlx_prv_discover, State0),
- DiscoverProvider = providers:get_provider(discover, rlx_state:providers(State1)),
+ {ok, State1} = providers:new(rlx_prv_app_discover, State0),
+ DiscoverProvider = providers:get_provider(app_discover, rlx_state:providers(State1)),
{ok, State2} = providers:do(DiscoverProvider, State1),
lists:foreach(fun(App) ->
@@ -114,10 +114,10 @@ no_beam_case(Config) ->
AppDir = filename:join([LibDir2, BadName]),
write_app_file(AppDir, BadName, BadVsn),
State0 = proplists:get_value(state, Config),
- %% Deliberately disable release discovery when running `rlx_prv_discover`
+ %% Deliberately disable release discovery when running `rlx_prv_app_discover`
State1 = rlx_state:put(State0, disable_rel_discovery, true),
- {ok, State2} = providers:new(rlx_prv_discover, State1),
- DiscoverProvider = providers:get_provider(discover, rlx_state:providers(State2)),
+ {ok, State2} = providers:new(rlx_prv_app_discover, State1),
+ DiscoverProvider = providers:get_provider(app_discover, rlx_state:providers(State2)),
?assertMatch({ok, _},
providers:do(DiscoverProvider, State2)).
@@ -146,8 +146,8 @@ bad_ebin_case(Config) ->
ok = filelib:ensure_dir(Filename),
ok = ec_file:write_term(Filename, get_bad_app_metadata(BadName, BadVsn)),
State0 = proplists:get_value(state, Config),
- {ok, State1} = providers:new(rlx_prv_discover, State0),
- DiscoverProvider = providers:get_provider(discover, rlx_state:providers(State1)),
+ {ok, State1} = providers:new(rlx_prv_app_discover, State0),
+ DiscoverProvider = providers:get_provider(app_discover, rlx_state:providers(State1)),
{ok, State2} = providers:do(DiscoverProvider, State1),
?assertMatch([], [App || App <- rlx_state:available_apps(State2),
BadName =:= rlx_app_info:name(App)]).
@@ -172,8 +172,8 @@ shallow_app_discovery(Config) ->
State0 = rlx_state:put(proplists:get_value(state, Config),
default_libs, false),
State1 = rlx_state:put(State0, enable_shallow_app_discovery, true),
- {ok, State2} = providers:new(rlx_prv_discover, State1),
- DiscoverProvider = providers:get_provider(discover, rlx_state:providers(State2)),
+ {ok, State2} = providers:new(rlx_prv_app_discover, State1),
+ DiscoverProvider = providers:get_provider(app_discover, rlx_state:providers(State2)),
{ok, State3} = providers:do(DiscoverProvider, State2),
lists:foreach(fun(App) ->
?assertMatch(true, lists:member(App, rlx_state:available_apps(State3)))
diff --git a/test/rlx_release_SUITE.erl b/test/rlx_release_SUITE.erl
index 112afc8..766eb40 100644
--- a/test/rlx_release_SUITE.erl
+++ b/test/rlx_release_SUITE.erl
@@ -29,6 +29,7 @@
make_scriptless_release/1,
make_overridden_release/1,
make_skip_app_release/1,
+ make_exclude_app_release/1,
make_auto_skip_empty_app_release/1,
make_app_type_none_release/1,
make_rerun_overridden_release/1,
@@ -40,12 +41,12 @@
make_relup_release/1,
make_relup_release2/1,
make_one_app_top_level_release/1,
- make_dev_mode_release/1]).
+ make_dev_mode_release/1,
+ make_config_script_release/1]).
-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
-include_lib("kernel/include/file.hrl").
--include_lib("kernel/include/file.hrl").
suite() ->
[{timetrap,{seconds,30}}].
@@ -58,7 +59,7 @@ end_per_suite(_Config) ->
init_per_testcase(_, Config) ->
DataDir = proplists:get_value(data_dir, Config),
- LibDir1 = filename:join([DataDir, create_random_name("lib_dir1_")]),
+ LibDir1 = filename:join([DataDir, rlx_test_utils:create_random_name("lib_dir1_")]),
ok = rlx_util:mkdir_p(LibDir1),
State = rlx_state:new([], [{lib_dirs, [LibDir1]}], [release]),
{ok, State1} = rlx_config:do(State),
@@ -68,30 +69,32 @@ init_per_testcase(_, Config) ->
all() ->
[make_release, make_extend_release, make_scriptless_release,
make_overridden_release, make_auto_skip_empty_app_release,
- make_skip_app_release, make_app_type_none_release,
+ make_skip_app_release, make_exclude_app_release, make_app_type_none_release,
make_implicit_config_release, make_rerun_overridden_release,
overlay_release, make_goalless_release, make_depfree_release,
make_invalid_config_release, make_relup_release, make_relup_release2,
- make_one_app_top_level_release, make_dev_mode_release].
+ make_one_app_top_level_release, make_dev_mode_release,
+ make_config_script_release].
make_release(Config) ->
LibDir1 = proplists:get_value(lib1, Config),
+
[(fun({Name, Vsn}) ->
- create_app(LibDir1, Name, Vsn, [kernel, stdlib], [])
+ rlx_test_utils:create_app(LibDir1, Name, Vsn, [kernel, stdlib], [])
end)(App)
- ||
+ ||
App <-
- [{create_random_name("lib_app1_"), create_random_vsn()}
- || _ <- lists:seq(1, 100)]],
+ [{rlx_test_utils:create_random_name("lib_app1_"), rlx_test_utils:create_random_vsn()}
+ || _ <- lists:seq(1, 100)]],
- create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []),
- create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []),
- create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []),
- create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]),
- create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []),
+ rlx_test_utils:create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []),
+ rlx_test_utils:create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []),
+ rlx_test_utils:create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []),
+ rlx_test_utils:create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]),
+ rlx_test_utils:create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []),
ConfigFile = filename:join([LibDir1, "relx.config"]),
- write_config(ConfigFile,
+ rlx_test_utils:write_config(ConfigFile,
[{release, {foo, "0.0.1"},
[goal_app_1,
goal_app_2]},
@@ -99,7 +102,7 @@ make_release(Config) ->
[goal_app_1,
goal_app_2]}]),
OutputDir = filename:join([proplists:get_value(data_dir, Config),
- create_random_name("relx-output")]),
+ rlx_test_utils:create_random_name("relx-output")]),
{ok, State} = relx:do(undefined, undefined, [], [LibDir1], 3,
OutputDir, ConfigFile),
[{{foo, "0.0.2"}, Release}] = ec_dictionary:to_list(rlx_state:realized_releases(State)),
@@ -114,22 +117,15 @@ make_release(Config) ->
make_extend_release(Config) ->
LibDir1 = proplists:get_value(lib1, Config),
- [(fun({Name, Vsn}) ->
- create_app(LibDir1, Name, Vsn, [kernel, stdlib], [])
- end)(App)
- ||
- App <-
- [{create_random_name("lib_app1_"), create_random_vsn()}
- || _ <- lists:seq(1, 100)]],
- create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []),
- create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []),
- create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []),
- create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]),
- create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []),
+ rlx_test_utils:create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []),
+ rlx_test_utils:create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []),
+ rlx_test_utils:create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []),
+ rlx_test_utils:create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]),
+ rlx_test_utils:create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []),
ConfigFile = filename:join([LibDir1, "relx.config"]),
- write_config(ConfigFile,
+ rlx_test_utils:write_config(ConfigFile,
[{release, {foo, "0.0.1"},
[goal_app_1,
goal_app_2]},
@@ -137,9 +133,9 @@ make_extend_release(Config) ->
[goal_app_2]},
{lib_dirs, [filename:join(LibDir1, "*")]}]),
OutputDir = filename:join([proplists:get_value(data_dir, Config),
- create_random_name("relx-output")]),
+ rlx_test_utils:create_random_name("relx-output")]),
- ?assertMatch({multiple_release_names,foo_test,foo},
+ ?assertMatch({error, {rlx_prv_release, {multiple_release_names,foo_test,foo}}},
catch relx:do(undefined, undefined, [], [LibDir1], 3, OutputDir, ConfigFile)),
{ok, State} = relx:do(foo_test, undefined, [], [LibDir1], 3,
@@ -156,19 +152,12 @@ make_extend_release(Config) ->
make_invalid_config_release(Config) ->
LibDir1 = proplists:get_value(lib1, Config),
- [(fun({Name, Vsn}) ->
- create_app(LibDir1, Name, Vsn, [kernel, stdlib], [])
- end)(App)
- ||
- App <-
- [{create_random_name("lib_app1_"), create_random_vsn()}
- || _ <- lists:seq(1, 100)]],
- create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []),
- create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []),
- create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []),
- create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]),
- create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []),
+ rlx_test_utils:create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []),
+ rlx_test_utils:create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []),
+ rlx_test_utils:create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []),
+ rlx_test_utils:create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]),
+ rlx_test_utils:create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []),
ConfigFile = filename:join([LibDir1, "relx.config"]),
ok = ec_file:write(ConfigFile,
@@ -176,35 +165,28 @@ make_invalid_config_release(Config) ->
[goal_app_1,
goal_app_2,]}"),
OutputDir = filename:join([proplists:get_value(data_dir, Config),
- create_random_name("relx-output")]),
+ rlx_test_utils:create_random_name("relx-output")]),
{error, {rlx_config,
{consult, _, _}}} = relx:do(undefined, undefined, [], [LibDir1], 3,
OutputDir, ConfigFile).
make_scriptless_release(Config) ->
LibDir1 = proplists:get_value(lib1, Config),
- [(fun({Name, Vsn}) ->
- create_app(LibDir1, Name, Vsn, [kernel, stdlib], [])
- end)(App)
- ||
- App <-
- [{create_random_name("lib_app1_"), create_random_vsn()}
- || _ <- lists:seq(1, 100)]],
- create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []),
- create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []),
- create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []),
- create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]),
- create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []),
+ rlx_test_utils:create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []),
+ rlx_test_utils:create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []),
+ rlx_test_utils:create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []),
+ rlx_test_utils:create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]),
+ rlx_test_utils:create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []),
ConfigFile = filename:join([LibDir1, "relx.config"]),
- write_config(ConfigFile,
+ rlx_test_utils:write_config(ConfigFile,
[{generate_start_script, false},
{release, {foo, "0.0.1"},
[goal_app_1,
goal_app_2]}]),
OutputDir = filename:join([proplists:get_value(data_dir, Config),
- create_random_name("relx-output")]),
+ rlx_test_utils:create_random_name("relx-output")]),
{ok, State} = relx:do(undefined, undefined, [], [LibDir1], 3,
OutputDir, ConfigFile),
@@ -223,36 +205,30 @@ make_scriptless_release(Config) ->
make_overridden_release(Config) ->
DataDir = proplists:get_value(data_dir, Config),
- OverrideDir1 = filename:join([DataDir, create_random_name("override_dir_")]),
+ OverrideDir1 = filename:join([DataDir, rlx_test_utils:create_random_name("override_dir_")]),
LibDir1 = proplists:get_value(lib1, Config),
- [(fun({Name, Vsn}) ->
- create_app(LibDir1, Name, Vsn, [kernel, stdlib], [])
- end)(App)
- ||
- App <-
- [{create_random_name("lib_app1_"), create_random_vsn()}
- || _ <- lists:seq(1, 100)]],
- OverrideApp = create_random_name("override_app"),
- OverrideVsn = create_random_vsn(),
+
+ OverrideApp = rlx_test_utils:create_random_name("override_app"),
+ OverrideVsn = rlx_test_utils:create_random_vsn(),
OverrideAppDir = filename:join(OverrideDir1, OverrideApp ++ "-" ++ OverrideVsn),
OverrideAppName = erlang:list_to_atom(OverrideApp),
- create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []),
- create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []),
- create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []),
- create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]),
- create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []),
+ rlx_test_utils:create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []),
+ rlx_test_utils:create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []),
+ rlx_test_utils:create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []),
+ rlx_test_utils:create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]),
+ rlx_test_utils:create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []),
- create_app(OverrideDir1, OverrideApp, OverrideVsn, [stdlib,kernel], []),
+ rlx_test_utils:create_app(OverrideDir1, OverrideApp, OverrideVsn, [stdlib,kernel], []),
ConfigFile = filename:join([LibDir1, "relx.config"]),
- write_config(ConfigFile,
+ rlx_test_utils:write_config(ConfigFile,
[{release, {foo, "0.0.1"},
[goal_app_1,
erlang:list_to_atom(OverrideApp),
goal_app_2]}]),
OutputDir = filename:join([proplists:get_value(data_dir, Config),
- create_random_name("relx-output")]),
+ rlx_test_utils:create_random_name("relx-output")]),
{ok, Cwd} = file:get_cwd(),
{ok, State} = relx:do(Cwd, undefined, undefined, [], [LibDir1], 3,
OutputDir, [{OverrideAppName, OverrideAppDir}],
@@ -273,27 +249,20 @@ make_overridden_release(Config) ->
make_skip_app_release(Config) ->
LibDir1 = proplists:get_value(lib1, Config),
- [(fun({Name, Vsn}) ->
- create_app(LibDir1, Name, Vsn, [kernel, stdlib], [])
- end)(App)
- ||
- App <-
- [{create_random_name("lib_app1_"), create_random_vsn()}
- || _ <- lists:seq(1, 100)]],
- create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []),
- create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []),
- create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []),
- create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]),
- create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []),
+ rlx_test_utils:create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []),
+ rlx_test_utils:create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []),
+ rlx_test_utils:create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []),
+ rlx_test_utils:create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]),
+ rlx_test_utils:create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []),
ConfigFile = filename:join([LibDir1, "relx.config"]),
- write_config(ConfigFile,
+ rlx_test_utils:write_config(ConfigFile,
[{release, {foo, "0.0.1"},
[goal_app_1]},
{skip_apps, [goal_app_2]}]),
OutputDir = filename:join([proplists:get_value(data_dir, Config),
- create_random_name("relx-output")]),
+ rlx_test_utils:create_random_name("relx-output")]),
{ok, Cwd} = file:get_cwd(),
{ok, State} = relx:do(Cwd, undefined, undefined, [], [LibDir1], 3,
OutputDir, [],
@@ -308,36 +277,57 @@ make_skip_app_release(Config) ->
?assertNot(lists:member({goal_app_2, "0.0.1"}, AppSpecs)),
?assert(lists:member({lib_dep_1, "0.0.1", load}, AppSpecs)).
+%% Test to ensure that an excluded app and its deps are not included in a release
+make_exclude_app_release(Config) ->
+ LibDir1 = proplists:get_value(lib1, Config),
+
+ rlx_test_utils:create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel, non_goal_1], []),
+ rlx_test_utils:create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel, non_goal_2], []),
+ rlx_test_utils:create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []),
+
+ ConfigFile = filename:join([LibDir1, "relx.config"]),
+ rlx_test_utils:write_config(ConfigFile,
+ [{release, {foo, "0.0.1"},
+ [goal_app_1]},
+ {exclude_apps, [non_goal_1]}]),
+ OutputDir = filename:join([proplists:get_value(data_dir, Config),
+ rlx_test_utils:create_random_name("relx-output")]),
+ {ok, Cwd} = file:get_cwd(),
+ {ok, State} = relx:do(Cwd, undefined, undefined, [], [LibDir1], 3,
+ OutputDir, [],
+ ConfigFile),
+ [{{foo, "0.0.1"}, Release}] = ec_dictionary:to_list(rlx_state:realized_releases(State)),
+ AppSpecs = rlx_release:applications(Release),
+ ?assert(lists:keymember(stdlib, 1, AppSpecs)),
+ ?assert(lists:keymember(kernel, 1, AppSpecs)),
+ ?assertNot(lists:member({non_goal_1, "0.0.1"}, AppSpecs)),
+ ?assertNot(lists:member({non_goal_2, "0.0.1"}, AppSpecs)),
+ ?assert(lists:member({goal_app_1, "0.0.1"}, AppSpecs)).
+
make_auto_skip_empty_app_release(Config) ->
DataDir = proplists:get_value(data_dir, Config),
- EmptyAppDir1 = filename:join([DataDir, create_random_name("skip_app_dir_")]),
+ EmptyAppDir1 = filename:join([DataDir, rlx_test_utils:create_random_name("skip_app_dir_")]),
LibDir1 = proplists:get_value(lib1, Config),
- [(fun({Name, Vsn}) ->
- create_app(LibDir1, Name, Vsn, [kernel, stdlib], [])
- end)(App)
- ||
- App <-
- [{create_random_name("lib_app1_"), create_random_vsn()}
- || _ <- lists:seq(1, 100)]],
- EmptyAppApp = create_random_name("empty_app_app"),
- EmptyAppVsn = create_random_vsn(),
+
+ EmptyAppApp = rlx_test_utils:create_random_name("empty_app_app"),
+ EmptyAppVsn = rlx_test_utils:create_random_vsn(),
EmptyAppAppName = erlang:list_to_atom(EmptyAppApp),
- create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []),
- create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []),
- create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []),
- create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]),
- create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []),
+ rlx_test_utils:create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []),
+ rlx_test_utils:create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []),
+ rlx_test_utils:create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []),
+ rlx_test_utils:create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]),
+ rlx_test_utils:create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []),
- create_empty_app(EmptyAppDir1, EmptyAppApp, EmptyAppVsn, [stdlib,kernel], []),
+ rlx_test_utils:create_empty_app(EmptyAppDir1, EmptyAppApp, EmptyAppVsn, [stdlib,kernel], []),
ConfigFile = filename:join([LibDir1, "relx.config"]),
- write_config(ConfigFile,
+ rlx_test_utils:write_config(ConfigFile,
[{release, {foo, "0.0.1"},
[goal_app_1,
goal_app_2]}]),
OutputDir = filename:join([proplists:get_value(data_dir, Config),
- create_random_name("relx-output")]),
+ rlx_test_utils:create_random_name("relx-output")]),
{ok, Cwd} = file:get_cwd(),
{ok, State} = relx:do(Cwd, undefined, undefined, [], [LibDir1], 3,
OutputDir, [],
@@ -355,27 +345,20 @@ make_auto_skip_empty_app_release(Config) ->
make_app_type_none_release(Config) ->
LibDir1 = proplists:get_value(lib1, Config),
- [(fun({Name, Vsn}) ->
- create_app(LibDir1, Name, Vsn, [kernel, stdlib], [])
- end)(App)
- ||
- App <-
- [{create_random_name("lib_app1_"), create_random_vsn()}
- || _ <- lists:seq(1, 100)]],
- create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []),
- create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []),
- create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []),
- create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]),
- create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []),
+ rlx_test_utils:create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []),
+ rlx_test_utils:create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []),
+ rlx_test_utils:create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []),
+ rlx_test_utils:create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]),
+ rlx_test_utils:create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []),
ConfigFile = filename:join([LibDir1, "relx.config"]),
- write_config(ConfigFile,
+ rlx_test_utils:write_config(ConfigFile,
[{release, {foo, "0.0.1"},
[goal_app_1,
{goal_app_2, none}]}]),
OutputDir = filename:join([proplists:get_value(data_dir, Config),
- create_random_name("relx-output")]),
+ rlx_test_utils:create_random_name("relx-output")]),
{ok, Cwd} = file:get_cwd(),
{ok, State} = relx:do(Cwd, undefined, undefined, [], [LibDir1], 3,
OutputDir, [],
@@ -394,27 +377,20 @@ make_implicit_config_release(Config) ->
LibDir1 = proplists:get_value(lib1, Config),
FooRoot = filename:join([LibDir1, "foodir1", "foodir2"]),
filelib:ensure_dir(filename:join([FooRoot, "tmp"])),
- [(fun({Name, Vsn}) ->
- create_app(LibDir1, Name, Vsn, [kernel, stdlib], [])
- end)(App)
- ||
- App <-
- [{create_random_name("lib_app1_"), create_random_vsn()}
- || _ <- lists:seq(1, 100)]],
- create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []),
- create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []),
- create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []),
- create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]),
- create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []),
+ rlx_test_utils:create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []),
+ rlx_test_utils:create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []),
+ rlx_test_utils:create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []),
+ rlx_test_utils:create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]),
+ rlx_test_utils:create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []),
ConfigFile = filename:join([LibDir1, "relx.config"]),
- write_config(ConfigFile,
+ rlx_test_utils:write_config(ConfigFile,
[{release, {foo, "0.0.1"},
[goal_app_1,
goal_app_2]}]),
OutputDir = filename:join([proplists:get_value(data_dir, Config),
- create_random_name("relx-output")]),
+ rlx_test_utils:create_random_name("relx-output")]),
ok = file:set_cwd(FooRoot),
{ok, FooRoot} = file:get_cwd(),
{ok, State} = relx:do(undefined, undefined, [], [LibDir1], 3,
@@ -432,39 +408,33 @@ make_implicit_config_release(Config) ->
make_rerun_overridden_release(Config) ->
DataDir = proplists:get_value(data_dir, Config),
- OverrideDir1 = filename:join([DataDir, create_random_name("override_dir_")]),
+ OverrideDir1 = filename:join([DataDir, rlx_test_utils:create_random_name("override_dir_")]),
LibDir1 = proplists:get_value(lib1, Config),
- [(fun({Name, Vsn}) ->
- create_app(LibDir1, Name, Vsn, [kernel, stdlib], [])
- end)(App)
- ||
- App <-
- [{create_random_name("lib_app1_"), create_random_vsn()}
- || _ <- lists:seq(1, 100)]],
- OverrideApp = create_random_name("override_app"),
- OverrideVsn = create_random_vsn(),
+
+ OverrideApp = rlx_test_utils:create_random_name("override_app"),
+ OverrideVsn = rlx_test_utils:create_random_vsn(),
OverrideAppDir = filename:join(OverrideDir1, OverrideApp ++ "-"
++ OverrideVsn),
OverrideAppName = erlang:list_to_atom(OverrideApp),
- create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []),
- create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []),
- create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []),
- create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]),
- create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []),
+ rlx_test_utils:create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []),
+ rlx_test_utils:create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []),
+ rlx_test_utils:create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []),
+ rlx_test_utils:create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]),
+ rlx_test_utils:create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []),
- create_app(OverrideDir1, OverrideApp, OverrideVsn, [stdlib,kernel], []),
+ rlx_test_utils:create_app(OverrideDir1, OverrideApp, OverrideVsn, [stdlib,kernel], []),
ConfigFile = filename:join([LibDir1, "relx.config"]),
OverlayVars = filename:join([LibDir1, "vars1.config"]),
- write_config(ConfigFile,
+ rlx_test_utils:write_config(ConfigFile,
[{release, {foo, "0.0.1"},
[goal_app_1,
erlang:list_to_atom(OverrideApp),
goal_app_2]},
{overlay_vars, [OverlayVars]}]),
OutputDir = filename:join([proplists:get_value(data_dir, Config),
- create_random_name("relx-output")]),
+ rlx_test_utils:create_random_name("relx-output")]),
{ok, Cwd} = file:get_cwd(),
{ok, _} = relx:do(Cwd, undefined, undefined, [], [LibDir1], 3,
OutputDir, [{OverrideAppName, OverrideAppDir}],
@@ -491,30 +461,24 @@ make_rerun_overridden_release(Config) ->
overlay_release(Config) ->
LibDir1 = proplists:get_value(lib1, Config),
- [(fun({Name, Vsn}) ->
- create_app(LibDir1, Name, Vsn, [kernel, stdlib], [])
- end)(App)
- ||
- App <-
- [{create_random_name("lib_app1_"), create_random_vsn()}
- || _ <- lists:seq(1, 100)]],
- create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []),
- create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []),
- create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []),
- create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]),
- create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []),
+ rlx_test_utils:create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []),
+ rlx_test_utils:create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []),
+ rlx_test_utils:create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []),
+ rlx_test_utils:create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]),
+ rlx_test_utils:create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []),
ConfigFile = filename:join([LibDir1, "relx.config"]),
OverlayVars1 = filename:join([LibDir1, "vars1.config"]),
OverlayVars2 = filename:join([LibDir1, "vars2.config"]),
+ OverlayVars3 = filename:join([LibDir1, "vars3.config"]),
Template = filename:join([LibDir1, "test_template"]),
TestDir = "first_test_dir",
TestFile = "test_file",
TestDirFull = filename:join([LibDir1, TestDir]),
TestFileFull = filename:join(TestDirFull, TestFile),
SecondTestDir = "second_test_dir",
- write_config(ConfigFile,
+ rlx_test_utils:write_config(ConfigFile,
[{overlay_vars, [OverlayVars1, OverlayVars2]},
{overlay, [{mkdir, "{{target_dir}}/fooo"},
{copy, OverlayVars1,
@@ -524,31 +488,38 @@ overlay_release(Config) ->
{copy, TestDirFull,
"{{target_dir}}/"++SecondTestDir++"/"},
{template, Template,
- "{{target_dir}}/test_template_resolved"}]},
+ "{{target_dir}}/test_template_resolved"},
+ {template, Template,
+ "bin/{{default_release_name}}-{{default_release_version}}"}]},
{release, {foo, "0.0.1"},
[goal_app_1,
goal_app_2]}]),
VarsFile1 = filename:join([LibDir1, "vars1.config"]),
- write_config(VarsFile1, [{yahoo, "yahoo"},
+ rlx_test_utils:write_config(VarsFile1, [{yahoo, "yahoo"},
{yahoo2, [{foo, "bar"}]},
{yahoo3, [{bar, "{{yahoo}}/{{yahoo2.foo}}"}]},
{foo_dir, "foodir"}]),
VarsFile2 = filename:join([LibDir1, "vars2.config"]),
- write_config(VarsFile2, [{google, "yahoo"},
- {yahoo2, [{foo, "foo"}]}]),
+ rlx_test_utils:write_config(VarsFile2, [{google, "yahoo"},
+ {yahoo2, [{foo, "foo"}]},
+ OverlayVars3]),
+
+ VarsFile3 = filename:join([LibDir1, "vars3.config"]),
+ rlx_test_utils:write_config(VarsFile3, [{google, "yahoo"},
+ {yahoo4, [{foo, "{{yahoo}}/{{yahoo2.foo}}4"}]}]),
ok = rlx_util:mkdir_p(TestDirFull),
- ok = file:write_file(TestFileFull, test_template_contents()),
+ ok = file:write_file(TestFileFull, rlx_test_utils:test_template_contents()),
TemplateFile = filename:join([LibDir1, "test_template"]),
- ok = file:write_file(TemplateFile, test_template_contents()),
+ ok = file:write_file(TemplateFile, rlx_test_utils:test_template_contents()),
{ok, FileInfo} = file:read_file_info(TemplateFile),
ok = file:write_file_info(TemplateFile, FileInfo#file_info{mode=8#00777}),
OutputDir = filename:join([proplists:get_value(data_dir, Config),
- create_random_name("relx-output")]),
+ rlx_test_utils:create_random_name("relx-output")]),
{ok, State} = relx:do(undefined, undefined, [], [LibDir1], 3,
OutputDir, ConfigFile),
@@ -639,57 +610,45 @@ overlay_release(Config) ->
proplists:get_value(foo_dir, TemplateData)),
?assertEqual("yahoo/foo",
proplists:get_value(yahoo3, TemplateData)),
+ ?assertEqual("yahoo/foo4",
+ proplists:get_value(yahoo4, TemplateData)),
?assertEqual("yahoo",
proplists:get_value(google, TemplateData)).
make_goalless_release(Config) ->
LibDir1 = proplists:get_value(lib1, Config),
- [(fun({Name, Vsn}) ->
- create_app(LibDir1, Name, Vsn, [kernel, stdlib], [])
- end)(App)
- ||
- App <-
- [{create_random_name("lib_app1_"), create_random_vsn()}
- || _ <- lists:seq(1, 100)]],
- create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []),
- create_app(LibDir1, "lib_dep_1", "0.0.1", [], []),
- create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []),
- create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]),
- create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []),
+ rlx_test_utils:create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []),
+ rlx_test_utils:create_app(LibDir1, "lib_dep_1", "0.0.1", [], []),
+ rlx_test_utils:create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []),
+ rlx_test_utils:create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]),
+ rlx_test_utils:create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []),
ConfigFile = filename:join([LibDir1, "relx.config"]),
- write_config(ConfigFile,
+ rlx_test_utils:write_config(ConfigFile,
[{release, {foo, "0.0.1"},
[]}]),
OutputDir = filename:join([proplists:get_value(data_dir, Config),
- create_random_name("relx-output")]),
+ rlx_test_utils:create_random_name("relx-output")]),
?assertMatch({error,{rlx_prv_release,no_goals_specified}},
relx:do(undefined, undefined, [], [LibDir1], 3,
OutputDir, ConfigFile)).
make_depfree_release(Config) ->
LibDir1 = proplists:get_value(lib1, Config),
- [(fun({Name, Vsn}) ->
- create_app(LibDir1, Name, Vsn, [kernel, stdlib], [])
- end)(App)
- ||
- App <-
- [{create_random_name("lib_app1_"), create_random_vsn()}
- || _ <- lists:seq(1, 100)]],
- create_app(LibDir1, "goal_app_1", "0.0.1", [kernel,stdlib], []),
- create_app(LibDir1, "lib_dep_1", "0.0.1", [kernel,stdlib], []),
- create_app(LibDir1, "goal_app_2", "0.0.1", [kernel,stdlib], []),
- create_app(LibDir1, "non_goal_1", "0.0.1", [kernel,stdlib], []),
- create_app(LibDir1, "non_goal_2", "0.0.1", [kernel,stdlib], []),
+ rlx_test_utils:create_app(LibDir1, "goal_app_1", "0.0.1", [kernel,stdlib], []),
+ rlx_test_utils:create_app(LibDir1, "lib_dep_1", "0.0.1", [kernel,stdlib], []),
+ rlx_test_utils:create_app(LibDir1, "goal_app_2", "0.0.1", [kernel,stdlib], []),
+ rlx_test_utils:create_app(LibDir1, "non_goal_1", "0.0.1", [kernel,stdlib], []),
+ rlx_test_utils:create_app(LibDir1, "non_goal_2", "0.0.1", [kernel,stdlib], []),
ConfigFile = filename:join([LibDir1, "relx.config"]),
- write_config(ConfigFile,
+ rlx_test_utils:write_config(ConfigFile,
[{release, {foo, "0.0.1"},
[goal_app_1]}]),
OutputDir = filename:join([proplists:get_value(data_dir, Config),
- create_random_name("relx-output")]),
+ rlx_test_utils:create_random_name("relx-output")]),
{ok, State} = relx:do(undefined, undefined, [], [LibDir1], 3,
OutputDir, ConfigFile),
[{{foo, "0.0.1"}, Release}] = ec_dictionary:to_list(rlx_state:realized_releases(State)),
@@ -699,29 +658,22 @@ make_depfree_release(Config) ->
make_relup_release(Config) ->
LibDir1 = proplists:get_value(lib1, Config),
- [(fun({Name, Vsn}) ->
- create_app(LibDir1, Name, Vsn, [kernel, stdlib], [])
- end)(App)
- ||
- App <-
- [{create_random_name("lib_app1_"), create_random_vsn()}
- || _ <- lists:seq(1, 100)]],
-
- create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []),
- create_app(LibDir1, "goal_app_1", "0.0.2", [stdlib,kernel,non_goal_1], []),
- {ok, GA1} = create_app(LibDir1, "goal_app_1", "0.0.3", [stdlib,kernel,non_goal_1], []),
- create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []),
- create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []),
- create_app(LibDir1, "goal_app_2", "0.0.2", [stdlib,kernel,goal_app_1,non_goal_2], []),
- {ok, GA2} = create_app(LibDir1, "goal_app_2", "0.0.3", [stdlib,kernel,goal_app_1,non_goal_2], []),
- create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]),
- create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []),
-
- write_appup_file(GA1, "0.0.2"),
- write_appup_file(GA2, "0.0.2"),
+
+ rlx_test_utils:create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []),
+ rlx_test_utils:create_app(LibDir1, "goal_app_1", "0.0.2", [stdlib,kernel,non_goal_1], []),
+ {ok, GA1} = rlx_test_utils:create_app(LibDir1, "goal_app_1", "0.0.3", [stdlib,kernel,non_goal_1], []),
+ rlx_test_utils:create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []),
+ rlx_test_utils:create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []),
+ rlx_test_utils:create_app(LibDir1, "goal_app_2", "0.0.2", [stdlib,kernel,goal_app_1,non_goal_2], []),
+ {ok, GA2} = rlx_test_utils:create_app(LibDir1, "goal_app_2", "0.0.3", [stdlib,kernel,goal_app_1,non_goal_2], []),
+ rlx_test_utils:create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]),
+ rlx_test_utils:create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []),
+
+ rlx_test_utils:write_appup_file(GA1, "0.0.2"),
+ rlx_test_utils:write_appup_file(GA2, "0.0.2"),
ConfigFile = filename:join([LibDir1, "relx.config"]),
- write_config(ConfigFile,
+ rlx_test_utils:write_config(ConfigFile,
[{release, {foo, "0.0.1"},
[sasl,
{goal_app_1, "0.0.1"},
@@ -735,11 +687,18 @@ make_relup_release(Config) ->
{goal_app_1, "0.0.3"},
{goal_app_2, "0.0.3"}]}]),
OutputDir = filename:join([proplists:get_value(data_dir, Config),
- create_random_name("relx-output")]),
+ rlx_test_utils:create_random_name("relx-output")]),
{ok, _} = relx:do(foo, "0.0.1", [], [LibDir1], 3,
- OutputDir, ConfigFile),
+ OutputDir, ConfigFile),
+
{ok, _} = relx:do(foo, "0.0.2", [], [LibDir1], 3,
- OutputDir, ConfigFile),
+ OutputDir, ConfigFile),
+
+ %% Goal apps are removed to simulate a users dev environment where the apps
+ %% being used in an appup/relup are likely only under _rel/<release>/lib/
+ ec_file:remove(filename:join(LibDir1, "goal_app_1-0.0.1"), [recursive]),
+ ec_file:remove(filename:join(LibDir1, "goal_app_1-0.0.2"), [recursive]),
+
{ok, State} = relx:do([{relname, foo},
{relvsn, "0.0.3"},
{goals, []},
@@ -779,29 +738,22 @@ make_relup_release(Config) ->
make_relup_release2(Config) ->
LibDir1 = proplists:get_value(lib1, Config),
- [(fun({Name, Vsn}) ->
- create_app(LibDir1, Name, Vsn, [kernel, stdlib], [])
- end)(App)
- ||
- App <-
- [{create_random_name("lib_app1_"), create_random_vsn()}
- || _ <- lists:seq(1, 100)]],
-
- create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []),
- create_app(LibDir1, "goal_app_1", "0.0.2", [stdlib,kernel,non_goal_1], []),
- {ok, GA1} = create_app(LibDir1, "goal_app_1", "0.0.3", [stdlib,kernel,non_goal_1], []),
- create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []),
- create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []),
- create_app(LibDir1, "goal_app_2", "0.0.2", [stdlib,kernel,goal_app_1,non_goal_2], []),
- {ok, GA2} = create_app(LibDir1, "goal_app_2", "0.0.3", [stdlib,kernel,goal_app_1,non_goal_2], []),
- create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]),
- create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []),
-
- write_appup_file(GA1, "0.0.1"),
- write_appup_file(GA2, "0.0.1"),
+
+ rlx_test_utils:create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []),
+ rlx_test_utils:create_app(LibDir1, "goal_app_1", "0.0.2", [stdlib,kernel,non_goal_1], []),
+ {ok, GA1} = rlx_test_utils:create_app(LibDir1, "goal_app_1", "0.0.3", [stdlib,kernel,non_goal_1], []),
+ rlx_test_utils:create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []),
+ rlx_test_utils:create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []),
+ rlx_test_utils:create_app(LibDir1, "goal_app_2", "0.0.2", [stdlib,kernel,goal_app_1,non_goal_2], []),
+ {ok, GA2} = rlx_test_utils:create_app(LibDir1, "goal_app_2", "0.0.3", [stdlib,kernel,goal_app_1,non_goal_2], []),
+ rlx_test_utils:create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]),
+ rlx_test_utils:create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []),
+
+ rlx_test_utils:write_appup_file(GA1, "0.0.1"),
+ rlx_test_utils:write_appup_file(GA2, "0.0.1"),
ConfigFile = filename:join([LibDir1, "relx.config"]),
- write_config(ConfigFile,
+ rlx_test_utils:write_config(ConfigFile,
[{release, {foo, "0.0.1"},
[sasl,
{goal_app_1, "0.0.1"},
@@ -815,19 +767,19 @@ make_relup_release2(Config) ->
{goal_app_1, "0.0.3"},
{goal_app_2, "0.0.3"}]}]),
OutputDir = filename:join([proplists:get_value(data_dir, Config),
- create_random_name("relx-output")]),
+ rlx_test_utils:create_random_name("relx-output")]),
{ok, _} = relx:do(foo, "0.0.1", [], [LibDir1], 3,
OutputDir, ConfigFile),
{ok, _} = relx:do(foo, "0.0.2", [], [LibDir1], 3,
OutputDir, ConfigFile),
{ok, State} = relx:do([{relname, foo},
- {relvsn, "0.0.3"},
- {upfrom, "0.0.1"},
- {goals, []},
- {lib_dirs, [LibDir1]},
- {log_level, 3},
- {output_dir, OutputDir},
- {config, ConfigFile}], ["release", "relup"]),
+ {relvsn, "0.0.3"},
+ {upfrom, "0.0.1"},
+ {goals, []},
+ {lib_dirs, [LibDir1]},
+ {log_level, 3},
+ {output_dir, OutputDir},
+ {config, ConfigFile}], ["release", "relup"]),
%% we should have one 'resolved' release and three discovered realized_releases.
?assertMatch([{foo, "0.0.1"},
@@ -860,15 +812,15 @@ make_relup_release2(Config) ->
make_one_app_top_level_release(Config) ->
LibDir1 = proplists:get_value(lib1, Config),
- {ok, AppInfo} = create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel], []),
+ {ok, AppInfo} = rlx_test_utils:create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel], []),
AppDir = rlx_app_info:dir(AppInfo),
ConfigFile = filename:join([AppDir, "relx.config"]),
- write_config(ConfigFile,
+ rlx_test_utils:write_config(ConfigFile,
[{release, {foo, "0.0.1"},
[{goal_app_1, "0.0.1"}]}]),
OutputDir = filename:join([AppDir,
- create_random_name("relx-output")]),
+ rlx_test_utils:create_random_name("relx-output")]),
{ok, Cwd} = file:get_cwd(),
ok = file:set_cwd(AppDir),
@@ -883,28 +835,21 @@ make_one_app_top_level_release(Config) ->
make_dev_mode_release(Config) ->
LibDir1 = proplists:get_value(lib1, Config),
- [(fun({Name, Vsn}) ->
- create_app(LibDir1, Name, Vsn, [kernel, stdlib], [])
- end)(App)
- ||
- App <-
- [{create_random_name("lib_app1_"), create_random_vsn()}
- || _ <- lists:seq(1, 100)]],
- create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []),
- create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []),
- create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []),
- create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]),
- create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []),
+ rlx_test_utils:create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []),
+ rlx_test_utils:create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []),
+ rlx_test_utils:create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []),
+ rlx_test_utils:create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]),
+ rlx_test_utils:create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []),
SysConfig = filename:join([LibDir1, "config", "sys.config"]),
- write_config(SysConfig, [{this_is_a_test, "yup it is"}]),
+ rlx_test_utils:write_config(SysConfig, [{this_is_a_test, "yup it is"}]),
VmArgs = filename:join([LibDir1, "config", "vm.args"]),
ec_file:write(VmArgs, ""),
ConfigFile = filename:join([LibDir1, "relx.config"]),
- write_config(ConfigFile,
+ rlx_test_utils:write_config(ConfigFile,
[{dev_mode, true},
{sys_config, SysConfig},
{vm_args, VmArgs},
@@ -912,7 +857,7 @@ make_dev_mode_release(Config) ->
[goal_app_1,
goal_app_2]}]),
OutputDir = filename:join([proplists:get_value(data_dir, Config),
- create_random_name("relx-output")]),
+ rlx_test_utils:create_random_name("relx-output")]),
{ok, State} = relx:do(undefined, undefined, [], [LibDir1], 3,
OutputDir, ConfigFile),
[{{foo, "0.0.1"}, _Release}] = ec_dictionary:to_list(rlx_state:realized_releases(State)),
@@ -927,99 +872,52 @@ make_dev_mode_release(Config) ->
?assert(ec_file:is_symlink(filename:join([OutputDir, "foo", "releases", "0.0.1",
"vm.args"]))).
+make_config_script_release(Config) ->
+ LibDir1 = proplists:get_value(lib1, Config),
+ FooRoot = filename:join([LibDir1, "foodir1", "foodir2"]),
+ filelib:ensure_dir(filename:join([FooRoot, "tmp"])),
+
+ rlx_test_utils:create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []),
+ rlx_test_utils:create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []),
+ rlx_test_utils:create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []),
+ rlx_test_utils:create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]),
+ rlx_test_utils:create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []),
+
+ ConfigFile = filename:join([LibDir1, "relx.config"]),
+ rlx_test_utils:write_config(ConfigFile,
+ [{release, {foo, "0.0.1"},
+ [goal_app_1,
+ goal_app_2]}]),
+ ConfigScriptFile = filename:join([LibDir1, "relx.config.script"]),
+ ok = file:write_file(ConfigScriptFile,
+ "case os:getenv(\"RELX_TEST\") of\n"
+ " \"true\" ->\n"
+ " {release, {RelName, Version}, Apps} = lists:keyfind(release, 1, CONFIG),\n"
+ " lists:keyreplace(release, 1, CONFIG, {release, {RelName, \"0.0.2\"}, Apps});\n"
+ " _ -> CONFIG % env var not defined or anything other than true\n"
+ "end.\n"),
+
+ OutputDir = filename:join([proplists:get_value(data_dir, Config),
+ rlx_test_utils:create_random_name("relx-output")]),
+ ok = file:set_cwd(FooRoot),
+ {ok, FooRoot} = file:get_cwd(),
+
+ % set the env var that will cause relx.config to be altered by the config script
+ os:putenv("RELX_TEST", "true"),
+
+ {ok, State} = relx:do(undefined, undefined, [], [LibDir1], 3,
+ OutputDir, undefined),
+ [{{foo, "0.0.2"}, Release}] = ec_dictionary:to_list(rlx_state:realized_releases(State)),
+ ?assert(ec_file:exists(OutputDir)),
+ AppSpecs = rlx_release:applications(Release),
+ ?assert(lists:keymember(stdlib, 1, AppSpecs)),
+ ?assert(lists:keymember(kernel, 1, AppSpecs)),
+ ?assert(lists:member({non_goal_1, "0.0.1"}, AppSpecs)),
+ ?assert(lists:member({non_goal_2, "0.0.1"}, AppSpecs)),
+ ?assert(lists:member({goal_app_1, "0.0.1"}, AppSpecs)),
+ ?assert(lists:member({goal_app_2, "0.0.1"}, AppSpecs)),
+ ?assert(lists:member({lib_dep_1, "0.0.1", load}, AppSpecs)).
%%%===================================================================
%%% Helper Functions
%%%===================================================================
-
-create_app(Dir, Name, Vsn, Deps, LibDeps) ->
- AppDir = filename:join([Dir, Name ++ "-" ++ Vsn]),
- write_app_file(AppDir, Name, Vsn, Deps, LibDeps),
- write_beam_file(AppDir, Name),
- rlx_app_info:new(erlang:list_to_atom(Name), Vsn, AppDir,
- Deps, []).
-
-create_empty_app(Dir, Name, Vsn, Deps, LibDeps) ->
- AppDir = filename:join([Dir, Name ++ "-" ++ Vsn]),
- write_app_file(AppDir, Name, Vsn, Deps, LibDeps),
- rlx_app_info:new(erlang:list_to_atom(Name), Vsn, AppDir,
- Deps, []).
-
-write_beam_file(Dir, Name) ->
- Beam = filename:join([Dir, "ebin", "not_a_real_beam" ++ Name ++ ".beam"]),
- ok = filelib:ensure_dir(Beam),
- ok = ec_file:write_term(Beam, testing_purposes_only).
-
-write_appup_file(AppInfo, DownVsn) ->
- Dir = rlx_app_info:dir(AppInfo),
- Name = rlx_util:to_string(rlx_app_info:name(AppInfo)),
- Vsn = rlx_app_info:vsn_as_string(AppInfo),
- Filename = filename:join([Dir, "ebin", Name ++ ".appup"]),
- ok = filelib:ensure_dir(Filename),
- ok = ec_file:write_term(Filename, {Vsn, [{DownVsn, []}], [{DownVsn, []}]}).
-
-write_app_file(Dir, Name, Version, Deps, LibDeps) ->
- Filename = filename:join([Dir, "ebin", Name ++ ".app"]),
- ok = filelib:ensure_dir(Filename),
- ok = ec_file:write_term(Filename, get_app_metadata(Name, Version, Deps, LibDeps)).
-
-get_app_metadata(Name, Vsn, Deps, LibDeps) ->
- {application, erlang:list_to_atom(Name),
- [{description, ""},
- {vsn, Vsn},
- {modules, []},
- {included_applications, LibDeps},
- {registered, []},
- {applications, Deps}]}.
-
-create_random_name(Name) ->
- random:seed(erlang:now()),
- Name ++ erlang:integer_to_list(random:uniform(1000000)).
-
-create_random_vsn() ->
- random:seed(erlang:now()),
- lists:flatten([erlang:integer_to_list(random:uniform(100)),
- ".", erlang:integer_to_list(random:uniform(100)),
- ".", erlang:integer_to_list(random:uniform(100))]).
-
-write_config(Filename, Values) ->
- ok = filelib:ensure_dir(Filename),
- ok = ec_file:write(Filename,
- [io_lib:format("~p.\n", [Val]) || Val <- Values]).
-
-test_template_contents() ->
- "{erts_vsn, \"{{erts_vsn}}\"}.\n"
- "{release_erts_version, \"{{release_erts_version}}\"}.\n"
- "{release_name, {{release_name}}}.\n"
- "{rel_vsn, \"{{release_version}}\"}.\n"
- "{release_version, \"{{release_version}}\"}.\n"
- "{release_applications, [{{ release_applications|join:\", \" }}]}.\n"
- "{std_version, \"{{release.stdlib.version}}\"}.\n"
- "{kernel_version, \"{{release.kernel.version}}\"}.\n"
- "{non_goal_1_version, \"{{release.non_goal_1.version}}\"}.\n"
- "{non_goal_2_version, \"{{release.non_goal_2.version}}\"}.\n"
- "{goal_app_1_version, \"{{release.goal_app_1.version}}\"}.\n"
- "{goal_app_2_version, \"{{release.goal_app_2.version}}\"}.\n"
- "{lib_dep_1, \"{{release.lib_dep_1.version}}\"}.\n"
- "{lib_dep_1_dir, \"{{release.lib_dep_1.dir}}\"}.\n"
- "{lib_dep_1_active, [{{ release.lib_dep_1.active_dependencies|join:\", \" }}]}.\n"
- "{lib_dep_1_library, [{{ release.lib_dep_1.library_dependencies|join:\", \" }}]}.\n"
- "{lib_dep_1_link, \"{{release.lib_dep_1.link}}\"}.\n"
- "{log, \"{{log}}\"}.\n"
- "{output_dir, \"{{output_dir}}\"}.\n"
- "{target_dir, \"{{target_dir}}\"}.\n"
- "{overridden, [{{ overridden|join:\", \" }}]}.\n"
- "{goals, [\"{{ goals|join:\", \" }}\"]}.\n"
- "{lib_dirs, [\"{{ lib_dirs|join:\", \" }}\"]}.\n"
- "{config_file, \"{{ config_file }}\"}.\n"
- "{providers, [{{ providers|join:\", \" }}]}.\n"
- "{sys_config, \"{{sys_config}}\"}.\n"
- "{root_dir, \"{{root_dir}}\"}.\n"
- "{default_release_name, {{default_release_name}}}.\n"
- "{default_release_version, \"{{default_release_version}}\"}.\n"
- "{default_release, \"{{default_release}}\"}.\n"
- "{yahoo, \"{{yahoo}}\"}.\n"
- "{yahoo2_foo, \"{{yahoo2.foo}}\"}.\n"
- "{foo_dir, \"{{foo_dir}}\"}.\n"
- "{yahoo3, \"{{yahoo3.bar}}\"}.\n"
- "{google, \"{{google}}\"}.\n".
diff --git a/test/rlx_test_utils.erl b/test/rlx_test_utils.erl
new file mode 100644
index 0000000..644c49f
--- /dev/null
+++ b/test/rlx_test_utils.erl
@@ -0,0 +1,98 @@
+%%% @author Tristan Sloughter <[email protected]>
+%%% @copyright (C) 2015, Tristan Sloughter
+-module(rlx_test_utils).
+
+-compile(export_all).
+
+create_app(Dir, Name, Vsn, Deps, LibDeps) ->
+ AppDir = filename:join([Dir, Name ++ "-" ++ Vsn]),
+ write_app_file(AppDir, Name, Vsn, Deps, LibDeps),
+ write_beam_file(AppDir, Name),
+ rlx_app_info:new(erlang:list_to_atom(Name), Vsn, AppDir,
+ Deps, []).
+
+create_empty_app(Dir, Name, Vsn, Deps, LibDeps) ->
+ AppDir = filename:join([Dir, Name ++ "-" ++ Vsn]),
+ write_app_file(AppDir, Name, Vsn, Deps, LibDeps),
+ rlx_app_info:new(erlang:list_to_atom(Name), Vsn, AppDir,
+ Deps, []).
+
+write_beam_file(Dir, Name) ->
+ Beam = filename:join([Dir, "ebin", "not_a_real_beam" ++ Name ++ ".beam"]),
+ ok = filelib:ensure_dir(Beam),
+ ok = ec_file:write_term(Beam, testing_purposes_only).
+
+write_appup_file(AppInfo, DownVsn) ->
+ Dir = rlx_app_info:dir(AppInfo),
+ Name = rlx_util:to_string(rlx_app_info:name(AppInfo)),
+ Vsn = rlx_app_info:vsn_as_string(AppInfo),
+ Filename = filename:join([Dir, "ebin", Name ++ ".appup"]),
+ ok = filelib:ensure_dir(Filename),
+ ok = ec_file:write_term(Filename, {Vsn, [{DownVsn, []}], [{DownVsn, []}]}).
+
+write_app_file(Dir, Name, Version, Deps, LibDeps) ->
+ Filename = filename:join([Dir, "ebin", Name ++ ".app"]),
+ ok = filelib:ensure_dir(Filename),
+ ok = ec_file:write_term(Filename, get_app_metadata(Name, Version, Deps, LibDeps)).
+
+get_app_metadata(Name, Vsn, Deps, LibDeps) ->
+ {application, erlang:list_to_atom(Name),
+ [{description, ""},
+ {vsn, Vsn},
+ {modules, []},
+ {included_applications, LibDeps},
+ {registered, []},
+ {applications, Deps}]}.
+
+create_random_name(Name) ->
+ random:seed(erlang:now()),
+ Name ++ erlang:integer_to_list(random:uniform(1000000)).
+
+create_random_vsn() ->
+ random:seed(erlang:now()),
+ lists:flatten([erlang:integer_to_list(random:uniform(100)),
+ ".", erlang:integer_to_list(random:uniform(100)),
+ ".", erlang:integer_to_list(random:uniform(100))]).
+
+write_config(Filename, Values) ->
+ ok = filelib:ensure_dir(Filename),
+ ok = ec_file:write(Filename,
+ [io_lib:format("~p.\n", [Val]) || Val <- Values]).
+
+test_template_contents() ->
+ "{erts_vsn, \"{{erts_vsn}}\"}.\n"
+ "{release_erts_version, \"{{release_erts_version}}\"}.\n"
+ "{release_name, {{release_name}}}.\n"
+ "{rel_vsn, \"{{release_version}}\"}.\n"
+ "{release_version, \"{{release_version}}\"}.\n"
+ "{release_applications, [{{ release_applications|join:\", \" }}]}.\n"
+ "{std_version, \"{{release.stdlib.version}}\"}.\n"
+ "{kernel_version, \"{{release.kernel.version}}\"}.\n"
+ "{non_goal_1_version, \"{{release.non_goal_1.version}}\"}.\n"
+ "{non_goal_2_version, \"{{release.non_goal_2.version}}\"}.\n"
+ "{goal_app_1_version, \"{{release.goal_app_1.version}}\"}.\n"
+ "{goal_app_2_version, \"{{release.goal_app_2.version}}\"}.\n"
+ "{lib_dep_1, \"{{release.lib_dep_1.version}}\"}.\n"
+ "{lib_dep_1_dir, \"{{release.lib_dep_1.dir}}\"}.\n"
+ "{lib_dep_1_active, [{{ release.lib_dep_1.active_dependencies|join:\", \" }}]}.\n"
+ "{lib_dep_1_library, [{{ release.lib_dep_1.library_dependencies|join:\", \" }}]}.\n"
+ "{lib_dep_1_link, \"{{release.lib_dep_1.link}}\"}.\n"
+ "{log, \"{{log}}\"}.\n"
+ "{output_dir, \"{{output_dir}}\"}.\n"
+ "{target_dir, \"{{target_dir}}\"}.\n"
+ "{overridden, [{{ overridden|join:\", \" }}]}.\n"
+ "{goals, [\"{{ goals|join:\", \" }}\"]}.\n"
+ "{lib_dirs, [\"{{ lib_dirs|join:\", \" }}\"]}.\n"
+ "{config_file, \"{{ config_file }}\"}.\n"
+ "{providers, [{{ providers|join:\", \" }}]}.\n"
+ "{sys_config, \"{{sys_config}}\"}.\n"
+ "{root_dir, \"{{root_dir}}\"}.\n"
+ "{default_release_name, {{default_release_name}}}.\n"
+ "{default_release_version, \"{{default_release_version}}\"}.\n"
+ "{default_release, \"{{default_release}}\"}.\n"
+ "{yahoo, \"{{yahoo}}\"}.\n"
+ "{yahoo2_foo, \"{{yahoo2.foo}}\"}.\n"
+ "{foo_dir, \"{{foo_dir}}\"}.\n"
+ "{yahoo3, \"{{yahoo3.bar}}\"}.\n"
+ "{yahoo4, \"{{yahoo4.foo}}\"}.\n"
+ "{google, \"{{google}}\"}.\n".