Module: Open4

Defined in:
lib/open4.rb,
lib/open4-0.4.0.rb

Defined Under Namespace

Classes: Error, SpawnError

Class Method Summary collapse

Class Method Details

.background(cmd, opts = {}) ⇒ Object



155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/open4.rb', line 155

def background cmd, opts = {}
#--{{{
  require 'thread'
  q = Queue.new
  opts['pid'] = opts[:pid] = q
  thread = Thread.new(cmd, opts){|cmd, opts| spawn cmd, opts}
  pid = q.pop
  sc = class << thread; self; end
  sc.module_eval {
    define_method(:pid){ pid }
    define_method(:spawn_status){ @spawn_status ||= value }
    define_method(:exitstatus){ spawn_status.exitstatus }
  }
  thread
#--}}}
end

.bgObject

–}}}



171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/open4.rb', line 171

def background cmd, opts = {}
#--{{{
  require 'thread'
  q = Queue.new
  opts['pid'] = opts[:pid] = q
  thread = Thread.new(cmd, opts){|cmd, opts| spawn cmd, opts}
  pid = q.pop
  sc = class << thread; self; end
  sc.module_eval {
    define_method(:pid){ pid }
    define_method(:spawn_status){ @spawn_status ||= value }
    define_method(:exitstatus){ spawn_status.exitstatus }
  }
  thread
#--}}}
end

.open4Object

–}}}



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/open4.rb', line 72

def popen4(*cmd)
#--{{{
  pw, pr, pe, ps = IO.pipe, IO.pipe, IO.pipe, IO.pipe

  verbose = $VERBOSE
  begin
    $VERBOSE = nil
    ps.last.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)

    cid = fork {
      pw.last.close
      STDIN.reopen pw.first
      pw.first.close

      pr.first.close
      STDOUT.reopen pr.last
      pr.last.close

      pe.first.close
      STDERR.reopen pe.last
      pe.last.close

      STDOUT.sync = STDERR.sync = true

      begin
        exec(*cmd)
        raise "exec failed!"
      rescue Exception => e
        Marshal.dump(e, ps.last)
        ps.last.flush
      end
      ps.last.close unless (ps.last.closed?)
      exit!
    }
  ensure
    $VERBOSE = verbose
  end

  [pw.first, pr.last, pe.last, ps.last].each{|fd| fd.close}

  begin
    e = Marshal.load ps.first
    raise(Exception === e ? e : "unknown failure!")
  rescue EOFError # If we get an EOF error, then the exec was successful
    42
  end

  pw.last.sync = true

  pi = [pw.last, pr.first, pe.first]

  if defined? yield
    begin
      yield(cid, *pi)
      Process.waitpid2(cid).last
    ensure
      pi.each{|fd| fd.close unless fd.closed?}
    end
  else
    [cid, pw.last, pr.first, pe.first]
  end
#--}}}
end

.popen4(*cmd) ⇒ Object



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/open4.rb', line 9

def popen4(*cmd)
#--{{{
  pw, pr, pe, ps = IO.pipe, IO.pipe, IO.pipe, IO.pipe

  verbose = $VERBOSE
  begin
    $VERBOSE = nil
    ps.last.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)

    cid = fork {
      pw.last.close
      STDIN.reopen pw.first
      pw.first.close

      pr.first.close
      STDOUT.reopen pr.last
      pr.last.close

      pe.first.close
      STDERR.reopen pe.last
      pe.last.close

      STDOUT.sync = STDERR.sync = true

      begin
        exec(*cmd)
        raise "exec failed!"
      rescue Exception => e
        Marshal.dump(e, ps.last)
        ps.last.flush
      end
      ps.last.close unless (ps.last.closed?)
      exit!
    }
  ensure
    $VERBOSE = verbose
  end

  [pw.first, pr.last, pe.last, ps.last].each{|fd| fd.close}

  begin
    e = Marshal.load ps.first
    raise(Exception === e ? e : "unknown failure!")
  rescue EOFError # If we get an EOF error, then the exec was successful
    42
  end

  pw.last.sync = true

  pi = [pw.last, pr.first, pe.first]

  if defined? yield
    begin
      yield(cid, *pi)
      Process.waitpid2(cid).last
    ensure
      pi.each{|fd| fd.close unless fd.closed?}
    end
  else
    [cid, pw.last, pr.first, pe.first]
  end
#--}}}
end

.spawn(cmd, opts = {}) ⇒ Object

–}}}

Raises:



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/open4.rb', line 90

def spawn cmd, opts = {} 
#--{{{
  getopt = lambda do |*args|
    keys, default, ignored = args
    catch('opt') do
      [keys].flatten.each do |key|
        [key, key.to_s, key.to_s.intern].each do |key|
          throw 'opt', opts[key] if opts.has_key?(key)
        end
      end
      default
    end
  end

  ignore_exit_failure = getopt[ 'ignore_exit_failure', getopt['quiet', false] ]
  ignore_exec_failure = getopt[ 'ignore_exec_failure', !getopt['raise', true] ]
  exitstatus = getopt[ %w( exitstatus exit_status status ), 0 ]
  stdin = getopt[ ['stdin', 'in', '0', 0] ]
  stdout = getopt[ ['stdout', 'out', '1', 1] ]
  stderr = getopt[ ['stderr', 'err', '2', 2] ]
  pid = getopt[ 'pid' ]

  started = false

  status =
    begin
      popen4(cmd) do |c, i, o, e|
        started = true

        if pid.respond_to? '<<'
          pid << c
        end

        it = Thread.new(i,stdin) do |i,stdin|
          if stdin
            if stdin.respond_to? :each
              stdin.each{|buf| i << buf}
            elsif stdin.respond_to? :read
              i << stdin.read
            else
              i << stdin.to_s
            end
          end
          i.close
        end

        ot = Thread.new(o,stdout){|o,stdout| o.each{|buf| stdout << buf if stdout}}
        et = Thread.new(e,stderr){|e,stderr| e.each{|buf| stderr << buf if stderr}}

        it.join
        ot.join if ot
        et.join if et
      end
    rescue
      raise unless(not started and ignore_exec_failure)
    end

  raise SpawnError.new(cmd, status) unless
    (ignore_exit_failure or (status.nil? and ignore_exec_failure) or (status.exitstatus == exitstatus))

  status
#--}}}
end

.versionObject

–{{{



5
6
7
# File 'lib/open4.rb', line 5

def self.version
  '0.4.0'
end