In Files

Parent

Class Index [+]

Quicksearch

Subexec

# Subexec

## Description

Subexec is a simple library that spawns an external command with an optional timeout parameter. It relies on Ruby 1.9’s Process.spawn method. Also, it works with synchronous and asynchronous code.

Useful for libraries that are Ruby wrappers for CLI’s. For example, resizing images with ImageMagick’s mogrify command sometimes stalls and never returns control back to the original process. Subexec executes mogrify and preempts if it gets lost.

## Usage

# Print hello sub = Subexec.run “echo ‘hello’ && sleep 3”, :timeout => 5 puts sub.output # returns: hello puts sub.exitstatus # returns: 0

# Timeout process after a second sub = Subexec.run “echo ‘hello’ && sleep 3”, :timeout => 1 puts sub.output # returns: puts sub.exitstatus # returns:

Constants

VERSION

Attributes

pid[RW]
command[RW]
lang[RW]
output[RW]
exitstatus[RW]
timeout[RW]
log_file[RW]

Public Class Methods

new(command, options={}) click to toggle source
    # File lib/subexec.rb, line 45
45:   def initialize(command, options={})
46:     self.command    = command
47:     self.lang       = options[:lang]      || "C"
48:     self.timeout    = options[:timeout]   || 1     # default is to never timeout
49:     self.log_file   = options[:log_file]
50:     self.exitstatus = 0
51:   end
run(command, options={}) click to toggle source
    # File lib/subexec.rb, line 39
39:   def self.run(command, options={})
40:     sub = new(command, options)
41:     sub.run!
42:     sub
43:   end

Public Instance Methods

run!() click to toggle source
    # File lib/subexec.rb, line 53
53:   def run!
54:     if RUBY_VERSION >= '1.9' && RUBY_ENGINE != 'jruby'
55:       spawn
56:     else
57:       exec
58:     end
59:   end

Private Instance Methods

exec() click to toggle source
     # File lib/subexec.rb, line 116
116:     def exec
117:       if !(RUBY_PLATFORM =~ /win32|mswin|mingw/).nil?
118:         self.output = `set LANG=#{lang} && #{command} 2>&1`
119:       else
120:         self.output = `LANG=#{lang} && export $LANG && #{command} 2>&1`
121:       end
122:       self.exitstatus = $?.exitstatus
123:     end
spawn() click to toggle source
     # File lib/subexec.rb, line 64
 64:     def spawn
 65:       # TODO: weak implementation for log_file support.
 66:       # Ideally, the data would be piped through to both descriptors
 67:       r, w = IO.pipe      
 68:       if !log_file.nil?
 69:         self.pid = Process.spawn({'LANG' => self.lang}, command, [:out, :err] => [log_file, 'a'])
 70:       else
 71:         self.pid = Process.spawn({'LANG' => self.lang}, command, STDERR=>w, STDOUT=>w)
 72:       end
 73:       w.close
 74:       
 75:       @timer = Time.now + timeout
 76:       timed_out = false
 77: 
 78:       waitpid = Proc.new do
 79:         begin
 80:           flags = (timeout > 0 ? Process::WUNTRACED|Process::WNOHANG : 0)
 81:           Process.waitpid(pid, flags)
 82:         rescue Errno::ECHILD
 83:           break
 84:         end
 85:       end
 86: 
 87:       if timeout > 0
 88:         loop do
 89:           ret = waitpid.call
 90: 
 91:           break if ret == pid
 92:           sleep 0.01
 93:           if Time.now > @timer
 94:             timed_out = true
 95:             break
 96:           end
 97:         end
 98:       else
 99:         waitpid.call
100:       end
101: 
102:       if timed_out
103:         # The subprocess timed out -- kill it
104:         Process.kill(9, pid) rescue Errno::ESRCH
105:         self.exitstatus = nil
106:       else
107:         # The subprocess exited on its own
108:         self.exitstatus = $?.exitstatus
109:         self.output = r.readlines.join("")
110:       end
111:       r.close
112:       
113:       self
114:     end

Disabled; run with --debug to generate this.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.