diff options
30 files changed, 999 insertions, 558 deletions
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 @@ -13,5 +13,9 @@ logs 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 ed0f025..0000000 --- a/.travis.yml +++ /dev/null @@ -1,42 +0,0 @@ -language: erlang -matrix: - include: - - os: linux - sudo: required - otp_release: 17.5 - - os: linux - sudo: required - otp_release: 18.3 - - os: linux - sudo: required - otp_release: 19.3 - - os: linux - sudo: required - otp_release: 20.0 - - os: linux - sudo: required - otp_release: 21.0 - - 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" -branches: - only: - - master -addons: - hostname: travis.dev -notifications: - email: - irc: - channels: - - "irc.freenode.org#erlware" - use_notice: true - skip_join: true @@ -1,4 +1,4 @@ -[![Build Status](https://travis-ci.org/erlware/relx.png?branch=master)](https://travis-ci.org/erlware/relx) +[![Build Status](https://api.cirrus-ci.com/github/erlware/relx.svg)](https://cirrus-ci.com/github/erlware/relx) Relx ======= @@ -81,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/examples/relx.config b/examples/relx.config index b19042b..3622d01 100644 --- a/examples/relx.config +++ b/examples/relx.config @@ -45,7 +45,7 @@ %% When we have multiple releases relx needs to know which one to build. You %% can specify that on the command line with the `-n` and `-v` arguments to %% relx. However, it is often more convenient to do it in the config. -{default_release, sexpr, "0.0.2"}. +{default_release, {sexpr, "0.0.2"}}. {release, {sexpr, "0.0.1"}, [sexpr, diff --git a/priv/templates/bin_windows b/priv/templates/bin_windows index b3ce796..19c0d2d 100644 --- a/priv/templates/bin_windows +++ b/priv/templates/bin_windows @@ -73,6 +73,23 @@ cd %rootdir% @set "possible_sys=%rel_dir%\sys.config" @if exist "%possible_sys%" ( set sys_config=-config "%possible_sys%" +) else ( + @if exist "%possible_sys%.orig" ( + ren "%possible_sys%.orig" sys.config + set sys_config=-config "%possible_sys%" + ) +) + +:: Find the vm.args file +:find_vm_args +@set "possible_vm_args=%rel_dir%\vm.args" +@if exist "%possible_vm_args%" ( + set vm_args="%possible_vm_args%" +) else ( + @if exist "%possible_vm_args%.orig" ( + ren "%possible_vm_args%.orig" vm.args + set vm_args="%possible_vm_args%" + ) ) @goto :eof diff --git a/priv/templates/extended_bin b/priv/templates/extended_bin index 11a0abc..a4cba4a 100755 --- a/priv/templates/extended_bin +++ b/priv/templates/extended_bin @@ -19,7 +19,7 @@ fi # OSX does not support readlink '-f' flag, work # around that -case $OSTYPE in +case $OSTYPE in darwin*) SCRIPT=$(readlink $0 || true) ;; @@ -150,10 +150,19 @@ relx_get_pid() { relx_get_nodename() { id="longname$(relx_gen_id)-${NAME}" - "$BINDIR/erl" -boot start_clean \ - -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 + if [ -z "$COOKIE" ]; then + "$BINDIR/erl" -boot start_clean \ + -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 \ + -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} \ + -noshell ${NAME_TYPE} $id + fi } # Connect to a remote node @@ -167,8 +176,8 @@ 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" -hidden -kernel net_ticktime $TICKTIME $VM_ARGS + -boot_var ERTS_LIB_DIR "$ERTS_LIB_DIR" $MAYBE_DIST_ARGS \ + -setcookie "$COOKIE" -hidden -kernel net_ticktime $TICKTIME } # Generate a random id @@ -180,15 +189,27 @@ relx_gen_id() { relx_nodetool() { command="$1"; shift - escript_emulator_args $ROOTDIR/bin/nodetool + # Generate a unique id used to allow multiple nodetool calls to the + # same node transparently + nodetool_id="maint$(relx_gen_id)-${NAME}" - "$ERTS_DIR/bin/escript" "$ROOTDIR/bin/nodetool" "$NAME_TYPE" "$NAME" \ - -setcookie "$COOKIE" "$command" $@ + if [ -z "${START_EPMD}" ]; then + ERL_FLAGS="${ERL_FLAGS} ${MAYBE_DIST_ARGS} ${NAME_TYPE} $nodetool_id -setcookie ${COOKIE}" \ + "$ERTS_DIR/bin/escript" \ + "$ROOTDIR/bin/nodetool" \ + "$NAME_TYPE" "$NAME" \ + "$command" $@ + else + ERL_FLAGS="${ERL_FLAGS} ${MAYBE_DIST_ARGS} ${NAME_TYPE} $nodetool_id -setcookie ${COOKIE}" \ + "$ERTS_DIR/bin/escript" \ + "$ROOTDIR/bin/nodetool" \ + $START_EPMD "$NAME_TYPE" "$NAME" "$command" $@ + fi } # Run an escript in the node's environment relx_escript() { - shift; scriptpath="$1"; shift + scriptpath="$1"; shift export RELEASE_ROOT_DIR "$ERTS_DIR/bin/escript" "$ROOTDIR/$scriptpath" $@ @@ -231,23 +252,6 @@ replace_os_vars() { }1' < "$1" > "$2" } -escript_emulator_args() { - if [ -n "${VM_ARGS}" ]; then - if grep -q '%%!' $1; then - cmd=$(echo sed -i"'.prev'" "'/%%!.*/ s| ${VM_ARGS}||'" $1) - eval "$cmd" - cmd=$(echo sed -i"'.prev'" "'/%%!.*/ s|$| ${VM_ARGS}|'" $1) - eval "$cmd" - rm ${1}.prev - else - cmd=$(echo sed -i"'.prev'" "'/#!.*/ a \\ -%%! ${VM_ARGS}\n'" $1) - eval "$cmd" - rm ${1}.prev - fi - fi -} - add_path() { # Use $CWD/$1 if exists, otherwise releases/VSN/$1 IN_FILE_PATH=$2 @@ -267,9 +271,9 @@ check_replace_os_vars() { SRC_FILE_PATH="$IN_FILE_PATH.src" ORIG_FILE_PATH="$IN_FILE_PATH.orig" if [ -f "$SRC_FILE_PATH" ]; then + OUT_FILE_PATH=$(make_out_file_path $IN_FILE_PATH) replace_os_vars "$SRC_FILE_PATH" "$OUT_FILE_PATH" elif [ $RELX_REPLACE_OS_VARS ]; then - # Create a new file in the same location as original OUT_FILE_PATH=$(make_out_file_path $IN_FILE_PATH) # If vm.args.orig or sys.config.orig is present then use that if [ -f "$ORIG_FILE_PATH" ]; then @@ -289,7 +293,8 @@ check_replace_os_vars() { else # If vm.arg.orig or sys.config.orig is present then use that if [ -f "$ORIG_FILE_PATH" ]; then - cp "$ORIG_FILE_PATH" "$OUT_FILE_PATH" + OUT_FILE_PATH=$(make_out_file_path $IN_FILE_PATH) + cp "$ORIG_FILE_PATH" "$OUT_FILE_PATH" fi fi echo $OUT_FILE_PATH @@ -312,14 +317,24 @@ relx_run_hooks() { done } +relx_disable_hooks() { + PRE_START_HOOKS="" + POST_START_HOOKS="" + PRE_STOP_HOOKS="" + POST_STOP_HOOKS="" + PRE_INSTALL_UPGRADE_HOOKS="" + POST_INSTALL_UPGRADE_HOOKS="" + STATUS_HOOK="" +} + relx_is_extension() { EXTENSION=$1 case "$EXTENSION" in {{{ extensions }}}) - echo "1" + echo "1" ;; *) - echo "0" + echo "0" ;; esac } @@ -330,7 +345,7 @@ relx_get_extension_script() { # of the form: # foo_extension="path/to/foo_script";bar_extension="path/to/bar_script" {{{extension_declarations}}} - # get the command extension (eg. foo) and + # get the command extension (eg. foo) and # obtain the actual script filename that it # refers to (eg. "path/to/foo_script" eval echo "$"${EXTENSION}_extension"" @@ -343,9 +358,29 @@ relx_run_extension() { shift # all extension script locations are expected to be # relative to the start script location - [ "$SCRIPT_DIR/$EXTENSION_SCRIPT" ] && . "$SCRIPT_DIR/$EXTENSION_SCRIPT" $@ + [ "$SCRIPT_DIR/$EXTENSION_SCRIPT" ] && . "$SCRIPT_DIR/$EXTENSION_SCRIPT" "$@" +} + +# given a list of arguments, identify the internal ones +# --relx-disable-hooks +# and process them accordingly +process_internal_args() { + for arg in $@ + do + shift + case "$arg" in + --relx-disable-hooks) + relx_disable_hooks + ;; + *) + ;; + esac + done } +# process internal arguments +process_internal_args $@ + find_erts_dir export ROOTDIR="$RELEASE_ROOT_DIR" export BINDIR="$ERTS_DIR/bin" @@ -433,39 +468,49 @@ NAME_ARG=$(eval echo "${NAME_ARG}") NAME_TYPE="$(echo "$NAME_ARG" | awk '{print $1}')" NAME="$(echo "$NAME_ARG" | awk '{print $2}')" -# User can specify an sname without @hostname -# This will fail when creating remote shell -# So here we check for @ and add @hostname if missing -case "${NAME}" in - *@*) ;; # Nothing to do - *) NAME=${NAME}@$(relx_get_nodename);; # Add @hostname -esac - -# Export the variable so that it's available in the 'eval' calls -export NAME - -# Make sure log directory exists -mkdir -p "$RUNNER_LOG_DIR" - -test -z "$PIPE_DIR" && PIPE_BASE_DIR='/tmp/erl_pipes/' -PIPE_DIR="${PIPE_DIR:-/tmp/erl_pipes/$NAME/}" +# Extract dist arguments +MAYBE_DIST_ARGS="" +PROTO_DIST="$(grep '^-proto_dist' "$VMARGS_PATH" || true)" +if [ "$PROTO_DIST" ]; then + MAYBE_DIST_ARGS="${PROTO_DIST}" +fi +START_EPMD="$(grep '^-start_epmd' "$VMARGS_PATH" || true)" +if [ "$START_EPMD" ]; then + MAYBE_DIST_ARGS="${MAYBE_DIST_ARGS} ${START_EPMD}" +fi +EPMD_MODULE="$(grep '^-epmd_module' "$VMARGS_PATH" || true)" +if [ "$EPMD_MODULE" ]; then + MAYBE_DIST_ARGS="${MAYBE_DIST_ARGS} ${EPMD_MODULE}" +fi # Extract the target cookie +# Do this before relx_get_nodename so we can use it and not create a ~/.erlang.cookie COOKIE_ARG="$(grep '^-setcookie' "$VMARGS_PATH" || true)" DEFAULT_COOKIE_FILE="$HOME/.erlang.cookie" if [ -z "$COOKIE_ARG" ]; then if [ -f "$DEFAULT_COOKIE_FILE" ]; then COOKIE="$(cat $DEFAULT_COOKIE_FILE)" else - echo "vm.args needs to have a -setcookie, or $DEFAULT_COOKIE_FILE (its permission must be 400) is required." - exit 1 + echo "No cookie is set or found. This limits the scripts functionality, installing, upgrading, rpc and getting a list of versions will not work." fi else # Extract cookie name from COOKIE_ARG COOKIE="$(echo "$COOKIE_ARG" | awk '{print $2}')" fi -VM_ARGS="$(grep -v -E '^#|^-name|^-sname|^-setcookie|^-heart|^-args_file' "$VMARGS_PATH" | xargs | sed -e 's/ / /g')" +# User can specify an sname without @hostname +# This will fail when creating remote shell +# So here we check for @ and add @hostname if missing +case "${NAME}" in + *@*) ;; # Nothing to do + *) NAME=${NAME}@$(relx_get_nodename);; # Add @hostname +esac + +# Export the variable so that it's available in the 'eval' calls +export NAME + +test -z "$PIPE_DIR" && PIPE_BASE_DIR='/tmp/erl_pipes/' +PIPE_DIR="${PIPE_DIR:-/tmp/erl_pipes/$NAME/}" cd "$ROOTDIR" @@ -492,10 +537,18 @@ case "$1" in test -z "$PIPE_BASE_DIR" || mkdir -m 1777 -p "$PIPE_BASE_DIR" mkdir -p "$PIPE_DIR" + if [ ! -w "$PIPE_DIR" ] + then + echo "failed to start, user '$USER' does not have write privileges on '$PIPE_DIR', either delete it or run node as a different user" + exit 1 + fi + + # Make sure log directory exists + mkdir -p "$RUNNER_LOG_DIR" relx_run_hooks "$PRE_START_HOOKS" "$BINDIR/run_erl" -daemon "$PIPE_DIR" "$RUNNER_LOG_DIR" \ - "exec \"$RELEASE_ROOT_DIR/bin/$REL_NAME\" \"$START_OPTION\" $ARGS" + "exec \"$RELEASE_ROOT_DIR/bin/$REL_NAME\" \"$START_OPTION\" $ARGS --relx-disable-hooks" relx_run_hooks "$POST_START_HOOKS" ;; @@ -543,6 +596,7 @@ case "$1" in escript) ## Run an escript under the node's environment + shift if ! relx_escript $@; then exit 1 fi @@ -555,6 +609,12 @@ case "$1" in exit 1 fi + if [ ! -w "$PIPE_DIR" ] + then + echo "failed to attach, user '$USER' does not have sufficient privileges on '$PIPE_DIR', please run node as a different user" + exit 1 + fi + shift exec "$BINDIR/to_erl" "$PIPE_DIR" ;; @@ -587,8 +647,6 @@ case "$1" in relx_run_hooks "$PRE_INSTALL_UPGRADE_HOOKS" - escript_emulator_args $ROOTDIR/bin/install_upgrade.escript - exec "$BINDIR/escript" "$ROOTDIR/bin/install_upgrade.escript" \ "$COMMAND" "{'$REL_NAME', \"$NAME_TYPE\", '$NAME', '$COOKIE'}" "$@" @@ -603,8 +661,6 @@ case "$1" in fi COMMAND="$1"; shift - - escript_emulator_args $ROOTDIR/bin/install_upgrade.escript exec "$BINDIR/escript" "$ROOTDIR/bin/install_upgrade.escript" \ "versions" "{'$REL_NAME', \"$NAME_TYPE\", '$NAME', '$COOKIE'}" "$@" @@ -664,6 +720,7 @@ case "$1" in echo "$RELEASE_ROOT_DIR" logger -t "$REL_NAME[$$]" "Starting up" + relx_run_hooks "$PRE_START_HOOKS" # Start the VM exec "$BINDIR/erlexec" $FOREGROUNDOPTIONS \ -boot "$BOOTFILE" -mode "$CODE_LOADING_MODE" \ @@ -671,6 +728,9 @@ case "$1" in -config "$RELX_CONFIG_PATH" \ -args_file "$VMARGS_PATH" \ -pa ${__code_paths} -- "$@" + # exec will replace the current image and nothing else gets + # executed from this point on, this explains the absence + # of the pre start hook ;; rpc) # Make sure a node IS running @@ -728,7 +788,7 @@ case "$1" in if [ "$IS_EXTENSION" = "1" ]; then EXTENSION_SCRIPT=$(relx_get_extension_script $1) shift - relx_run_extension $EXTENSION_SCRIPT $@ + relx_run_extension $EXTENSION_SCRIPT "$@" # all extension scripts are expected to exit else relx_usage $1 diff --git a/priv/templates/extended_bin_windows b/priv/templates/extended_bin_windows index d30d78d..16e3d96 100644 --- a/priv/templates/extended_bin_windows +++ b/priv/templates/extended_bin_windows @@ -37,14 +37,18 @@ @set vm_args=%rel_dir%\vm.args @set progname=erl.exe @set clean_boot_script=%release_root_dir%\bin\start_clean -@set erlsrv="%bindir%\erlsrv.exe" -@set epmd="%bindir%\epmd.exe" -@set escript="%bindir%\escript.exe" -@set werl="%bindir%\werl.exe" -@set nodetool="%release_root_dir%\bin\nodetool" +@set "erlsrv=%bindir%\erlsrv.exe" +@set "epmd=%bindir%\epmd.exe" +@set "escript=%bindir%\escript.exe" +@set "werl=%bindir%\werl.exe" +@set "erl=%bindir%\erl.exe" +@set "nodetool=%release_root_dir%\bin\nodetool" +@set "extensions0={{ extensions }}" +@set "extensions1=%extensions0:|= %" +@set "extensions=%extensions1: undefined=%" :: Extract node type and name from vm.args -@for /f "usebackq tokens=1-2" %%I in (`findstr /b "\-name \-sname" "%vm_args%"`) do @( +@for /f "usebackq tokens=1-2" %%I in ('findstr /b "\-name \-sname" "%vm_args%"') do @( set node_type=%%I set node_name=%%J ) @@ -73,9 +77,18 @@ set "hostname=@%hostname%" ) -:: Extract cookie from vm.args -@for /f "usebackq tokens=1-2" %%I in (`findstr /b \-setcookie "%vm_args%"`) do @( - set cookie=%%J +:: Extract the target cookie +:: Do this before relx_get_nodename so we can use it and not create a ~/.erlang.cookie +@for /f "usebackq tokens=1-2" %%I in ('findstr /b \-setcookie "%vm_args%"') do @( + set "cookie=%%J" +) +@set "default_cookie_file=%USERPROFILE%\.erlang.cookie" +@if "%cookie%" == "" @( + if exist "%default_cookie_file%" ( + set /p cookie=<%default_cookie_file% + ) else ( + echo No cookie is set or found. This limits the scripts functionality, installing, upgrading, rpc and getting a list of versions will not work. + ) ) :: Write the erl.ini file to set up paths relative to this script @@ -83,7 +96,7 @@ :: Collect any additional VM args into erl_opts @setlocal EnableDelayedExpansion -@for /f "usebackq tokens=1-2" %%I in (`findstr /r "^[^#]" "%vm_args%"`) do @( +@for /f "usebackq tokens=1-2" %%I in ('findstr /r "^[^#]" "%vm_args%"') do @( if not "%%I" == "-name" ( if not "%%I" == "-sname" ( if not "%%I" == "-setcookie" ( @@ -99,6 +112,7 @@ copy "%rel_dir%\%rel_name%.boot" "%rel_dir%\start.boot" >nul ) +@if "%1"=="help" @goto usage @if "%1"=="install" @goto install @if "%1"=="uninstall" @goto uninstall @if "%1"=="start" @goto start @@ -112,6 +126,10 @@ @if "%1"=="attach" @goto attach @if "%1"=="remote_console" @goto attach @if "%1"=="" @goto usage + +@call :is_extension "%1" +@if "%ERRORLEVEL%"=="0" @goto run_extension + @echo Unknown command: "%1" @goto :eof @@ -135,11 +153,10 @@ :: Set the ERTS dir from erl :set_erts_dir_from_erl @for /f "delims=" %%i in ('where erl') do @( - set erl=%%i + set "erl=%%i" ) -@set dir_cmd="%erl%" -boot no_dot_erlang -noshell -eval "io:format(\"~s\", [filename:nativename(code:root_dir())])." -s init stop -@for /f "delims=" %%i in ('%%dir_cmd%%') do @( - set erl_root=%%i +@for /f "delims=" %%i in ('"%erl%" -boot no_dot_erlang -noshell -eval "io:format(\"~s\", [filename:nativename(code:root_dir())])." -s init stop') do @( + set "erl_root=%%i" ) @set "erts_dir=%erl_root%\erts-%erts_vsn%" @set "rootdir=%erl_root%" @@ -148,8 +165,22 @@ :: Find the sys.config file :find_sys_config @set "possible_sys=%rel_dir%\sys.config" -@if exist %possible_sys% ( +@if exist "%possible_sys%" ( set sys_config=-config "%possible_sys%" +) else ( + @if exist "%possible_sys%.orig" ( + ren "%possible_sys%.orig" sys.config + set sys_config=-config "%possible_sys%" + ) +) +@goto :eof + +:: Find the vm.args file +:find_vm_args +@if not exist "%vm_args%" ( + @if exist "%vm_args%.orig" ( + ren "%vm_args%.orig" vm.args + ) ) @goto :eof @@ -175,7 +206,63 @@ :: Display usage information :usage -@echo usage: %~n0 ^(install^|uninstall^|start^|stop^|restart^|upgrade^|downgrade^|console^|ping^|list^|attach^|remote_console^) +@if "%2"=="install" ( + @echo "Usage: %rel_name% install [VERSION]" + @echo "Installs a release package VERSION, it assumes that this" + @echo "release package tarball has already been deployed at one" + @echo "of the following locations:" + @echo " releases/<relname>-<version>.tar.gz" + @echo " releases/<version>/<relname>-<version>.tar.gz" + @echo " releases/<version>/<relname>.tar.gz" + @echo "" + @echo " --no-permanent Install release package VERSION but" + @echo " don't make it permanent" + @goto :eof +) +@if "%2"=="uninstall" ( + @echo "Usage: %rel_name% uninstall [VERSION]" + @echo "Uninstalls a release VERSION, it will only accept" + @echo "versions that are not currently in use" + @goto :eof +) +@if "%2"=="upgrade" ( + @echo "Usage: %rel_name% upgrade [VERSION]" + @echo "Upgrades the currently running release to VERSION, it assumes" + @echo "that a release package tarball has already been deployed at one" + @echo "of the following locations:" + @echo " releases/<relname>-<version>.tar.gz" + @echo " releases/<version>/<relname>-<version>.tar.gz" + @echo " releases/<version>/<relname>.tar.gz" + @echo "" + @echo " --no-permanent Install release package VERSION but" + @echo " don't make it permanent" + @goto :eof +) +@if "%2"=="downgrade" ( + @echo "Usage: %rel_name% downgrade [VERSION]" + @echo "Downgrades the currently running release to VERSION, it assumes" + @echo "that a release package tarball has already been deployed at one" + @echo "of the following locations:" + @echo " releases/<relname>-<version>.tar.gz" + @echo " releases/<version>/<relname>-<version>.tar.gz" + @echo " releases/<version>/<relname>.tar.gz" + @echo "" + @echo " --no-permanent Install release package VERSION but" + @echo " don't make it permanent" + @goto :eof +) +@call :is_extension "%2" +@if "%ERRORLEVEL%"=="0" ( + @if exist "%script_dir%\extensions\%2.cmd" ( + call "%script_dir%\extensions\%2.cmd" help + @goto :eof + ) +) +set commands=install uninstall start stop restart upgrade downgrade console ping list attach remote_console +if not "%extensions%"=="" ( + set "commands=%commands% %extensions%" +) +@echo Usage: %~n0 ^(%commands: =^|%^) @goto :eof :: Install the release as a Windows service @@ -183,10 +270,10 @@ :install set args=%erl_opts% -setcookie %cookie% ++ -rootdir \"%rootdir%\" set start_erl=%erts_dir%\bin\start_erl.exe -set description=Erlang node %node_name% in %rootdir% +set description=Erlang node %node_name%%hostname% in %rootdir% @if "" == "%2" ( :: Install the service - %erlsrv% add %service_name% %node_type% "%node_name%" -c "%description%" -w "%rootdir%" -m "%start_erl%" -args "%args%" -stopaction "init:stop()." + %erlsrv% add %service_name% %node_type% "%node_name%%hostname%" -c "%description%" -w "%rootdir%" -m "%start_erl%" -args "%args%" -stopaction "init:stop()." ) else ( :: relup and reldown goto relup @@ -243,3 +330,35 @@ set description=Erlang node %node_name% in %rootdir% @start "%node_name% attach" %werl% %boot% ^ -remsh %node_name%%hostname% %node_type% console -setcookie %cookie% @goto :eof + +:: Run extension script +:run_extension +@if exist "%script_dir%\extensions\%1.cmd" ( + set _extension_params=%* + call set _extension_params=%%_extension_params:*%1=%% + call "%script_dir%\extensions\%1.cmd" %%_extension_params%% +) + +@goto :eof + +:: Local Functions + +:is_extension + +@set "ext=%~1" + +:: Check for entries in the list, not at the ends +@call set "ext_test_1=x%%extensions: %ext% =%%" + +:: Check for entry at the start of the list +@call set "ext_test_2=x%%extensions:%ext% =%%" + +:: Check for entry at the end of the list +@call set "ext_test_3=x%%extensions: %ext%=%%" + +@if not "%ext_test_1%"=="x%extensions%" exit /b 0 +@if not "%ext_test_2%"=="x%extensions%" exit /b 0 +@if not "%ext_test_3%"=="x%extensions%" exit /b 0 + +@exit /b 1 + diff --git a/priv/templates/nodetool b/priv/templates/nodetool index 816be9c..9e24f32 100644 --- a/priv/templates/nodetool +++ b/priv/templates/nodetool @@ -8,9 +8,10 @@ %% ------------------------------------------------------------------- main(Args) -> - ok = start_epmd(), %% Extract the args - {RestArgs, TargetNode} = process_args(Args, [], undefined), + {RestArgs, TargetNode, StartEpmd} = process_args(Args, [], undefined, true), + + ok = start_epmd(StartEpmd), %% See if the node is currently running -- if it's not, we'll bail case {net_kernel:hidden_connect_node(TargetNode), net_adm:ping(TargetNode)} of @@ -87,25 +88,35 @@ main(Args) -> end, net_kernel:stop(). -process_args([], Acc, TargetNode) -> - {lists:reverse(Acc), TargetNode}; -process_args(["-setcookie", Cookie | Rest], Acc, TargetNode) -> +process_args([], Acc, TargetNode, StartEpmd) -> + {lists:reverse(Acc), TargetNode, StartEpmd}; +process_args(["-setcookie", Cookie | Rest], Acc, TargetNode, StartEpmd) -> erlang:set_cookie(node(), list_to_atom(Cookie)), - process_args(Rest, Acc, TargetNode); -process_args(["-name", TargetName | Rest], Acc, _) -> - ThisNode = append_node_suffix(TargetName, "_maint_"), - {ok, _} = net_kernel:start([ThisNode, longnames]), - process_args(Rest, Acc, nodename(TargetName)); -process_args(["-sname", TargetName | Rest], Acc, _) -> - ThisNode = append_node_suffix(TargetName, "_maint_"), - {ok, _} = net_kernel:start([ThisNode, shortnames]), - process_args(Rest, Acc, nodename(TargetName)); -process_args([Arg | Rest], Acc, Opts) -> - process_args(Rest, [Arg | Acc], Opts). - - -start_epmd() -> + process_args(Rest, Acc, TargetNode, StartEpmd); +process_args(["-start_epmd", StartEpmd | Rest], Acc, TargetNode, _StartEpmd) -> + process_args(Rest, Acc, TargetNode, list_to_atom(StartEpmd)); +process_args(["-name", TargetName | Rest], Acc, _, StartEpmd) -> + maybe_start_node(TargetName, longnames), + process_args(Rest, Acc, nodename(TargetName), StartEpmd); +process_args(["-sname", TargetName | Rest], Acc, _, StartEpmd) -> + maybe_start_node(TargetName, shortnames), + process_args(Rest, Acc, nodename(TargetName), StartEpmd); +process_args([Arg | Rest], Acc, Opts, StartEpmd) -> + process_args(Rest, [Arg | Acc], Opts, StartEpmd). + +maybe_start_node(TargetName, Names) -> + case erlang:node() of + 'nonode@nohost' -> + ThisNode = append_node_suffix(TargetName, "_maint_"), + {ok, _} = net_kernel:start([ThisNode, Names]); + _ -> + ok + end. + +start_epmd(true) -> [] = os:cmd("\"" ++ epmd_path() ++ "\" -daemon"), + ok; +start_epmd(_) -> ok. epmd_path() -> 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.app.src b/src/relx.app.src index c8915d5..c845982 100644 --- a/src/relx.app.src +++ b/src/relx.app.src @@ -1,11 +1,9 @@ {application,relx, - [{description,"Release assembler for Erlang/OTP Releases"}, - {vsn,"git"}, - {modules,[]}, - {registered,[]}, - {applications,[kernel,stdlib,getopt,erlware_commons,bbmustache, - providers]}, - {maintainers,["Eric Merritt","Tristan Sloughter", - "Jordan Wilberding"]}, - {licenses,["Apache"]}, - {links,[{"Github","https://github.com/erlware/relx"}]}]}. + [{description,"Release assembler for Erlang/OTP Releases"}, + {vsn,"git"}, + {modules,[]}, + {registered,[]}, + {applications,[kernel,stdlib,getopt,erlware_commons,bbmustache, + providers]}, + {licenses,["Apache"]}, + {links,[{"Github","https://github.com/erlware/relx"}]}]}. 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 c67bf16..90cfe7c 100644 --- a/src/rlx_config.erl +++ b/src/rlx_config.erl @@ -333,8 +333,9 @@ list_of_overlay_vars_files(undefined) -> []; list_of_overlay_vars_files([]) -> []; -list_of_overlay_vars_files([H | _]=FileNames) when erlang:is_list(H) -> - FileNames; +list_of_overlay_vars_files([H | _]=Vars) when erlang:is_list(H) ; + is_tuple(H) -> + Vars; list_of_overlay_vars_files(FileName) when is_list(FileName) -> [FileName]. @@ -358,7 +359,8 @@ merge_configs([{Key, Value} | CliTerms], ConfigTerms) -> end; overlay_vars -> case lists:keyfind(overlay_vars, 1, ConfigTerms) of - {_, [H | _] = Vars} when is_list(H) -> + {_, [H | _] = Vars} when is_list(H) ; + is_tuple(H) -> MergedValue = Vars ++ Value, merge_configs(CliTerms, lists:keyreplace(overlay_vars, 1, ConfigTerms, {Key, MergedValue})); {_, Vars} when is_list(Vars) -> @@ -367,10 +369,23 @@ merge_configs([{Key, Value} | CliTerms], ConfigTerms) -> false -> merge_configs(CliTerms, ConfigTerms++[{Key, Value}]) end; + default_release when Value =:= {undefined, undefined} -> + %% No release specified in cli. Prevent overwriting default_release in ConfigTerms. + merge_configs(CliTerms, lists:keymerge(1, ConfigTerms, [{Key, Value}])); _ -> 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; @@ -382,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 88f2da4..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. %% 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_archive.erl b/src/rlx_prv_archive.erl index e1735d1..8fd03c1 100644 --- a/src/rlx_prv_archive.erl +++ b/src/rlx_prv_archive.erl @@ -141,9 +141,10 @@ update_tar(State, TempDir, OutputDir, Name, Vsn, ErtsVersion) -> config_files(Vsn, OutputDir) -> VMArgs = {filename:join(["releases", Vsn, "vm.args"]), filename:join([OutputDir, "releases", Vsn, "vm.args"])}, + VMArgsSrc = {filename:join(["releases", Vsn, "vm.args.src"]), filename:join([OutputDir, "releases", Vsn, "vm.args.src"])}, VMArgsOrig = {filename:join(["releases", Vsn, "vm.args.orig"]), filename:join([OutputDir, "releases", Vsn, "vm.args.orig"])}, SysConfigOrig = {filename:join(["releases", Vsn, "sys.config.orig"]), filename:join([OutputDir, "releases", Vsn, "sys.config.orig"])}, - [{NameInArchive, Filename} || {NameInArchive, Filename} <- [VMArgs, VMArgsOrig, SysConfigOrig], filelib:is_file(Filename)]. + [{NameInArchive, Filename} || {NameInArchive, Filename} <- [VMArgsSrc, VMArgs, VMArgsOrig, SysConfigOrig], filelib:is_file(Filename)]. overlay_files(_, undefined, _) -> diff --git a/src/rlx_prv_assembler.erl b/src/rlx_prv_assembler.erl index cb5bbed..4f9a41e 100644 --- a/src/rlx_prv_assembler.erl +++ b/src/rlx_prv_assembler.erl @@ -433,13 +433,13 @@ write_bin_file(State, Release, OutputDir, RelDir) -> win32 -> rlx_string:concat(VsnRel, ".cmd") end, ok = file:write_file(VsnRelStartFile, StartFile), - ok = file:change_mode(VsnRelStartFile, 8#777), + ok = file:change_mode(VsnRelStartFile, 8#755), BareRelStartFile = case OsFamily of unix -> BareRel; win32 -> rlx_string:concat(BareRel, ".cmd") end, ok = file:write_file(BareRelStartFile, StartFile), - ok = file:change_mode(BareRelStartFile, 8#777) + ok = file:change_mode(BareRelStartFile, 8#755) end, ReleasesDir = filename:join(OutputDir, "releases"), generate_start_erl_data_file(Release, ReleasesDir), diff --git a/src/rlx_prv_overlay.erl b/src/rlx_prv_overlay.erl index 645f691..516d238 100644 --- a/src/rlx_prv_overlay.erl +++ b/src/rlx_prv_overlay.erl @@ -145,7 +145,8 @@ get_overlay_vars_from_file(State, OverlayVars) -> OverlayVars; [] -> OverlayVars; - [H | _]=FileNames when is_list(H) -> + [H | _]=FileNames when is_list(H) ; + is_tuple(H) -> read_overlay_vars(State, OverlayVars, FileNames); FileName when is_list(FileName) -> read_overlay_vars(State, OverlayVars, [FileName]) @@ -181,30 +182,24 @@ check_overlay_inclusion(_State, _RelativeRoot, [], Terms) -> proplists:proplist(). merge_overlay_vars(State, FileNames) -> RelativeRoot = get_relative_root(State), - lists:foldl(fun(FileName, Acc) -> - RelativePath = filename:join(RelativeRoot, erlang:iolist_to_binary(FileName)), + lists:foldl(fun(FileName, Acc) when is_list(FileName) -> + RelativePath = filename:join(RelativeRoot, 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); {ok, Terms} -> %% 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:foldl(fun(NewTerm, A) -> - lists:keystore(element(1, NewTerm), 1, A, NewTerm) + lists:keystore(element(1, NewTerm), 1, A, NewTerm) end, Acc, NewTerms); {error, Reason} -> ec_cmd_log:warn(rlx_state:log(State), format_error({unable_to_read_varsfile, FileName, Reason})), Acc - end + end; + (Var, Acc) -> + lists:keystore(element(1, Var), 1, Acc, Var) end, [], FileNames). -spec render_overlay_vars(proplists:proplist(), proplists:proplist(), 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/src/rlx_util.erl b/src/rlx_util.erl index b3fc2b7..5d3744d 100644 --- a/src/rlx_util.erl +++ b/src/rlx_util.erl @@ -45,6 +45,8 @@ -define(DFLT_INTENSITY, high). -define(ONE_LEVEL_INDENT, " "). + +-include_lib("kernel/include/file.hrl"). %%============================================================================ %% types %%============================================================================ @@ -233,81 +235,65 @@ symlink_or_copy(Source, Target) -> ok; {error, eexist} -> {error, eexist}; - {error, _} -> - case os:type() of - {win32, _} -> - S = unicode:characters_to_list(Source), - T = unicode:characters_to_list(Target), - win32_symlink(filename:nativename(S), filename:nativename(T)); + {error, Err} -> + case {os:type(), Err} of + {{win32, _}, eperm} -> + % We get eperm on Windows if we do not have + % SeCreateSymbolicLinkPrivilege + % Try the next alternative + win32_make_junction_or_copy(Source, Target); _ -> - case filelib:is_dir(Target) of - true -> ok; - false -> - cp_r([Source], Target) - end + % On other systems we try to copy next + cp_r(Source, Target) end end. +cp_r(Source, Target) -> + ec_file:copy(Source, Target, [{recursive, true}, {fileinfo, [mode, time, owner, group]}]). -win32_symlink(Source, Target) -> - os:cmd("cmd /c mklink /j " ++ Target ++ " " ++ Source), - ok. - --spec cp_r(list(string()), file:filename()) -> 'ok'. -cp_r(Sources, Dest) -> - case os:type() of - {unix, _} -> - ok; - {win32, _} -> - lists:foreach(fun(Src) -> ok = cp_r_win32(Src,Dest) end, Sources), - ok +win32_make_junction_or_copy(Source, Target) -> + case filelib:is_dir(Source) of + true -> + win32_make_junction(Source, Target); + _ -> + cp_r(Source, Target) end. -xcopy_win32(Source,Dest)-> - %% "xcopy \"~s\" \"~s\" /q /y /e 2> nul", Chanegd to robocopy to - %% handle long names. May have issues with older windows. - os:cmd("robocopy " ++ Source ++ " " ++ Dest ++ " /e /is"), - ok. - -cp_r_win32({true, SourceDir}, {true, DestDir}) -> - %% from directory to directory - ok = case file:make_dir(DestDir) of - {error, eexist} -> ok; - Other -> Other - end, - ok = xcopy_win32(SourceDir, DestDir); -cp_r_win32({false, Source} = S,{true, DestDir}) -> - %% from file to directory - cp_r_win32(S, {false, filename:join(DestDir, filename:basename(Source))}); -cp_r_win32({false, Source},{false, Dest}) -> - %% from file to file - {ok,_} = file:copy(Source, Dest), - ok; -cp_r_win32({true, SourceDir}, {false, DestDir}) -> - case filelib:is_regular(DestDir) of - true -> - %% From directory to file? This shouldn't happen - {error, lists:flatten( - io_lib:format("Cannot copy dir (~p) to file (~p)\n", - [SourceDir, DestDir]))}; - false -> - %% Specifying a target directory that doesn't currently exist. - %% So let's attempt to create this directory - case filelib:ensure_dir(filename:join(DestDir, "dummy")) of - ok -> - ok = xcopy_win32(SourceDir, DestDir); +win32_make_junction(Source, Target) -> + % The mklink will fail if the target already exists, check for that first + case file:read_link_info(Target) of + {error, enoent} -> + win32_make_junction_cmd(Source, Target); + {ok, #file_info{type = symlink}} -> + case file:read_link(Target) of + {ok, Source} -> + ok; + {ok, _} -> + ok = file:del_dir(Target), + win32_make_junction_cmd(Source, Target); {error, Reason} -> - {error, lists:flatten( - io_lib:format("Unable to create dir ~p: ~p\n", - [DestDir, Reason]))} - end - end; -cp_r_win32(Source,Dest) -> - Dst = {filelib:is_dir(Dest), Dest}, - lists:foreach(fun(Src) -> - ok = cp_r_win32({filelib:is_dir(Src), Src}, Dst) - end, filelib:wildcard(Source)), - ok. + {error, {readlink, Reason}} + end; + {ok, #file_info{type = _Type}} -> + % Directory already exists, so we overwrite the copy + cp_r(Source, Target); + Error -> + Error + end. + +win32_make_junction_cmd(Source, Target) -> + S = unicode:characters_to_list(Source), + T = unicode:characters_to_list(Target), + Cmd = "cmd /c mklink /j " ++ filename:nativename(T) ++ " " ++ filename:nativename(S), + case os:cmd(Cmd) of + "Junction created " ++ _ -> + ok; + [] -> + % When mklink fails it prints the error message to stderr which + % is not picked up by os:cmd() hence this case switch is for + % an empty message + cp_r(Source, Target) + end. %% @doc Returns the color intensity, we first check the application envorinment %% if that is not set we check the environment variable RELX_COLOR. diff --git a/test/rlx_archive_SUITE.erl b/test/rlx_archive_SUITE.erl index 5122c11..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. @@ -55,11 +55,19 @@ basic_tar(Config) -> 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], []), + SysConfigSrc = filename:join([LibDir1, "config", "sys.config.src"]), + rlx_test_utils:write_config(SysConfigSrc, [{this_is_a_test, "yup it is"}]), + + VmArgsSrc = filename:join([LibDir1, "config", "vm.args.src"]), + ec_file:write(VmArgsSrc, ""), + ConfigFile = filename:join([LibDir1, "relx.config"]), rlx_test_utils:write_config(ConfigFile, [{release, {foo, "0.0.1"}, [goal_app_1, - goal_app_2]}]), + goal_app_2]}, + {sys_config_src, SysConfigSrc}, + {vm_args_src, VmArgsSrc}]), OutputDir = filename:join([proplists:get_value(priv_dir, Config), rlx_test_utils:create_random_name("relx-output")]), {ok, State} = relx:do([{relname, foo}, @@ -84,6 +92,16 @@ basic_tar(Config) -> {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)), + + %% only works in otp-21 and above + case erlang:system_info(otp_release) of + R when R =:= "21" orelse R =:= "22" -> + ?assert(lists:member("releases/0.0.1/vm.args.src", Files)), + ?assert(lists:member("releases/0.0.1/sys.config.src", Files)); + _ -> + ok + end, + ?assert(filelib:is_regular(TarFile)). exclude_erts(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 86a9d23..8444cb4 100644 --- a/test/rlx_extended_bin_SUITE.erl +++ b/test/rlx_extended_bin_SUITE.erl @@ -49,6 +49,7 @@ replace_os_vars_dev_mode/1, replace_os_vars_twice/1, custom_start_script_hooks/1, + custom_start_script_hooks_console/1, builtin_wait_for_vm_start_script_hook/1, builtin_pid_start_script_hook/1, builtin_wait_for_process_start_script_hook/1, @@ -62,8 +63,10 @@ -include_lib("eunit/include/eunit.hrl"). -include_lib("kernel/include/file.hrl"). +-define(SLEEP_TIME, 2500). + suite() -> - [{timetrap,{seconds,30}}]. + [{timetrap,{seconds,300}}]. init_per_suite(Config) -> Config. @@ -83,12 +86,13 @@ 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, replace_os_vars_included_config, - replace_os_vars_custom_location, replace_os_vars_dev_mode, replace_os_vars_twice, custom_start_script_hooks, + replace_os_vars_custom_location, replace_os_vars_dev_mode, replace_os_vars_twice, + custom_start_script_hooks, custom_start_script_hooks_console, builtin_wait_for_vm_start_script_hook, builtin_pid_start_script_hook, builtin_wait_for_process_start_script_hook, mixed_custom_and_builtin_start_script_hooks, builtin_status_script, custom_status_script, @@ -122,7 +126,7 @@ ping(Config) -> %% now start/stop the release to make sure the extended script is working {ok, _} = sh(filename:join([OutputDir, "foo", "bin", "foo start"])), - timer:sleep(2000), + timer:sleep(?SLEEP_TIME), {ok, "pong"} = sh(filename:join([OutputDir, "foo", "bin", "foo ping"])), {ok, _} = sh(filename:join([OutputDir, "foo", "bin", "foo stop"])), %% a ping should fail after stopping a node @@ -145,7 +149,7 @@ shortname_ping(Config) -> {extended_start_script, true} ]), - ec_file:write(VmArgs, "-sname foo\n\n" + ec_file:write(VmArgs, "-sname foo@localhost\n\n" "-setcookie cookie\n"), OutputDir = filename:join([proplists:get_value(priv_dir, Config), @@ -161,7 +165,7 @@ shortname_ping(Config) -> %% now start/stop the release to make sure the extended script is working {ok, _} = sh(filename:join([OutputDir, "foo", "bin", "foo start"])), - timer:sleep(2000), + timer:sleep(?SLEEP_TIME), {ok, "pong"} = sh(filename:join([OutputDir, "foo", "bin", "foo ping"])), {ok, _} = sh(filename:join([OutputDir, "foo", "bin", "foo stop"])), %% a ping should fail after stopping a node @@ -184,7 +188,7 @@ longname_ping(Config) -> {extended_start_script, true} ]), - ec_file:write(VmArgs, "-name foo\n\n" + ec_file:write(VmArgs, "-name [email protected]\n\n" "-setcookie cookie\n"), OutputDir = filename:join([proplists:get_value(priv_dir, Config), @@ -200,7 +204,7 @@ longname_ping(Config) -> %% now start/stop the release to make sure the extended script is working {ok, _} = sh(filename:join([OutputDir, "foo", "bin", "foo start"])), - timer:sleep(2000), + timer:sleep(?SLEEP_TIME), {ok, "pong"} = sh(filename:join([OutputDir, "foo", "bin", "foo ping"])), {ok, _} = sh(filename:join([OutputDir, "foo", "bin", "foo stop"])), %% a ping should fail after stopping a node @@ -233,10 +237,10 @@ attach(Config) -> %% now start/stop the release to make sure the extended script is working {ok, _} = sh(filename:join([OutputDir, "foo", "bin", "foo start"])), - timer:sleep(2000), + timer:sleep(?SLEEP_TIME), {ok, "pong"} = sh(filename:join([OutputDir, "foo", "bin", "foo ping"])), {ok, _} = sh(filename:join([OutputDir, "foo", "bin", "foo attach", "&"])), - timer:sleep(2000), + timer:sleep(?SLEEP_TIME), {ok, _} = sh(filename:join([OutputDir, "foo", "bin", "foo stop"])), {error, 1, _} = sh(filename:join([OutputDir, "foo", "bin", "foo ping"])). @@ -267,7 +271,7 @@ pid(Config) -> %% check for a valid pid {ok, _} = sh(filename:join([OutputDir, "foo", "bin", "foo start"])), - timer:sleep(2000), + timer:sleep(?SLEEP_TIME), {ok, "pong"} = sh(filename:join([OutputDir, "foo", "bin", "foo ping"])), {ok, _Pid} = sh(filename:join([OutputDir, "foo", "bin", "foo pid"])), {ok, _} = sh(filename:join([OutputDir, "foo", "bin", "foo stop"])), @@ -301,11 +305,11 @@ restart(Config) -> %% a restart is a gracious operation that does not involve the %% death of the VM, so the pid should be the same {ok, _} = sh(filename:join([OutputDir, "foo", "bin", "foo start"])), - timer:sleep(2000), + timer:sleep(?SLEEP_TIME), {ok, "pong"} = sh(filename:join([OutputDir, "foo", "bin", "foo ping"])), {ok, Pid1} = sh(filename:join([OutputDir, "foo", "bin", "foo pid"])), {ok, _} = sh(filename:join([OutputDir, "foo", "bin", "foo restart"])), - timer:sleep(2000), + timer:sleep(?SLEEP_TIME), {ok, Pid2} = sh(filename:join([OutputDir, "foo", "bin", "foo pid"])), {ok, _} = sh(filename:join([OutputDir, "foo", "bin", "foo stop"])), {error, 1, _} = sh(filename:join([OutputDir, "foo", "bin", "foo ping"])), @@ -339,13 +343,13 @@ reboot(Config) -> %% a reboot involves stopping the emulator, it needs to be restarted %% though {ok, _} = sh(filename:join([OutputDir, "foo", "bin", "foo start"])), - timer:sleep(2000), + timer:sleep(?SLEEP_TIME), {ok, "pong"} = sh(filename:join([OutputDir, "foo", "bin", "foo ping"])), {ok, Pid1} = sh(filename:join([OutputDir, "foo", "bin", "foo pid"])), {ok, _} = sh(filename:join([OutputDir, "foo", "bin", "foo reboot"])), - timer:sleep(2000), + timer:sleep(?SLEEP_TIME), {ok, _} = sh(filename:join([OutputDir, "foo", "bin", "foo start"])), - timer:sleep(2000), + timer:sleep(?SLEEP_TIME), {ok, Pid2} = sh(filename:join([OutputDir, "foo", "bin", "foo pid"])), {ok, _} = sh(filename:join([OutputDir, "foo", "bin", "foo stop"])), {error, 1, _} = sh(filename:join([OutputDir, "foo", "bin", "foo ping"])), @@ -381,7 +385,7 @@ escript(Config) -> %% now start/stop the release to make sure the extended script is working {ok, _} = sh(filename:join([OutputDir, "foo", "bin", "foo start"])), - timer:sleep(2000), + timer:sleep(?SLEEP_TIME), {ok, "pong"} = sh(filename:join([OutputDir, "foo", "bin", "foo ping"])), [ExpectedOutput] = io_lib:format("~s", [filename:join([OutputDir, "foo"])]), @@ -415,10 +419,10 @@ remote_console(Config) -> %% now start/stop the release to make sure the extended script is working {ok, _} = sh(filename:join([OutputDir, "foo", "bin", "foo start"])), - timer:sleep(2000), + timer:sleep(?SLEEP_TIME), {ok, "pong"} = sh(filename:join([OutputDir, "foo", "bin", "foo ping"])), {ok, _} = sh(filename:join([OutputDir, "foo", "bin", "foo remote_console &"])), - timer:sleep(2000), + timer:sleep(?SLEEP_TIME), {ok, NodesStr} = sh(filename:join([OutputDir, "foo", "bin", "foo eval 'nodes(connected).'"])), Nodes = rlx_test_utils:list_to_term(NodesStr), ?assertEqual(1, length(Nodes)), @@ -432,7 +436,7 @@ shortname_remote_console(Config) -> ConfigFile = filename:join([LibDir1, "relx.config"]), VmArgs = filename:join([LibDir1, "vm.args"]), - ec_file:write(VmArgs, "-sname foo\n\n" + ec_file:write(VmArgs, "-sname foo@localhost\n\n" "-setcookie cookie\n"), rlx_test_utils:write_config(ConfigFile, @@ -457,10 +461,10 @@ shortname_remote_console(Config) -> %% now start/stop the release to make sure the extended script is working {ok, _} = sh(filename:join([OutputDir, "foo", "bin", "foo start"])), - timer:sleep(2000), + timer:sleep(?SLEEP_TIME), {ok, "pong"} = sh(filename:join([OutputDir, "foo", "bin", "foo ping"])), {ok, _} = sh(filename:join([OutputDir, "foo", "bin", "foo remote_console &"])), - timer:sleep(2000), + timer:sleep(?SLEEP_TIME), {ok, NodesStr} = sh(filename:join([OutputDir, "foo", "bin", "foo eval 'nodes(connected).'"])), Nodes = rlx_test_utils:list_to_term(NodesStr), ?assertEqual(1, length(Nodes)), @@ -489,7 +493,7 @@ replace_os_vars(Config) -> [[{goal_app, [{var1, "${VAR1}"}, {var2, "${VAR2}"}]}]]), - ec_file:write(VmArgs, "-sname ${NODENAME}\n\n" + ec_file:write(VmArgs, "-sname ${NODENAME}@localhost\n\n" "-setcookie ${COOKIE}\n"), OutputDir = filename:join([proplists:get_value(priv_dir, Config), @@ -508,7 +512,7 @@ replace_os_vars(Config) -> {"NODENAME", "node1"}, {"COOKIE", "cookie1"}, {"VAR1", "v1"}]), - timer:sleep(2000), + timer:sleep(?SLEEP_TIME), {ok, "pong"} = sh(filename:join([OutputDir, "foo", "bin", "foo ping"]), [{"RELX_REPLACE_OS_VARS", "1"}, {"NODENAME", "node1"}, @@ -547,7 +551,7 @@ replace_os_vars(Config) -> {"NODENAME", "node2"}, {"COOKIE", "cookie2"}, {"VAR1", "v2"}]), - timer:sleep(2000), + timer:sleep(?SLEEP_TIME), {ok, "pong"} = sh(filename:join([OutputDir, "foo", "bin", "foo ping"]), [{"RELX_REPLACE_OS_VARS", "1"}, {"NODENAME", "node2"}, @@ -604,7 +608,7 @@ replace_os_vars_sys_config_vm_args_src(Config) -> %% new with sys.config.src it doesn't have to be valid Erlang %% until after var replacemen at runtime. ec_file:write(SysConfigSrc, "[{goal_app, [{var1, ${VAR1}}]}]."), - ec_file:write(VmArgs, "-sname ${NODENAME}\n\n" + ec_file:write(VmArgs, "-sname ${NODENAME}@localhost\n\n" "-setcookie ${COOKIE}\n"), OutputDir = filename:join([proplists:get_value(priv_dir, Config), @@ -623,7 +627,7 @@ replace_os_vars_sys_config_vm_args_src(Config) -> {"NODENAME", "node1"}, {"COOKIE", "cookie1"}, {"VAR1", "101"}]), - timer:sleep(2000), + timer:sleep(?SLEEP_TIME), {ok, "pong"} = sh(filename:join([OutputDir, "foo", "bin", "foo ping"]), [{"RELX_REPLACE_OS_VARS", "1"}, {"NODENAME", "node1"}, @@ -662,7 +666,7 @@ replace_os_vars_sys_config_vm_args_src(Config) -> {"NODENAME", "node2"}, {"COOKIE", "cookie2"}, {"VAR1", "201"}]), - timer:sleep(2000), + timer:sleep(?SLEEP_TIME), {ok, "pong"} = sh(filename:join([OutputDir, "foo", "bin", "foo ping"]), [{"RELX_REPLACE_OS_VARS", "1"}, {"NODENAME", "node2"}, @@ -717,7 +721,7 @@ replace_os_vars_multi_node(Config) -> rlx_test_utils:write_config(SysConfig, [[{goal_app, [{var1, "${VAR1}"}]}]]), - ec_file:write(VmArgs, "-sname ${NODENAME}\n\n" + ec_file:write(VmArgs, "-sname ${NODENAME}@localhost\n\n" "-setcookie ${COOKIE}\n"), OutputDir = filename:join([proplists:get_value(priv_dir, Config), @@ -737,7 +741,7 @@ replace_os_vars_multi_node(Config) -> {"NODENAME", "node1"}, {"COOKIE", "cookie1"}, {"VAR1", "v1"}]), - timer:sleep(2000), + timer:sleep(?SLEEP_TIME), {ok, "pong"} = sh(filename:join([OutputDir, "foo", "bin", "foo ping"]), [{"RELX_REPLACE_OS_VARS", "1"}, {"RELX_MULTI_NODE", "1"}, @@ -785,7 +789,7 @@ replace_os_vars_multi_node(Config) -> {"NODENAME", "node2"}, {"COOKIE", "cookie2"}, {"VAR1", "v2"}]), - timer:sleep(2000), + timer:sleep(?SLEEP_TIME), {ok, "pong"} = sh(filename:join([OutputDir, "foo", "bin", "foo ping"]), [{"RELX_REPLACE_OS_VARS", "1"}, {"RELX_MULTI_NODE", "1"}, @@ -862,7 +866,7 @@ replace_os_vars_included_config(Config) -> }, "releases/0.0.1/config/included.config"] ]), - ec_file:write(VmArgs, "-sname ${NODENAME}\n\n" + ec_file:write(VmArgs, "-sname ${NODENAME}@localhost\n\n" "-setcookie ${COOKIE}\n"), OutputDir = filename:join([proplists:get_value(priv_dir, Config), @@ -881,7 +885,7 @@ replace_os_vars_included_config(Config) -> {"NODENAME", "node1"}, {"COOKIE", "cookie1"}, {"VAR1", "v1"}]), - timer:sleep(2000), + timer:sleep(?SLEEP_TIME), {ok, "pong"} = sh(filename:join([OutputDir, "foo", "bin", "foo ping"]), [{"RELX_REPLACE_OS_VARS", "1"}, {"NODENAME", "node1"}, @@ -920,7 +924,7 @@ replace_os_vars_included_config(Config) -> {"NODENAME", "node2"}, {"COOKIE", "cookie2"}, {"VAR1", "v2"}]), - timer:sleep(2000), + timer:sleep(?SLEEP_TIME), {ok, "pong"} = sh(filename:join([OutputDir, "foo", "bin", "foo ping"]), [{"RELX_REPLACE_OS_VARS", "1"}, {"NODENAME", "node2"}, @@ -975,7 +979,7 @@ replace_os_vars_custom_location(Config) -> rlx_test_utils:write_config(SysConfig, [[{goal_app, [{var1, "${VAR1}"}]}]]), - ec_file:write(VmArgs, "-sname ${NODENAME}\n\n" + ec_file:write(VmArgs, "-sname ${NODENAME}@localhost\n\n" "-setcookie ${COOKIE}\n"), OutputDir = filename:join([proplists:get_value(priv_dir, Config), @@ -995,7 +999,7 @@ replace_os_vars_custom_location(Config) -> {"NODENAME", "node1"}, {"COOKIE", "cookie1"}, {"VAR1", "v1"}]), - timer:sleep(2000), + timer:sleep(?SLEEP_TIME), {ok, "pong"} = sh(filename:join([OutputDir, "foo", "bin", "foo ping"]), [{"RELX_REPLACE_OS_VARS", "1"}, {"RELX_OUT_FILE_PATH", "/tmp"}, @@ -1041,7 +1045,7 @@ replace_os_vars_custom_location(Config) -> {"NODENAME", "node2"}, {"COOKIE", "cookie2"}, {"VAR1", "v2"}]), - timer:sleep(2000), + timer:sleep(?SLEEP_TIME), {ok, "pong"} = sh(filename:join([OutputDir, "foo", "bin", "foo ping"]), [{"RELX_REPLACE_OS_VARS", "1"}, {"RELX_OUT_FILE_PATH", "/tmp"}, @@ -1102,7 +1106,7 @@ replace_os_vars_twice(Config) -> rlx_test_utils:write_config(SysConfig, [[{goal_app, [{var1, "${VAR1}"}]}]]), - ec_file:write(VmArgs, "-sname node\n\n" + ec_file:write(VmArgs, "-sname node@localhost\n\n" "-setcookie cookie\n"), OutputDir = filename:join([proplists:get_value(priv_dir, Config), @@ -1119,7 +1123,7 @@ replace_os_vars_twice(Config) -> {ok, _} = sh(filename:join([OutputDir, "foo", "bin", "foo start"]), [{"RELX_REPLACE_OS_VARS", "1"}, {"VAR1", "v1"}]), - timer:sleep(2000), + timer:sleep(?SLEEP_TIME), {ok, "pong"} = sh(filename:join([OutputDir, "foo", "bin", "foo ping"]), [{"RELX_REPLACE_OS_VARS", "1"}]), {ok, "\"v1\""} = sh(filename:join([OutputDir, "foo", "bin", @@ -1142,7 +1146,7 @@ replace_os_vars_twice(Config) -> %% start the node again but this time don't replace env variables {ok, _} = sh(filename:join([OutputDir, "foo", "bin", "foo start"])), - timer:sleep(2000), + timer:sleep(?SLEEP_TIME), {ok, "pong"} = sh(filename:join([OutputDir, "foo", "bin", "foo ping"])), {ok, "\"${VAR1}\""} = sh(filename:join([OutputDir, "foo", "bin", "foo eval '{ok, V} = application:get_env(goal_app, var1), V.'"])), @@ -1175,7 +1179,7 @@ replace_os_vars_dev_mode(Config) -> rlx_test_utils:write_config(SysConfig, [[{goal_app, [{var1, "${VAR1}"}]}]]), - ec_file:write(VmArgs, "-sname ${NODENAME}\n\n" + ec_file:write(VmArgs, "-sname ${NODENAME}@localhost\n\n" "-setcookie ${COOKIE}\n"), OutputDir = filename:join([proplists:get_value(priv_dir, Config), @@ -1194,7 +1198,7 @@ replace_os_vars_dev_mode(Config) -> {"NODENAME", "node1"}, {"COOKIE", "cookie1"}, {"VAR1", "v1"}]), - timer:sleep(2000), + timer:sleep(?SLEEP_TIME), {ok, "pong"} = sh(filename:join([OutputDir, "foo", "bin", "foo ping"]), [{"RELX_REPLACE_OS_VARS", "1"}, {"NODENAME", "node1"}, @@ -1233,7 +1237,7 @@ replace_os_vars_dev_mode(Config) -> {"NODENAME", "node2"}, {"COOKIE", "cookie2"}, {"VAR1", "v2"}]), - timer:sleep(2000), + timer:sleep(?SLEEP_TIME), {ok, "pong"} = sh(filename:join([OutputDir, "foo", "bin", "foo ping"]), [{"RELX_REPLACE_OS_VARS", "1"}, {"NODENAME", "node2"}, @@ -1318,7 +1322,7 @@ custom_start_script_hooks(Config) -> %% now start/stop the release to make sure the script hooks are really getting %% executed os:cmd(filename:join([OutputDir, "foo", "bin", "foo start"])), - timer:sleep(2000), + timer:sleep(?SLEEP_TIME), os:cmd(filename:join([OutputDir, "foo", "bin", "foo stop"])), %% now check that the output file contains the expected format {ok,[{pre_start, foo, _, foo}, @@ -1359,6 +1363,42 @@ builtin_pid_start_script_hook(Config) -> os:cmd(filename:join([OutputDir, "foo", "bin", "foo stop"])), ok. +custom_start_script_hooks_console(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + + rlx_test_utils:create_app(LibDir1, "goal_app", "0.0.1", [stdlib,kernel], []), + + ConfigFile = filename:join([LibDir1, "relx.config"]), + rlx_test_utils:write_config(ConfigFile, + [{release, {foo, "0.0.1"}, + [goal_app]}, + {lib_dirs, [filename:join(LibDir1, "*")]}, + {generate_start_script, true}, + {extended_start_script, true}, + {extended_start_script_hooks, [ + {pre_start, [ + {custom, "hooks/pre_start"} + ]} + ]}, + {mkdir, "scripts"}, + {overlay, [{copy, "./pre_start", "bin/hooks/pre_start"}]} + ]), + + %% write the hook scripts, each of them will write an erlang term to a file + %% that will later be consulted + ok = file:write_file(filename:join([LibDir1, "./pre_start"]), + "#!/bin/bash\n# $*\necho \\{pre_start, $REL_NAME, \\'$NAME\\', $COOKIE\\}. >> test"), + + OutputDir = filename:join([proplists:get_value(priv_dir, Config), + rlx_test_utils:create_random_name("relx-output")]), + {ok, _State} = relx:do(foo, undefined, [], [LibDir1], 3, + OutputDir, ConfigFile), + %% now start/stop the release to make sure the script hooks are really getting + %% executed + {ok, _} = sh(filename:join([OutputDir, "foo", "bin", "foo console &"])), + %% now check that the output file contains the expected format + {ok,[{pre_start, foo, _, foo}]} = file:consult(filename:join([OutputDir, "foo", "test"])). + builtin_wait_for_vm_start_script_hook(Config) -> LibDir1 = proplists:get_value(lib1, Config), @@ -1385,7 +1425,7 @@ builtin_wait_for_vm_start_script_hook(Config) -> os:cmd(filename:join([OutputDir, "foo", "bin", "foo start"])), % this run doesn't need the sleep because the wait_for_vm_start % start script makes it unnecessary - %timer:sleep(2000), + %timer:sleep(?SLEEP_TIME), {ok, "pong"} = sh(filename:join([OutputDir, "foo", "bin", "foo ping"])), os:cmd(filename:join([OutputDir, "foo", "bin", "foo stop"])), ok. @@ -1521,7 +1561,7 @@ builtin_status_script(Config) -> {ok, _State} = relx:do(foo, undefined, [], [LibDir1], 3, OutputDir, ConfigFile), os:cmd(filename:join([OutputDir, "foo", "bin", "foo start"])), - timer:sleep(2000), + timer:sleep(?SLEEP_TIME), {ok, "pong"} = sh(filename:join([OutputDir, "foo", "bin", "foo ping"])), %% write the status to a file {ok, ""} = sh(filename:join([OutputDir, "foo", "bin", "foo status"])). @@ -1558,7 +1598,7 @@ custom_status_script(Config) -> {ok, _State} = relx:do(foo, undefined, [], [LibDir1], 3, OutputDir, ConfigFile), os:cmd(filename:join([OutputDir, "foo", "bin", "foo start"])), - timer:sleep(2000), + timer:sleep(?SLEEP_TIME), {ok, "pong"} = sh(filename:join([OutputDir, "foo", "bin", "foo ping"])), %% write the status to a file {ok, StatusStr} = sh(filename:join([OutputDir, "foo", "bin", "foo status"])), @@ -1588,7 +1628,7 @@ start_sname_in_other_argsfile(Config) -> ec_file:write(VmArgs, "-args_file " ++ VmArgs2 ++ "\n\n" "-setcookie cookie\n"), - ec_file:write(VmArgs2, "-sname foo\n"), + ec_file:write(VmArgs2, "-sname foo@localhost\n"), OutputDir = filename:join([proplists:get_value(priv_dir, Config), rlx_test_utils:create_random_name("relx-output")]), @@ -1603,7 +1643,7 @@ start_sname_in_other_argsfile(Config) -> %% now start/stop the release to make sure the extended script is working {ok, _} = sh(filename:join([OutputDir, "foo", "bin", "foo start"])), - timer:sleep(2000), + timer:sleep(?SLEEP_TIME), {ok, "pong"} = sh(filename:join([OutputDir, "foo", "bin", "foo ping"])), {ok, _} = sh(filename:join([OutputDir, "foo", "bin", "foo stop"])), %% a ping should fail after stopping a node @@ -1639,7 +1679,7 @@ start_preserves_arguments(Config) -> %% and preserving the "tricky" argument that contains a string with a space %% in it {ok, _} = sh(filename:join([OutputDir, "foo", "bin", "foo start -goal_app baz '\"bat zing\"'"])), - timer:sleep(2000), + timer:sleep(?SLEEP_TIME), BinFile = filename:join([PrivDir, "goal_app.bin"]), Eval = io_lib:format("{ok,Env}=application:get_env(goal_app,baz),file:write_file(\"~s\",term_to_binary(Env)).", [BinFile]), @@ -1670,7 +1710,7 @@ start_nodetool_with_data_from_argsfile(Config) -> ]), ec_file:write(VmArgs, "-setcookie cookie\n" - "-sname foo\n\n" + "-sname foo@localhost\n\n" "-proto_dist inet_tcp\n\n"), OutputDir = filename:join([proplists:get_value(priv_dir, Config), @@ -1686,7 +1726,7 @@ start_nodetool_with_data_from_argsfile(Config) -> %% now start/stop the release to make sure the extended script is working {ok, _} = sh(filename:join([OutputDir, "foo", "bin", "foo start"])), - timer:sleep(2000), + timer:sleep(?SLEEP_TIME), {ok, "pong"} = sh(filename:join([OutputDir, "foo", "bin", "foo ping"])), {ok, _} = sh(filename:join([OutputDir, "foo", "bin", "foo stop"])), %% a ping should fail after stopping a node @@ -1710,7 +1750,7 @@ start_upgrade_escript_with_argsfile_data(Config) -> ]), ec_file:write(VmArgs, "-setcookie cookie\n" - "-sname foo\n\n" + "-sname foo@localhost\n\n" "-proto_dist inet_tcp\n\n"), OutputDir = filename:join([proplists:get_value(priv_dir, Config), @@ -1726,7 +1766,7 @@ start_upgrade_escript_with_argsfile_data(Config) -> %% now start/stop the release to make sure the extended script is working {ok, _} = sh(filename:join([OutputDir, "foo", "bin", "foo start"])), - timer:sleep(2000), + timer:sleep(?SLEEP_TIME), {ok, _Ver} = sh(filename:join([OutputDir, "foo", "bin", "foo versions"])), {ok, _} = sh(filename:join([OutputDir, "foo", "bin", "foo stop"])), %% a ping should fail after stopping a node @@ -1758,7 +1798,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, ""), @@ -1794,7 +1834,7 @@ extension_script(Config) -> proplists:get_value(priv_dir, Config), ExtensionScript), os:cmd(filename:join([OutputDir, "foo", "bin", "foo start"])), - timer:sleep(2000), + timer:sleep(?SLEEP_TIME), {ok, "pong"} = sh(filename:join([OutputDir, "foo", "bin", "foo ping"])), %% write the extension script output to a file {ok, Str} = sh(filename:join([OutputDir, "foo", "bin", "foo bar"])), 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 f0c10c3..3d77732 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, @@ -65,7 +67,7 @@ -include_lib("kernel/include/file.hrl"). suite() -> - [{timetrap,{seconds,30}}]. + [{timetrap,{seconds,120}}]. init_per_suite(Config) -> Config. @@ -83,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_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]. + 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), @@ -134,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), @@ -171,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), @@ -666,8 +759,10 @@ overlay_release(Config) -> TestFileFull = filename:join(TestDirFull, TestFile), SecondTestDir = "second_test_dir", rlx_test_utils:write_config(ConfigFile, - [{overlay_vars, [OverlayVars1, OverlayVars2, OverlayVars4]}, + [{overlay_vars, [{var_list_dir, "non-file-variable-list"}, + OverlayVars1, OverlayVars2, OverlayVars4]}, {overlay, [{mkdir, "{{target_dir}}/fooo"}, + {mkdir, "{{target_dir}}/{{var_list_dir}}"}, {copy, OverlayVars1, "{{target_dir}}/{{foo_dir}}/vars1.config"}, {copy, OverlayVars1, @@ -728,6 +823,7 @@ overlay_release(Config) -> ?assert(lists:member({goal_app_2, "0.0.1"}, AppSpecs)), ?assert(lists:member({lib_dep_1, "0.0.1", load}, AppSpecs)), + ?assert(ec_file:exists(filename:join([OutputDir, "foo", "non-file-variable-list"]))), ?assert(ec_file:exists(filename:join([OutputDir, "foo", "fooo"]))), ?assert(ec_file:exists(filename:join([OutputDir, "foo", "foodir", "vars1.config"]))), ?assert(ec_file:exists(filename:join([OutputDir, "foo", "yahoo", "vars1.config"]))), |