aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.circleci/config.yml39
-rw-r--r--.cirrus.yml23
-rw-r--r--.gitignore3
-rw-r--r--.travis.yml35
-rw-r--r--README.md4
-rwxr-xr-xpriv/templates/extended_bin28
-rw-r--r--rebar.config3
-rw-r--r--src/relx.erl3
-rw-r--r--src/rlx_cmd_args.erl13
-rw-r--r--src/rlx_config.erl69
-rw-r--r--src/rlx_depsolver.erl85
-rw-r--r--src/rlx_depsolver_culprit.erl2
-rw-r--r--src/rlx_prv_overlay.erl149
-rw-r--r--src/rlx_prv_release.erl8
-rw-r--r--src/rlx_release.erl102
-rw-r--r--src/rlx_state.erl6
-rw-r--r--src/rlx_string.erl10
-rw-r--r--test/rlx_archive_SUITE.erl2
-rw-r--r--test/rlx_command_SUITE.erl16
-rw-r--r--test/rlx_depsolver_tester.erl500
-rw-r--r--test/rlx_depsolver_tests.erl2
-rw-r--r--test/rlx_discover_SUITE.erl2
-rw-r--r--test/rlx_eunit_SUITE.erl2
-rw-r--r--test/rlx_extended_bin_SUITE.erl11
-rw-r--r--test/rlx_prv_release_alias.erl27
-rw-r--r--test/rlx_release_SUITE.erl153
26 files changed, 780 insertions, 517 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml
deleted file mode 100644
index ca75335..0000000
--- a/.circleci/config.yml
+++ /dev/null
@@ -1,39 +0,0 @@
-version: 2.1
-orbs:
- rebar3: tsloughter/[email protected]
-
-jobs:
- ct:
- parameters:
- tag:
- description: The docker tag to use.
- type: string
- default: "21.2"
- executor:
- name: rebar3/erlang
- tag: <<parameters.tag>>
- steps:
- - checkout
- - rebar3/ct
- # Delete OTP files which don't need to be stored
- - run: |
- find _build/test/logs -type d -and \( -path "*/erts-*" -or -path "*/kernel-*" -or -path "*/stdlib-*" \) -exec rm -rf '{}' \+ || true
- find _build/test/logs -type f -name "*.beam" -exec rm -rf '{}' \+ || true
- - store_artifacts:
- path: _build/test/logs
-
-workflows:
- build-test:
- jobs:
- - ct:
- name: "21"
- tag: "21.2"
- - ct:
- name: "20"
- tag: "20"
- - ct:
- name: "19"
- tag: "19"
- - ct:
- name: "18"
- tag: "18"
diff --git a/.cirrus.yml b/.cirrus.yml
new file mode 100644
index 0000000..8e693dd
--- /dev/null
+++ b/.cirrus.yml
@@ -0,0 +1,23 @@
+test_task:
+ use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true'
+ container:
+ matrix:
+ - image: erlang:22
+ - image: erlang:21
+ - image: erlang:20
+ - image: erlang:19
+ - image: erlang:18
+ test_script: |
+ rebar3 eunit && rebar3 ct
+ always:
+ junit_artifacts:
+ path: "_build/test/logs/ct_run.*/junit_report.xml"
+
+osx_check_task:
+ osx_instance:
+ image: mojave-base
+ install_script: brew install erlang
+ test_script: |
+ wget https://s3.amazonaws.com/rebar3/rebar3
+ chmod +x rebar3
+ ./rebar3 eunit && ./rebar3 ct
diff --git a/.gitignore b/.gitignore
index 287aef8..64d4e0b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,5 +14,8 @@ test/*_data
_rel/*
.*
!.circleci
+!.cirrus.yml
erl_crash.dump
rebar
+TEST-*
+tags
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 4e4f877..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,35 +0,0 @@
-language: erlang
-matrix:
- include:
- - os: linux
- sudo: required
- otp_release: 17.5
- - os: osx
- sudo: required
- language: generic
-before_script:
- - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi
- ## should eventually use a tap that has previous erlang versions here
- ## as this only uses the latest erlang available via brew
- - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install erlang; fi
- - wget https://s3.amazonaws.com/rebar3/rebar3
- - chmod +x rebar3
-script: "./rebar3 update && ./rebar3 ct"
-after_failure:
- ## Useful for troubleshooting to view test logs
- - find _build/test/logs/ct_run*/lib*logs/run*/log_private/*-output*/*/log -type f -name "erlang*" -exec ls -1rt "{}" \+ | xargs -I % sh -c 'echo "\n\n%"; cat %'
-branches:
- only:
- - master
-addons:
- hostname: travis.dev
- hosts:
- - travis.dev
-notifications:
- email:
- irc:
- channels:
- - "irc.freenode.org#erlware"
- use_notice: true
- skip_join: true
diff --git a/README.md b/README.md
index dfc2ef2..2cd3b42 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,4 @@
-[![Build Status](https://travis-ci.org/erlware/relx.png?branch=master)](https://travis-ci.org/erlware/relx)
-[![CircleCI](https://circleci.com/gh/erlware/relx.svg?style=svg)](https://circleci.com/gh/erlware/relx)
+[![Build Status](https://api.cirrus-ci.com/github/erlware/relx.svg)](https://cirrus-ci.com/github/erlware/relx)
Relx
=======
@@ -82,6 +81,7 @@ Options
| | --sys_config | string | | Path to a file to use for sys.config |
| -d | --dev-mode | boolean | false | Symlink all applications and configuration into the release instead of copying|
| -i | --include-erts | boolean/string | true | If true include a copy of erts used to build with, if a path include erts at that path. If false, do not include erts |
+| | --provider | string | | Specify an additional relx provider |
Wiki
----
diff --git a/priv/templates/extended_bin b/priv/templates/extended_bin
index a4cba4a..d8aa9b7 100755
--- a/priv/templates/extended_bin
+++ b/priv/templates/extended_bin
@@ -34,7 +34,6 @@ RELEASE_ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd -P)"
export 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}"
@@ -152,12 +151,14 @@ relx_get_nodename() {
id="longname$(relx_gen_id)-${NAME}"
if [ -z "$COOKIE" ]; then
"$BINDIR/erl" -boot start_clean \
+ -mode interactive \
-boot_var ERTS_LIB_DIR "$ERTS_LIB_DIR" \
-eval '[_,H]=re:split(atom_to_list(node()),"@",[unicode,{return,list}]), io:format("~s~n",[H]), halt()' \
-noshell ${NAME_TYPE} $id
else
# running with setcookie prevents a ~/.erlang.cookie from being created
"$BINDIR/erl" -boot start_clean \
+ -mode interactive \
-boot_var ERTS_LIB_DIR "$ERTS_LIB_DIR" \
-eval '[_,H]=re:split(atom_to_list(node()),"@",[unicode,{return,list}]), io:format("~s~n",[H]), halt()' \
-setcookie ${COOKIE} \
@@ -175,7 +176,7 @@ relx_rem_sh() {
TICKTIME="$(relx_nodetool rpcterms net_kernel get_net_ticktime)"
# Setup remote shell command to control node
- exec "$BINDIR/erl" "$NAME_TYPE" "$id" -remsh "$NAME" -boot start_clean \
+ exec "$BINDIR/erl" "$NAME_TYPE" "$id" -remsh "$NAME" -boot start_clean -mode interactive \
-boot_var ERTS_LIB_DIR "$ERTS_LIB_DIR" $MAYBE_DIST_ARGS \
-setcookie "$COOKIE" -hidden -kernel net_ticktime $TICKTIME
}
@@ -215,16 +216,6 @@ relx_escript() {
"$ERTS_DIR/bin/escript" "$ROOTDIR/$scriptpath" $@
}
-relx_get_code_paths() {
- code="{ok, [{release,_,_,Apps}]} = file:consult(\"$REL_DIR/$REL_NAME.rel\"),"\
-"lists:foreach(fun(A) ->"\
-" io:fwrite(\"$ROOTDIR/lib/~p-~s/ebin \", [element(1, A), element(2, A)]) "\
-"end, Apps),"\
-"halt()."
-
- "$BINDIR/erl" -noshell -boot start_clean -eval "$code"
-}
-
make_out_file_path() {
# Use output directory provided in the RELX_OUT_FILE_PATH environment variable
# (default to the current location of vm.args and sys.config)
@@ -691,7 +682,8 @@ case "$1" in
FOREGROUNDOPTIONS="-noshell -noinput +Bd"
;;
console_clean)
- __code_paths=$(relx_get_code_paths)
+ # if not set by user use interactive mode for console_clean
+ CODE_LOADING_MODE="${CODE_LOADING_MODE:-interactive}"
BOOTFILE="$ROOTDIR/bin/start_clean"
;;
console_boot)
@@ -700,6 +692,10 @@ case "$1" in
shift
;;
esac
+
+ # if not set by user or console_clean use embedded
+ CODE_LOADING_MODE="${CODE_LOADING_MODE:-embedded}"
+
# Setup beam-required vars
EMU="beam"
PROGNAME="${0#*/}"
@@ -712,8 +708,7 @@ case "$1" in
-boot "$BOOTFILE" -mode "$CODE_LOADING_MODE" \
-boot_var ERTS_LIB_DIR "$ERTS_LIB_DIR" \
-config "$RELX_CONFIG_PATH" \
- -args_file "$VMARGS_PATH" \
- -pa ${__code_paths} -- "$@"
+ -args_file "$VMARGS_PATH" -- "$@"
echo "Root: $ROOTDIR"
# Log the startup
@@ -726,8 +721,7 @@ case "$1" in
-boot "$BOOTFILE" -mode "$CODE_LOADING_MODE" \
-boot_var ERTS_LIB_DIR "$ERTS_LIB_DIR" \
-config "$RELX_CONFIG_PATH" \
- -args_file "$VMARGS_PATH" \
- -pa ${__code_paths} -- "$@"
+ -args_file "$VMARGS_PATH" -- "$@"
# exec will replace the current image and nothing else gets
# executed from this point on, this explains the absence
# of the pre start hook
diff --git a/rebar.config b/rebar.config
index d7f5312..285b1ce 100644
--- a/rebar.config
+++ b/rebar.config
@@ -69,7 +69,8 @@
{override, providers, [{erl_opts, [no_debug_info]}]}
]}.
-{ct_opts, [{cover_spec, "cover.spec"}]}.
+{ct_opts, [{cover_spec, "cover.spec"},
+ {ct_hooks, [cth_surefire]}]}.
{cover_enabled, true}.
{cover_print_enabled, true}.
diff --git a/src/relx.erl b/src/relx.erl
index 8027fd4..b5c3ec5 100644
--- a/src/relx.erl
+++ b/src/relx.erl
@@ -214,7 +214,8 @@ opt_spec_list() ->
{sys_config, undefined, "sys_config", string, "Path to a file to use for sys.config"},
{system_libs, undefined, "system_libs", string, "Path to dir of Erlang system libs"},
{version, undefined, "version", undefined, "Print relx version"},
- {root_dir, $r, "root", string, "The project root directory"}].
+ {root_dir, $r, "root", string, "The project root directory"},
+ {provider, undefined, "provider", atom, "Specify an additional relx provider"}].
-spec format_error(Reason::term()) -> string().
format_error({invalid_return_value, Provider, Value}) ->
diff --git a/src/rlx_cmd_args.erl b/src/rlx_cmd_args.erl
index b20344c..4f5e9da 100644
--- a/src/rlx_cmd_args.erl
+++ b/src/rlx_cmd_args.erl
@@ -285,6 +285,19 @@ create(include_erts, Opts) ->
create(warnings_as_errors, Opts) ->
WarningsAsErrors = proplists:get_value(warnings_as_errors, Opts, false),
{warnings_as_errors, WarningsAsErrors};
+create(provider, Opts) ->
+ case proplists:get_all_values(provider, Opts) of
+ [] ->
+ [];
+ Providers ->
+ {add_providers, Providers}
+ end;
+create(add_providers, Opts) ->
+ Providers = proplists:get_value(add_providers, Opts, []),
+ {add_providers, Providers};
+create(providers, Opts) ->
+ Providers = proplists:get_value(providers, Opts, []),
+ {providers, Providers};
create(_, _) ->
[].
diff --git a/src/rlx_config.erl b/src/rlx_config.erl
index 4160bba..90cfe7c 100644
--- a/src/rlx_config.erl
+++ b/src/rlx_config.erl
@@ -53,7 +53,11 @@ format_error({consult, ConfigFile, Reason}) ->
io_lib:format("Unable to read file ~s: ~s", [ConfigFile,
file:format_error(Reason)]);
format_error({invalid_term, Term}) ->
- io_lib:format("Invalid term in config file: ~p", [Term]).
+ io_lib:format("Invalid term in config file: ~p", [Term]);
+format_error({failed_to_parse, Goal}) ->
+ io_lib:format("Unable to parse goal ~s", [Goal]);
+format_error({invalid_goal, Goal}) ->
+ io_lib:format("Invalid goal: ~p", [Goal]).
%%%===================================================================
%%% Internal Functions
@@ -182,7 +186,7 @@ load_terms({overrides, Overrides0}, {ok, State0}) ->
load_terms({dev_mode, DevMode}, {ok, State0}) ->
{ok, rlx_state:dev_mode(State0, DevMode)};
load_terms({goals, Goals}, {ok, State0}) ->
- {ok, rlx_state:goals(State0, Goals)};
+ parse_goals(Goals, State0);
load_terms({upfrom, UpFrom}, {ok, State0}) ->
{ok, rlx_state:upfrom(State0, UpFrom)};
load_terms({include_src, IncludeSrc}, {ok, State0}) ->
@@ -193,8 +197,7 @@ load_terms({release, {RelName, Vsn, {extend, RelName2}}, Applications}, {ok, Sta
ExtendRelease = rlx_state:get_configured_release(State0, RelName2, NewVsn),
Applications1 = rlx_release:goals(ExtendRelease),
case rlx_release:goals(Release0,
- lists:umerge(lists:usort(Applications),
- lists:usort(Applications1))) of
+ rlx_release:merge_application_goals(Applications, Applications1)) of
E={error, _} ->
E;
{ok, Release1} ->
@@ -206,8 +209,7 @@ load_terms({release, {RelName, Vsn, {extend, RelName2}}, Applications, Config},
ExtendRelease = rlx_state:get_configured_release(State0, RelName2, NewVsn),
Applications1 = rlx_release:goals(ExtendRelease),
case rlx_release:goals(Release0,
- lists:umerge(lists:usort(Applications),
- lists:usort(Applications1))) of
+ rlx_release:merge_application_goals(Applications, Applications1)) of
E={error, _} ->
E;
{ok, Release1} ->
@@ -299,6 +301,34 @@ add_hooks(Hooks, State) ->
rlx_state:append_hook(StateAcc, Target, Hook)
end, State, Hooks)}.
+parse_goals(Goals0, State) ->
+ {Goals, Error} = lists:mapfoldl(fun
+ (Goal, ok) when is_list(Goal); is_binary(Goal) ->
+ case rlx_goal:parse(Goal) of
+ {ok, Constraint} ->
+ {Constraint, ok};
+ {fail, _} ->
+ {[], ?RLX_ERROR({failed_to_parse, Goal})}
+ end;
+ (Goal, ok) when is_tuple(Goal); is_atom(Goal) ->
+ case rlx_depsolver:is_valid_raw_constraint(Goal) of
+ true ->
+ {Goal, ok};
+ false ->
+ {[], ?RLX_ERROR({invalid_goal, Goal})}
+ end;
+ (_, Err = {error, _}) ->
+ {[], Err};
+ (Goal, _) ->
+ {[], ?RLX_ERROR({invalid_goal, Goal})}
+ end, ok, Goals0),
+ case Error of
+ ok ->
+ {ok, rlx_state:goals(State, Goals)};
+ _ ->
+ Error
+ end.
+
list_of_overlay_vars_files(undefined) ->
[];
list_of_overlay_vars_files([]) ->
@@ -346,6 +376,16 @@ merge_configs([{Key, Value} | CliTerms], ConfigTerms) ->
merge_configs(CliTerms, lists:reverse(lists:keystore(Key, 1, lists:reverse(ConfigTerms), {Key, Value})))
end.
+parse_vsn(Vsn) when Vsn =:= git ; Vsn =:= "git" ->
+ {ok, V} = ec_git_vsn:vsn(ec_git_vsn:new()),
+ V;
+parse_vsn({git, short}) ->
+ git_ref("--short");
+parse_vsn({git, long}) ->
+ git_ref("");
+parse_vsn({file, File}) ->
+ {ok, Vsn} = file:read_file(File),
+ binary_to_list(rlx_string:trim(Vsn, both, "\n"));
parse_vsn(Vsn) when Vsn =:= semver ; Vsn =:= "semver" ->
{ok, V} = ec_git_vsn:vsn(ec_git_vsn:new()),
V;
@@ -357,3 +397,20 @@ parse_vsn({cmd, Command}) ->
V;
parse_vsn(Vsn) ->
Vsn.
+
+git_ref(Arg) ->
+ case os:cmd("git rev-parse " ++ Arg ++ " HEAD") of
+ String ->
+ Vsn = rlx_string:trim(String, both, "\n"),
+ case length(Vsn) =:= 40 orelse length(Vsn) =:= 7 of
+ true ->
+ Vsn;
+ false ->
+ %% if the result isn't exactly either 40 or 7 characters then
+ %% it must have failed
+ {ok, Dir} = file:get_cwd(),
+ ec_cmd_log:warn("Getting ref of git repo failed in ~ts. "
+ "Falling back to version 0", [Dir]),
+ {plain, "0"}
+ end
+ end.
diff --git a/src/rlx_depsolver.erl b/src/rlx_depsolver.erl
index 8a0f632..0bde8c7 100644
--- a/src/rlx_depsolver.erl
+++ b/src/rlx_depsolver.erl
@@ -1,5 +1,5 @@
%% -*- erlang-indent-level: 4; indent-tabs-mode: nil; fill-column: 80 -*-
-%% ex: ts=4 sx=4 et
+%% ex: ts=4 sw=4 et
%%
%% Copyright 2012 Opscode, Inc. All Rights Reserved.
%%
@@ -88,7 +88,7 @@
add_package_version/3,
add_package_version/4,
parse_version/1,
- is_valid_constraint/1,
+ is_valid_raw_constraint/1,
filter_packages/2]).
%% Internally Exported API. This should *not* be used outside of the rlx_depsolver
@@ -132,7 +132,7 @@
-type raw_constraint() :: pkg_name()
| {pkg_name(), raw_vsn()}
| {pkg_name(), raw_vsn(), constraint_op()}
- | {pkg_name(), raw_vsn(), vsn(), between}.
+ | {pkg_name(), raw_vsn(), raw_vsn(), between}.
-type constraint() :: pkg_name()
| {pkg_name(), vsn()}
@@ -272,39 +272,14 @@ parse_version(Vsn)
when erlang:is_tuple(Vsn) ; erlang:is_atom(Vsn) ->
Vsn.
-%% @doc check that a specified constraint is a valid constraint.
--spec is_valid_constraint(constraint()) -> boolean().
-is_valid_constraint(Pkg) when is_atom(Pkg) orelse is_binary(Pkg) ->
- true;
-is_valid_constraint({_Pkg, Vsn}) when is_tuple(Vsn) ->
- true;
-is_valid_constraint({_Pkg, Vsn, '='}) when is_tuple(Vsn) ->
- true;
-is_valid_constraint({_Pkg, _LVsn, gte}) ->
- true;
-is_valid_constraint({_Pkg, _LVsn, '>='}) ->
- true;
-is_valid_constraint({_Pkg, _LVsn, lte}) ->
- true;
-is_valid_constraint({_Pkg, _LVsn, '<='}) ->
- true;
-is_valid_constraint({_Pkg, _LVsn, gt}) ->
- true;
-is_valid_constraint({_Pkg, _LVsn, '>'}) ->
- true;
-is_valid_constraint({_Pkg, _LVsn, lt}) ->
- true;
-is_valid_constraint({_Pkg, _LVsn, '<'}) ->
- true;
-is_valid_constraint({_Pkg, _LVsn, pes}) ->
- true;
-is_valid_constraint({_Pkg, _LVsn, '~>'}) ->
- true;
-is_valid_constraint({_Pkg, _LVsn1, _LVsn2, between}) ->
- true;
-is_valid_constraint(_InvalidConstraint) ->
- false.
-
+-spec is_valid_raw_constraint(raw_constraint()) -> true; (any()) -> false.
+is_valid_raw_constraint(RawConstraint) ->
+ try fix_con(RawConstraint)
+ of
+ Constraint -> is_valid_constraint(Constraint)
+ catch
+ error:function_clause -> false
+ end.
%% @doc given a list of package name version pairs, and a list of constraints
%% return every member of that list that matches all constraints.
@@ -357,9 +332,9 @@ format_version(Version) ->
rlx_depsolver_culprit:format_version(Version).
%% @doc A formatted constraint tuple
--spec format_constraint(constraint()) -> iolist().
-format_constraint(Constraint) ->
- rlx_depsolver_culprit:format_constraint(Constraint).
+-spec format_constraint(raw_constraint()) -> iolist().
+format_constraint(RawConstraint) ->
+ rlx_depsolver_culprit:format_constraint(fix_con(RawConstraint)).
%%====================================================================
%% Internal Functions
@@ -470,6 +445,38 @@ dep_pkg({Pkg, _Vsn1, _Vsn2, _}) ->
dep_pkg(Pkg) when is_atom(Pkg) orelse is_binary(Pkg) ->
Pkg.
+-spec is_valid_constraint(constraint()) -> boolean().
+is_valid_constraint(Pkg) when is_atom(Pkg) orelse is_binary(Pkg) ->
+ true;
+is_valid_constraint({_Pkg, Vsn}) when is_tuple(Vsn) ->
+ true;
+is_valid_constraint({_Pkg, Vsn, '='}) when is_tuple(Vsn) ->
+ true;
+is_valid_constraint({_Pkg, _LVsn, gte}) ->
+ true;
+is_valid_constraint({_Pkg, _LVsn, '>='}) ->
+ true;
+is_valid_constraint({_Pkg, _LVsn, lte}) ->
+ true;
+is_valid_constraint({_Pkg, _LVsn, '<='}) ->
+ true;
+is_valid_constraint({_Pkg, _LVsn, gt}) ->
+ true;
+is_valid_constraint({_Pkg, _LVsn, '>'}) ->
+ true;
+is_valid_constraint({_Pkg, _LVsn, lt}) ->
+ true;
+is_valid_constraint({_Pkg, _LVsn, '<'}) ->
+ true;
+is_valid_constraint({_Pkg, _LVsn, pes}) ->
+ true;
+is_valid_constraint({_Pkg, _LVsn, '~>'}) ->
+ true;
+is_valid_constraint({_Pkg, _LVsn1, _LVsn2, between}) ->
+ true;
+is_valid_constraint(_InvalidConstraint) ->
+ false.
+
-spec add_constraint(pkg_name(), vsn(), [constraint()],constraint()) -> ordered_constraints().
add_constraint(SrcPkg, SrcVsn, PkgsConstraints, PkgConstraint) ->
case is_valid_constraint(PkgConstraint) of
diff --git a/src/rlx_depsolver_culprit.erl b/src/rlx_depsolver_culprit.erl
index cf6dcb2..6368d24 100644
--- a/src/rlx_depsolver_culprit.erl
+++ b/src/rlx_depsolver_culprit.erl
@@ -1,5 +1,5 @@
%% -*- erlang-indent-level: 4; indent-tabs-mode: nil; fill-column: 80 -*-
-%% ex: ts=4 sx=4 et
+%% ex: ts=4 sw=4 et
%%
%% @author Eric Merritt <[email protected]>
%%
diff --git a/src/rlx_prv_overlay.erl b/src/rlx_prv_overlay.erl
index 516d238..2b91c0b 100644
--- a/src/rlx_prv_overlay.erl
+++ b/src/rlx_prv_overlay.erl
@@ -82,9 +82,6 @@ format_error({read_template, FileName, Reason}) ->
[FileName, file:format_error(Reason)]);
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}) ->
io_lib:format("Unable to symlink directory ~s to ~s because \n~s~s",
[AppDir, TargetDir, rlx_util:indent(2),
@@ -312,14 +309,12 @@ do_individual_overlay(State, _Files, OverlayVars, {chmod, Mode, Path}) ->
NewMode =
case is_integer(Mode) of
true -> Mode;
- false -> erlang:list_to_integer(erlang:binary_to_list(render_string (OverlayVars, Mode)))
+ false -> erlang:binary_to_integer(render_string (OverlayVars, Mode))
end,
- Root = rlx_state:output_dir(State),
file_render_do(OverlayVars, Path,
fun(NewPath) ->
- Absolute = absolutize(State,
- filename:join(Root,erlang:iolist_to_binary (NewPath))),
+ Absolute = absolute_path_to(State, NewPath),
case file:change_mode(Absolute, NewMode) of
{error, Error} ->
?RLX_ERROR({unable_to_chmod, NewMode, NewPath, Error});
@@ -327,20 +322,16 @@ do_individual_overlay(State, _Files, OverlayVars, {chmod, Mode, Path}) ->
end
end);
do_individual_overlay(State, _Files, OverlayVars, {mkdir, Dir}) ->
- case rlx_util:render(erlang:iolist_to_binary(Dir), OverlayVars) of
- {ok, IoList} ->
- Absolute = absolutize(State,
- filename:join(rlx_state:output_dir(State),
- erlang:iolist_to_binary(IoList))),
- case rlx_util:mkdir_p(Absolute) of
- {error, Error} ->
- ?RLX_ERROR({unable_to_make_dir, Absolute, Error});
- ok ->
- ok
- end;
- {error, Error} ->
- ?RLX_ERROR({dir_render_failed, Dir, Error})
- end;
+ file_render_do(OverlayVars, Dir,
+ fun(Dir0) ->
+ Absolute = absolute_path_to(State, Dir0),
+ case rlx_util:mkdir_p(Absolute) of
+ {error, Error} ->
+ ?RLX_ERROR({unable_to_make_dir, Absolute, Error});
+ ok ->
+ ok
+ end
+ end);
do_individual_overlay(State, _Files, OverlayVars, {copy, From, To}) ->
file_render_do(OverlayVars, From,
fun(FromFile) ->
@@ -367,73 +358,65 @@ do_individual_overlay(State, _Files, OverlayVars, {template, From, To}) ->
fun(FromFile) ->
file_render_do(OverlayVars, To,
fun(ToFile) ->
- RelativeRoot = get_relative_root(State),
- FromFile0 = absolutize(State,
- filename:join(RelativeRoot,
- erlang:iolist_to_binary(FromFile))),
- FromFile1 = erlang:binary_to_list(FromFile0),
write_template(OverlayVars,
- FromFile1,
- absolutize(State,
- filename:join(rlx_state:output_dir(State),
- erlang:iolist_to_binary(ToFile))))
+ absolute_path_from(State, FromFile),
+ absolute_path_to(State, ToFile))
end)
end).
--spec copy_to(rlx_state:t(), file:name(), file:name()) -> ok | relx:error().
-copy_to(State, FromFile0, ToFile0) ->
- RelativeRoot = get_relative_root(State),
- ToFile1 = absolutize(State, filename:join(rlx_state:output_dir(State),
- erlang:iolist_to_binary(ToFile0))),
-
- FromFile1 = absolutize(State, filename:join(RelativeRoot,
- erlang:iolist_to_binary(FromFile0))),
- ToFile2 = case is_directory(ToFile0, ToFile1) of
- false ->
- filelib:ensure_dir(ToFile1),
- ToFile1;
- true ->
- rlx_util:mkdir_p(ToFile1),
- erlang:iolist_to_binary(filename:join(ToFile1,
- filename:basename(FromFile1)))
- end,
- case ec_file:copy(FromFile1, ToFile2, [recursive, {file_info, [mode, time]}]) of
+-spec wildcard_copy(rlx_state:t(), file:filename_all(), file:filename_all(),
+ fun((file:filename_all(), file:filename_all()) -> ok | {error, term()}),
+ ErrorTag :: atom()) -> ok | relx:error().
+wildcard_copy(State, FromFile0, ToFile0, CopyFun, ErrorTag) ->
+ FromFile1 = absolute_path_from(State, FromFile0),
+ ToFile1 = absolute_path_to(State, ToFile0),
+
+ Res = case is_directory(ToFile0, ToFile1) of
+ false ->
+ filelib:ensure_dir(ToFile1),
+ CopyFun(FromFile1, ToFile1);
+ true ->
+ Root = absolute_path_from(State, "."),
+ FromFiles = if
+ is_list(FromFile0) -> filelib:wildcard(FromFile0, Root);
+ true -> [FromFile1]
+ end,
+ rlx_util:mkdir_p(ToFile1),
+ lists:foldl(fun
+ (_, {error, _} = Error) -> Error;
+ (FromFile, ok) ->
+ CopyFun(filename:join(Root, FromFile), filename:join(ToFile1, filename:basename(FromFile)))
+ end, ok, FromFiles)
+ end,
+
+ case Res of
ok ->
ok;
{error, Err} ->
- ?RLX_ERROR({copy_failed,
+ ?RLX_ERROR({ErrorTag,
FromFile1,
ToFile1, Err})
end.
+
+-spec copy_to(rlx_state:t(), file:name(), file:name()) -> ok | relx:error().
+copy_to(State, FromFile0, ToFile0) ->
+ wildcard_copy(State, FromFile0, ToFile0,
+ fun(FromPath, ToPath) -> ec_file:copy(FromPath, ToPath, [recursive, {file_info, [mode, time]}]) end,
+ copy_failed).
+
-spec link_to(rlx_state:t(), file:name(), file:name()) -> ok | relx:error().
link_to(State, FromFile0, ToFile0) ->
- RelativeRoot = get_relative_root(State),
- ToFile1 = absolutize(State, filename:join(rlx_state:output_dir(State),
- erlang:iolist_to_binary(ToFile0))),
-
- FromFile1 = absolutize(State, filename:join(RelativeRoot,
- erlang:iolist_to_binary(FromFile0))),
- ToFile2 = case is_directory(ToFile0, ToFile1) of
- false ->
- filelib:ensure_dir(ToFile1),
- ToFile1;
- true ->
- rlx_util:mkdir_p(ToFile1),
- erlang:iolist_to_binary(filename:join(ToFile1,
- filename:basename(FromFile1)))
- end,
- case ec_file:is_symlink(ToFile2) of
- true -> file:delete(ToFile2);
- false -> ec_file:remove(ToFile2, [recursive])
+ wildcard_copy(State, FromFile0, ToFile0,
+ fun make_link/2,
+ link_failed).
+
+make_link(FromFile, ToFile) ->
+ case ec_file:is_symlink(ToFile) of
+ true -> file:delete(ToFile);
+ false -> ec_file:remove(ToFile, [recursive])
end,
- case file:make_symlink(FromFile1, ToFile2) of
- ok -> ok;
- {error, Err} ->
- ?RLX_ERROR({link_failed,
- FromFile1,
- ToFile1, Err})
- end.
+ file:make_symlink(FromFile, ToFile).
get_relative_root(State) ->
case rlx_state:config_file(State) of
@@ -448,6 +431,12 @@ get_relative_root(State) ->
end
end.
+absolute_path_from(State, Path) ->
+ absolutize(State, filename:join(get_relative_root(State), Path)).
+
+absolute_path_to(State, Path) ->
+ absolutize(State, filename:join(rlx_state:output_dir(State), Path)).
+
-spec is_directory(file:name(), file:name()) -> boolean().
is_directory(ToFile0, ToFile1) ->
case re:run(ToFile0, ?DIRECTORY_RE) of
@@ -512,16 +501,18 @@ render_string(OverlayVars, Data) ->
end.
-spec file_render_do(proplists:proplist(), iolist(),
- fun((term()) -> {ok, rlx_state:t()} | relx:error())) ->
+ fun((string() | binary()) -> {ok, rlx_state:t()} | relx:error())) ->
{ok, rlx_state:t()} | relx:error().
file_render_do(OverlayVars, File, NextAction) ->
+ io:format("render ~p~n", [File]),
case rlx_util:render(File, OverlayVars) of
- {ok, IoList} ->
- NextAction(IoList);
+ {ok, Binary} when is_binary(File) ->
+ NextAction(Binary);
+ {ok, Binary} when is_list(File) ->
+ NextAction(binary_to_list(Binary));
{error, Error} ->
?RLX_ERROR({render_failed, File, Error})
end.
absolutize(State, FileName) ->
- filename:absname(filename:join(rlx_state:root_dir(State),
- erlang:iolist_to_binary(FileName))).
+ filename:absname(filename:join(rlx_state:root_dir(State), FileName)).
diff --git a/src/rlx_prv_release.erl b/src/rlx_prv_release.erl
index 8de1a51..9be190e 100644
--- a/src/rlx_prv_release.erl
+++ b/src/rlx_prv_release.erl
@@ -168,12 +168,14 @@ solve_release(State0, DepGraph, RelName, RelVsn) ->
%% get per release config values and override the State with them
Config = rlx_release:config(Release),
{ok, State1} = lists:foldl(fun rlx_config:load_terms/2, {ok, State0}, Config),
- Goals = rlx_release:goals(Release),
- case Goals of
+ Goals = rlx_release:constraints(Release),
+ GlobalGoals = rlx_state:goals(State1),
+ MergedGoals = rlx_release:merge_application_goals(Goals, GlobalGoals),
+ case MergedGoals of
[] ->
?RLX_ERROR(no_goals_specified);
_ ->
- case rlx_depsolver:solve(DepGraph, Goals) of
+ case rlx_depsolver:solve(DepGraph, MergedGoals) of
{ok, Pkgs} ->
set_resolved(State1, Release, Pkgs);
{error, Error} ->
diff --git a/src/rlx_release.erl b/src/rlx_release.erl
index a183043..78e5970 100644
--- a/src/rlx_release.erl
+++ b/src/rlx_release.erl
@@ -30,6 +30,8 @@
erts/1,
goals/2,
goals/1,
+ constraints/1,
+ merge_application_goals/2,
name/1,
vsn/1,
realize/3,
@@ -138,7 +140,11 @@ goals(Release, Goals0) ->
{ok, Release}, Goals0).
-spec goals(t()) -> [application_goal()].
-goals(#release_t{goals=Goals}) ->
+goals(#release_t{goals=Goals, annotations=Annots}) ->
+ [application_goal(Goal, Annots) || Goal <- Goals].
+
+-spec constraints(t()) -> [rlx_depsolver:raw_constraint()].
+constraints(#release_t{goals=Goals}) ->
Goals.
-spec realize(t(), [{app_name(), app_vsn()}], [rlx_app_info:t()]) ->
@@ -191,14 +197,23 @@ start_clean_metadata(#release_t{name=Name, vsn=Vsn, erts=ErtsVsn, applications=A
realized=Realized}) ->
case Realized of
true ->
- Kernel = lists:keyfind(kernel, 1, Apps),
- StdLib = lists:keyfind(stdlib, 1, Apps),
+ {value, Kernel, Apps1} = lists:keytake(kernel, 1, Apps),
+ {value, StdLib, Apps2} = lists:keytake(stdlib, 1, Apps1),
{ok, {release, {erlang:atom_to_list(Name), Vsn}, {erts, ErtsVsn},
- [Kernel, StdLib]}};
+ [Kernel, StdLib | none_type_apps(Apps2)]}};
false ->
?RLX_ERROR({not_realized, Name, Vsn})
end.
+none_type_apps([]) ->
+ [];
+none_type_apps([{Name, Version} | Rest]) ->
+ [{Name, Version, none} | none_type_apps(Rest)];
+none_type_apps([{Name, Version, _} | Rest]) ->
+ [{Name, Version, none} | none_type_apps(Rest)];
+none_type_apps([{Name, Version, _, _} | Rest]) ->
+ [{Name, Version, none} | none_type_apps(Rest)].
+
%% The no_dot_erlang.rel.src file is a literal copy of start_clean.rel.src
%% in Erlang/OTP itself.
-spec no_dot_erlang_metadata(t()) -> term().
@@ -364,6 +379,14 @@ parse_goal0({Constraint0, Annots, Incls}, {ok, Release})
Error ->
Error
end;
+parse_goal0({Constraint0, Incls}, {ok, Release})
+ when erlang:is_list(Incls), Incls == [] orelse is_atom(hd(Incls)) ->
+ case parse_constraint(Constraint0) of
+ {ok, Constraint1} ->
+ parse_goal1(Release, Constraint1, {void, Incls});
+ Error ->
+ Error
+ end;
parse_goal0(Constraint0, {ok, Release}) ->
case parse_constraint(Constraint0) of
{ok, Constraint1} ->
@@ -400,12 +423,11 @@ parse_constraint(Constraint0)
parse_constraint(Constraint0)
when erlang:is_tuple(Constraint0);
erlang:is_atom(Constraint0) ->
- Constraint1 = parse_version(Constraint0),
- case rlx_depsolver:is_valid_constraint(Constraint1) of
+ case rlx_depsolver:is_valid_raw_constraint(Constraint0) of
false ->
?RLX_ERROR({invalid_constraint, 2, Constraint0});
true ->
- {ok, Constraint1}
+ {ok, Constraint0}
end;
parse_constraint(Constraint) ->
?RLX_ERROR({invalid_constraint, 3, Constraint}).
@@ -423,22 +445,44 @@ get_app_name({AppName, _, _, _}) when erlang:is_atom(AppName) ->
get_app_name(V) ->
?RLX_ERROR({invalid_constraint, 4, V}).
--spec parse_version(rlx_depsolver:raw_constraint()) ->
- rlx_depsolver:constraint().
-parse_version({AppName, Version})
- when erlang:is_binary(Version);
- erlang:is_list(Version) ->
- {AppName, rlx_depsolver:parse_version(Version)};
-parse_version({AppName, Version, Constraint})
- when erlang:is_binary(Version);
- erlang:is_list(Version) ->
- {AppName, rlx_depsolver:parse_version(Version), Constraint};
-parse_version({AppName, Version, Constraint0, Constraint1})
- when erlang:is_binary(Version);
- erlang:is_list(Version) ->
- {AppName, rlx_depsolver:parse_version(Version), Constraint1, Constraint0};
-parse_version(Constraint) ->
- Constraint.
+-spec get_goal_app_name(application_goal()) -> atom() | relx:error().
+get_goal_app_name({Constraint, Annots})
+ when Annots =:= permanent;
+ Annots =:= transient;
+ Annots =:= temporary;
+ Annots =:= load;
+ Annots =:= none ->
+ get_app_name(Constraint);
+get_goal_app_name({Constraint, Annots, Incls})
+ when (Annots =:= permanent orelse
+ Annots =:= transient orelse
+ Annots =:= temporary orelse
+ Annots =:= load orelse
+ Annots =:= none),
+ erlang:is_list(Incls) ->
+ get_app_name(Constraint);
+get_goal_app_name({Constraint, Incls})
+ when erlang:is_list(Incls), Incls == [] orelse is_atom(hd(Incls)) ->
+ get_app_name(Constraint);
+get_goal_app_name(Constraint) ->
+ get_app_name(Constraint).
+
+-spec application_goal(rlx_depsolver:raw_constraint(), annotations()) -> application_goal().
+application_goal(Constraint, Annots) ->
+ AppName = get_app_name(Constraint),
+ try ec_dictionary:get(AppName, Annots) of
+ {void, void} ->
+ Constraint;
+ {void, Incls} ->
+ {Constraint, Incls};
+ {Type, void} ->
+ {Constraint, Type};
+ {Type, Incls} ->
+ {Constraint, Type, Incls}
+ catch
+ throw:not_found ->
+ Constraint
+ end.
to_atom(RelName)
when erlang:is_list(RelName) ->
@@ -446,3 +490,15 @@ to_atom(RelName)
to_atom(Else)
when erlang:is_atom(Else) ->
Else.
+
+-spec merge_application_goals([application_goal()], [application_goal()]) -> [application_goal()].
+merge_application_goals(Goals, BaseGoals) ->
+ Goals ++ lists:foldl(fun filter_goal_by_name/2, BaseGoals, Goals).
+
+filter_goal_by_name(AppGoal, GoalList) when is_list(GoalList) ->
+ case get_goal_app_name(AppGoal) of
+ AppName when is_atom(AppName) ->
+ lists:filter(fun(Goal) -> get_goal_app_name(Goal) /= AppName end, GoalList);
+ _Error ->
+ GoalList
+ end.
diff --git a/src/rlx_state.erl b/src/rlx_state.erl
index 5488a41..cab55f6 100644
--- a/src/rlx_state.erl
+++ b/src/rlx_state.erl
@@ -105,7 +105,7 @@
lib_dirs=[] :: [file:name()],
config_file=[] :: file:filename() | undefined,
cli_args=[] :: proplists:proplist(),
- goals=[] :: [rlx_depsolver:constraint()],
+ goals=[] :: [rlx_depsolver:raw_constraint()],
providers=[] :: [providers:t()],
available_apps=[] :: [rlx_app_info:t()],
default_configured_release :: {rlx_release:name() | undefined, rlx_release:vsn() |undefined} | undefined,
@@ -254,11 +254,11 @@ lib_dirs(#state_t{lib_dirs=LibDir}) ->
add_lib_dirs(State=#state_t{lib_dirs=LibDir}, Dirs) ->
State#state_t{lib_dirs=lists:umerge(lists:sort(LibDir), lists:sort(Dirs))}.
--spec goals(t()) -> [rlx_depsolver:constraint()].
+-spec goals(t()) -> [rlx_depsolver:raw_constraint()].
goals(#state_t{goals=TS}) ->
TS.
--spec goals(t(), [rlx_depsolver:constraint()]) -> t().
+-spec goals(t(), [rlx_depsolver:raw_constraint()]) -> t().
goals(State, Goals) ->
State#state_t{goals=Goals}.
diff --git a/src/rlx_string.erl b/src/rlx_string.erl
index 1f9cc0c..d5f5046 100644
--- a/src/rlx_string.erl
+++ b/src/rlx_string.erl
@@ -2,14 +2,22 @@
%% OTP-19 and OTP-21, where Unicode support means the deprecation
%% of a lot of string functions.
-module(rlx_string).
--export([concat/2, lexemes/2, join/2]).
+-export([concat/2, lexemes/2, join/2, trim/3]).
-ifdef(unicode_str).
concat(Str1, Str2) -> unicode:characters_to_list([Str1,Str2]).
lexemes(Str, Separators) -> string:lexemes(Str, Separators).
+trim(Str, Direction, Cluster=[_]) -> string:trim(Str, Direction, Cluster).
-else.
concat(Str1, Str2) -> string:concat(Str1, Str2).
lexemes(Str, Separators) -> string:tokens(Str, Separators).
+trim(Str, Direction, [Char]) ->
+ Dir = case Direction of
+ both -> both;
+ leading -> left;
+ trailing -> right
+ end,
+ string:strip(Str, Dir, Char).
-endif.
%% string:join/2 copy; string:join/2 is getting obsoleted
diff --git a/test/rlx_archive_SUITE.erl b/test/rlx_archive_SUITE.erl
index 68a5b07..8d30915 100644
--- a/test/rlx_archive_SUITE.erl
+++ b/test/rlx_archive_SUITE.erl
@@ -18,7 +18,7 @@
-include_lib("kernel/include/file.hrl").
suite() ->
- [{timetrap, {seconds, 30}}].
+ [{timetrap, {seconds, 120}}].
init_per_suite(Config) ->
Config.
diff --git a/test/rlx_command_SUITE.erl b/test/rlx_command_SUITE.erl
index e0beec1..8dd2da8 100644
--- a/test/rlx_command_SUITE.erl
+++ b/test/rlx_command_SUITE.erl
@@ -27,13 +27,14 @@
lib_expansion_case/1,
lib_fail_case/1,
spec_parse_fail_case/1,
- config_fail_case/1]).
+ config_fail_case/1,
+ provider_case/1]).
-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
suite() ->
- [{timetrap,{seconds,30}}].
+ [{timetrap,{seconds,120}}].
init_per_suite(Config) ->
Config.
@@ -42,7 +43,7 @@ end_per_suite(_Config) ->
ok.
all() ->
- [normal_passing_case, lib_expansion_case, lib_fail_case, config_fail_case].
+ [normal_passing_case, lib_expansion_case, lib_fail_case, config_fail_case, provider_case].
normal_passing_case(Config) ->
DataDir = filename:join(proplists:get_value(priv_dir, Config), ?MODULE),
@@ -111,3 +112,12 @@ config_fail_case(_Config) ->
{ok, {Opts, Targets}} = getopt:parse(relx:opt_spec_list(), CmdLine),
?assertMatch({error, {_, {invalid_config_file, ConfigFile}}},
rlx_cmd_args:args2state(Opts, Targets)).
+
+provider_case(_Config) ->
+ CmdLine = ["--provider", "relx_provider_1",
+ "--provider", "relx_provider_2"],
+ {ok, {Opts, Targets}} = getopt:parse(relx:opt_spec_list(), CmdLine),
+ {ok, State} = rlx_cmd_args:args2state(Opts, Targets),
+ ?assertEqual(
+ [relx_provider_1, relx_provider_2],
+ proplists:get_value(add_providers, rlx_state:cli_args(State))).
diff --git a/test/rlx_depsolver_tester.erl b/test/rlx_depsolver_tester.erl
index 9defd91..b3bc146 100644
--- a/test/rlx_depsolver_tester.erl
+++ b/test/rlx_depsolver_tester.erl
@@ -1,5 +1,5 @@
%% -*- erlang-indent-level: 4; indent-tabs-mode: nil; fill-column: 92 -*-
-%% ex: ts=4 sx=4 et
+%% ex: ts=4 sw=4 et
%%-------------------------------------------------------------------
%%
%% Copyright 2012 Opscode, Inc. All Rights Reserved.
@@ -49,153 +49,167 @@ run_log(FileName) ->
run_log_file(Device).
data1_test() ->
- ExpectedResult = versionify([{"app6","0.0.1"},
- {"dep_pkg13","0.0.2"},
- {"app13","0.0.1"},
- {"dep_pkg2","0.0.5"},
- {"dep_pkg1","0.0.2"},
+ ExpectedResult = versionify([
+ {"app9","0.0.1"},
{"dep_pkg7","0.1.2"},
- {"app9","0.0.1"}]),
+ {"dep_pkg1","0.0.2"},
+ {"dep_pkg2","0.0.5"},
+ {"app13","0.0.1"},
+ {"dep_pkg13","0.0.2"},
+ {"app6","0.0.1"}
+ ]),
?assertMatch({ok, ExpectedResult},
run_data(fix_rebar_brokenness("data1.txt"))).
data2_test() ->
- ExpectedResult = versionify([{"app18","0.0.1"},
- {"app4","0.0.7"},
- {"app1","0.0.1"},
- {"app6","0.0.1"},
- {"dep_pkg13","0.0.2"},
- {"app13","0.0.1"},
- {"dep_pkg5","0.0.3"},
- {"dep_pkg1","0.0.2"},
- {"dep_pkg2","0.0.5"},
- {"dep_pkg7","0.1.2"},
+ ExpectedResult = versionify([
+ {"dep_pkg16","1.0.2"},
{"app9","0.0.1"},
- {"dep_pkg16","1.0.2"}]),
+ {"dep_pkg7","0.1.2"},
+ {"dep_pkg2","0.0.5"},
+ {"dep_pkg1","0.0.2"},
+ {"dep_pkg5","0.0.3"},
+ {"app13","0.0.1"},
+ {"dep_pkg13","0.0.2"},
+ {"app6","0.0.1"},
+ {"app1","0.0.1"},
+ {"app4","0.0.7"},
+ {"app18","0.0.1"}
+ ]),
?assertMatch({ok, ExpectedResult},
run_data(fix_rebar_brokenness("data2.txt"))).
-
+
data3_test() ->
- ExpectedResult = versionify([{"app68","0.0.1"},
- {"app58","0.0.1"},
- {"app48","0.0.7"},
- {"app38","0.0.1"},
- {"app28","0.0.1"},
- {"app18","0.0.1"},
- {"app4","0.0.7"},
- {"app1","0.0.1"},
- {"app6","0.0.1"},
- {"dep_pkg13","0.0.2"},
- {"app13","0.0.1"},
- {"dep_pkg5","0.0.3"},
- {"dep_pkg1","0.0.2"},
- {"dep_pkg2","0.0.5"},
- {"dep_pkg7","0.1.2"},
+ ExpectedResult = versionify([
+ {"dep_pkg16","1.0.2"},
{"app9","0.0.1"},
- {"dep_pkg16","1.0.2"}]),
+ {"dep_pkg7","0.1.2"},
+ {"dep_pkg2","0.0.5"},
+ {"dep_pkg1","0.0.2"},
+ {"dep_pkg5","0.0.3"},
+ {"app13","0.0.1"},
+ {"dep_pkg13","0.0.2"},
+ {"app6","0.0.1"},
+ {"app1","0.0.1"},
+ {"app4","0.0.7"},
+ {"app18","0.0.1"},
+ {"app28","0.0.1"},
+ {"app38","0.0.1"},
+ {"app48","0.0.7"},
+ {"app58","0.0.1"},
+ {"app68","0.0.1"}
+ ]),
?assertMatch({ok,ExpectedResult}, run_data(fix_rebar_brokenness("data3.txt"))).
data4_test() ->
- ExpectedResult = versionify([{"dep_pkg20","0.0.2"},
- {"app78","0.0.1"},
- {"app68","0.0.1"},
- {"app58","0.0.1"},
- {"app48","0.0.7"},
- {"app38","0.0.1"},
- {"app28","0.0.1"},
- {"app18","0.0.1"},
- {"app4","0.0.7"},
- {"app1","0.0.1"},
- {"app6","0.0.1"},
- {"dep_pkg13","0.0.2"},
- {"app13","0.0.1"},
- {"dep_pkg5","0.0.3"},
- {"dep_pkg1","0.0.2"},
- {"dep_pkg2","0.0.5"},
- {"dep_pkg7","0.1.2"},
+ ExpectedResult = versionify([
+ {"dep_pkg16","1.0.2"},
{"app9","0.0.1"},
- {"dep_pkg16","1.0.2"}]),
+ {"dep_pkg7","0.1.2"},
+ {"dep_pkg2","0.0.5"},
+ {"dep_pkg1","0.0.2"},
+ {"dep_pkg5","0.0.3"},
+ {"app13","0.0.1"},
+ {"dep_pkg13","0.0.2"},
+ {"app6","0.0.1"},
+ {"app1","0.0.1"},
+ {"app4","0.0.7"},
+ {"app18","0.0.1"},
+ {"app28","0.0.1"},
+ {"app38","0.0.1"},
+ {"app48","0.0.7"},
+ {"app58","0.0.1"},
+ {"app68","0.0.1"},
+ {"app78","0.0.1"},
+ {"dep_pkg20","0.0.2"}
+ ]),
?assertMatch({ok, ExpectedResult},
run_data(fix_rebar_brokenness("data4.txt"))).
data5_test() ->
- ExpectedResult = versionify([{"dep_pkg14","0.0.2"},
- {"dep_pkg22","0.0.2"},
- {"dep_pkg20","0.0.2"},
- {"app78","0.0.1"},
- {"app68","0.0.1"},
- {"app58","0.0.1"},
- {"app48","0.0.7"},
- {"app38","0.0.1"},
- {"app28","0.0.1"},
- {"app18","0.0.1"},
- {"app4","0.0.7"},
- {"app1","0.0.1"},
- {"app6","0.0.1"},
- {"dep_pkg13","0.0.2"},
- {"app13","0.0.1"},
- {"dep_pkg5","0.0.3"},
- {"dep_pkg1","0.0.2"},
- {"dep_pkg2","0.0.5"},
- {"dep_pkg7","0.1.2"},
+ ExpectedResult = versionify([
+ {"dep_pkg16","1.0.2"},
{"app9","0.0.1"},
- {"dep_pkg16","1.0.2"}]),
+ {"dep_pkg7","0.1.2"},
+ {"dep_pkg2","0.0.5"},
+ {"dep_pkg1","0.0.2"},
+ {"dep_pkg5","0.0.3"},
+ {"app13","0.0.1"},
+ {"dep_pkg13","0.0.2"},
+ {"app6","0.0.1"},
+ {"app1","0.0.1"},
+ {"app4","0.0.7"},
+ {"app18","0.0.1"},
+ {"app28","0.0.1"},
+ {"app38","0.0.1"},
+ {"app48","0.0.7"},
+ {"app58","0.0.1"},
+ {"app68","0.0.1"},
+ {"app78","0.0.1"},
+ {"dep_pkg20","0.0.2"},
+ {"dep_pkg22","0.0.2"},
+ {"dep_pkg14","0.0.2"}
+ ]),
?assertMatch({ok, ExpectedResult},
run_data(fix_rebar_brokenness("data5.txt"))).
data6_test() ->
- ExpectedResult = versionify([{"app108","0.0.1"},
- {"app98","0.0.1"},
- {"app88","0.0.1"},
- {"dep_pkg14","0.0.2"},
- {"dep_pkg22","0.0.2"},
- {"dep_pkg20","0.0.2"},
- {"app78","0.0.1"},
- {"app68","0.0.1"},
- {"app58","0.0.1"},
- {"app48","0.0.7"},
- {"app38","0.0.1"},
- {"app28","0.0.1"},
- {"app18","0.0.1"},
- {"app4","0.0.7"},
- {"app1","0.0.1"},
- {"app6","0.0.1"},
- {"dep_pkg13","0.0.2"},
- {"app13","0.0.1"},
- {"dep_pkg5","0.0.3"},
- {"dep_pkg1","0.0.2"},
- {"dep_pkg2","0.0.5"},
- {"dep_pkg7","0.1.2"},
+ ExpectedResult = versionify([
+ {"dep_pkg16","1.0.2"},
{"app9","0.0.1"},
- {"dep_pkg16","1.0.2"}]),
+ {"dep_pkg7","0.1.2"},
+ {"dep_pkg2","0.0.5"},
+ {"dep_pkg1","0.0.2"},
+ {"dep_pkg5","0.0.3"},
+ {"app13","0.0.1"},
+ {"dep_pkg13","0.0.2"},
+ {"app6","0.0.1"},
+ {"app1","0.0.1"},
+ {"app4","0.0.7"},
+ {"app18","0.0.1"},
+ {"app28","0.0.1"},
+ {"app38","0.0.1"},
+ {"app48","0.0.7"},
+ {"app58","0.0.1"},
+ {"app68","0.0.1"},
+ {"app78","0.0.1"},
+ {"dep_pkg20","0.0.2"},
+ {"dep_pkg22","0.0.2"},
+ {"dep_pkg14","0.0.2"},
+ {"app88","0.0.1"},
+ {"app98","0.0.1"},
+ {"app108","0.0.1"}
+ ]),
?assertMatch({ok, ExpectedResult},
run_data(fix_rebar_brokenness("data6.txt"))).
log_07be9e47_test() ->
Data = run_log(fix_rebar_brokenness("log-07be9e47-6f42-4a5d-b8b5-1d2eae1ad83b.txt")),
- ExpectedResult = versionify([{"0","0"},
- {"1","0"},
- {"3","0"},
- {"4","0"},
- {"5","0"},
- {"6","0"},
- {"7","0"},
- {"8","0"},
- {"9","0"},
- {"10","0"},
- {"11","0"},
- {"12","0"},
- {"13","0"},
- {"14","0"},
- {"15","0"},
- {"16","0"},
- {"18","0"},
- {"19","0"},
- {"21","0"},
- {"22","0"},
- {"23","0"},
+ ExpectedResult = versionify([
+ {"25","0"},
{"24","0"},
- {"25","0"}]),
+ {"23","0"},
+ {"22","0"},
+ {"21","0"},
+ {"19","0"},
+ {"18","0"},
+ {"16","0"},
+ {"15","0"},
+ {"14","0"},
+ {"13","0"},
+ {"12","0"},
+ {"11","0"},
+ {"10","0"},
+ {"9","0"},
+ {"8","0"},
+ {"7","0"},
+ {"6","0"},
+ {"5","0"},
+ {"4","0"},
+ {"3","0"},
+ {"1","0"},
+ {"0","0"}
+ ]),
?assertMatch({ok, ExpectedResult},
Data).
@@ -206,144 +220,152 @@ log_183998c1_test() ->
log_311a15e7_test() ->
{ok, Data} = run_log(fix_rebar_brokenness("log-311a15e7-3378-4c5b-beb7-86a1b9cf0ea9.txt")),
- ExpectedResult = lists:sort(versionify([{"45", "22"},
- {"40","1"},
- {"3","5"},
- {"9","0"},
- {"8","0"},
- {"7","0"},
- {"6","2"},
- {"1","5"},
- {"0","2"},
- {"61","1"},
- {"60","0"},
- {"35","4"},
- {"39","0"},
- {"38","2"},
- {"37","2"},
- {"36","3"},
- {"32","24"},
- {"30","0"},
- {"19","1"},
- {"18","0"},
- {"17","2"},
- {"16","0"},
- {"15","0"},
- {"14","1"},
- {"13","0"},
- {"12","1"},
- {"11","0"},
- {"10","1"},
- {"59","0"},
- {"58","1"},
- {"57","0"},
- {"56","0"},
- {"55","4"},
- {"29","2"},
- {"27","2"},
- {"26","0"},
- {"25","5"},
- {"24","3"},
- {"23","1"},
- {"22","3"},
+ ExpectedResult = lists:sort(versionify([
+ {"20","0"},
{"21","2"},
- {"20","0"}])),
+ {"22","3"},
+ {"23","1"},
+ {"24","3"},
+ {"25","5"},
+ {"26","0"},
+ {"27","2"},
+ {"29","2"},
+ {"55","4"},
+ {"56","0"},
+ {"57","0"},
+ {"58","1"},
+ {"59","0"},
+ {"10","1"},
+ {"11","0"},
+ {"12","1"},
+ {"13","0"},
+ {"14","1"},
+ {"15","0"},
+ {"16","0"},
+ {"17","2"},
+ {"18","0"},
+ {"19","1"},
+ {"30","0"},
+ {"32","24"},
+ {"36","3"},
+ {"37","2"},
+ {"38","2"},
+ {"39","0"},
+ {"35","4"},
+ {"60","0"},
+ {"61","1"},
+ {"0","2"},
+ {"1","5"},
+ {"6","2"},
+ {"7","0"},
+ {"8","0"},
+ {"9","0"},
+ {"3","5"},
+ {"40","1"},
+ {"45", "22"}
+ ])),
?assertMatch(ExpectedResult, lists:sort(Data)).
log_382cfe5b_test() ->
{ok, Data} =
run_log(fix_rebar_brokenness("log-382cfe5b-0ac2-48b8-83d1-717cb4620990.txt")),
- ExpectedResult = lists:sort(versionify([{"18","0"},
- {"17","0"},
- {"15","1"},
- {"14","0"},
- {"10","0"},
- {"7","0"},
- {"6","0"},
- {"5","0"},
- {"4","0"},
- {"3","0"},
- {"2","1"},
+ ExpectedResult = lists:sort(versionify([
+ {"0","0"},
{"1","0"},
- {"0","0"}])),
+ {"2","1"},
+ {"3","0"},
+ {"4","0"},
+ {"5","0"},
+ {"6","0"},
+ {"7","0"},
+ {"10","0"},
+ {"14","0"},
+ {"15","1"},
+ {"17","0"},
+ {"18","0"}
+ ])),
?assertMatch(ExpectedResult, lists:sort(Data)).
log_d3564ef6_test() ->
{ok, Data} = run_log(fix_rebar_brokenness("log-d3564ef6-6437-41e7-90b6-dbdb849551a6_mod.txt")),
- ExpectedResult = lists:sort(versionify([{"57","5"},
- {"56","3"},
- {"55","4"},
- {"54","0"},
- {"53","1"},
- {"82","0"},
- {"81","0"},
- {"80","1"},
- {"29","0"},
- {"28","5"},
- {"27","3"},
- {"26","1"},
- {"25","3"},
- {"24","2"},
- {"23","0"},
- {"22","1"},
- {"21","0"},
- {"20","2"},
- {"75","32"},
- {"79","2"},
- {"78","4"},
- {"74","7"},
- {"73","11"},
- {"72","0"},
- {"70","1"},
- {"47","4"},
- {"45","1"},
- {"44","1"},
- {"43","7"},
- {"42","1"},
- {"41","2"},
- {"40","2"},
- {"19","0"},
- {"18","0"},
- {"17","1"},
- {"16","0"},
- {"15","1"},
- {"14","0"},
- {"13","1"},
- {"12","0"},
- {"11","0"},
- {"10","0"},
- {"9","2"},
- {"4","5"},
- {"3","2"},
- {"0","3"},
- {"69","0"},
- {"68","1"},
- {"67","7"},
- {"39","3"},
- {"35","24"},
- {"33","0"},
+ ExpectedResult = lists:sort(versionify([
+ {"30","2"},
{"32","2"},
- {"30","2"}])),
+ {"33","0"},
+ {"35","24"},
+ {"39","3"},
+ {"67","7"},
+ {"68","1"},
+ {"69","0"},
+ {"0","3"},
+ {"3","2"},
+ {"4","5"},
+ {"9","2"},
+ {"10","0"},
+ {"11","0"},
+ {"12","0"},
+ {"13","1"},
+ {"14","0"},
+ {"15","1"},
+ {"16","0"},
+ {"17","1"},
+ {"18","0"},
+ {"19","0"},
+ {"40","2"},
+ {"41","2"},
+ {"42","1"},
+ {"43","7"},
+ {"44","1"},
+ {"45","1"},
+ {"47","4"},
+ {"70","1"},
+ {"72","0"},
+ {"73","11"},
+ {"74","7"},
+ {"78","4"},
+ {"79","2"},
+ {"75","32"},
+ {"20","2"},
+ {"21","0"},
+ {"22","1"},
+ {"23","0"},
+ {"24","2"},
+ {"25","3"},
+ {"26","1"},
+ {"27","3"},
+ {"28","5"},
+ {"29","0"},
+ {"80","1"},
+ {"81","0"},
+ {"82","0"},
+ {"53","1"},
+ {"54","0"},
+ {"55","4"},
+ {"56","3"},
+ {"57","5"}
+ ])),
?assertMatch(ExpectedResult, lists:sort(Data)).
log_ea2d264b_test() ->
{ok, Data} = run_log(fix_rebar_brokenness("log-ea2d264b-003e-4611-94ed-14efc7732083.txt")),
- ExpectedResult = lists:sort(versionify([{"18","1"},
- {"17","0"},
- {"16","0"},
- {"15","0"},
- {"14","0"},
- {"13","1"},
- {"10","1"},
- {"9","1"},
- {"8","2"},
- {"6","0"},
- {"5","0"},
- {"4","0"},
- {"3","0"},
- {"2","0"},
+ ExpectedResult = lists:sort(versionify([
+ {"0","1"},
{"1","0"},
- {"0","1"}])),
+ {"2","0"},
+ {"3","0"},
+ {"4","0"},
+ {"5","0"},
+ {"6","0"},
+ {"8","2"},
+ {"9","1"},
+ {"10","1"},
+ {"13","1"},
+ {"14","0"},
+ {"15","0"},
+ {"16","0"},
+ {"17","0"},
+ {"18","1"}
+ ])),
?assertMatch(ExpectedResult, lists:sort(Data)).
%%============================================================================
diff --git a/test/rlx_depsolver_tests.erl b/test/rlx_depsolver_tests.erl
index 206bad4..b1c8228 100644
--- a/test/rlx_depsolver_tests.erl
+++ b/test/rlx_depsolver_tests.erl
@@ -1,5 +1,5 @@
%% -*- erlang-indent-level: 4; indent-tabs-mode: nil; fill-column: 80 -*-
-%% ex: ts=4 sx=4 et
+%% ex: ts=4 sw=4 et
%%
%%-------------------------------------------------------------------
%% Copyright 2012 Opscode, Inc. All Rights Reserved.
diff --git a/test/rlx_discover_SUITE.erl b/test/rlx_discover_SUITE.erl
index 36d77ae..9385229 100644
--- a/test/rlx_discover_SUITE.erl
+++ b/test/rlx_discover_SUITE.erl
@@ -34,7 +34,7 @@
-include_lib("eunit/include/eunit.hrl").
suite() ->
- [{timetrap,{seconds,30}}].
+ [{timetrap,{seconds,120}}].
init_per_suite(Config) ->
Config.
diff --git a/test/rlx_eunit_SUITE.erl b/test/rlx_eunit_SUITE.erl
index 874e5a6..c7c0751 100644
--- a/test/rlx_eunit_SUITE.erl
+++ b/test/rlx_eunit_SUITE.erl
@@ -30,7 +30,7 @@
-include_lib("eunit/include/eunit.hrl").
suite() ->
- [{timetrap,{seconds,30}}].
+ [{timetrap,{seconds,120}}].
init_per_suite(Config) ->
Config.
diff --git a/test/rlx_extended_bin_SUITE.erl b/test/rlx_extended_bin_SUITE.erl
index 041afca..710d2c4 100644
--- a/test/rlx_extended_bin_SUITE.erl
+++ b/test/rlx_extended_bin_SUITE.erl
@@ -66,7 +66,7 @@
-define(SLEEP_TIME, 2500).
suite() ->
- [{timetrap,{seconds,30}}].
+ [{timetrap,{seconds,300}}].
init_per_suite(Config) ->
Config.
@@ -86,7 +86,7 @@ init_per_testcase(_, Config) ->
all() ->
[start_sname_in_other_argsfile, start_preserves_arguments, start_nodetool_with_data_from_argsfile,
start_upgrade_escript_with_argsfile_data, start_fail_when_no_name, start_fail_when_multiple_names,
- start_fail_when_missing_argsfile, start_fail_when_nonreadable_argsfile,
+ start_fail_when_missing_argsfile, %% start_fail_when_nonreadable_argsfile,
start_fail_when_relative_argsfile, start_fail_when_circular_argsfiles,
ping, shortname_ping, longname_ping, attach, pid, restart, reboot, escript,
remote_console, shortname_remote_console, replace_os_vars, replace_os_vars_sys_config_vm_args_src, replace_os_vars_multi_node,
@@ -1298,10 +1298,7 @@ custom_start_script_hooks(Config) ->
]}
]},
{mkdir, "scripts"},
- {overlay, [{copy, "./pre_start", "bin/hooks/pre_start"},
- {copy, "./post_start", "bin/hooks/post_start"},
- {copy, "./pre_stop", "bin/hooks/pre_stop"},
- {copy, "./post_stop", "bin/hooks/post_stop"}]}
+ {overlay, [{copy, "./{pre,post}_{start,stop}", "bin/hooks/"}]}
]),
%% write the hook scripts, each of them will write an erlang term to a file
@@ -1798,7 +1795,7 @@ start_fail_when_nonreadable_argsfile(Config) ->
LibDir1 = proplists:get_value(lib1, Config),
VmArgs = filename:join([LibDir1, "vm.args"]),
VmArgs2 = VmArgs ++ ".nonreadable",
- ec_file:write(VmArgs, "-name foo\n\n"
+ ec_file:write(VmArgs, "-name [email protected]\n\n"
"-args_file " ++ VmArgs2 ++ "\n\n"
"-setcookie cookie\n"),
ec_file:write(VmArgs2, ""),
diff --git a/test/rlx_prv_release_alias.erl b/test/rlx_prv_release_alias.erl
new file mode 100644
index 0000000..523940c
--- /dev/null
+++ b/test/rlx_prv_release_alias.erl
@@ -0,0 +1,27 @@
+-module(rlx_prv_release_alias).
+
+-behaviour(provider).
+
+-export([init/1, do/1, format_error/1]).
+
+-define(PROVIDER, test_release_alias).
+-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(State) ->
+ rlx_prv_release:do(State).
+
+-spec format_error(ErrorDetail::term()) -> iolist().
+format_error(ErrorDetail) ->
+ rlx_prv_release:format_error(ErrorDetail).
diff --git a/test/rlx_release_SUITE.erl b/test/rlx_release_SUITE.erl
index 052b5c2..a582526 100644
--- a/test/rlx_release_SUITE.erl
+++ b/test/rlx_release_SUITE.erl
@@ -25,7 +25,9 @@
init_per_testcase/2,
all/0,
providers/1,
+ providers_via_api_options/1,
add_providers/1,
+ add_providers_via_api_options/1,
make_release/1,
make_config_release/1,
make_extend_release/1,
@@ -40,6 +42,7 @@
make_implicit_config_release/1,
overlay_release/1,
make_goalless_release/1,
+ make_external_goal_release/1,
make_depfree_release/1,
make_invalid_config_release/1,
make_relup_release/1,
@@ -64,7 +67,7 @@
-include_lib("kernel/include/file.hrl").
suite() ->
- [{timetrap,{seconds,30}}].
+ [{timetrap,{seconds,120}}].
init_per_suite(Config) ->
Config.
@@ -82,19 +85,18 @@ init_per_testcase(_, Config) ->
{state, State1} | Config].
all() ->
- [providers, add_providers, make_release, make_config_release,
- make_extend_release, make_extend_config_release, make_scriptless_release,
- make_overridden_release, make_auto_skip_empty_app_release,
+ [providers, providers_via_api_options, add_providers, add_providers_via_api_options,
+ make_release, make_config_release, make_extend_release, make_extend_config_release,
+ make_scriptless_release, make_overridden_release, make_auto_skip_empty_app_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_dev_mode_template_release,
- make_config_script_release, make_release_twice, make_release_twice_dev_mode,
- make_erts_release, make_erts_config_release,
- make_included_nodetool_release, make_not_included_nodetool_release,
- make_src_release, make_excluded_src_release, make_exclude_modules_release,
- make_release_with_sys_config_vm_args_src].
+ make_implicit_config_release, make_rerun_overridden_release, overlay_release,
+ make_goalless_release, make_external_goal_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_dev_mode_template_release, make_config_script_release,
+ make_release_twice, make_release_twice_dev_mode, make_erts_release,
+ make_erts_config_release, make_included_nodetool_release,
+ make_not_included_nodetool_release, make_src_release, make_excluded_src_release,
+ make_exclude_modules_release, make_release_with_sys_config_vm_args_src].
add_providers(Config) ->
LibDir1 = proplists:get_value(lib1, Config),
@@ -133,6 +135,52 @@ add_providers(Config) ->
?assert(lists:member({goal_app_2, "0.0.1"}, AppSpecs)),
?assert(lists:member({lib_dep_1, "0.0.1", load}, AppSpecs)).
+add_providers_via_api_options(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(priv_dir, Config),
+ rlx_test_utils:create_random_name("relx-output")]),
+ {ok, Cwd} = file:get_cwd(),
+ Opts = [{relname, undefined},
+ {relvsn, undefined},
+ {goals, []},
+ {overrides, []},
+ {output_dir, OutputDir},
+ {lib_dirs, [LibDir1]},
+ {root_dir, Cwd},
+ {log_level, 3},
+ {config, ConfigFile},
+ {add_providers, [rlx_prv_release_alias]}],
+ {ok, State} = relx:do(Opts, ["test_release_alias"]),
+ [{{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)).
+
providers(Config) ->
LibDir1 = proplists:get_value(lib1, Config),
@@ -170,6 +218,52 @@ providers(Config) ->
?assert(lists:member({goal_app_2, "0.0.1"}, AppSpecs)),
?assert(lists:member({lib_dep_1, "0.0.1", load}, AppSpecs)).
+providers_via_api_options(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(priv_dir, Config),
+ rlx_test_utils:create_random_name("relx-output")]),
+ {ok, Cwd} = file:get_cwd(),
+ Opts = [{relname, undefined},
+ {relvsn, undefined},
+ {goals, []},
+ {overrides, []},
+ {output_dir, OutputDir},
+ {lib_dirs, [LibDir1]},
+ {root_dir, Cwd},
+ {log_level, 3},
+ {config, ConfigFile},
+ {providers, [rlx_prv_release_alias]}],
+ {ok, State} = relx:do(Opts, ["test_release_alias"]),
+ [{{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)).
+
make_release(Config) ->
LibDir1 = proplists:get_value(lib1, Config),
@@ -671,7 +765,7 @@ overlay_release(Config) ->
{mkdir, "{{target_dir}}/{{var_list_dir}}"},
{copy, OverlayVars1,
"{{target_dir}}/{{foo_dir}}/vars1.config"},
- {copy, OverlayVars1,
+ {copy, filename:join([LibDir1, "vars1*.config"]),
"{{target_dir}}/{{yahoo}}/"},
{link, OverlayVars4,
"{{target_dir}}/{{yahoo}}/vars4.config"},
@@ -784,6 +878,37 @@ make_goalless_release(Config) ->
relx:do(undefined, undefined, [], [LibDir1], 3,
OutputDir, ConfigFile)).
+make_external_goal_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, "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"]),
+
+ ConfigFile = filename:join([LibDir1, "relx.config"]),
+ rlx_test_utils:write_config(ConfigFile,
+ [{goals, [{goal_app_2, "0.0.1"}]},
+ {release, {foo, "0.0.1"},
+ [goal_app_1]}]),
+ OutputDir = filename:join([proplists:get_value(priv_dir, Config),
+ 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)),
+ 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)).
+
+
make_depfree_release(Config) ->
LibDir1 = proplists:get_value(lib1, Config),