Packages

Execution Plane process launch, stdio, PTY, and process-session runtime.

Current section

Files

Jump to
execution_plane_process lib execution_plane process transport run_options.ex
Raw

lib/execution_plane/process/transport/run_options.ex

defmodule ExecutionPlane.Process.Transport.RunOptions do
@moduledoc """
Validated options for synchronous non-PTY command execution.
"""
alias ExecutionPlane.Command
alias ExecutionPlane.Process.OS
@default_timeout_ms 30_000
@default_os OS
@enforce_keys [:command]
defstruct command: nil,
stdin: nil,
timeout: @default_timeout_ms,
stderr: :separate,
close_stdin: true,
os: @default_os
@type stderr_mode :: :separate | :stdout
@type t :: %__MODULE__{
command: Command.t(),
stdin: term(),
timeout: timeout(),
stderr: stderr_mode(),
close_stdin: boolean(),
os: module()
}
@type validation_error ::
{:invalid_command, term()}
| {:invalid_args, term()}
| {:invalid_cwd, term()}
| {:invalid_env, term()}
| {:invalid_clear_env, term()}
| {:invalid_user, term()}
| {:invalid_timeout, term()}
| {:invalid_stderr, term()}
| {:invalid_close_stdin, term()}
| {:invalid_os, term()}
@doc """
Builds validated run options for the raw transport command lane.
"""
@spec new(Command.t(), keyword()) ::
{:ok, t()} | {:error, {:invalid_run_options, validation_error()}}
def new(%Command{} = command, opts \\ []) when is_list(opts) do
normalized = %{
command: command,
stdin: Keyword.get(opts, :stdin),
timeout: Keyword.get(opts, :timeout, @default_timeout_ms),
stderr: Keyword.get(opts, :stderr, :separate),
close_stdin: Keyword.get(opts, :close_stdin, true),
os: Keyword.get(opts, :os, @default_os)
}
with :ok <- Command.validate(command),
:ok <- validate_timeout(normalized.timeout),
:ok <- validate_stderr(normalized.stderr),
:ok <- validate_close_stdin(normalized.close_stdin),
:ok <- validate_os(normalized.os) do
{:ok, struct!(__MODULE__, normalized)}
else
{:error, reason} -> {:error, {:invalid_run_options, reason}}
end
end
@doc """
Returns the default synchronous command timeout in milliseconds.
"""
@spec default_timeout_ms() :: 30_000
def default_timeout_ms, do: @default_timeout_ms
defp validate_timeout(:infinity), do: :ok
defp validate_timeout(timeout) when is_integer(timeout) and timeout >= 0, do: :ok
defp validate_timeout(timeout), do: {:error, {:invalid_timeout, timeout}}
defp validate_stderr(mode) when mode in [:separate, :stdout], do: :ok
defp validate_stderr(mode), do: {:error, {:invalid_stderr, mode}}
defp validate_close_stdin(value) when is_boolean(value), do: :ok
defp validate_close_stdin(value), do: {:error, {:invalid_close_stdin, value}}
defp validate_os(module) when is_atom(module) do
if OS.valid_boundary?(module) do
:ok
else
{:error, {:invalid_os, module}}
end
end
defp validate_os(module), do: {:error, {:invalid_os, module}}
end