class BoxGrinder::ExecHelper

Public Class Methods

new(options = {}) click to toggle source
# File lib/boxgrinder-core/helpers/exec-helper.rb, line 33
def initialize(options = {})
  @log = options[:log] || Logger.new(STDOUT)
end

Public Instance Methods

execute(command, options = {}) click to toggle source
# File lib/boxgrinder-core/helpers/exec-helper.rb, line 37
def execute(command, options = {})
  redacted = options[:redacted] || []

  redacted_command = command
  redacted.each { |word| redacted_command = redacted_command.gsub(word, '<REDACTED>') }

  @log.debug "Executing command: '#{redacted_command}'"

  output = ""

  # dirty workaround for ruby segfaults related to logger.rb
  STDOUT.sync = true
  STDERR.sync = true

  begin
    pid, stdin, stdout, stderr = (RUBY_PLATFORM =~ %rjava/ ? IO : Open4).send(:popen4, command)
    threads = []

    threads << Thread.new(stdout) do |out|
      out.each do |l|
        l.chomp!
        l.strip!

        output << "\n#{l}"
        @log.debug l
      end
    end

    threads << Thread.new(stderr) do |err|
      err.each do |l|
        l.chomp!
        l.strip!

        output << "\n#{l}"
        @log.debug l
      end
    end

    threads.each { |t| t.join }

    # Assume the process exited cleanly, which can cause some bad behaviour, but I don't see better way
    # to get reliable status for processes both on MRI and JRuby
    #
    # http://jira.codehaus.org/browse/JRUBY-5673
    status = AStruct.new(:exitstatus => 0)
    
    fakepid, status = Process.waitpid2(pid) if process_alive?(pid)

    raise "process exited with wrong exit status: #{status.exitstatus}" if !(RUBY_PLATFORM =~ %rjava/) and status.exitstatus != 0

    return output.strip
  rescue Interrupt
    raise InterruptionError.new(pid), "Program was interrupted."
  rescue => e
    @log.error e.backtrace.join($/)
    raise "An error occurred while executing command: '#{redacted_command}', #{e.message}"
  end
end
process_alive?(pid) click to toggle source
# File lib/boxgrinder-core/helpers/exec-helper.rb, line 96
def process_alive?(pid)
  begin
    Process.getpgid(pid)
    true
  rescue Errno::ESRCH
    false
  end
end