aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xpriv/templates/extended_bin94
-rw-r--r--priv/templates/extended_bin_windows45
-rw-r--r--priv/templates/nodetool49
-rw-r--r--src/relx.app.src18
-rw-r--r--src/rlx_util.erl120
5 files changed, 183 insertions, 143 deletions
diff --git a/priv/templates/extended_bin b/priv/templates/extended_bin
index 059f5bf..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)
;;
@@ -127,12 +127,10 @@ find_erts_dir() {
if [ -d "$__erts_dir" ]; then
ERTS_DIR="$__erts_dir";
ROOTDIR="$RELEASE_ROOT_DIR"
- # run a dummy distributed erlang node just to ensure that a cookie exists
- $ERTS_DIR/bin/erl -sname dummy -boot no_dot_erlang -noshell -eval "halt()"
else
__erl="$(which erl)"
code="io:format(\"~s\", [code:root_dir()]), halt()."
- __erl_root="$("$__erl" -sname dummy -boot no_dot_erlang -sasl errlog_type error -noshell -eval "$code")"
+ __erl_root="$("$__erl" -boot no_dot_erlang -sasl errlog_type error -noshell -eval "$code")"
ERTS_DIR="$__erl_root/erts-$ERTS_VSN"
ROOTDIR="$__erl_root"
fi
@@ -152,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
@@ -169,7 +176,7 @@ relx_rem_sh() {
# Setup remote shell command to control node
exec "$BINDIR/erl" "$NAME_TYPE" "$id" -remsh "$NAME" -boot start_clean \
- -boot_var ERTS_LIB_DIR "$ERTS_LIB_DIR" \
+ -boot_var ERTS_LIB_DIR "$ERTS_LIB_DIR" $MAYBE_DIST_ARGS \
-setcookie "$COOKIE" -hidden -kernel net_ticktime $TICKTIME
}
@@ -182,8 +189,22 @@ relx_gen_id() {
relx_nodetool() {
command="$1"; shift
- "$ERTS_DIR/bin/escript" "$ROOTDIR/bin/nodetool" "$NAME_TYPE" "$NAME" \
- -setcookie "$COOKIE" "$command" $@
+ # Generate a unique id used to allow multiple nodetool calls to the
+ # same node transparently
+ nodetool_id="maint$(relx_gen_id)-${NAME}"
+
+ 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
@@ -310,10 +331,10 @@ relx_is_extension() {
EXTENSION=$1
case "$EXTENSION" in
{{{ extensions }}})
- echo "1"
+ echo "1"
;;
*)
- echo "0"
+ echo "0"
;;
esac
}
@@ -324,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""
@@ -447,36 +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
-
-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"
diff --git a/priv/templates/extended_bin_windows b/priv/templates/extended_bin_windows
index 6d8f084..16e3d96 100644
--- a/priv/templates/extended_bin_windows
+++ b/priv/templates/extended_bin_windows
@@ -37,17 +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
)
@@ -76,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
@@ -86,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" (
@@ -143,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%" -sname dummy -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%"
@@ -164,12 +173,13 @@
set sys_config=-config "%possible_sys%"
)
)
+@goto :eof
:: Find the vm.args file
:find_vm_args
-@if not exist "%m_args%" (
- @if exist "%m_args%.orig" (
- ren "%m_args%.orig" vm.args
+@if not exist "%vm_args%" (
+ @if exist "%vm_args%.orig" (
+ ren "%vm_args%.orig" vm.args
)
)
@goto :eof
@@ -351,3 +361,4 @@ set description=Erlang node %node_name%%hostname% in %rootdir%
@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/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/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.