Skip to content

Commit 1c7d667

Browse files
author
Robert Adams
committed
Pipe node eval result to IO.inspect
1 parent 0f162e3 commit 1c7d667

File tree

7 files changed

+161
-5
lines changed

7 files changed

+161
-5
lines changed

docs/extensibility/release_tasks.md

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
Once your release is built, you can execute a number of helpful commands from the entry script.
2+
3+
If you've built a release for `#!elixir :myapp`, you can run `bin/myapp` to see the full list of commands.
4+
5+
## Release tasks
6+
7+
| Task | Description |
8+
|:--------------------|:--------------------------------------------------------------------------------|
9+
| start | Start myapp as a daemon |
10+
| start_boot <file> | Start myapp as a daemon, but supply a custom .boot file |
11+
| foreground | Start myapp in the foreground<br>This is similar to running `mix run --no-halt` |
12+
| console | Start myapp with a console attached<br>This is similar to running `iex -S mix` |
13+
| console_clean | Start a console with code paths set but no apps loaded/started |
14+
| console_boot <file> | Start myapp with a console attached, but supply a custom .boot file |
15+
| stop | Stop the myapp daemon |
16+
| restart | Restart the myapp daemon without shutting down the VM |
17+
| reboot | Restart the myapp daemon |
18+
| upgrade <version> | Upgrade myapp to <version> |
19+
| downgrade <version> | Downgrade myapp to <version> |
20+
| attach | Attach the current TTY to myapp's console |
21+
| remote_console | Remote shell to myapp's console |
22+
| reload_config | Reload the current system's configuration from disk |
23+
| pid | Get the pid of the running myapp instance |
24+
| ping | Checks if myapp is running, pong is returned if successful |
25+
| pingpeer <peer> | Check if a peer node is running, pong is returned if successful |
26+
| escript | Execute an escript |
27+
| rpc | Execute Elixir code on the running node |
28+
| eval | Execute Elixir code locally |
29+
| describe | Print useful information about the myapp release |
30+
31+
## Running code in releases
32+
33+
Distillery comes with two very useful tasks for working with your release.
34+
35+
* Both will take some Elixir code and run it for you and show you the result.
36+
* Both tasks use the exact same syntax, the only difference is the context your code is run in.
37+
38+
### Running code with `rpc`
39+
40+
This task executes code on the running node, and is what you'd want to use to interact with your application when _it's already running_.
41+
42+
!!! example "Using Module.fun/arity"
43+
```bash tab="Command"
44+
$ ./bin/myapp rpc --mfa "Application.loaded_applications/0"
45+
```
46+
47+
```elixir tab="Output"
48+
[
49+
{:lz_string,
50+
'Elixir implementation of pieroxy\'s lz-string compression algorithm.',
51+
'0.0.7'},
52+
{:phoenix_html,
53+
...snip
54+
```
55+
56+
??? example "Using Module.fun/arity with arguments"
57+
```bash tab="Commands"
58+
$ ./bin/myapp rpc --mfa "Application.put_env/3" -- myapp token supersecret
59+
$ ./bin/myapp rpc --mfa "Application.get_env/2" -- myapp token
60+
```
61+
62+
```bash tab="Output"
63+
$ ./bin/myapp rpc --mfa "Application.put_env/3" -- myapp token supersecret
64+
:ok
65+
$ ./bin/myapp rpc --mfa "Application.get_env/2" -- myapp token
66+
"supersecret"
67+
```
68+
69+
??? example "Using Module.fun/1 with arguments as a single list"
70+
Here, the `--argv` option can be used to construct a list before passing your arguments to the function specified.
71+
72+
```bash tab="Command"
73+
$ ./bin/myapp rpc --mfa "Enum.join/1" --argv -- foo bar baz
74+
```
75+
76+
```elixir tab="Output"
77+
"foobarbaz"
78+
```
79+
80+
??? example "Using an expression, getting application version"
81+
You can also use an expression, but you'll need to be mindful of shell quoting.
82+
83+
```bash tab="Command"
84+
$ ./bin/myapp rpc 'Application.spec(:myapp, :vsn)'
85+
```
86+
87+
```elixir tab="Output"
88+
'0.0.1'
89+
```
90+
91+
??? example "Using an expression, broadcasting to a Phoenix channel"
92+
```bash
93+
$ ./bin/myapp rpc 'MyappWeb.Endpoint.broadcast!("channel:lobby", "status", %{current_status: "oopsy"})'
94+
```
95+
96+
### Running code with `eval`
97+
98+
This task executes code locally in a clean instance. Although execution will be within the context of your release, no applications will have been started. This is very useful for things like migrations, where you'll want to start only some applications (e.g. Ecto) manually before doing some work.
99+
100+
!!! example "Using Module.fun/arity"
101+
Assuming that you've created a `Myapp.ReleaseTasks` module, you can call it into like so:
102+
```
103+
$ ./bin/myapp eval --mfa 'Myapp.ReleaseTasks.migrate/0'
104+
```
105+
106+
??? example "Using Module.fun/arity with arguments"
107+
Like with `rpc`, arguments can be specified (but are generally treated as strings).
108+
109+
```bash
110+
$ ./bin/myapp eval --mfa 'File.touch/1' -- /tmp/foo
111+
:ok
112+
```
113+
114+
??? example "Using an expression"
115+
Like with `rpc`, an expression can be used.
116+
117+
```bash tab="Command"
118+
$ ./bin/myapp eval 'Timex.Duration.now |> Timex.format_duration(:humanized)'
119+
```
120+
121+
```elixir tab="Output"
122+
"48 years, 10 months, 2 weeks, 2 days, 4 hours, 8 minutes, 52 seconds, 883.16 milliseconds"
123+
```

