8
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
|
# File 'lib/pretty_multitask/run_callable.rb', line 8
def run(opts = @opts)
cmd = opts[:cmd]
name = opts[:name]
out = opts[:out] || STDOUT
err = opts[:err] || STDERR
@padding = opts[:padding]
master, slave = PTY.open
err_read, err_write = IO.pipe
r, w = UNIXSocket.pair(:STREAM, 0)
pid = fork do
STDERR.reopen err_write
STDOUT.reopen master
begin
result = cmd.call
obj = { result: result, error: nil }
rescue StandardError => e
new_error = e.class.new(e.message)
new_error.set_backtrace e.backtrace
Logger.new(STDERR).error new_error
obj = { result: nil, error: new_error }
File.open('/tmp/error','w+'){|f| f.puts obj.to_yaml}
w.puts Marshal.dump(obj), 0
end
w.puts Marshal.dump(obj), 0
w.close
end
t_out = consume_and_print slave, out, name, false
t_err = consume_and_print err_read, out, name, true
Process.wait pid
i[slave err_read].each do |e|
loop { break unless binding.local_variable_get(e).ready? }
end
begin
Timeout.timeout(0.1) do
i[t_out t_err].each { |e| binding.local_variable_get(e).join }
end
rescue Timeout::Error
nil
end
i[master slave err_read err_write].each { |e| binding.local_variable_get(e).close }
chars = []
chars << r.getc while r.ready?
r.close
result = Marshal.load(chars.join)
raise result[:error] if result[:error]
result[:result]
end
|