#!/usr/local/bin/ruby require 'rubygems' require 'optparse' require 'ostruct' require 'fileutils' require 'yaml' require 'erubis' module Merb end class Merb::Config def self.setup defaults = { :host => "0.0.0.0", :port => "4000", :allow_reloading => true, :merb_root => Dir.pwd, :template_ext => {:html => :herb, :js => :jerb, :xml => :xerb} } begin options = defaults.merge(YAML.load(Erubis::Eruby.new(IO.read("#{defaults[:merb_root]}/dist/conf/merb.yml")).result)) rescue options = defaults end options end end class Merb::Server def self.merb_config options = Merb::Config.setup opts = OptionParser.new do |opts| opts.on("-f", "--config-file [String]") do |config| options[:config] = config end opts.on("-d", "--daemonize [String]") do |config| options[:daemonize] = true end opts.on("-c", "--cluster-nodes [String]") do |nodes| options[:cluster] = nodes end opts.on("-p", "--port [Integer]") do |port| options[:port] = port end opts.on("-h", "--host [String]") do |host| options[:host] = host end opts.on("-m", "--merb-root [String]") do |merb_root| options[:merb_root] = File.expand_path(merb_root) end opts.on("-i", "--irb-console [String]") do |console| options[:console] = true end opts.on("-s", "--session-drb-port [Integer]") do |drb_port| options[:session] = drb_port end opts.on("-l", "--log-level [String]") do |loglevel| options[:log_level] = loglevel end end opts.parse!(@@merb_raw_opts) @@merb_opts = options puts %{Merb started with these options:} puts @@merb_opts.to_yaml; puts end def self.initialize_merb require 'merb' require @@merb_opts[:merb_root]+'/dist/conf/router.rb' require @@merb_opts[:merb_root]+'/dist/conf/merb_init.rb' end def self.run @@merb_raw_opts = ARGV merb_config @@merb_opts[:dist_root] = @@merb_opts[:merb_root]+'/dist' $LOAD_PATH.unshift( File.join(@@merb_opts[:dist_root] , '/app/controllers') ) $LOAD_PATH.unshift( File.join(@@merb_opts[:dist_root] , '/app/models') ) $LOAD_PATH.unshift( File.join(@@merb_opts[:dist_root] , '/lib') ) if @@merb_opts[:console] initialize_merb ARGV.clear # Avoid passing args to IRB require 'irb' require 'irb/completion' def exit exit! end if File.exists? ".irbrc" ENV['IRBRC'] = ".irbrc" end IRB.start exit! end if @@merb_opts[:session] start(@@merb_opts[:session], :drbserver_start) end if @@merb_opts[:cluster] delete_pidfiles @@merb_opts[:port].to_i.upto(@@merb_opts[:port].to_i+@@merb_opts[:cluster].to_i-1) do |port| puts "Starting merb server on port: #{port}" start(port) end elsif @@merb_opts[:daemonize] delete_pidfiles(@@merb_opts[:port]) start(@@merb_opts[:port]) else initialize_merb trap('TERM') { exit } mongrel_start(@@merb_opts[:port]) end end def self.store_pid(pid,port) File.open("#{@@merb_opts[:merb_root]}/log/merb.#{port}.pid", 'w'){|f| f.write("#{Process.pid}\n")} end def self.start(port,what=:mongrel_start) fork do Process.setsid exit if fork if what == :mongrel_start store_pid(Process.pid, port) else store_pid(Process.pid, "drb.#{port}") end Dir.chdir @@merb_opts[:merb_root] File.umask 0000 STDIN.reopen "/dev/null" STDOUT.reopen "/dev/null", "a" STDERR.reopen STDOUT trap("TERM") { exit } send(what, port) end end def self.delete_pidfiles(portor_star='*') Dir["#{@@merb_opts[:merb_root]}/log/merb.#{portor_star}.pid"].each do |pid| FileUtils.rm(pid) rescue nil end end def self.drbserver_start(port) require 'merb/session/merb_drb_server' DRb.start_service("druby://#{@@merb_opts[:host]}:#{port}", Merb::DRbSession.setup) DRb.thread.join end def self.mongrel_start(port) initialize_merb config = Mongrel::Configurator.new :host => (@@merb_opts[:host]||"0.0.0.0"), :port => (port ||4000) do load_plugins( :includes => ["mongrel"], :excludes => ["rails"] ) if @@merb_opts[:config] listener do run_config(@@merb_opts[:config]) if @@merb_opts[:config] uri "/", :handler => MerbHandler.new(@@merb_opts[:dist_root]+'/public') uri "/favicon.ico", :handler => Mongrel::Error404Handler.new("") end trap("INT") { stop } run end config.join end def self.config @@merb_opts end end Merb::Server.run