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