require 'rubygems' require 'optparse' require 'ostruct' require 'fileutils' require 'yaml' require 'erubis' module Merb class 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}, :cache_templates => false } 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 Server class << self def merb_config options = Merb::Config.setup opts = OptionParser.new do |opts| opts.banner = "Usage: merb [fdcphmisl] [argument]" opts.define_head "Merb Mongrel+ Erb. Lightweight replacement for ActionPack" opts.separator '*'*80 opts.separator 'If no flags are given, Merb starts in the foreground on port 4000' opts.separator '*'*80 opts.on("-f", "--config-file FILENAME", "This flag is for adding extra config files for things like the upload progress module") do |config| options[:config] = config end opts.on("-d", "--daemonize", "This will run a single merb in the background") do |config| options[:daemonize] = true end opts.on("-c", "--cluster-nodes NUM_MERBS", "Number of merb daemons to run") do |nodes| options[:cluster] = nodes end opts.on("-p", "--port PORTNUM", "Port to run merb on, defaults to 4000") do |port| options[:port] = port end opts.on("-h", "--host HOSTNAME", "Host to bind to(default is all IP's)") do |host| options[:host] = host end opts.on("-m", "--merb-root MERB_ROOT", "the path to the MERB_ROOT for the app you want to run") do |merb_root| options[:merb_root] = File.expand_path(merb_root) end opts.on("-i", "--irb-console", "This flag will start merb in irb console mode. All your models and other classes will be available for you in an irb session.") do |console| options[:console] = true end opts.on("-s", "--drb-server-port PORTNUM", "This is the port number to run the drb daemon on for sessions and uplod progress monitoring.") do |drb_port| options[:drb_server_port] = drb_port end opts.on("-l", "--log-level LEVEL", "Log levels can be set to any of these options: DEBUG < INFO < WARN < ERROR < FATAL < UNKNOWN") do |loglevel| options[:log_level] = loglevel end opts.on("-e", "--environment STRING", "Run merb in the correct mode(development, production, testing)") do |env| options[:environment] = env end opts.on("-g", "--generate-app PATH", "Generate a fresh merb app at PATH") do |path| options[:generate] = path || Dir.pwd end opts.on("-?", "--help", "Show this help message") do puts opts exit end end opts.parse!(@@merb_raw_opts) @@merb_opts = options unless options[:generate] || options[:console] puts %{Merb started with these options:} puts @@merb_opts.to_yaml; puts end end def 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 run @@merb_raw_opts = ARGV merb_config case @@merb_opts[:environment].to_s when 'development' @@merb_opts[:allow_reloading] ||= true @@merb_opts[:show_error] ||= true when 'production' @@merb_opts[:allow_reloading] = false @@merb_opts[:show_error] ||= false @@merb_opts[:cache_templates] = true when 'test' @@merb_opts[:allow_reloading] ||= true @@merb_opts[:show_error] ||= true else @@merb_opts[:allow_reloading] ||= true @@merb_opts[:show_error] ||= true end @@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 File.exist? File.join(@@merb_opts[:dist_root] , '/framework') $LOAD_PATH.unshift( File.join(@@merb_opts[:dist_root] , '/framework') ) end if @@merb_opts[:generate] require 'merb/generators/merb_app/merb_app' ::Merb::AppGenerator.run @@merb_opts[:generate] exit! end 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[:drb_server_port] puts "Starting merb drb server on port: #{@@merb_opts[:drb_server_port]}" start(@@merb_opts[:drb_server_port], :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 store_pid(pid,port) File.open("#{@@merb_opts[:merb_root]}/log/merb.#{port}.pid", 'w'){|f| f.write("#{Process.pid}\n")} end def 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 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 drbserver_start(port) puts "Starting merb drb server on port: #{port}" require 'merb/merb_drb_server' DRb.start_service("druby://#{@@merb_opts[:host]}:#{port}", Merb::DrbServiceProvider) DRb.thread.join end def mongrel_start(port) @@merb_opts[:port] = port initialize_merb mconfig = Mongrel::Configurator.new :host => (@@merb_opts[:host]||"0.0.0.0"), :port => (port ||4000) do yconfig = YAML.load(Erubis::Eruby.new(IO.read(File.expand_path(@@merb_opts[:config]))).result) if @@merb_opts[:config] listener do uri( "/", :handler => MerbUploadHandler.new(yconfig), :in_front => true) 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 mconfig.join end def config @@merb_opts end end end # Server end # Merb