Class: POSIX::Spawn::Child

Inherits:
Object
  • Object
show all
Includes:
POSIX::Spawn
Defined in:
lib/posix/spawn/child.rb

Overview

POSIX::Spawn::Child includes logic for executing child processes and reading/writing from their standard input, output, and error streams. It’s designed to take all input in a single string and provides all output (stderr and stdout) as single strings and is therefore not well-suited to streaming large quantities of data in and out of commands.

Create and run a process to completion:

>> child = POSIX::Spawn::Child.new('git', '--help')

Retrieve stdout or stderr output:

>> child.out
=> "usage: git [--version] [--exec-path[=GIT_EXEC_PATH]]\n ..."
>> child.err
=> ""

Check process exit status information:

>> child.status
=> #<Process::Status: pid=80718,exited(0)>

To write data on the new process’s stdin immediately after spawning:

>> child = POSIX::Spawn::Child.new('bc', :input => '40 + 2')
>> child.out
"42\n"

Q: Why use POSIX::Spawn::Child instead of popen3, hand rolled fork/exec code, or Process::spawn?

  • It’s more efficient than popen3 and provides meaningful process hierarchies because it performs a single fork/exec. (popen3 double forks to avoid needing to collect the exit status and also calls Process::detach which creates a Ruby Thread!!!!).

  • It handles all max pipe buffer (PIPE_BUF) hang cases when reading and writing semi-large amounts of data. This is non-trivial to implement correctly and must be accounted for with popen3, spawn, or hand rolled fork/exec code.

  • It’s more portable than hand rolled pipe, fork, exec code because fork(2) and exec aren’t available on all platforms. In those cases, POSIX::Spawn::Child falls back to using whatever janky substitutes the platform provides.

Constant Summary

Constants included from POSIX::Spawn

VERSION

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from POSIX::Spawn

#_pspawn, #`, #fspawn, #popen4, #pspawn, #spawn, #system

Constructor Details

#initialize(*args) ⇒ Child

Spawn a new process, write all input and read all output, and wait for the program to exit. Supports the standard spawn interface as described in the POSIX::Spawn module documentation:

new([env], command, [argv1, ...], [options])

The following options are supported in addition to the standard POSIX::Spawn options:

:input   => str      Write str to the new process's standard input.
:timeout => int      Maximum number of seconds to allow the process
                     to execute before aborting with a TimeoutExceeded
                     exception.
:max     => total    Maximum number of bytes of output to allow the
                     process to generate before aborting with a
                     MaximumOutputExceeded exception.

Returns a new Child instance whose underlying process has already executed to completion. The out, err, and status attributes are immediately available.



73
74
75
76
77
78
79
80
81
# File 'lib/posix/spawn/child.rb', line 73

def initialize(*args)
  @env, @argv, options = extract_process_spawn_arguments(*args)
  @options = options.dup
  @input = @options.delete(:input)
  @timeout = @options.delete(:timeout)
  @max = @options.delete(:max)
  @options.delete(:chdir) if @options[:chdir].nil?
  exec!
end

Instance Attribute Details

#errObject (readonly)

All data written to the child process’s stderr stream as a String.



87
88
89
# File 'lib/posix/spawn/child.rb', line 87

def err
  @err
end

#outObject (readonly)

All data written to the child process’s stdout stream as a String.



84
85
86
# File 'lib/posix/spawn/child.rb', line 84

def out
  @out
end

#runtimeObject (readonly)

Total command execution time (wall-clock time)



93
94
95
# File 'lib/posix/spawn/child.rb', line 93

def runtime
  @runtime
end

#statusObject (readonly)

A Process::Status object with information on how the child exited.



90
91
92
# File 'lib/posix/spawn/child.rb', line 90

def status
  @status
end

Instance Method Details

#success?Boolean

Determine if the process did exit with a zero exit status.

Returns:

  • (Boolean)


96
97
98
# File 'lib/posix/spawn/child.rb', line 96

def success?
  @status && @status.success?
end