Reputation: 2819
I want to execute a system command (git clone) and stream the output to the user through a channel in Phoenix?
Can I somehow make System.cmd stream the results instead of waiting until it's done?
Or, can I write the output to a file and stream the content from there, as it's being appended?
Upvotes: 6
Views: 3014
Reputation: 1430
If you don't want to use Porcelain, which has a go executable dependency, you can use port, like so:
def long do
port = Port.open({:spawn_executable, /path/to/command"}, [:stderr_to_stdout, :binary, :exit_status, args: ["arg1"]])
stream_output(port)
end
defp stream_output(port) do
receive do
{^port, {:data, data}} ->
Logger.info(data) # send to phoenix channel
stream_output(port)
{^port, {:exit_status, 0}} ->
Logger.info("Command success")
{^port, {:exit_status, status}} ->
Logger.info("Command error, status #{status}")
end
end
Upvotes: 3
Reputation: 18080
It is possible to override output with:
System.cmd "git", ["clone", "YOUR_GIT"], into: IO.stream(:stdio, :line)
Result:
Cloning into 'YOUR_GIT'... remote: Counting objects: 1665, done. remote: Compressing objects: 0% (1/979) remote: Compressing objects: 100% (979/979), done. Receiving objects: 0% (1/166remote: Total 1665 (delta 855), reused 1331 (delta 597) Receiving objects: 92% (Receiving objects: 100% (1665/1665), 5.25 MiB | 376.00 KiB/s, done. Resolving delResolving deltas: 100% (855/855), done. Checking connectivity... done.
{%IO.Stream{device: :standard_io, line_or_bytes: :line, raw: false}, 0}
To help you achieve your specific task, redirecting the local standard stream into external one, there's a library porcelain, which handles it perfectly.
Upvotes: 3
Reputation: 1462
I would advice on using Porcelain for this. Specifically check https://github.com/alco/porcelain#messages.
You can use Porcelain.spawn_shell
to run your command with the out: {:send, self()}
option and implement matching handle_info
callbacks.
Upvotes: 3