alco / porcelain

Work with external processes like a boss

Home Page:http://hexdocs.pm/porcelain

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Porcelain.exec does not capture stderr output

markmark206 opened this issue · comments

stderr output produced by the process invoked via Porcelain.exec is not captured into result (printed by the program instead).

Repro info:

  1. External program, prints to stderr:
15:20:55 markmark ~$ cat mine_err.sh
#!/usr/bin/env bash
echo "mine stderr" 1>&2
15:23:39 markmark ~$ ./mine_err.sh
mine stderr

(if attempting a repro, please make sure to chmod +x mine_err.sh)

  1. Elixir code:
r = Porcelain.exec("/Users/markmark/mine_err.sh", [])
IO.inspect r
  1. Elixir output:
mine stderr
%Porcelain.Result{err: nil, out: "", status: 0}

^^^^ Note: mine stderr was printed by the program, but not included in Result.


For comparison, when the external program outputs to stdout, things work as expected:

  • external program, prints to stdout:
15:17:43 markmark  ~$ cat mine.sh
#!/usr/bin/env bash
echo "mine stdout"
15:20:23 markmark  ~$ ./mine.sh
mine stdout
  • elixir code:
r = Porcelain.exec("/Users/markmark/mine.sh", [])
IO.inspect r
  • elixir output (stdout text captured in out, as expected):
%Porcelain.Result{err: nil, out: "mine stdout\n", status: 0}

Same for spawn_shell;

%Proc{pid: pid, out: {:send, out_pid}, err: {:send, err_pid}} = Porcelain.spawn_shell(command, out: {:send, self()}, err: {:send, self()})
IO.puts "out pid is #{inspect out_pid}, err pid is #{inspect err_pid}"
# out pid is #PID<0.177.0>, err pid is #PID<0.177.0>

I can write a full example with receive etc, but the problem is the same as @markmark206's.
In my case, I'm processing the output with GenServer.handle_info/2;

  def handle_info({pid, :data, :out, data}, state) do
    # do things with pid
    IO.puts data
    {:noreply, state}
  end

  @doc false
  def handle_info({_pid, :data, :err, data}, state) do
    IO.puts "ERROR: #{data}"
    {:noreply, state}
  end

The :out messages are being processed, while the err ones aren't.
The stderr ones are being just printed to screen, same as OPs description.

Also, thanks for all the work :)

EDIT: sorry for that! Reading the docs again, I see that :err is not supported for {:send, <pid>} using the basic driver.

markmark206, I think that is how it is intended to work, and Elixir's System.cmd does the same. See ":err – specify the way stderr will be passed back to Elixir." https://hexdocs.pm/porcelain/Porcelain.html