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 | 
