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
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
|
# File 'lib/rbbt/util/cmd.rb', line 30
def self.cmd(cmd, options = {}, &block)
options = Misc.add_defaults options, :stderr => Log::DEBUG
in_content = options.delete(:in)
stderr = options.delete(:stderr)
pipe = options.delete(:pipe)
post = options.delete(:post)
log = options.delete(:log)
no_fail = options.delete(:no_fail)
no_wait = options.delete(:no_wait)
dont_close_in = options.delete(:dont_close_in)
log = true if log.nil?
if stderr == true
stderr = Log::HIGH
end
cmd_options = process_cmd_options options
if cmd =~ /'\{opt\}'/
cmd.sub!('\'{opt}\'', cmd_options)
else
cmd << " " << cmd_options
end
in_content = StringIO.new in_content if String === in_content
sin, sout, serr, wait_thr = begin
Open3.popen3(ENV, cmd)
rescue
Log.warn $!.message
raise ProcessFailed, cmd unless no_fail
return
end
pid = wait_thr.pid
Log.debug{"CMD: [#{pid}] #{cmd}" if log}
if in_content.respond_to?(:read)
in_thread = Thread.new(Thread.current) do |parent|
begin
begin
while c = in_content.readpartial(Misc::BLOCK_SIZE)
sin << c
end
rescue EOFError
end
sin.close unless sin.closed?
unless dont_close_in
in_content.close unless in_content.closed?
in_content.join if in_content.respond_to? :join
end
rescue
Log.error "Error in CMD [#{pid}] #{cmd}: #{$!.message}"
raise $!
end
end
else
in_thread = nil
sin.close
end
pids = [pid]
if pipe
err_thread = Thread.new do
while line = serr.gets
Log.log "STDERR [#{pid}]: " + line, stderr
end if Integer === stderr and log
serr.close
end
ConcurrentStream.setup sout, :pids => pids, :threads => [in_thread, err_thread, wait_thr].compact, :autojoin => no_wait, :no_fail => no_fail
sout
else
err = ""
err_thread = Thread.new do
while not serr.eof?
err << serr.gets if Integer === stderr
end
serr.close
end
ConcurrentStream.setup sout, :pids => pids, :threads => [in_thread, err_thread].compact, :autojoin => no_wait, :no_fail => no_fail
out = StringIO.new sout.read
sout.close unless sout.closed?
status = wait_thr.value
if not status.success? and not no_fail
raise ProcessFailed.new "Command [#{pid}] #{cmd} failed with error status #{status.exitstatus}.\n#{err}"
else
Log.log err, stderr if Integer === stderr and log
end
out
end
end
|