diff options
author | José Valim <jose.valim@gmail.com> | 2019-02-02 21:27:28 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-02-02 21:27:28 +0100 |
commit | a5395fc374a00c1b5622a1ea0ce5cbea6e4f46cb (patch) | |
tree | 9233cb9b7de62daa0d40cccd6d2293ca4f888aae | |
parent | c95506bb44fe49571b57aae3311dae7192401dba (diff) | |
download | elixir-a5395fc374a00c1b5622a1ea0ce5cbea6e4f46cb.tar.gz |
Add eval and version commands to releases (#8758)
We also split start | daemon iex | elixir into start and start_iex,
daemon and daemon_iex.
-rw-r--r-- | bin/elixir.bat | 40 | ||||
-rw-r--r-- | lib/mix/lib/mix/tasks/release.ex | 156 | ||||
-rw-r--r-- | lib/mix/test/fixtures/release_test/lib/release_test.ex | 9 | ||||
-rw-r--r-- | lib/mix/test/mix/tasks/release_test.exs | 43 |
4 files changed, 171 insertions, 77 deletions
diff --git a/bin/elixir.bat b/bin/elixir.bat index b41241779..558c6a125 100644 --- a/bin/elixir.bat +++ b/bin/elixir.bat @@ -117,27 +117,27 @@ if ""==!par:--rpc-eval=! ( goto startloop ) rem ******* ELIXIR PARAMETERS ********************** -if ""==!par:-r=! (set parsElixir=!parsElixir! -r %1 && shift && goto startloop) -if ""==!par:-pr=! (set parsElixir=!parsElixir! -pr %1 && shift && goto startloop) -if ""==!par:-pa=! (set parsElixir=!parsElixir! -pa %1 && shift && goto startloop) -if ""==!par:-pz=! (set parsElixir=!parsElixir! -pz %1 && shift && goto startloop) -if ""==!par:-v=! (set parsElixir=!parsElixir! -v && goto startloop) -if ""==!par:--app=! (set parsElixir=!parsElixir! --app %1 && shift && goto startloop) -if ""==!par:--no-halt=! (set parsElixir=!parsElixir! --no-halt && goto startloop) -if ""==!par:--remsh=! (set parsElixir=!parsElixir! --remsh %1 && shift && goto startloop) -if ""==!par:--dot-iex=! (set parsElixir=!parsElixir! --dot-iex %1 && shift && goto startloop) +if ""==!par:-r=! (set "parsElixir=!parsElixir! -r %1" && shift && goto startloop) +if ""==!par:-pr=! (set "parsElixir=!parsElixir! -pr %1" && shift && goto startloop) +if ""==!par:-pa=! (set "parsElixir=!parsElixir! -pa %1" && shift && goto startloop) +if ""==!par:-pz=! (set "parsElixir=!parsElixir! -pz %1" && shift && goto startloop) +if ""==!par:-v=! (set "parsElixir=!parsElixir! -v" && goto startloop) +if ""==!par:--app=! (set "parsElixir=!parsElixir! --app %1" && shift && goto startloop) +if ""==!par:--no-halt=! (set "parsElixir=!parsElixir! --no-halt" && goto startloop) +if ""==!par:--remsh=! (set "parsElixir=!parsElixir! --remsh %1" && shift && goto startloop) +if ""==!par:--dot-iex=! (set "parsElixir=!parsElixir! --dot-iex %1" && shift && goto startloop) rem ******* ERLANG PARAMETERS ********************** -if ""==!par:--boot=! (set parsErlang=!parsErlang! -boot %1 && shift && goto startloop) -if ""==!par:--boot-var=! (set parsErlang=!parsErlang! -boot_var %1 %2 && shift && shift && goto startloop) -if ""==!par:--cookie=! (set parsErlang=!parsErlang! -setcookie %1 && shift && goto startloop) -if ""==!par:--hidden=! (set parsErlang=!parsErlang! -hidden && goto startloop) -if ""==!par:--detached=! (set parsErlang=!parsErlang! -detached && echo warning: the --detached option is deprecated && goto startloop) -if ""==!par:--erl-config=! (set parsErlang=!parsErlang! -config %1 && shift && goto startloop) -if ""==!par:--logger-otp-reports=! (set parsErlang=!parsErlang! -logger handle_otp_reports %1 && shift && goto startloop) -if ""==!par:--logger-sasl-reports=! (set parsErlang=!parsErlang! -logger handle_sasl_reports %1 && shift && goto startloop) -if ""==!par:--name=! (set parsErlang=!parsErlang! -name %1 && shift && goto startloop) -if ""==!par:--sname=! (set parsErlang=!parsErlang! -sname %1 && shift && goto startloop) -if ""==!par:--vm-args=! (set parsErlang=!parsErlang! -args_file %1 && shift && goto startloop) +if ""==!par:--boot=! (set "parsErlang=!parsErlang! -boot %1" && shift && goto startloop) +if ""==!par:--boot-var=! (set "parsErlang=!parsErlang! -boot_var %1 %2" && shift && shift && goto startloop) +if ""==!par:--cookie=! (set "parsErlang=!parsErlang! -setcookie %1" && shift && goto startloop) +if ""==!par:--hidden=! (set "parsErlang=!parsErlang! -hidden" && goto startloop) +if ""==!par:--detached=! (set "parsErlang=!parsErlang! -detached" && echo warning: the --detached option is deprecated && goto startloop) +if ""==!par:--erl-config=! (set "parsErlang=!parsErlang! -config %1" && shift && goto startloop) +if ""==!par:--logger-otp-reports=! (set "parsErlang=!parsErlang! -logger handle_otp_reports %1" && shift && goto startloop) +if ""==!par:--logger-sasl-reports=! (set "parsErlang=!parsErlang! -logger handle_sasl_reports %1" && shift && goto startloop) +if ""==!par:--name=! (set "parsErlang=!parsErlang! -name %1" && shift && goto startloop) +if ""==!par:--sname=! (set "parsErlang=!parsErlang! -sname %1" && shift && goto startloop) +if ""==!par:--vm-args=! (set "parsErlang=!parsErlang! -args_file %1" && shift && goto startloop) if ""==!par:--erl=! (set "beforeExtra=!beforeExtra! %~1" && shift && goto startloop) if ""==!par:--pipe-to=! (echo --pipe-to : Option is not supported on Windows && goto end) set endLoop=1 diff --git a/lib/mix/lib/mix/tasks/release.ex b/lib/mix/lib/mix/tasks/release.ex index a167b977d..2f855f424 100644 --- a/lib/mix/lib/mix/tasks/release.ex +++ b/lib/mix/lib/mix/tasks/release.ex @@ -63,14 +63,14 @@ defmodule Mix.Tasks.Release do For those looking for alternate ways of running the system, you can run it as a daemon on Unix-like system or install it as a service on - Windows. + Windows. Then we list all commands supported by `bin/RELEASE_NAME`. ### Daemon mode (Unix-like) If you open up `bin/start`, you will also see there is an option to run the release in daemon mode written as a comment: - bin/RELEASE_NAME daemon iex + bin/RELEASE_NAME daemon_iex In daemon mode, the system is started on the background via [run_erl](http://erlang.org/doc/man/run_erl.html). You may also @@ -87,9 +87,9 @@ defmodule Mix.Tasks.Release do will actually shut down the daemon. Therefore, using `bin/RELEASE_NAME remote` should be preferred, even in daemon mode. - You can customize the tmp directory used both for logging and for piping - in daemon mode by setting the `RELEASE_TMP` environment variable before - starting the system. + You can customize the tmp directory used both for logging and for + piping in daemon mode by setting the `RELEASE_TMP` environment + variable before starting the system. ### Services mode @@ -117,6 +117,23 @@ defmodule Mix.Tasks.Release do The `install` command must be executed as an administrator. + ## `bin/RELEASE_NAME` commands + + The following commands are supported by `bin/RELEASE_NAME`: + + start Starts the system + start_iex Starts the system with IEx attached + daemon Starts the system as a daemon (Unix-like only) + daemon_iex Starts the system as a daemon with IEx attached (Unix-like only) + install Installs this system as a Windows service (Windows only) + eval "EXPR" Executes the given expression on a new, non-booted system + rpc "EXPR" Executes the given expression remotely on the running system + remote Connects to the running system via a remote shell + restart Restarts the running system via a remote command + stop Stops the running system via a remote command + pid Prints the OS PID of the running system via a remote command + version Prints the release name and version to be booted + ## Deployments ### Requirements @@ -858,8 +875,8 @@ defmodule Mix.Tasks.Release do # export HEART_COMMAND # export ELIXIR_ERL_OPTIONS="-heart" - # To start your system using IEx: "$(dirname "$0")/<%= @name %>" start iex - # To start it as a daemon using IEx: "$(dirname "$0")/<%= @name %>" daemon iex + # To start your system using IEx: "$(dirname "$0")/<%= @name %>" start_iex + # To start it as a daemon using IEx: "$(dirname "$0")/<%= @name %>" daemon_iex "$(dirname "$0")/<%= @name %>" start """) @@ -884,7 +901,7 @@ defmodule Mix.Tasks.Release do rpc () { exec "$REL_VSN_DIR/elixir" \ --hidden --name "rpc-$(gen_id)@127.0.0.1" --cookie "$RELEASE_COOKIE" \ - --boot "${REL_VSN_DIR}/start_clean" \ + --boot "$REL_VSN_DIR/start_clean" \ --boot-var RELEASE_LIB "$RELEASE_ROOT/lib" \ --rpc-eval "$RELEASE_NODE" "$1" } @@ -892,28 +909,51 @@ defmodule Mix.Tasks.Release do start () { REL_EXEC="$1" shift - exec "$REL_VSN_DIR/$REL_EXEC" --no-halt \ - --werl --name "$RELEASE_NODE" --cookie "$RELEASE_COOKIE" \ - --erl-config "${REL_VSN_DIR}/sys" \ - --boot "${REL_VSN_DIR}/start" \ + exec "$REL_VSN_DIR/$REL_EXEC" \ + --name "$RELEASE_NODE" --cookie "$RELEASE_COOKIE" \ + --erl-config "$REL_VSN_DIR/sys" \ + --boot "$REL_VSN_DIR/start" \ --boot-var RELEASE_LIB "$RELEASE_ROOT/lib" \ - --vm-args "${REL_VSN_DIR}/vm.args" "$@" + --vm-args "$REL_VSN_DIR/vm.args" "$@" } case $1 in start) - start "${2:-elixir}" + start "elixir" --no-halt + ;; + + start_iex) + start "iex" --werl ;; daemon) export RELEASE_TMP="${RELEASE_TMP:-"$RELEASE_ROOT/tmp"}" - start "${2:-elixir}" --pipe-to "${RELEASE_TMP}/pipe" "${RELEASE_TMP}/log" + start "elixir" --no-halt --pipe-to "${RELEASE_TMP}/pipe" "${RELEASE_TMP}/log" + ;; + + daemon_iex) + export RELEASE_TMP="${RELEASE_TMP:-"$RELEASE_ROOT/tmp"}" + start "iex" --pipe-to "${RELEASE_TMP}/pipe" "${RELEASE_TMP}/log" + ;; + + eval) + if [ -z "$2" ]; then + echo "ERROR: EVAL expects an expression as argument" >&2 + exit 1 + fi + + exec "$REL_VSN_DIR/elixir" \ + --cookie "$RELEASE_COOKIE" \ + --erl-config "$REL_VSN_DIR/sys" \ + --boot "$REL_VSN_DIR/start_clean" \ + --boot-var RELEASE_LIB "$RELEASE_ROOT/lib" \ + --vm-args "$REL_VSN_DIR/vm.args" --eval "$2" ;; remote) exec "$REL_VSN_DIR/iex" \ --werl --hidden --name "remote-$(gen_id)@127.0.0.1" --cookie "$RELEASE_COOKIE" \ - --boot "${REL_VSN_DIR}/start_clean" \ + --boot "$REL_VSN_DIR/start_clean" \ --boot-var RELEASE_LIB "$RELEASE_ROOT/lib" \ --remsh "$RELEASE_NODE" ;; @@ -934,18 +974,26 @@ defmodule Mix.Tasks.Release do rpc "IO.puts System.pid" ;; + version) + echo "$RELEASE_NAME $RELEASE_VSN" + ;; + *) echo "Usage: $(basename "$0") COMMAND [ARGS] The known commands are: - start [elixir | iex] Starts the system using elixir or iex - daemon [elixir | iex] Starts the system as a daemon using elixir or iex - remote Connects to the running system via a remote shell - rpc \"EXPR\" Executes the given expression remotely on the running system - restart Restarts the running system via a remote command - stop Stops the running system via a remote command - pid Prints the OS PID of the running system via a remote command + start Starts the system + start_iex Starts the system with IEx attached + daemon Starts the system as a daemon + daemon_iex Starts the system as a daemon with IEx attached + eval \"EXPR\" Executes the given expression on a new, non-booted system + rpc \"EXPR\" Executes the given expression remotely on the running system + remote Connects to the running system via a remote shell + restart Restarts the running system via a remote command + stop Stops the running system via a remote command + pid Prints the OS PID of the running system via a remote command + version Prints the release name and version to be booted " >&2 if [ -n "$1" ]; then @@ -959,7 +1007,7 @@ defmodule Mix.Tasks.Release do embed_template(:start_bat, ~S""" @echo off rem Feel free to edit this file in anyway you want - rem To start your system using IEx: %~dp0/<%= @name %> start iex + rem To start your system using IEx: %~dp0/<%= @name %> start_iex %~dp0/<%= @name %> start """) @@ -978,45 +1026,67 @@ defmodule Mix.Tasks.Release do if not defined RELEASE_NODE (set RELEASE_NODE=!RELEASE_NAME!@127.0.0.1) set REL_VSN_DIR=!RELEASE_ROOT!/releases/!RELEASE_VSN! - if "%~1" == "start" (goto start) + if "%~1" == "start" (set "REL_EXEC=elixir" && set "REL_EXTRA=--no-halt" && goto start) + if "%~1" == "start_iex" (set "REL_EXEC=iex" && set "REL_EXTRA=--werl" && goto start) if "%~1" == "remote" (goto remote) if "%~1" == "install" (goto install) - if "%~1" == "stop" (set REL_RPC="System.stop()" && goto rpc) - if "%~1" == "restart" (set REL_RPC="System.stop()" && goto rpc) - if "%~1" == "pid" (set REL_RPC="IO.puts System.pid" && goto rpc) + if "%~1" == "version" (goto version) + if "%~1" == "stop" (set "REL_RPC=System.stop()" && goto rpc) + if "%~1" == "restart" (set "REL_RPC=System.stop()" && goto rpc) + if "%~1" == "pid" (set "REL_RPC=IO.puts(System.pid())" && goto rpc) + if "%~1" == "eval" ( + if "%~2" == "" ( + echo ERROR: EVAL expects an expression as argument + goto end + ) + goto eval + ) if "%~1" == "rpc" ( if "%~2" == "" ( echo ERROR: RPC expects an expression as argument - goto end + goto end ) - set REL_RPC="%~2" && goto rpc + set "REL_RPC=%~2" + goto rpc ) echo Usage: %~nx0 COMMAND [ARGS] echo. echo The known commands are: echo. - echo start [elixir ^| iex] Starts the system using elixir or iex - echo install Installs this system as a Windows service - echo remote Connects to the running system via a remote shell - echo rpc "EXPR" Executes the given expression remotely on the running system - echo restart Restarts the running system via a remote command - echo stop Stops the running system via a remote command - echo pid Prints the OS PID of the running system via a remote command + echo start Starts the system + echo start_iex Starts the system with IEx attached + echo install Installs this system as a Windows service + echo eval "EXPR" Executes the given expression on a new, non-booted system + echo rpc "EXPR" Executes the given expression remotely on the running system + echo remote Connects to the running system via a remote shell + echo restart Restarts the running system via a remote command + echo stop Stops the running system via a remote command + echo pid Prints the OS PID of the running system via a remote command + echo version Prints the release name and version to be booted echo. if not "%~1" == "" (echo ERROR: Unknown command %~1) goto end :start - if not "%~2" == "" (set REL_EXEC=%~2) else (set REL_EXEC=elixir) - "!REL_VSN_DIR!/!REL_EXEC!.bat" --no-halt ^ - --werl --name "!RELEASE_NODE!" --cookie "!RELEASE_COOKIE!" ^ + "!REL_VSN_DIR!/!REL_EXEC!.bat" !REL_EXTRA! ^ + --name "!RELEASE_NODE!" --cookie "!RELEASE_COOKIE!" ^ --erl-config "!REL_VSN_DIR!\sys" ^ --boot "!REL_VSN_DIR!\start" ^ --boot-var RELEASE_LIB "!RELEASE_ROOT!\lib" ^ --vm-args "!REL_VSN_DIR!\vm.args" goto end + :eval + "!REL_VSN_DIR!/elixir.bat" ^ + --eval "%~2" ^ + --cookie "!RELEASE_COOKIE!" ^ + --erl-config "!REL_VSN_DIR!\sys" ^ + --boot "!REL_VSN_DIR!\start_clean" ^ + --boot-var RELEASE_LIB "!RELEASE_ROOT!\lib" ^ + --vm-args "!REL_VSN_DIR!\vm.args" + goto end + :remote "!REL_VSN_DIR!/iex.bat" ^ --werl --hidden --name "remote-!RANDOM!@127.0.0.1" --cookie "!RELEASE_COOKIE!" ^ @@ -1030,7 +1100,11 @@ defmodule Mix.Tasks.Release do --hidden --name "rpc-!RANDOM!@127.0.0.1" --cookie "!RELEASE_COOKIE!" ^ --boot "!REL_VSN_DIR!\start_clean" ^ --boot-var RELEASE_LIB "!RELEASE_ROOT!\lib" ^ - --rpc-eval "!RELEASE_NODE!" !REL_RPC! + --rpc-eval "!RELEASE_NODE!" "!REL_RPC!" + goto end + + :version + echo !RELEASE_NAME! !RELEASE_VSN! goto end :install diff --git a/lib/mix/test/fixtures/release_test/lib/release_test.ex b/lib/mix/test/fixtures/release_test/lib/release_test.ex index ac8744a33..d47527c7c 100644 --- a/lib/mix/test/fixtures/release_test/lib/release_test.ex +++ b/lib/mix/test/fixtures/release_test/lib/release_test.ex @@ -12,7 +12,6 @@ defmodule ReleaseTest do release_node: System.get_env("RELEASE_NODE"), release_vsn: System.get_env("RELEASE_VSN"), cookie_env: cookie, - cookie_node: wait_until_connected(String.to_atom(cookie)), node: node(), root_dir: :code.root_dir() |> to_string(), static_config: Application.fetch_env!(:release_test, :static) @@ -28,14 +27,6 @@ defmodule ReleaseTest do end end - def wait_until_connected(cookie) do - if Node.get_cookie() == cookie do - cookie - else - wait_until_connected(cookie) - end - end - def hello_world do IO.puts("hello world") end diff --git a/lib/mix/test/mix/tasks/release_test.exs b/lib/mix/test/mix/tasks/release_test.exs index dc9810260..27c831042 100644 --- a/lib/mix/test/mix/tasks/release_test.exs +++ b/lib/mix/test/mix/tasks/release_test.exs @@ -33,16 +33,14 @@ defmodule Mix.Tasks.ReleaseTest do |> File.read_link() |> elem(0) == :error - cookie_string = File.read!(Path.join(root, "releases/COOKIE")) - cookie_atom = String.to_atom(cookie_string) + cookie = File.read!(Path.join(root, "releases/COOKIE")) # Assert runtime open_port(Path.join(root, "bin/start")) assert %{ app_dir: app_dir, - cookie_env: ^cookie_string, - cookie_node: ^cookie_atom, + cookie_env: ^cookie, node: :"release_test@127.0.0.1", protocols_consolidated?: true, release_name: "release_test", @@ -94,7 +92,6 @@ defmodule Mix.Tasks.ReleaseTest do assert %{ app_dir: app_dir, cookie_env: "abcdefghijk", - cookie_node: :abcdefghijk, node: :"demo@127.0.0.1", protocols_consolidated?: true, release_name: "demo", @@ -138,6 +135,39 @@ defmodule Mix.Tasks.ReleaseTest do end) end + test "runs eval and version commands" do + in_fixture("release_test", fn -> + config = [releases: [eval: [include_erts: false, cookie: "abcdefghij"]]] + + Mix.Project.in_project(:release_test, ".", config, fn _ -> + root = Path.absname("_build/dev/rel/eval") + Mix.Task.run("release") + + script = Path.join(root, "bin/eval") + {version, 0} = System.cmd(script, ["version"]) + assert String.trim_trailing(version) == "eval 0.1.0" + refute File.exists?(Path.join(root, "RELEASE_BOOTED")) + + {hello_world, 0} = System.cmd(script, ["eval", ~s[IO.puts :hello_world]]) + assert String.trim_trailing(hello_world) == "hello_world" + refute File.exists?(Path.join(root, "RELEASE_BOOTED")) + + open_port(script, ['eval', 'Application.ensure_all_started(:release_test)']) + + assert %{ + cookie_env: "abcdefghij", + node: :nonode@nohost, + protocols_consolidated?: true, + release_name: "eval", + release_node: "eval@127.0.0.1", + release_root: root, + release_vsn: "0.1.0", + static_config: :was_set + } = wait_until_evaled(Path.join(root, "RELEASE_BOOTED")) + end) + end) + end + @tag :unix test "runs in daemon mode" do in_fixture("release_test", fn -> @@ -148,12 +178,11 @@ defmodule Mix.Tasks.ReleaseTest do Mix.Task.run("release") script = Path.join(root, "bin/permanent2") - open_port(script, ['daemon', 'iex']) + open_port(script, ['daemon_iex']) assert wait_until_evaled(Path.join(root, "RELEASE_BOOTED")) == %{ app_dir: Path.join(root, "lib/release_test-0.1.0"), cookie_env: "abcdefghij", - cookie_node: :abcdefghij, node: :"permanent2@127.0.0.1", protocols_consolidated?: true, release_name: "permanent2", |