FFix.Runner (ffix v0.1.0)

Copy Markdown View Source

Thin execution layer for %FFix.Command{} values or raw argv lists.

The core library models commands as data. FFix.Runner is the boundary that starts an OS process and turns stdout, stderr, logs, progress, and exit status into Elixir data.

Collected Execution

{:ok, result} =
  FFix.run(command,
    stdout: :discard,
    stderr: :collect
  )

result.exit_status
result.stderr

run/2 returns {:ok, result} for exit status 0 and {:error, error} for non-zero exits or spawn failures. run!/2 returns the result or raises FFix.Runner.Error.

Streaming Events

FFix.stream(command, progress: true, stderr: :collect)
|> Enum.each(fn
  {:log, log} -> IO.puts("[#{log.level}] #{log.message}")
  {:progress, progress} -> IO.inspect(progress.status)
  {:exit, result} -> IO.inspect(result.exit_status)
  _event -> :ok
end)

stream/2 is lazy and emits:

  • {:start, info}
  • {:stdout, chunk}
  • {:stderr, chunk}
  • {:log, %FFix.Runner.Log{}}
  • {:progress, %FFix.Runner.Progress{}}
  • {:exit, %FFix.Runner.Result{}}

When running ffmpeg, the runner prepends a few quiet-by-default execution flags:

  • -hide_banner
  • -nostats
  • -loglevel level+warning

Later command options still win, so callers can override log level or stats in the command itself.

Summary

Collected execution

Runs a command and returns a collected result tuple.

Runs a command and raises FFix.Runner.Error on spawn failure or non-zero exit.

Streaming execution

Runs a command as a lazy event stream.

Runs a command as a lazy event stream and raises on non-zero exit.

Collected execution

run(command, options \\ [])

@spec run(FFix.Command.t() | [String.t(), ...], [option()]) ::
  {:ok, FFix.Runner.Result.t()} | {:error, FFix.Runner.Error.t()}

Runs a command and returns a collected result tuple.

Options:

  • :stdin - enumerable input for process stdin
  • :stdout - :discard or :collect
  • :stderr - :discard, :collect, or {:tail, bytes}
  • :progress - when true, adds -progress pipe:2 for ffmpeg commands
  • :on_event - callback invoked with each emitted event

By default stdout is discarded and only the trailing stderr is kept.

FFix.run(command, stderr: :collect)

run!(command, options \\ [])

@spec run!(FFix.Command.t() | [String.t(), ...], [option()]) :: FFix.Runner.Result.t()

Runs a command and raises FFix.Runner.Error on spawn failure or non-zero exit.

Streaming execution

stream(command, options \\ [])

@spec stream(FFix.Command.t() | [String.t(), ...], [option()]) :: term()

Runs a command as a lazy event stream.

This is useful for progress reporting, log streaming, or large stdout streams that should not be collected into memory.

FFix.stream(command, progress: true, stdout: :collect)
|> Enum.each(fn
  {:stdout, chunk} -> IO.binwrite(chunk)
  {:progress, progress} -> IO.inspect(progress.frame)
  {:exit, result} -> IO.inspect(result.exit_status)
  _event -> :ok
end)

stream!(command, options \\ [])

@spec stream!(FFix.Command.t() | [String.t(), ...], [option()]) :: term()

Runs a command as a lazy event stream and raises on non-zero exit.

Types

event()

@type event() ::
  {:start,
   %{command: FFix.Command.t() | nil, argv: [String.t()], shell: String.t()}}
  | {:stdout, binary()}
  | {:stderr, binary()}
  | {:log, FFix.Runner.Log.t()}
  | {:progress, FFix.Runner.Progress.t()}
  | {:exit, FFix.Runner.Result.t()}

option()

@type option() ::
  {:stdin, stdin_source()}
  | {:stdout, stdout_mode()}
  | {:stderr, stderr_mode()}
  | {:progress, boolean()}
  | {:on_event, (event() -> any())}

stderr_mode()

@type stderr_mode() :: :discard | :collect | {:tail, pos_integer()}

stdin_source()

@type stdin_source() :: Enumerable.t() | (Collectable.t() -> any())

stdout_mode()

@type stdout_mode() :: :discard | :collect