class Kopflos::Xvfb

Attributes

font_path[RW]
resolution[RW]
screen[RW]
wait[RW]

Public Class Methods

new(options = {}) click to toggle source
# File lib/kopflos/xvfb.rb, line 24
def initialize(options = {})
  @font_path  = options[:font_path]      || self.class.determine_font_path
  @resolution = options[:resolution]     || '1024x768x24'
  @screen     = options[:screen]         || '1'
  @wait       = options[:wait]           || 5
  @manager    = options[:manager] || options[:wm]
  raise NotSupported unless self.class.supported?
end
start(options={}) click to toggle source
# File lib/kopflos/xvfb.rb, line 33
def self.start(options={})
  xvfb = new(options)
  xvfb.start
  xvfb
end
supported?() click to toggle source
# File lib/kopflos/xvfb.rb, line 39
def self.supported?
  RUBY_PLATFORM =~ /linux/
end

Protected Class Methods

determine_font_path() click to toggle source
# File lib/kopflos/xvfb.rb, line 111
def self.determine_font_path
  if RUBY_PLATFORM =~ /linux/
    case `cat /etc/issue`
    when /Debian|Ubuntu/
      return '/usr/share/fonts/X11/misc'
    else
      return ENV['XVFB_FONT_PATH'] if ENV['XVFB_FONT_PATH']
    end
  end
  raise NotSupported, "#{RUBY_PLATFORM} not supported by default, Export $XVFB_FONT_PATH with a path to your X11 fonts/misc directory"
end

Public Instance Methods

authorize() click to toggle source
# File lib/kopflos/xvfb.rb, line 86
def authorize
  @origin_env = current_env
  ENV['XAUTHORITY'] = authfile.path
  ENV['DISPLAY'] = ":#{servernum}.#{@screen}"
  IO.popen('xauth source -', 'w') do |xauth|
    xauth.puts %Q~add :#{servernum} . #{mcookie}~
  end
end
command() click to toggle source
# File lib/kopflos/xvfb.rb, line 75
def command
  [
    executable,
    ":#{servernum}",
    '-br', # black background
    "-fp", @font_path,
    '-screen', @screen,
    @resolution,
  ]
end
running?() click to toggle source
# File lib/kopflos/xvfb.rb, line 52
def running?
  !!@server && !!@server.status
end
screenshot(filename='screenshot.png') click to toggle source
# File lib/kopflos/xvfb.rb, line 71
def screenshot(filename='screenshot.png')
  system 'import', '-window', 'root', filename
end
start() click to toggle source
# File lib/kopflos/xvfb.rb, line 43
def start
  authorize
  @server = start_server_in_subprocess
  log "started => #{@server.pid}"
  sleep @wait # FIXME is there a generic way to find out if Xvfb has started?
  @window_manager = start_window_manager
  log "finished"
end
stop() click to toggle source
# File lib/kopflos/xvfb.rb, line 56
def stop
  kill_window_manager
  kill_server
  Process.wait
rescue Errno::ENOENT => e
rescue Errno::ECHILD => e
rescue Errno::EPIPE => e
ensure
  if @servernum
    File.unlink( lockfile ) if File.exist?(lockfile)
  end
  load_env @origin_env
  @server = nil
end
to_s() click to toggle source
# File lib/kopflos/xvfb.rb, line 95
def to_s
  "<#{self.class} :#{servernum}.#{@screen}>"
end

Protected Instance Methods

authfile() click to toggle source
# File lib/kopflos/xvfb.rb, line 123
def authfile
  @authfile ||= Tempfile.new('kopflos_Xauthority')
end
current_env() click to toggle source
# File lib/kopflos/xvfb.rb, line 195
def current_env
  { :display => ENV['DISPLAY'], :xauthority => ENV['XAUTHORITY'] }
end
executable() click to toggle source
# File lib/kopflos/xvfb.rb, line 102
def executable
  return @executable if defined?(@executable)
  @executable = `which Xvfb`.chomp
  if @executable.empty?
    raise NotInstalled
  end
  @executable
end
find_free_servernum() click to toggle source

Find a free server number by looking at .X*-lock files in /tmp.

# File lib/kopflos/xvfb.rb, line 133
def find_free_servernum
  servernum  = 99
  while File.exists?( lockfile( servernum ) )
    servernum += 1
  end
  servernum
end
kill_server() click to toggle source
# File lib/kopflos/xvfb.rb, line 173
def kill_server
  if @server
    # first, kill the X server
    Process.kill("USR1", @server.pid)
    # then wait for the thread to finish
    @server.join
  else
    log "no server found to kill"
  end
end
kill_window_manager() click to toggle source
# File lib/kopflos/xvfb.rb, line 184
def kill_window_manager
  if @window_manager && @window_manager.respond_to?(:pid)
    # first, kill the external process
    Process.kill("USR1", @window_manager.pid)
    # then wait for the thread to finish
    @window_manager.join
  else
    log "no server found to kill"
  end
end
load_env(env) click to toggle source
# File lib/kopflos/xvfb.rb, line 199
def load_env(env)
  if env && env.respond_to?(:[])
    ENV['DISPLAY'], ENV['XAUTHORITY'] = env[:display], env[:xauthority]
  end
end
lockfile(num=servernum) click to toggle source
# File lib/kopflos/xvfb.rb, line 161
def lockfile(num=servernum)
  "/tmp/.X#{num}-lock"
end
log(message) click to toggle source
# File lib/kopflos/xvfb.rb, line 152
def log(message)
  message = "#{self} #{message}"
  if defined?(Rails)
    Rails.logger.info(message)
  else
    STDERR.puts message
  end
end
mcookie() click to toggle source
# File lib/kopflos/xvfb.rb, line 127
def mcookie
  @mcookie ||= `mcookie`.chomp
end
servernum() click to toggle source
# File lib/kopflos/xvfb.rb, line 141
def servernum
  @servernum ||= find_free_servernum
end
start_server_in_subprocess() click to toggle source
# File lib/kopflos/xvfb.rb, line 165
def start_server_in_subprocess
  empty = ''
  log "starting: #{command.join(' ')}"
  Open4::background(command, 0 => empty, 1 => empty, 2 => empty, 'ignore_exit_failure' => true)
rescue Errno::ECHILD => e
  log "could not start server: #{e}"
end
start_window_manager() click to toggle source
# File lib/kopflos/xvfb.rb, line 145
def start_window_manager
  return unless @manager
  Open4::background @manager
rescue Errno::ECHILD => e
  log "could not start window manager: #{e}"
end