class PidFile

Constants

DEFAULT_OPTIONS
VERSION

Attributes

piddir[R]
pidfile[R]
pidpath[R]

Public Class Methods

new(*args) click to toggle source
# File lib/pidfile.rb, line 15
def initialize(*args)
  opts = {}

  #----- set options -----#
  if args.empty?
  elsif args.length == 1 && args[0].class == Hash
    arg = args.shift

    opts = arg if arg.class == Hash
  else
    raise ArgumentError, 'new() expects hash or hashref as argument'
  end

  opts = DEFAULT_OPTIONS.merge opts

  @piddir     = opts[:piddir]
  @pidfile    = opts[:pidfile]
  @pidpath    = File.join(@piddir, @pidfile)
  @fh         = nil

  #----- Does the pidfile or pid exist? -----#
  if pidfile_exists?
    if self.class.running?(@pidpath)
      raise DuplicateProcessError, "TinyCI is already running, process #{self.class.pid} will test your commit, don't worry!"

      exit! # exit without removing the existing pidfile
    end

    release
  end

  #----- create the pidfile -----#
  create_pidfile

  at_exit { release }
end
pid(path = nil) click to toggle source

Returns the PID, if any, of the instantiating process

# File lib/pidfile.rb, line 94
def self.pid(path = nil)
  open(path, 'r').read.to_i if pidfile_exists?(path)
end
pidfile_exists?(path = nil) click to toggle source

class method for determining the existence of pidfile

# File lib/pidfile.rb, line 99
def self.pidfile_exists?(path = nil)
  path ||= File.join(DEFAULT_OPTIONS[:piddir], DEFAULT_OPTIONS[:pidfile])

  File.exist?(path)
end
running?(path = nil) click to toggle source

boolean stating whether the calling program is already running

# File lib/pidfile.rb, line 106
def self.running?(path = nil)
  calling_pid = nil
  path ||= File.join(DEFAULT_OPTIONS[:piddir], DEFAULT_OPTIONS[:pidfile])

  calling_pid = pid(path) if pidfile_exists?(path)

  process_exists?(calling_pid)
end

Private Class Methods

process_exists?(process_id) click to toggle source
# File lib/pidfile.rb, line 133
def self.process_exists?(process_id)
  Process.kill(0, process_id)
  true
rescue Errno::ESRCH, TypeError # "PID is NOT running or is zombied
  false
end

Public Instance Methods

alive?() click to toggle source

Boolean stating whether this process is alive and running

# File lib/pidfile.rb, line 64
def alive?
  return false unless pid && (pid == Process.pid)

  self.class.process_exists?(pid)
end
locktime() click to toggle source

returns the modification time of the pidfile

# File lib/pidfile.rb, line 85
def locktime
  File.mtime(pidpath)
end
pid() click to toggle source

Returns the PID, if any, of the instantiating process

# File lib/pidfile.rb, line 57
def pid
  return @pid unless @pid.nil?

  @pid = (open(pidpath, 'r').read.to_i if pidfile_exists?)
end
pidfile_exists?() click to toggle source

does the pidfile exist?

# File lib/pidfile.rb, line 71
def pidfile_exists?
  self.class.pidfile_exists?(pidpath)
end
release() click to toggle source

unlock and remove the pidfile. Sets pid to nil

# File lib/pidfile.rb, line 76
def release
  unless @fh.nil?
    @fh.flock(File::LOCK_UN)
    remove_pidfile
  end
  @pid = nil
end

Private Instance Methods

create_pidfile() click to toggle source

Writes the process ID to the pidfile and defines @pid as such

# File lib/pidfile.rb, line 118
def create_pidfile
  # Once the filehandle is created, we don't release until the process dies.
  @fh = open(pidpath, 'w')
  @fh.flock(File::LOCK_EX | File::LOCK_NB) || raise
  @pid = Process.pid
  @fh.puts @pid
  @fh.flush
  @fh.rewind
end
remove_pidfile() click to toggle source

removes the pidfile.

# File lib/pidfile.rb, line 129
def remove_pidfile
  File.unlink(pidpath) if pidfile_exists?
end