docs/tooling/cli.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ entry point, i.e. the `bin/myapp` script.
3030

3131
There are numerous tasks available, you have already seen a few of them:
3232

33-
* `foreground` - run the release in the foreground, like `mix run --no-halt`
3433
* `console` - run the release with a shell attached, like `iex -S mix`
3534
* `start` - run the release in the background
3635

@@ -40,4 +39,4 @@ There are a few other important tasks:
4039
* `remote_console` - attach a shell to a running release
4140
* `describe` - print metadata about the release
4241

43-
To see a full listing of tasks available, run `bin/myapp` with no arguments.
42+
To see a full listing of tasks available, run `bin/myapp` with no arguments, or refer to the [Release Tasks](/extensibility/release_tasks.md) reference page.

lib/mix/lib/releases/runtime/control.ex

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -675,7 +675,9 @@ defmodule Mix.Releases.Runtime.Control do
675675
Executes an expression or a file locally (i.e. not on the running node)
676676
"""
677677
def eval(_argv, %{file: file}) do
678-
Code.eval_file(file)
678+
file
679+
|> Code.eval_file()
680+
|> IO.inspect()
679681
rescue
680682
err in [Code.LoadError] ->
681683
Console.error("""
@@ -714,7 +716,9 @@ defmodule Mix.Releases.Runtime.Control do
714716
[argv]
715717
end
716718

717-
apply(module, fun, args)
719+
module
720+
|> apply(fun, args)
721+
|> IO.inspect()
718722

719723
{:ok, [_module, _fun, _arity]} when use_argv? ->
720724
Console.error("""
@@ -736,7 +740,9 @@ defmodule Mix.Releases.Runtime.Control do
736740
but the function has a different arity!
737741
""")
738742
else
739-
apply(module, fun, args)
743+
module
744+
|> apply(fun, args)
745+
|> IO.inspect()
740746
end
741747

742748
{:ok, _parts} ->

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ nav:
6060
- 'Release Plugins': 'extensibility/release_plugins.md'
6161
- 'Config Providers': 'extensibility/config_providers.md'
6262
- 'Custom Commands': 'extensibility/custom_commands.md'
63+
- 'Release Tasks': 'extensibility/release_tasks.md'
6364
- 'Overlays': 'extensibility/overlays.md'
6465
- 'Boot Hooks': 'extensibility/boot_hooks.md'
6566
- 'Shell Scripts': 'extensibility/shell_scripts.md'

test/cases/cli_test.exs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ defmodule Distillery.Test.CliTest do
6363
end) =~ "[\"foo\", \"bar\"]"
6464
end
6565

66+
test "eval --mfa --argv outputs result" do
67+
assert is_success(fn ->
68+
Control.main(["eval", "--mfa", "Enum.join/1", "--argv", "--", "foo", "bar"])
69+
end) =~ "foobar"
70+
end
71+
6672
test "eval --mfa correct args" do
6773
assert is_success(fn ->
6874
Control.main(["eval", "--mfa", "Distillery.Test.Tasks.run/2", "--", "foo", "bar"])
@@ -75,12 +81,24 @@ defmodule Distillery.Test.CliTest do
7581
end) =~ "function has a different arity!"
7682
end
7783

84+
test "eval --mfa outputs result" do
85+
assert is_success(fn ->
86+
Control.main(["eval", "--mfa", "Distillery.Test.Tasks.eval/2", "--", "foo", "bar"])
87+
end) =~ "{\"foo\", \"bar\"}"
88+
end
89+
7890
test "eval --file" do
7991
assert is_success(fn ->
8092
Control.main(["eval", "--file", Path.join([@fixtures_path, "files", "eval_file_example.exs"]) |> Path.expand])
8193
end) =~ "ok from [email protected]\n"
8294
end
8395

96+
test "eval --file outputs result" do
97+
assert is_success(fn ->
98+
Control.main(["eval", "--file", Path.join([@fixtures_path, "files", "eval_file_example_noout.exs"]) |> Path.expand])
99+
end) =~ "{{:ok, \"done\"}, []}\n"
100+
end
101+
84102
test "eval syntax error produces friendly error" do
85103
assert is_failure(fn ->
86104
Control.main(["eval", "div(2, 0)"])
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
defmodule FooTuple do
2+
def do_something, do: {:ok, "done"}
3+
end
4+
5+
FooTuple.do_something

test/support/tasks.ex

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,8 @@ defmodule Distillery.Test.Tasks do
88
def run(arg1, arg2) do
99
IO.inspect(arg1: arg1, arg2: arg2)
1010
end
11+
12+
def eval(arg1, arg2) do
13+
{arg1, arg2}
14+
end
1115
end

0 commit comments

Comments
 (0)