diff --git a/bin/emqx b/bin/emqx index 41f2c0db5..e6cd421f1 100755 --- a/bin/emqx +++ b/bin/emqx @@ -14,6 +14,11 @@ ROOT_DIR="$(cd "$(dirname "$(readlink "$0" || echo "$0")")"/..; pwd -P)" # shellcheck disable=SC1090 . "$ROOT_DIR"/releases/emqx_vars +# defined in emqx_vars +export RUNNER_ROOT_DIR +export RUNNER_ETC_DIR +export REL_VSN + RUNNER_SCRIPT="$RUNNER_BIN_DIR/$REL_NAME" CODE_LOADING_MODE="${CODE_LOADING_MODE:-embedded}" REL_DIR="$RUNNER_ROOT_DIR/releases/$REL_VSN" @@ -109,7 +114,7 @@ relx_usage() { echo " don't make it permanent" ;; *) - echo "Usage: $REL_NAME {start|start_boot |ertspath|foreground|stop|pid|ping|console|console_clean|console_boot |attach|remote_console|upgrade|downgrade|install|uninstall|versions|escript|ctl|rpc|rpcterms|eval|root_dir}" + echo "Usage: $REL_NAME {start|start_boot |ertspath|foreground|stop|pid|ping|console|console_clean|console_boot |attach|remote_console|upgrade|downgrade|install|uninstall|versions|escript|ctl|rpc|rpcterms|eval|cold_eval|root_dir}" ;; esac } @@ -198,18 +203,12 @@ relx_gen_id() { # Control a node relx_nodetool() { command="$1"; shift - export RUNNER_ROOT_DIR - export REL_VSN - ERL_FLAGS="$ERL_FLAGS $EPMD_ARG" \ "$ERTS_DIR/bin/escript" "$ROOTDIR/bin/nodetool" "$NAME_TYPE" "$NAME" \ -setcookie "$COOKIE" "$command" "$@" } call_hocon() { - export RUNNER_ROOT_DIR - export RUNNER_ETC_DIR - export REL_VSN "$ERTS_DIR/bin/escript" "$ROOTDIR/bin/nodetool" hocon "$@" \ || die "call_hocon_failed: $*" $? } @@ -217,8 +216,6 @@ call_hocon() { # Run an escript in the node's environment relx_escript() { shift; scriptpath="$1"; shift - export RUNNER_ROOT_DIR - "$ERTS_DIR/bin/escript" "$ROOTDIR/$scriptpath" "$@" } @@ -709,6 +706,10 @@ case "$1" in shift relx_nodetool "eval" "$@" ;; + cold_eval) + shift; + "$ERTS_DIR/bin/escript" "$ROOTDIR/bin/nodetool" cold_eval "$@" + ;; *) relx_usage "$1" exit 1 diff --git a/bin/nodetool b/bin/nodetool index 377ade040..298d15a0b 100755 --- a/bin/nodetool +++ b/bin/nodetool @@ -24,6 +24,8 @@ main(Args) -> ["hocon" | Rest] -> %% forward the call to hocon_cli hocon_cli:main(Rest); + ["cold_eval" | Rest] -> + code_eval(Rest); _ -> do(Args) end. @@ -117,40 +119,53 @@ do(Args) -> io:format("~p\n", [Other]) end; ["eval" | ListOfArgs] -> - % shells may process args into more than one, and end up stripping - % spaces, so this converts all of that to a single string to parse - String = binary_to_list( - list_to_binary( - join(ListOfArgs," ") - ) - ), - - % then just as a convenience to users, if they forgot a trailing - % '.' add it for them. - Normalized = - case lists:reverse(String) of - [$. | _] -> String; - R -> lists:reverse([$. | R]) - end, - - % then scan and parse the string - {ok, Scanned, _} = erl_scan:string(Normalized), - {ok, Parsed } = erl_parse:parse_exprs(Scanned), - + Parsed = parse_eval_args(ListOfArgs), % and evaluate it on the remote node case rpc:call(TargetNode, erl_eval, exprs, [Parsed, [] ]) of {value, Value, _} -> - io:format ("~p\n",[Value]); + io:format ("~p~n",[Value]); {badrpc, Reason} -> - io:format("RPC to ~p failed: ~p\n", [TargetNode, Reason]), + io:format("RPC to ~p failed: ~p~n", [TargetNode, Reason]), halt(1) end; Other -> - io:format("Other: ~p\n", [Other]), - io:format("Usage: nodetool {genconfig, chkconfig|getpid|ping|stop|rpc|rpc_infinity|rpcterms|eval [Terms]} [RPC]\n") + io:format("Other: ~p~n", [Other]), + io:format("Usage: nodetool chkconfig|getpid|ping|stop|rpc|rpc_infinity|rpcterms|eval|cold_eval [Terms] [RPC]\n") end, net_kernel:stop(). +code_eval(Args) -> + Parsed = parse_eval_args(Args), + case erl_eval:exprs(Parsed, []) of + {value, Value, _} -> + io:format ("~p~n", [Value]); + Other -> + io:format("cold_eval_failed_with: ~p~n", [Other]), + halt(1) + end. + +parse_eval_args(Args) -> + % shells may process args into more than one, and end up stripping + % spaces, so this converts all of that to a single string to parse + String = binary_to_list( + list_to_binary( + join(Args," ") + ) + ), + + % then just as a convenience to users, if they forgot a trailing + % '.' add it for them. + Normalized = + case lists:reverse(String) of + [$. | _] -> String; + R -> lists:reverse([$. | R]) + end, + + % then scan and parse the string + {ok, Scanned, _} = erl_scan:string(Normalized), + {ok, Parsed } = erl_parse:parse_exprs(Scanned), + Parsed. + do_with_ret(Args, Name, Handler) -> {arity, Arity} = erlang:fun_info(Handler, arity), case take_args(Args, Name, Arity) of