class PTYBackgroundProcess

Public Class Methods

run(*command_with_args) click to toggle source

Runs a subprocess in a pseudo terminal, tricking a program into not buffering its output.

A great write up on pseudo-terminals here: stackoverflow.com/questions/1154846/continuously-read-from-stdout-of-external-process-in-ruby

It has the following disadvantages:

  • You can't get the exit status

  • When the process dies, whatever output you haven't read yet is lost.

  • stderr is merged into stdout

# File lib/background_process/pty_background_process.rb, line 14
def self.run(*command_with_args)
  command = sanitize_command(command_with_args)
  thread = Thread.new do # why run PTY separate thread? When a PTY instance
                         # dies, it raises PTY::ChildExited on the thread that
                         # spawned it, interrupting whatever happens to be
                         # running at the time
    PTY.spawn(command) do |output, input, pid|
      begin
        bp = new(pid, input, output)
        Thread.current[:background_process] = bp
        bp.wait
      rescue Exception => e
        puts e
        puts e.backtrace
      end
    end
  end
  sleep 0.01 until thread[:background_process]
  thread[:background_process]
end

Public Instance Methods

exitstatus() click to toggle source
# File lib/background_process/pty_background_process.rb, line 53
def exitstatus
  raise ArgumentError, "exitstatus is not available for PTY subprocesses"
end
stderr() click to toggle source
# File lib/background_process/pty_background_process.rb, line 35
def stderr
  raise ArgumentError, "stderr is merged into stdout with PTY subprocesses"
end
wait(timeout = nil) click to toggle source
# File lib/background_process/pty_background_process.rb, line 39
def wait(timeout = nil)
  begin
    Timeout.timeout(timeout) do
      Process.wait(@pid)
    end
  rescue Timeout::Error
    nil
  rescue PTY::ChildExited
    true
  rescue Errno::ECHILD
    true
  end
end

Protected Instance Methods

select_streams(which) click to toggle source
# File lib/background_process/pty_background_process.rb, line 58
def select_streams(which)
  case which
  when :stderr        then stderr # let stderr throw the exception
  when :stdout, :both then [stdout]
  else raise(ArgumentError, "invalid stream specification: #{which}")
  end.compact
end