class ProcessExecuter::Runner


@api public
This class is used internally by {ProcessExecuter.run}.
- Raise detailed exceptions for common command failures, such as timeouts or subprocess errors.
- Process command results, including logging and error handling.
- Run commands (‘call`) with options for capturing output, handling timeouts, and merging stdout/stderr.
It does the following:
The `Runner` class executes subprocess commands and captures their status and output.

def call(command, options)

Returns:
  • (ProcessExecuter::Result) - The result of the completed subprocess

Parameters:
  • options (ProcessExecuter::Options::RunOptions) -- Options for running the command
  • command (Array) -- The command to run
def call(command, options)
  spawn(command, options).tap { |result| process_result(result) }
end

def log_result(result)

Other tags:
    Api: - private

Returns:
  • (void) -

Parameters:
  • result (ProcessExecuter::Result) -- the result of the command including
def log_result(result)
  result.options.logger.info { "#{result.command} exited with status #{result}" }
  result.options.logger.debug { "stdout:\n#{result.stdout.inspect}\nstderr:\n#{result.stderr.inspect}" }
end

def process_result(result)

Other tags:
    Api: - private

Raises:
  • (ProcessExecuter::Error) - if the command could not be executed or failed

Returns:
  • (Void) -

Parameters:
  • result (ProcessExecuter::Result) -- The result of the command
def process_result(result)
  log_result(result)
  raise_errors(result) if result.options.raise_errors
end

def raise_errors(result)

Other tags:
    Api: - private

Raises:
  • (ProcessExecuter::TimeoutError) - If the command times out
  • (ProcessExecuter::SignaledError) - If the command was signaled
  • (ProcessExecuter::FailedError) - If the command failed

Returns:
  • (void) -
def raise_errors(result)
  raise TimeoutError, result if result.timed_out?
  raise SignaledError, result if result.signaled?
  raise FailedError, result unless result.success?
end

def raise_pipe_error(command, option_key, pipe)

Other tags:
    Api: - private

Returns:
  • (void) - This method always raises an error

Raises:
  • (ProcessExecuter::ProcessIOError) -

Parameters:
  • pipe (ProcessExecuter::MonitoredPipe) -- The pipe that raised the exception
  • option_key (Symbol) -- The name of the pipe that raised the exception
  • command (Array) -- The command that was executed
def raise_pipe_error(command, option_key, pipe)
  return unless pipe.exception
  error = ProcessExecuter::ProcessIOError.new("Pipe Exception for #{command}: #{option_key.inspect}")
  raise(error, cause: pipe.exception)
end

def should_wrap?(options, key, value)

Other tags:
    Api: - private

Returns:
  • (Boolean) - Whether the option should be wrapped

Parameters:
  • value (Object) -- The option value
  • key (Object) -- The option key
def should_wrap?(options, key, value)
  (options.stdout_redirection?(key) || options.stderr_redirection?(key)) &&
    ProcessExecuter::Destinations.compatible_with_monitored_pipe?(value)
end

def spawn(command, options)

Other tags:
    Api: - private

Returns:
  • (ProcessExecuter::Result) - The result of the completed subprocess

Raises:
  • (ProcessExecuter::Error) - if the command could not be executed or failed

Parameters:
  • options (ProcessExecuter::Options::RunOptions) -- Options for running the command
  • command (Array) -- The command to execute
def spawn(command, options)
  opened_pipes = wrap_stdout_stderr(options)
  ProcessExecuter.spawn_and_wait_with_options(command, options)
ensure
  opened_pipes.each_value(&:close)
  opened_pipes.each { |option_key, pipe| raise_pipe_error(command, option_key, pipe) }
end

def wrap_stdout_stderr(options)

Other tags:
    Api: - private

Returns:
  • (Hash) - The opened pipes (the Object is the option key)

Parameters:
  • options (ProcessExecuter::Options::RunOptions) -- Options for running the command
def wrap_stdout_stderr(options)
  options.each_with_object({}) do |key_value, opened_pipes|
    key, value = key_value
    next unless should_wrap?(options, key, value)
    wrapped_destination = ProcessExecuter::MonitoredPipe.new(value)
    opened_pipes[key] = wrapped_destination
    options.merge!(key => wrapped_destination)
  end
end