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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
|
# File 'lib/rbbt/util/cmd.rb', line 75
def self.cmd(tool, cmd = nil, options = {}, &block)
options, cmd = cmd, nil if Hash === cmd
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 cmd.nil? and ! Symbol === tool
cmd = tool
else
tool = get_tool(tool)
if cmd.nil?
cmd = tool
else
cmd = tool + ' ' + cmd
end
end
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
ConcurrentStream.setup sout, :pids => pids, :autojoin => no_wait, :no_fail => no_fail
err_thread = Thread.new do
while line = serr.gets
sout.log = line
Log.log "STDERR [#{pid}]: " + line, stderr
end if Integer === stderr and log
serr.close
end
sout.threads = [in_thread, err_thread, wait_thr].compact
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
|