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)
-
(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)
- 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)
- 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)
- 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)
- 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)
- 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)
- 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)
- 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