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
130
131
132
133
134
135
136
137
138
139
140
141
|
# File 'lib/rbbt/util/cmd.rb', line 42
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
|