diff options
24 files changed, 367 insertions, 107 deletions
diff --git a/.travis.yml b/.travis.yml index c01e70c..191d337 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,6 @@ language: erlang otp_release: + - R16B - R15B01 - R15B - R14B04 @@ -24,7 +24,7 @@ dialyzer: dialyzer_warnings @diff -U0 dialyzer_reference dialyzer_warnings dialyzer_warnings: - -@dialyzer -q -n ebin -Wunmatched_returns -Werror_handling \ + -@dialyzer -q -nn -n ebin -Wunmatched_returns -Werror_handling \ -Wrace_conditions > dialyzer_warnings binary: VSN = $(shell ./rebar -V) @@ -38,6 +38,6 @@ deps: test: @$(REBAR) eunit - @$(RETEST) inttest + @$(RETEST) -v inttest travis: clean debug xref clean all deps test diff --git a/inttest/depplugins/depplugins_rt.erl b/inttest/depplugins/depplugins_rt.erl new file mode 100644 index 0000000..7b106eb --- /dev/null +++ b/inttest/depplugins/depplugins_rt.erl @@ -0,0 +1,50 @@ +%%% @doc Plugin handling test +%%% +%%% This test checks if plugins are loaded correctly. +%%% +%%% It has three applications: +%%% <ol> +%%% <li>fish. top-level module, has one dependency: `dependsonplugin'.</li> +%%% <li>dependsonplugin. This depends on some pre-compile actions by the +%%% plugin. In the test the plugin creates a file `pre.compile' in the +%%% top-level folder of this application.</li> +%%% <li>testplugin. This is a plugin application which creates the file.</li> +%%% </ol> + +-module(depplugins_rt). +-compile(export_all). + +-include_lib("eunit/include/eunit.hrl"). + +files() -> + [ + {copy, "../../rebar", "rebar"}, + {copy, "rebar.config", "rebar.config"}, + {create, "ebin/fish.app", app(fish, [])}, + + {create, "deps/dependsonplugin/ebin/dependsonplugin.app", + app(dependsonplugin, [])}, + {copy, "rebar_dependsonplugin.config", + "deps/dependsonplugin/rebar.config"}, + {copy, "testplugin_mod.erl", + "deps/testplugin/plugins/testplugin_mod.erl"}, + {create, "deps/testplugin/ebin/testplugin.app", + app(testplugin, [])} + ]. + +run(_Dir) -> + ?assertMatch({ok, _}, retest_sh:run("./rebar compile", [])), + ?assertEqual(true, filelib:is_regular("deps/dependsonplugin/pre.compile")), + ok. + +%% +%% Generate the contents of a simple .app file +%% +app(Name, Modules) -> + App = {application, Name, + [{description, atom_to_list(Name)}, + {vsn, "1"}, + {modules, Modules}, + {registered, []}, + {applications, [kernel, stdlib]}]}, + io_lib:format("~p.\n", [App]). diff --git a/inttest/depplugins/rebar.config b/inttest/depplugins/rebar.config new file mode 100644 index 0000000..3a2e34e --- /dev/null +++ b/inttest/depplugins/rebar.config @@ -0,0 +1 @@ +{deps, [dependsonplugin]}. diff --git a/inttest/depplugins/rebar_dependsonplugin.config b/inttest/depplugins/rebar_dependsonplugin.config new file mode 100644 index 0000000..df36213 --- /dev/null +++ b/inttest/depplugins/rebar_dependsonplugin.config @@ -0,0 +1,2 @@ +{deps, [testplugin]}. +{plugins, [testplugin_mod]}. diff --git a/inttest/depplugins/testplugin_mod.erl b/inttest/depplugins/testplugin_mod.erl new file mode 100644 index 0000000..055bbc7 --- /dev/null +++ b/inttest/depplugins/testplugin_mod.erl @@ -0,0 +1,6 @@ +-module(testplugin_mod). +-compile(export_all). + +pre_compile(Config, _) -> + ok = file:write_file("pre.compile", <<"Yadda!">>), + rebar_log:log(info, "Wrote ~p/pre.compile~n", [rebar_utils:get_cwd()]). diff --git a/inttest/tdeps1/tdeps1_rt.erl b/inttest/tdeps1/tdeps1_rt.erl index 9f21c81..3de1a2b 100644 --- a/inttest/tdeps1/tdeps1_rt.erl +++ b/inttest/tdeps1/tdeps1_rt.erl @@ -23,12 +23,23 @@ files() -> {copy, "c.hrl", "repo/c/include/c.hrl"} ]. +apply_cmds([], _Params) -> + ok; +apply_cmds([Cmd | Rest], Params) -> + io:format("Running: ~s (~p)\n", [Cmd, Params]), + {ok, _} = retest_sh:run(Cmd, Params), + apply_cmds(Rest, Params). + run(_Dir) -> %% Initialize the b/c apps as git repos so that dependencies pull %% properly - GitCmd = "/bin/sh -c \"git init && git add -A && git commit -a -m 'Initial commit'\"", - {ok, _} = retest_sh:run(GitCmd, [{dir, "repo/b"}]), - {ok, _} = retest_sh:run(GitCmd, [{dir, "repo/c"}]), + GitCmds = ["git init", + "git add -A", + "git config user.email 'tdeps@example.com'", + "git config user.name 'tdeps'", + "git commit -a -m 'Initial Commit'"], + apply_cmds(GitCmds, [{dir, "repo/b"}]), + apply_cmds(GitCmds, [{dir, "repo/c"}]), {ok, _} = retest_sh:run("./rebar get-deps compile", []), diff --git a/inttest/tdeps2/tdeps2_rt.erl b/inttest/tdeps2/tdeps2_rt.erl index dca5f03..987567e 100644 --- a/inttest/tdeps2/tdeps2_rt.erl +++ b/inttest/tdeps2/tdeps2_rt.erl @@ -31,12 +31,23 @@ files() -> {copy, "c.hrl", "repo/c/include/c.hrl"} ]. +apply_cmds([], _Params) -> + ok; +apply_cmds([Cmd | Rest], Params) -> + io:format("Running: ~s (~p)\n", [Cmd, Params]), + {ok, _} = retest_sh:run(Cmd, Params), + apply_cmds(Rest, Params). + run(_Dir) -> - %% Initialize the b/c apps as mercurial repos so that dependencies pull + %% Initialize the b/c apps as git repos so that dependencies pull %% properly - GitCmd = "/bin/sh -c \"git init && git add -A && git commit -a -m 'Initial commit'\"", - {ok, _} = retest_sh:run(GitCmd, [{dir, "repo/b"}]), - {ok, _} = retest_sh:run(GitCmd, [{dir, "repo/c"}]), + GitCmds = ["git init", + "git add -A", + "git config user.email 'tdeps@example.com'", + "git config user.name 'tdeps'", + "git commit -a -m 'Initial Commit'"], + ok = apply_cmds(GitCmds, [{dir, "repo/b"}]), + ok = apply_cmds(GitCmds, [{dir, "repo/c"}]), {ok, _} = retest_sh:run("./rebar -v get-deps compile", []), ok. diff --git a/priv/templates/simpleapp_sup.erl b/priv/templates/simpleapp_sup.erl index 931db75..477479f 100644 --- a/priv/templates/simpleapp_sup.erl +++ b/priv/templates/simpleapp_sup.erl @@ -1,4 +1,3 @@ - -module({{appid}}_sup). -behaviour(supervisor). diff --git a/priv/templates/simplenode.erl.script b/priv/templates/simplenode.erl.script index 7919d69..f4c63af 100644 --- a/priv/templates/simplenode.erl.script +++ b/priv/templates/simplenode.erl.script @@ -20,7 +20,7 @@ unset POSIX_SHELL ## start_clean.boot file available in $ROOTDIR/release/VSN. # Determine the abspath of where this script is executing from. -ERTS_BIN_DIR=$(cd ${0%/*} && pwd) +ERTS_BIN_DIR=$(cd ${0%/*} && pwd -P) # Now determine the root directory -- this script runs from erts-VSN/bin, # so we simply need to strip off two dirs from the end of the ERTS_BIN_DIR diff --git a/priv/templates/simplenode.nodetool b/priv/templates/simplenode.nodetool index 54ee6d6..ce06c6a 100755 --- a/priv/templates/simplenode.nodetool +++ b/priv/templates/simplenode.nodetool @@ -6,8 +6,6 @@ %% nodetool: Helper Script for interacting with live nodes %% %% ------------------------------------------------------------------- --mode(compile). - main(Args) -> ok = start_epmd(), %% Extract the args diff --git a/priv/templates/simplenode.reltool.config b/priv/templates/simplenode.reltool.config index 4189329..bac7270 100644 --- a/priv/templates/simplenode.reltool.config +++ b/priv/templates/simplenode.reltool.config @@ -19,9 +19,9 @@ {boot_rel, "{{nodeid}}"}, {profile, embedded}, {incl_cond, derived}, - {mod_cond, derived}, {excl_archive_filters, [".*"]}, %% Do not archive built libs - {excl_sys_filters, ["^bin/.*", "^erts.*/bin/(dialyzer|typer)", + {excl_sys_filters, ["^bin/(?!start_clean.boot)", + "^erts.*/bin/(dialyzer|typer)", "^erts.*/(doc|info|include|lib|man|src)"]}, {excl_app_filters, ["\.gitignore"]}, {app, {{nodeid}}, [{mod_cond, app}, {incl_cond, include}]} @@ -33,6 +33,8 @@ {mkdir, "log/sasl"}, {copy, "files/erl", "\{\{erts_vsn\}\}/bin/erl"}, {copy, "files/nodetool", "\{\{erts_vsn\}\}/bin/nodetool"}, + {copy, "{{nodeid}}/bin/start_clean.boot", + "\{\{erts_vsn\}\}/bin/start_clean.boot"}, {copy, "files/{{nodeid}}", "bin/{{nodeid}}"}, {copy, "files/{{nodeid}}.cmd", "bin/{{nodeid}}.cmd"}, {copy, "files/start_erl.cmd", "bin/start_erl.cmd"}, diff --git a/priv/templates/simplenode.runner b/priv/templates/simplenode.runner index 9835d92..c2ef258 100755 --- a/priv/templates/simplenode.runner +++ b/priv/templates/simplenode.runner @@ -15,7 +15,7 @@ fi # clear it so if we invoke other scripts, they run as ksh unset POSIX_SHELL -RUNNER_SCRIPT_DIR=$(cd ${0%/*} && pwd) +RUNNER_SCRIPT_DIR=$(cd ${0%/*} && pwd -P) CALLER_DIR=$PWD diff --git a/priv/templates/simplenode.windows.runner.cmd b/priv/templates/simplenode.windows.runner.cmd index 16da5b9..d45f438 100644 --- a/priv/templates/simplenode.windows.runner.cmd +++ b/priv/templates/simplenode.windows.runner.cmd @@ -30,6 +30,7 @@ @set epmd="%erts_bin%\epmd.exe" @set escript="%erts_bin%\escript.exe" @set werl="%erts_bin%\werl.exe" +@set nodetool="%erts_bin%\nodetool" @if "%1"=="usage" @goto usage @if "%1"=="install" @goto install @@ -38,13 +39,14 @@ @if "%1"=="stop" @goto stop @if "%1"=="restart" @call :stop && @goto start @if "%1"=="console" @goto console +@if "%1"=="ping" @goto ping @if "%1"=="query" @goto query @if "%1"=="attach" @goto attach @if "%1"=="upgrade" @goto upgrade @echo Unknown command: "%1" :usage -@echo Usage: %~n0 [install^|uninstall^|start^|stop^|restart^|console^|query^|attach^|upgrade] +@echo Usage: %~n0 [install^|uninstall^|start^|stop^|restart^|console^|ping^|query^|attach^|upgrade] @goto :EOF :install @@ -71,6 +73,11 @@ @start "%node_name% console" %werl% -boot "%node_boot_script%" -config "%sys_config%" -args_file "%vm_args%" -sname %node_name% @goto :EOF +:ping +@%escript% %nodetool% ping -sname "%node_name%" -setcookie "%erlang_cookie%" +@exit %ERRORLEVEL% +@goto :EOF + :query @%erlsrv% list %service_name% @exit %ERRORLEVEL% diff --git a/src/rebar_base_compiler.erl b/src/rebar_base_compiler.erl index 260cdaf..a0dec30 100644 --- a/src/rebar_base_compiler.erl +++ b/src/rebar_base_compiler.erl @@ -226,6 +226,8 @@ format_warnings(Config, Source, Warnings, Opts) -> maybe_report([{error, {error, _Es, _Ws}=ErrorsAndWarnings}, {source, _}]) -> maybe_report(ErrorsAndWarnings); +maybe_report([{error, E}, {source, S}]) -> + report(["unexpected error compiling " ++ S, io_lib:fwrite("~n~p~n", [E])]); maybe_report({error, Es, Ws}) -> report(Es), report(Ws); diff --git a/src/rebar_core.erl b/src/rebar_core.erl index 36923a5..3172d64 100644 --- a/src/rebar_core.erl +++ b/src/rebar_core.erl @@ -530,35 +530,41 @@ plugin_modules(Config, PredirsAssoc, FoundModules, MissingModules) -> load_plugin_modules(Config, PredirsAssoc, Modules) -> Cwd = rebar_utils:get_cwd(), - PluginDir = case rebar_config:get_local(Config, plugin_dir, undefined) of - undefined -> - filename:join(Cwd, "plugins"); - Dir -> - Dir - end, + PluginDirs = case rebar_config:get_local(Config, plugin_dir, undefined) of + undefined -> + % Plugin can be in the project's "plugins" folder + [filename:join(Cwd, "plugins")]; + Dir -> + [Dir] + end ++ + % We also want to include this case: + % Plugin can be in "plugins" directory of the plugin base directory. For + % example, Cwd depends on Plugin, and deps/Plugin/plugins/Plugin.erl is the + % plugin. + [ + filename:join(Dir, "plugins") || + Dir <- get_plugin_base_dirs(Cwd, PredirsAssoc) + ], %% Find relevant sources in base_dir and plugin_dir Erls = string:join([atom_to_list(M)++"\\.erl" || M <- Modules], "|"), RE = "^" ++ Erls ++ "\$", - BaseDir = get_plugin_base_dir(Cwd, PredirsAssoc), %% If a plugin is found both in base_dir and plugin_dir, the clash %% will provoke an error and we'll abort. - Sources = rebar_utils:find_files(PluginDir, RE, false) - ++ rebar_utils:find_files(BaseDir, RE, false), + Sources = [rebar_utils:find_files(PD, RE, false) || PD <- PluginDirs], %% Compile and load plugins - Loaded = [load_plugin(Src) || Src <- Sources], + Loaded = [load_plugin(Src) || Src <- lists:append(Sources)], FilterMissing = is_missing_plugin(Loaded), NotLoaded = [V || V <- Modules, FilterMissing(V)], {Loaded, NotLoaded}. -get_plugin_base_dir(Cwd, PredirsAssoc) -> - case dict:find(Cwd, PredirsAssoc) of - {ok, BaseDir} -> - BaseDir; - error -> - Cwd - end. +%% @doc PredirsAssoc is a dictionary of plugindir -> 'parent' pairs +%% 'parent' in this case depends on plugin; therefore we have to give +%% all plugins that Cwd ('parent' in this case) depends on. +get_plugin_base_dirs(Cwd, PredirsAssoc) -> + [PluginDir || {PluginDir, Master} <- dict:to_list(PredirsAssoc), + Master =:= Cwd]. is_missing_plugin(Loaded) -> fun(Mod) -> not lists:member(Mod, Loaded) end. diff --git a/src/rebar_ct.erl b/src/rebar_ct.erl index d5b1d26..9951f8e 100644 --- a/src/rebar_ct.erl +++ b/src/rebar_ct.erl @@ -108,8 +108,16 @@ run_test(TestDir, LogDir, Config, _File) -> " 2>&1 | tee -a " ++ RawLog end, - rebar_utils:sh(Cmd ++ Output, [{env,[{"TESTDIR", TestDir}]}]), - check_log(Config, RawLog). + case rebar_utils:sh(Cmd ++ Output, [{env,[{"TESTDIR", TestDir}]}, return_on_error]) of + {ok,_} -> + %% in older versions of ct_run, this could have been a failure + %% that returned a non-0 code. Check for that! + check_success_log(Config, RawLog); + {error,Res} -> + %% In newer ct_run versions, this may be a sign of a good compile + %% that failed cases. In older version, it's a worse error. + check_fail_log(Config, RawLog, Cmd ++ Output, Res) + end. clear_log(LogDir, RawLog) -> case filelib:ensure_dir(filename:join(LogDir, "index.html")) of @@ -124,7 +132,16 @@ clear_log(LogDir, RawLog) -> %% calling ct with erl does not return non-zero on failure - have to check %% log results -check_log(Config, RawLog) -> +check_success_log(Config, RawLog) -> + check_log(Config, RawLog, fun(Msg) -> ?CONSOLE("DONE.\n~s\n", [Msg]) end). + +check_fail_log(Config, RawLog, Command, {Rc, Output}) -> + check_log(Config, RawLog, fun(_Msg) -> + ?ABORT("~s failed with error: ~w and output:~n~s~n", + [Command, Rc, Output]) + end). + +check_log(Config,RawLog,Fun) -> {ok, Msg} = rebar_utils:sh("grep -e 'TEST COMPLETE' -e '{error,make_failed}' " ++ RawLog, [{use_stdout, false}]), @@ -142,9 +159,10 @@ check_log(Config, RawLog) -> ?FAIL; true -> - ?CONSOLE("DONE.\n~s\n", [Msg]) + Fun(Msg) end. + %% Show the log if it hasn't already been shown because verbose was on show_log(Config, RawLog) -> ?CONSOLE("Showing log\n", []), diff --git a/src/rebar_port_compiler.erl b/src/rebar_port_compiler.erl index 36d741d..0abb044 100644 --- a/src/rebar_port_compiler.erl +++ b/src/rebar_port_compiler.erl @@ -100,7 +100,8 @@ compile(Config, AppFile) -> [] -> ok; Specs -> - SharedEnv = rebar_config:get_env(Config, ?MODULE), + SharedEnv = rebar_config:get_env(Config, rebar_deps) ++ + rebar_config:get_env(Config, ?MODULE), %% Compile each of the sources NewBins = compile_sources(Config, Specs, SharedEnv), diff --git a/src/rebar_qc.erl b/src/rebar_qc.erl index 826ba9a..53a6f52 100644 --- a/src/rebar_qc.erl +++ b/src/rebar_qc.erl @@ -175,6 +175,7 @@ qc_module(QC=triq, _QCOpts, M) -> Failed -> [Failed] end; +qc_module(QC=eqc, [], M) -> QC:module(M); qc_module(QC=eqc, QCOpts, M) -> QC:module(QCOpts, M). find_prop_mods() -> diff --git a/test/upgrade_project/rel/files/dummy b/test/upgrade_project/rel/files/dummy index cfbfd4f..c2ef258 100755 --- a/test/upgrade_project/rel/files/dummy +++ b/test/upgrade_project/rel/files/dummy @@ -2,25 +2,41 @@ # -*- tab-width:4;indent-tabs-mode:nil -*- # ex: ts=4 sw=4 et -RUNNER_SCRIPT_DIR=$(cd ${0%/*} && pwd) +# /bin/sh on Solaris is not a POSIX compatible shell, but /usr/bin/ksh is. +if [ `uname -s` = 'SunOS' -a "${POSIX_SHELL}" != "true" ]; then + POSIX_SHELL="true" + export POSIX_SHELL + # To support 'whoami' add /usr/ucb to path + PATH=/usr/ucb:$PATH + export PATH + exec /usr/bin/ksh $0 "$@" +fi + +# clear it so if we invoke other scripts, they run as ksh +unset POSIX_SHELL + +RUNNER_SCRIPT_DIR=$(cd ${0%/*} && pwd -P) + +CALLER_DIR=$PWD RUNNER_BASE_DIR=${RUNNER_SCRIPT_DIR%/*} RUNNER_ETC_DIR=$RUNNER_BASE_DIR/etc -RUNNER_LOG_DIR=$RUNNER_BASE_DIR/log # Note the trailing slash on $PIPE_DIR/ PIPE_DIR=/tmp/$RUNNER_BASE_DIR/ RUNNER_USER= +WHOAMI=$(whoami) # Make sure this script is running as the appropriate user -if [ ! -z "$RUNNER_USER" ] && [ `whoami` != "$RUNNER_USER" ]; then - exec sudo -u $RUNNER_USER -i $0 $@ +if ([ "$RUNNER_USER" ] && [ "x$WHOAMI" != "x$RUNNER_USER" ]); then + type sudo > /dev/null 2>&1 + if [ $? -ne 0 ]; then + echo "sudo doesn't appear to be installed and your EUID isn't $RUNNER_USER" 1>&2 + exit 1 + fi + echo "Attempting to restart script through sudo -H -u $RUNNER_USER" >&2 + exec sudo -H -u $RUNNER_USER -i $RUNNER_SCRIPT_DIR/$RUNNER_SCRIPT $@ fi -# Make sure CWD is set to runner base dir -cd $RUNNER_BASE_DIR - -# Make sure log directory exists -mkdir -p $RUNNER_LOG_DIR # Identify the script name SCRIPT=`basename $0` @@ -29,22 +45,37 @@ START_ERL=`cat $RUNNER_BASE_DIR/releases/start_erl.data` ERTS_VSN=${START_ERL% *} APP_VSN=${START_ERL#* } -# Use releases/VSN/vm.args if it exists otherwise use etc/vm.args -if [ -e "$RUNNER_BASE_DIR/releases/$APP_VSN/vm.args" ]; then - VMARGS_PATH="$RUNNER_BASE_DIR/releases/$APP_VSN/vm.args" +# Use $CWD/vm.args if exists, otherwise releases/APP_VSN/vm.args, or +# else etc/vm.args +if [ -e "$CALLER_DIR/vm.args" ]; then + VMARGS_PATH=$CALLER_DIR/vm.args + USE_DIR=$CALLER_DIR else - VMARGS_PATH="$RUNNER_ETC_DIR/vm.args" + USE_DIR=$RUNNER_BASE_DIR + if [ -e "$RUNNER_BASE_DIR/releases/$APP_VSN/vm.args" ]; then + VMARGS_PATH="$RUNNER_BASE_DIR/releases/$APP_VSN/vm.args" + else + VMARGS_PATH="$RUNNER_ETC_DIR/vm.args" + fi fi +RUNNER_LOG_DIR=$USE_DIR/log +# Make sure log directory exists +mkdir -p $RUNNER_LOG_DIR + # Use releases/VSN/sys.config if it exists otherwise use etc/app.config -if [ -e "$RUNNER_BASE_DIR/releases/$APP_VSN/sys.config" ]; then - CONFIG_PATH="$RUNNER_BASE_DIR/releases/$APP_VSN/sys.config" +if [ -e "$USE_DIR/sys.config" ]; then + CONFIG_PATH="$USE_DIR/sys.config" else - CONFIG_PATH="$RUNNER_ETC_DIR/app.config" + if [ -e "$RUNNER_BASE_DIR/releases/$APP_VSN/sys.config" ]; then + CONFIG_PATH="$RUNNER_BASE_DIR/releases/$APP_VSN/sys.config" + else + CONFIG_PATH="$RUNNER_ETC_DIR/app.config" + fi fi # Extract the target node name from node.args -NAME_ARG=`egrep '^-s?name' $VMARGS_PATH` +NAME_ARG=`egrep '^\-s?name' $VMARGS_PATH` if [ -z "$NAME_ARG" ]; then echo "vm.args needs to have either -name or -sname parameter." exit 1 @@ -54,17 +85,24 @@ fi REMSH_TYPE=`echo $NAME_ARG | awk '{print $1}'` REMSH_NAME=`echo $NAME_ARG | awk '{print $2}'` -# Note the `date +%s`, used to allow multiple remsh to the same node transparently -REMSH_NAME_ARG="$REMSH_TYPE attach`date +%s`@`echo $REMSH_NAME | awk -F@ '{print $2}'`" +# Note the `date +%s`, used to allow multiple remsh to the same node +# transparently +REMSH_NAME_ARG="$REMSH_TYPE remsh`date +%s`@`echo $REMSH_NAME | awk -F@ '{print $2}'`" REMSH_REMSH_ARG="-remsh $REMSH_NAME" # Extract the target cookie -COOKIE_ARG=`grep '^-setcookie' $VMARGS_PATH` +COOKIE_ARG=`grep '^\-setcookie' $VMARGS_PATH` if [ -z "$COOKIE_ARG" ]; then echo "vm.args needs to have a -setcookie parameter." exit 1 fi +# Make sure CWD is set to the right dir +cd $USE_DIR + +# Make sure log directory exists +mkdir -p $USE_DIR/log + # Add ERTS bin dir to our path ERTS_PATH=$RUNNER_BASE_DIR/erts-$ERTS_VSN/bin @@ -74,47 +112,83 @@ NODETOOL="$ERTS_PATH/escript $ERTS_PATH/nodetool $NAME_ARG $COOKIE_ARG" # Setup remote shell command to control node REMSH="$ERTS_PATH/erl $REMSH_NAME_ARG $REMSH_REMSH_ARG $COOKIE_ARG" +# Common functions + +# Ping node without allowing nodetool to take stdin +ping_node() { + $NODETOOL ping < /dev/null +} + +# Set the PID global variable, return 1 on error +get_pid() { + PID=`$NODETOOL getpid < /dev/null` + ES=$? + if [ "$ES" -ne 0 ]; then + echo "Node is not running!" + return 1 + fi + + # don't allow empty or init pid's + if [ -z $PID ] || [ "$PID" -le 1 ]; then + return 1 + fi + + return 0 +} + # Check the first argument for instructions case "$1" in - start) + start|start_boot) # Make sure there is not already a node running - RES=`$NODETOOL ping` + RES=`ping_node` if [ "$RES" = "pong" ]; then echo "Node is already running!" exit 1 fi - shift # remove $1 + case "$1" in + start) + shift + START_OPTION="console" + HEART_OPTION="start" + ;; + start_boot) + shift + START_OPTION="console_boot" + HEART_OPTION="start_boot" + ;; + esac RUN_PARAM=$(printf "\'%s\' " "$@") - HEART_COMMAND="$RUNNER_BASE_DIR/bin/$SCRIPT start $RUN_PARAM" + HEART_COMMAND="$RUNNER_BASE_DIR/bin/$SCRIPT $HEART_OPTION $RUN_PARAM" export HEART_COMMAND mkdir -p $PIPE_DIR - $ERTS_PATH/run_erl -daemon $PIPE_DIR $RUNNER_LOG_DIR "exec $RUNNER_BASE_DIR/bin/$SCRIPT console $RUN_PARAM" 2>&1 + $ERTS_PATH/run_erl -daemon $PIPE_DIR $RUNNER_LOG_DIR "exec $RUNNER_BASE_DIR/bin/$SCRIPT $START_OPTION $RUN_PARAM" 2>&1 ;; stop) # Wait for the node to completely stop... case `uname -s` in - Linux|Darwin|FreeBSD|DragonFly|NetBSD|OpenBSD) - # PID COMMAND - PID=`ps ax -o pid= -o command=|\ - grep "$RUNNER_BASE_DIR/.*/[b]eam"|awk '{print $1}'` - ;; - SunOS) - # PID COMMAND - PID=`ps -ef -o pid= -o args=|\ - grep "$RUNNER_BASE_DIR/.*/[b]eam"|awk '{print $1}'` - ;; - CYGWIN*) - # UID PID PPID TTY STIME COMMAND - PID=`ps -efW|grep "$RUNNER_BASE_DIR/.*/[b]eam"|awk '{print $2}'` - ;; + Darwin) + # Make sure we explicitly set this because iTerm.app doesn't for + # some reason. + COMMAND_MODE=unix2003 esac + + # Get the PID from nodetool + get_pid + GPR=$? + if [ "$GPR" -ne 0 ] || [ -z $PID ]; then + exit $GPR + fi + + # Tell nodetool to initiate a stop $NODETOOL stop ES=$? if [ "$ES" -ne 0 ]; then exit $ES fi - while `kill -0 $PID 2>/dev/null`; + + # Wait for the node to completely stop... + while `kill -s 0 $PID 2>/dev/null` do sleep 1 done @@ -140,7 +214,7 @@ case "$1" in ping) ## See if the VM is alive - $NODETOOL ping + ping_node ES=$? if [ "$ES" -ne 0 ]; then exit $ES @@ -148,8 +222,8 @@ case "$1" in ;; attach) - # Make sure a node IS running - RES=`$NODETOOL ping` + # Make sure a node is running + ping_node ES=$? if [ "$ES" -ne 0 ]; then echo "Node is not running!" @@ -161,8 +235,8 @@ case "$1" in ;; remote_console) - # Make sure a node IS running - RES=`$NODETOOL ping` + # Make sure a node is running + ping_node ES=$? if [ "$ES" -ne 0 ]; then echo "Node is not running!" @@ -182,7 +256,7 @@ case "$1" in fi # Make sure a node IS running - RES=`$NODETOOL ping` + ping_node ES=$? if [ "$ES" -ne 0 ]; then echo "Node is not running!" @@ -195,12 +269,18 @@ case "$1" in $ERTS_PATH/escript $RUNNER_BASE_DIR/bin/install_upgrade.escript $node_name $erlang_cookie $2 ;; - console|console_clean) + console|console_clean|console_boot) # .boot file typically just $SCRIPT (ie, the app name) - # however, for debugging, sometimes start_clean.boot is useful: + # however, for debugging, sometimes start_clean.boot is useful. + # For e.g. 'setup', one may even want to name another boot script. case "$1" in console) BOOTFILE=$SCRIPT ;; console_clean) BOOTFILE=start_clean ;; + console_boot) + shift + BOOTFILE="$1" + shift + ;; esac # Setup beam-required vars ROOTDIR=$RUNNER_BASE_DIR @@ -249,8 +329,17 @@ case "$1" in # Start the VM exec $CMD -- ${1+"$@"} ;; + getpid) + # Get the PID from nodetool + get_pid + ES=$? + if [ "$ES" -ne 0 ] || [ -z $PID ]; then + exit $ES + fi + echo $PID + ;; *) - echo "Usage: $SCRIPT {start|foreground|stop|restart|reboot|ping|console|console_clean|attach|remote_console|upgrade}" + echo "Usage: $SCRIPT {start|start_boot <file>|foreground|stop|restart|reboot|ping|console|getpid|console_clean|console_boot <file>|attach|remote_console|upgrade}" exit 1 ;; esac diff --git a/test/upgrade_project/rel/files/erl b/test/upgrade_project/rel/files/erl index 6f65e3f..f4c63af 100755 --- a/test/upgrade_project/rel/files/erl +++ b/test/upgrade_project/rel/files/erl @@ -1,16 +1,26 @@ #!/bin/sh -## This script replaces the default "erl" in erts-VSN/bin. This is necessary -## as escript depends on erl and in turn, erl depends on having access to a -## bootscript (start.boot). Note that this script is ONLY invoked as a side-effect -## of running escript -- the embedded node bypasses erl and uses erlexec directly -## (as it should). +# /bin/sh on Solaris is not a POSIX compatible shell, but /usr/bin/ksh is. +if [ `uname -s` = 'SunOS' -a "${POSIX_SHELL}" != "true" ]; then + POSIX_SHELL="true" + export POSIX_SHELL + exec /usr/bin/ksh $0 "$@" +fi + +# clear it so if we invoke other scripts, they run as ksh as well +unset POSIX_SHELL + +## This script replaces the default "erl" in erts-VSN/bin. This is +## necessary as escript depends on erl and in turn, erl depends on +## having access to a bootscript (start.boot). Note that this script +## is ONLY invoked as a side-effect of running escript -- the embedded +## node bypasses erl and uses erlexec directly (as it should). ## -## Note that this script makes the assumption that there is a start_clean.boot -## file available in $ROOTDIR/release/VSN. +## Note that this script makes the assumption that there is a +## start_clean.boot file available in $ROOTDIR/release/VSN. # Determine the abspath of where this script is executing from. -ERTS_BIN_DIR=$(cd ${0%/*} && pwd) +ERTS_BIN_DIR=$(cd ${0%/*} && pwd -P) # Now determine the root directory -- this script runs from erts-VSN/bin, # so we simply need to strip off two dirs from the end of the ERTS_BIN_DIR diff --git a/test/upgrade_project/rel/files/nodetool b/test/upgrade_project/rel/files/nodetool index eb08fa4..ce06c6a 100644 --- a/test/upgrade_project/rel/files/nodetool +++ b/test/upgrade_project/rel/files/nodetool @@ -1,3 +1,4 @@ +#!/usr/bin/env escript %% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*- %% ex: ft=erlang ts=4 sw=4 et %% ------------------------------------------------------------------- @@ -5,25 +6,51 @@ %% nodetool: Helper Script for interacting with live nodes %% %% ------------------------------------------------------------------- - main(Args) -> ok = start_epmd(), %% Extract the args {RestArgs, TargetNode} = process_args(Args, [], undefined), + %% any commands that don't need a running node + case RestArgs of + ["chkconfig", File] -> + case file:consult(File) of + {ok, _} -> + io:format("ok\n"), + halt(0); + {error, {Line, Mod, Term}} -> + io:format(standard_error, ["Error on line ", + file:format_error({Line, Mod, Term}), "\n"], []), + halt(1); + {error, R} -> + io:format(standard_error, ["Error reading config file: ", + file:format_error(R), "\n"], []), + halt(1) + end; + _ -> + ok + end, + %% 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 + case {net_kernel:hidden_connect_node(TargetNode), + net_adm:ping(TargetNode)} of {true, pong} -> ok; + {false,pong} -> + io:format("Failed to connect to node ~p .\n", [TargetNode]), + halt(1); {_, pang} -> io:format("Node ~p not responding to pings.\n", [TargetNode]), halt(1) end, case RestArgs of + ["getpid"] -> + io:format("~p\n", + [list_to_integer(rpc:call(TargetNode, os, getpid, []))]); ["ping"] -> - %% If we got this far, the node already responsed to a ping, so just dump - %% a "pong" + %% If we got this far, the node already responsed to a + %% ping, so just dump a "pong" io:format("pong\n"); ["stop"] -> io:format("~p\n", [rpc:call(TargetNode, init, stop, [], 60000)]); @@ -32,7 +59,9 @@ main(Args) -> ["reboot"] -> io:format("~p\n", [rpc:call(TargetNode, init, reboot, [], 60000)]); ["rpc", Module, Function | RpcArgs] -> - case rpc:call(TargetNode, list_to_atom(Module), list_to_atom(Function), + case rpc:call(TargetNode, + list_to_atom(Module), + list_to_atom(Function), [RpcArgs], 60000) of ok -> ok; @@ -42,8 +71,23 @@ main(Args) -> _ -> halt(1) end; + ["rpc_infinity", Module, Function | RpcArgs] -> + case rpc:call(TargetNode, + list_to_atom(Module), + list_to_atom(Function), + [RpcArgs], infinity) of + ok -> + ok; + {badrpc, Reason} -> + io:format("RPC to ~p failed: ~p\n", [TargetNode, Reason]), + halt(1); + _ -> + halt(1) + end; ["rpcterms", Module, Function, ArgsAsString] -> - case rpc:call(TargetNode, list_to_atom(Module), list_to_atom(Function), + case rpc:call(TargetNode, + list_to_atom(Module), + list_to_atom(Function), consult(ArgsAsString), 60000) of {badrpc, Reason} -> io:format("RPC to ~p failed: ~p\n", [TargetNode, Reason]), @@ -53,7 +97,7 @@ main(Args) -> end; Other -> io:format("Other: ~p\n", [Other]), - io:format("Usage: nodetool {ping|stop|restart|reboot}\n") + io:format("Usage: nodetool {chkconfig|getpid|ping|stop|restart|reboot|rpc|rpc_infinity|rpcterms}\n") end, net_kernel:stop(). diff --git a/test/upgrade_project/rel/files/sys.config b/test/upgrade_project/rel/files/sys.config index d7677e7..3b7f6bd 100644 --- a/test/upgrade_project/rel/files/sys.config +++ b/test/upgrade_project/rel/files/sys.config @@ -8,3 +8,4 @@ {error_logger_mf_maxfiles, 5} % 5 files max ]} ]. + diff --git a/test/upgrade_project/rel/files/vm.args b/test/upgrade_project/rel/files/vm.args index 2d64e25..a9aeb64 100644 --- a/test/upgrade_project/rel/files/vm.args +++ b/test/upgrade_project/rel/files/vm.args @@ -9,11 +9,11 @@ ##-heart ## Enable kernel poll and a few async threads -+K true -+A 5 +##+K true +##+A 5 ## Increase number of concurrent ports/sockets --env ERL_MAX_PORTS 4096 +##-env ERL_MAX_PORTS 4096 ## Tweak GC to run more often --env ERL_FULLSWEEP_AFTER 10 +##-env ERL_FULLSWEEP_AFTER 10 |