Repository URL to install this package:
|
Version:
0.4.2 ▾
|
#!/usr/bin/env ruby
# encoding: utf-8
$:.unshift File.expand_path('../../lib', __FILE__)
require 'pp'
require 'fileutils'
require 'optparse'
require 'daemons'
require 'jarvis'
class Launcher
def initialize(options = {})
@options = options
@options[:pid_file] = File.expand_path(options[:pid_file]) if pid_file?
@options[:log_file] = File.expand_path(options[:log_file]) if log_file?
end
def launch(startable)
@startable = startable
puts "Launching..."
puts startable.banner if startable.respond_to?(:banner)
check_pid
daemonize if options[:daemonize]
write_pid
trap_signals
if log_file?
redirect_output if options[:daemonize]
elsif options[:daemonize]
suppress_output
end
@startable.start! #blocking operation
end
def quit
@startable.stop
info "Finished"
exit 0
end
private
attr_reader :options
def pretty_print(hash)
pp hash
end
def log_file
options[:log_file]
end
def pid_file
options[:pid_file]
end
def log_file?
!log_file.nil?
end
def pid_file?
!pid_file.nil?
end
def info(msg)
puts "[#{Process.pid}] [#{Time.now}] #{msg}"
end
#==========================================================================
# DAEMONIZING, PID MANAGEMENT, and OUTPUT REDIRECTION
#==========================================================================
def daemonize
exit if fork
Process.setsid
exit if fork
Dir.chdir options[:work_dir]
end
def redirect_output
FileUtils.mkdir_p(File.dirname(log_file), :mode => 0755)
FileUtils.touch log_file
File.chmod(0644, log_file)
$stderr.reopen(log_file, 'a')
$stdout.reopen($stderr)
$stdout.sync = $stderr.sync = true
end
def suppress_output
$stderr.reopen('/dev/null', 'a')
$stdout.reopen($stderr)
end
def write_pid
if pid_file?
begin
File.open(pid_file, ::File::CREAT | ::File::EXCL | ::File::WRONLY) { |f| f.write("#{Process.pid}") }
at_exit { File.delete(pid_file) if File.exists?(pid_file) }
rescue Errno::EEXIST
check_pid
retry
end
end
end
def check_pid
if pid_file?
case pid_status(pid_file)
when :running, :not_owned
puts "A server is already running. Check #{pid_file}"
exit(1)
when :dead
File.delete(pid_file)
end
end
end
def pid_status(pid_file)
return :exited unless File.exists?(pid_file)
pid = ::File.read(pid_file).to_i
return :dead if pid == 0
Process.kill(0, pid)
:running
rescue Errno::ESRCH
:dead
rescue Errno::EPERM
:not_owned
end
#==========================================================================
# SIGNAL HANDLING
#==========================================================================
def trap_signals
trap(:QUIT) do # graceful shutdown
quit
end
trap("SIGINT") do
quit
end
trap("TERM") do
quit
end
end
#==========================================================================
end
options = {
daemonize: false,
log_file: '/tmp/jarvis.log',
work_dir: '.'
}
daemonize_help = 'run daemonized in the background (default: false)'
pid_file_help = 'the pid filename'
log_file_help = 'the log filename'
include_help = 'an additional $LOAD_PATH (may be used more than once)'
debug_help = 'set $DEBUG to true'
warn_help = 'enable warnings'
work_dir_help = 'set workdir for process (Default: /)'
op = OptionParser.new
op.banner = 'J.A.R.V.I.S. Just Another Rather Very Intelligent System'
op.separator ''
op.separator 'Usage: jarvis [options]'
op.separator ''
op.separator ''
op.separator 'Process options:'
op.on('-d', '--daemonize', daemonize_help) { options[:daemonize] = true }
op.on('-p', '--pid PIDFILE', pid_file_help) { |value| options[:pid_file] = value }
op.on('-l', '--log LOGFILE', log_file_help) { |value| options[:log_file] = value }
op.on('-w', '--workdir DIR', work_dir_help) { |value| options[:work_dir] = value }
op.separator ''
op.separator 'Ruby options:'
op.on('--debug', debug_help) { $DEBUG = true }
op.on('--warn', warn_help) { $-w = true }
op.on('-I', '--include PATH', include_help) do |value|
$LOAD_PATH.unshift(*value.split(":").map { |v| File.expand_path(v) })
end
op.separator ''
op.separator 'Common options:'
op.on('-h', '--help') { options[:action] = :help }
op.on('-v', '--version') { options[:action] = :version }
op.separator ''
op.parse!(ARGV)
class Startable
include Jarvis::Daemon
def setup_dependencies
puts 'Startable::setup_dependencies'
end
def run
puts 'non-blocking run method'
puts Jarvis.configuration.to_h
end
end
case options[:action]
when :help then
puts op.to_s
when :version then
puts Jarvis::VERSION
else
contents = File.read('config.jrv')
class_name = contents.match(%r(run (.*)))[1]
Dir[Dir.pwd + "/app/*.rb"].each {|file| require file}
clazz = Object.const_get class_name
Launcher.new(options).launch clazz.new
end