Class: Grit::Process

Inherits:
Object
  • Object
show all
Defined in:
lib/grit/jruby.rb,
lib/grit/process.rb

Overview

Grit::Process includes logic for executing child processes and reading/writing from their standard input, output, and error streams.

Create an run a process to completion:

>> process = Grit::Process.new(['git', '--help'])

Retrieve stdout or stderr output:

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

Check process exit status information:

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

Grit::Process is designed to take all input in a single string and provides all output as single strings. It is therefore not well suited to streaming large quantities of data in and out of commands.

Q: Why not use popen3 or hand-roll fork/exec code?

  • 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's more portable than hand rolled pipe, fork, exec code because fork(2) and exec(2) aren't available on all platforms. In those cases, Grit::Process falls back to using whatever janky substitutes the platform provides.

  • It handles all max pipe buffer hang cases, which is non trivial to implement correctly and must be accounted for with either popen3 or hand rolled fork/exec code.

Defined Under Namespace

Classes: FakeStatus, MaximumOutputExceeded, TimeoutExceeded

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(argv, env = {}, options = {}) ⇒ Process

Create and execute a new process.

argv - Array of [command, arg1, …] strings to use as the new

process's argv. When argv is a String, the shell is used
to interpret the command.

env - The new process's environment variables. This is merged with

the current environment as if by ENV.merge(env).

options - Additional options:

  :input   => str to write str to the process's stdin.
  :timeout => int number of seconds before we given up.
  :max     => total number of output bytes
A subset of Process:spawn options are also supported on all
platforms:
  :chdir => str to start the process in different working dir.

Returns a new Process instance that has already executed to completion. The out, err, and status attributes are immediately available.


58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/grit/process.rb', line 58

def initialize(argv, env={}, options={})
  @argv = argv
  @env = env

  @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.


75
76
77
# File 'lib/grit/process.rb', line 75

def err
  @err
end

#outObject (readonly)

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


72
73
74
# File 'lib/grit/process.rb', line 72

def out
  @out
end

#runtimeObject (readonly)

Total command execution time (wall-clock time)


81
82
83
# File 'lib/grit/process.rb', line 81

def runtime
  @runtime
end

#statusObject (readonly)

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


78
79
80
# File 'lib/grit/process.rb', line 78

def status
  @status
end

Instance Method Details

#success?Boolean

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

Returns:

  • (Boolean)

84
85
86
# File 'lib/grit/process.rb', line 84

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