class Execute
Public Class Methods
default_options(hash)
click to toggle source
# File lib/execute.rb, line 44 def self.default_options(hash) hash.each { |key, value| @@default_options[key] = value} end
new(cmd, options=nil)
click to toggle source
# File lib/execute.rb, line 14 def initialize(cmd, options=nil) initialize_defaults if(@@default_options.nil?) self[:output] = '' self[:error] = '' #1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL #5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE #9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2 #13) SIGPIPE 14) SIGALRM 15) SIGTERM 17) SIGCHLD #18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN #22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ #26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO #30) SIGPWR 31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 #36) SIGRTMIN+2 37) SIGRTMIN+3 38) SIGRTMIN+4 39) SIGRTMIN+5 #40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8 43) SIGRTMIN+9 #44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13 #48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 #52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 #56) SIGRTMAX-8 57) SIGRTMAX-7 58) SIGRTMAX-6 59) SIGRTMAX-5 #60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2 63) SIGRTMAX-1 #64) SIGRTMAX self[:timeout_signal] = 2 self[:timeout_raise_error] = true @@default_options.each { |key, value| self[key] = value} options.each { |key, value| self[key] = value} unless(options.nil?) self[:command]=cmd end
Public Instance Methods
[](key)
click to toggle source
Calls superclass method
# File lib/execute.rb, line 187 def [](key) value = nil mutex = Mutex.new mutex.synchronize { value = super(key) } return value end
[]=(key,value)
click to toggle source
Calls superclass method
# File lib/execute.rb, line 182 def []=(key,value) mutex = Mutex.new mutex.synchronize { super(key, value) } end
call_capture()
click to toggle source
# File lib/execute.rb, line 152 def call_capture begin if(key?(:timeout)) start_time = Time.now Thread.new do while !key?(:exit_code) do sleep(0.1) if((Time.now - start_time).to_f > self[:timeout]) self[:timed_out] = true interrupt sleep(0.1) break end end end end self[:output] = self[:error] = '' self[:output], self[:error], status = Open3.capture3(self[:command]) self[:exit_code] = status.to_i puts self[:output] if(self[:echo_output] && !self[:output].empty?) raise TimeoutException.new("Command '#{self[:command]}' timed out after #{self[:timeout]} seconds") if(key?(:timed_out) && self[:timeout_raise_error]) rescue Exception => e self[:error] = "#{self[:error]}\nException: #{e.to_s}" self[:exit_code]=1 unless(!self[:exit_code].nil? || (self[:exit_code] == 0)) end end
call_popen()
click to toggle source
# File lib/execute.rb, line 76 def call_popen begin output = '' error = '' threads = [] mutex = Mutex.new stop_threads = false timeout = nil timeout = self[:timeout] if(key?(:timeout)) Open3.popen3(self[:command]) do |stdin, stdout, stderr, wait_thr| self[:pid] = wait_thr.pid unless(timeout.nil?) start_time = Time.now threads << Thread.new do begin while wait_thr.alive? do if((Time.now - start_time).to_f > timeout) self[:timed_out] = true self[:pre_timeout_command].execute if(self.key?(:pre_timeout_command)) interrupt mutex.synchronize {stop_threads = true } else sleep(1) Thread.pass end break if(stop_threads) end rescue Exception mutex.synchronize { stop_threads = true } end end end {:output => stdout,:error => stderr}.each do |key, stream| threads << Thread.new do begin last_pass_time = Time.now while wait_thr.alive? do while !stream.closed? && !(char = stream.getc).nil? do case key when :output output << char putc char if(self[:echo_output]) when :error error << char end if(wait_thr.alive? && ((Time.now - last_pass_time).to_i > 15)) last_pass_time = Time.now Thread.pass end end break if(stop_threads) sleep(0.1) end mutex.synchronize { stop_threads = true } rescue Exception mutex.synchronize { stop_threads = true } end end end threads.each { |thr| thr.join } self[:output] = output unless(output.empty?) self[:error] = error unless(error.empty?) self[:exit_code] = wait_thr.value.to_i end rescue Exception => e self[:error] = "#{self[:error]}\nException: #{e.to_s}" self[:exit_code]=1 unless(self[:exit_code].nil? || (self[:exit_code] == 0)) end end def call_capture begin if(key?(:timeout)) start_time = Time.now Thread.new do while !key?(:exit_code) do sleep(0.1) if((Time.now - start_time).to_f > self[:timeout]) self[:timed_out] = true interrupt sleep(0.1) break end end end end self[:output] = self[:error] = '' self[:output], self[:error], status = Open3.capture3(self[:command]) self[:exit_code] = status.to_i puts self[:output] if(self[:echo_output] && !self[:output].empty?) raise TimeoutException.new("Command '#{self[:command]}' timed out after #{self[:timeout]} seconds") if(key?(:timed_out) && self[:timeout_raise_error]) rescue Exception => e self[:error] = "#{self[:error]}\nException: #{e.to_s}" self[:exit_code]=1 unless(!self[:exit_code].nil? || (self[:exit_code] == 0)) end end def []=(key,value) mutex = Mutex.new mutex.synchronize { super(key, value) } end def [](key) value = nil mutex = Mutex.new mutex.synchronize { value = super(key) } return value end def command_pid Sys::ProcTable.ps do |p| if(p.ppid == $$) return self[:pid] = p.pid end end raise "Failed to find child process for command: '#{self[:command]}'" end def interrupt self[:pid] = command_pid unless(key?(:pid)) raise "Do not have a process id for #{self[:pid]}" unless(key?(:pid)) processes = get_child_processes(self[:pid]) Process.kill(self[:timeout_signal], self[:pid]) Process.waitpid(pid: self[:pid]) unless(Sys::ProcTable.ps(pid: self[:pid]).nil?) processes.each { |p| Process.kill(self[:timeout_signal],p.pid) unless(Sys::ProcTable.ps(pid: p.pid).nil?) } end def get_child_processes(pid) processes = [] Sys::ProcTable.ps do |p| if(p.ppid == pid) get_child_processes(p.pid).each { |cp| processes << cp } processes << p end end return processes end end
command_pid()
click to toggle source
# File lib/execute.rb, line 194 def command_pid Sys::ProcTable.ps do |p| if(p.ppid == $$) return self[:pid] = p.pid end end raise "Failed to find child process for command: '#{self[:command]}'" end
execute()
click to toggle source
# File lib/execute.rb, line 48 def execute if(self[:quiet]) self[:echo_output] = false self[:echo_command] = false end puts self[:command] if(self[:echo_command] || self[:debug]) self[:elapsed_time] = Benchmark.realtime { call_popen } #self[:elapsed_time] = Benchmark.realtime { call_capture } if(self[:debug]) puts "command: #{self[:command]}" puts "output: #{self[:output]}" puts "error: #{self[:error]}" puts "exit_code: #{self[:exit_code]}" end raise TimeoutException.new("Command '#{self[:command]}' timed out after #{self[:timeout]} seconds") if(key?(:timed_out) && self[:timeout_raise_error]) if((self[:exit_code] != 0) && !self[:ignore_exit_code]) exception_text = "Command: '#{self[:command]}'" exception_text = "#{exception_text}\nExit code: #{self[:exit_code]}" exception_text = "#{exception_text}\nError: '#{self[:error]}'" exception_text = "#{exception_text}\nOutput: '#{self[:output]}'" raise StandardError.new(exception_text) end end
get_child_processes(pid)
click to toggle source
# File lib/execute.rb, line 214 def get_child_processes(pid) processes = [] Sys::ProcTable.ps do |p| if(p.ppid == pid) get_child_processes(p.pid).each { |cp| processes << cp } processes << p end end return processes end
interrupt()
click to toggle source
# File lib/execute.rb, line 203 def interrupt self[:pid] = command_pid unless(key?(:pid)) raise "Do not have a process id for #{self[:pid]}" unless(key?(:pid)) processes = get_child_processes(self[:pid]) Process.kill(self[:timeout_signal], self[:pid]) Process.waitpid(pid: self[:pid]) unless(Sys::ProcTable.ps(pid: self[:pid]).nil?) processes.each { |p| Process.kill(self[:timeout_signal],p.pid) unless(Sys::ProcTable.ps(pid: p.pid).nil?) } end