philiprehberger-task_runner
Shell command runner with output capture, timeout, streaming, signal handling, and stdin piping
Requirements
- Ruby >= 3.1
Installation
Add to your Gemfile:
gem "philiprehberger-task_runner"
Or install directly:
gem install philiprehberger-task_runner
Usage
require "philiprehberger/task_runner"
result = Philiprehberger::TaskRunner.run('ls', '-la')
puts result.stdout
puts result.exit_code # => 0
puts result.success? # => true
puts result.duration # => 0.012
Raising on Failure
# Raises CommandError if the command exits non-zero
result = Philiprehberger::TaskRunner.run!('make', 'build')
# The error includes the full Result for inspection
begin
Philiprehberger::TaskRunner.run!('false')
rescue Philiprehberger::TaskRunner::CommandError => e
puts e. # => "command exited with code 1"
puts e.result.stderr # => captured stderr
end
Timeout
result = Philiprehberger::TaskRunner.run('long-process', timeout: 30)
Environment Variables and Working Directory
result = Philiprehberger::TaskRunner.run(
'make', 'build',
env: { 'DEBUG' => '1' },
chdir: '/path/to/project'
)
Signal Handling
result = Philiprehberger::TaskRunner.run(
'long-process',
timeout: 30,
signal: :TERM,
kill_after: 5
)
# On timeout: sends SIGTERM first, then SIGKILL after 5 seconds if still running
# result.signal reports which signal killed the process (:TERM, :KILL, or nil)
Input Piping
result = Philiprehberger::TaskRunner.run('cat', stdin: "hello world")
puts result.stdout # => "hello world"
# Also accepts IO objects
result = Philiprehberger::TaskRunner.run('wc', '-l', stdin: File.open('data.txt'))
Streaming Output
Philiprehberger::TaskRunner.run('tail', '-f', '/var/log/app.log', timeout: 10) do |line|
puts ">> #{line}"
end
Stderr Streaming
Philiprehberger::TaskRunner.run('make', 'build') do |line, stream|
case stream
when :stdout then puts "OUT: #{line}"
when :stderr then puts "ERR: #{line}"
end
end
API
| Method / Class | Description |
|---|---|
.run(cmd, *args, timeout:, env:, chdir:, signal:, kill_after:, stdin:) |
Run a command and return a Result |
.run!(cmd, *args, **opts) |
Same as run, raises CommandError on non-zero exit |
CommandError#result |
The failed Result object |
| `.run(cmd) { \ | line\ |
| `.run(cmd) { \ | line, stream\ |
Result#stdout |
Captured standard output |
Result#stderr |
Captured standard error |
Result#exit_code |
Process exit code |
Result#success? |
Whether exit code is 0 |
Result#failure? |
Logical inverse of #success? |
Result#duration |
Execution time in seconds |
Result#signal |
Signal that killed the process (:TERM, :KILL, or nil) |
Result#timed_out? |
Whether the process was killed for exceeding its timeout |
Result#to_h |
Hash representation of the result (includes :success and :timed_out) |
Development
bundle install
bundle exec rspec
bundle exec rubocop
Support
If you find this project useful: