require 'optparse' require 'glue/configuration' require 'nitro/compiler' #require 'facet/kernel/autoreload' require 'glue/autoreload' module Nitro # The Runner is a helper class that encapsulates a web # application and is responsible for launching the # application in different modes. # # The runner provides default parsing of command line # and environment parameters. # # The default execution modes are: # # :debug, :stage, :live # # You can implement your own, custom version of the Runner # to run your custom web applications. #-- # FIXME: Rename/Reimplement this class. #++ class Runner # The adapter used. setting :adapter, :default => :webrick, :doc => 'The web adapter' # Execution mode = (:debug, :stage, :live) # # [:debug] # useful when debugging, extra debug information # is emmited, actions, templates and shaders are # reloaded, etc. The execution speed of the application # is impaired. # # [:stage] # test the application with live parameters # (typically on a staging server). # # [:live] # use the parameters for the live (production) # server. Optimized for speed. # # The default mode is :debug setting :mode, :default => :debug, :doc => 'The execution mode' # :start, :stop, :restart attr_accessor :action # The server used to run this web application. # :webrick, :nitro, :lhttp, :apache, :mod_apache # # At the moment only :webrick and :lhttp are available. attr_accessor :server # Run as daemon. attr_accessor :daemon # Spidering mode. Acceptable values are :crawl, :render # and false. attr_accessor :spider # Parse the command line arguments and the environment # parameters to setup the application. def setup_options @action ||= :start @server ||= :webrick @daemon = false @spider = false # Setup from environment if mode = ENV['NITRO_MODE'] self.class.mode = mode.to_sym else self.class.mode ||= :debug end # Setup from command line arguments. parser = OptionParser.new do |opts| opts.banner = 'Usage: run.rb [options]' opts.separator '' opts.separator 'Specific options:' opts.on('-s', '--start', 'Start application.') do @action = :start end opts.on('-S', '--stop', 'Stop application.') do @action = :stop end opts.on('-r', '--restart', 'Restart application.') do @action = :restart end opts.on('-d', '--daemon', 'Run application as a daemon.') do @daemon = true end opts.on('-D', '--debug', 'Run application in debug mode.') do self.class.mode = :debug end opts.on('-T', '--stage', 'Run application in stage mode.') do self.class.mode = :stage end opts.on('-L', '--live', 'Run application in live mode.') do self.class.mode = :live end opts.on('--address IP', 'Force the server to run on this address.') do |a| @server_address = a end opts.on('--port PORT', 'Force the server to run on this port.') do |p| @server_port = p.to_i end opts.on('-w', '--webrick', 'Use a webrick server [default].') do @server = :webrick end opts.on('-m', '--mongrel', 'Use the Mongrel Ruby server.') do @server = :mongrel # FIXME: handle logging. end opts.on('-l', '--lhttpd', 'Use a lighttpd server (FastCGI).') do @server = :lhttpd Logger.set(Logger.new('log/app.log')) end opts.on('-l', '--lhttpd-scgi', 'Use the SCGI adapter (Lighttpd).') do @server = :lhttpd_scgi Logger.set(Logger.new('log/app.log')) end opts.on('-a', '--apache', 'Use an apache server.') do @server = :apache Logger.set(Logger.new('log/app.log')) end opts.on('--apache-cgi', 'Use the CGI adapter (Apache)') do @server = :cgi Logger.set(Logger.new('log/app.log')) end opts.on('--scgi', 'Use the generic SCGI adapter') do @server = :scgi end opts.on('-C', '--console', 'Start a console attached to an instance of the application.') do if RUBY_PLATFORM =~ /mswin32/ irb_name = 'irb.bat' else irb_name = 'irb' end ENV['NITRO_INVOKE'] = 'irb' $NITRO_NO_INVOKE = true @server = :console conf_file = File.basename(caller.last.split(':').first) exec "#{irb_name} -r #{conf_file} -r irb/completion --noinspect" exit end opts.on('--crawl', 'Crawl the application.') do @server = :webrick @spider = :crawl end opts.on('--render', 'Crawl the application and render all pages as static html files.') do @server = :webrick @spider = :render end opts.on_tail('-v', '--version', 'Show version.') do puts "Nitro #{Nitro::Version}" exit end opts.on_tail('-h', '--help', 'Show this message.') do puts opts exit end end parser.parse!(ARGV) return self end # Setup the declared execution mode, # using the passed configuration parameters. def setup_mode case self.class.mode when :debug setup_debug when :stage setup_stage when :live setup_live end # Special setup for distributed sessions. =begin if defined?(Session) and defined?(DRbObject) if Session.store.is_a?(DRbObject) system('ruby ' + File.join(Nitro::LibPath, 'session', 'drbserver.rb') + ' --address #{Session.drb_address} --port #{Session.drb_port} --daemon') end end =end end # Setup in debug mode. def setup_debug $DBG = true Compiler.reload = true autoreload(3) Caching.caching_enabled = false load_external_configuration(:debug) end def setup_stage $DBG = false Compiler.reload = true autoreload(3) Logger.set(Logger.new('log/app.log')) load_external_configuration(:stage) end def setup_live $DBG = false # Enable the reloading even on live apps by default. # But have a longer thread sleep time. # If you really need sligthly faster dispatching enable # reloading (Compiler.reload = false) Compiler.reload = true autoreload(2 * 60) Logger.set(Logger.new('log/app.log')) load_external_configuration(:live) load_external_configuration(:production) end alias_method :setup_production, :setup_live # ... def invoke(server) case ENV['NITRO_INVOKE'] when 'fcgi_proc' require 'nitro/adapter/fastcgi' FastCGI.start(server) when 'scgi_proc' require 'nitro/adapter/scgi' Scgi.start(server) when 'cgi_proc' require 'nitro/adapter/cgi' CgiAdapter.start(server) when 'irb' $server = server when 'acgi_proc' require 'nitro/adapter/acgi' ACGI.start(server) else invoke_server(server) end end # ... def invoke_server(server) spider_thread = nil # FIXME refactor ! server.address = @server_address if @server_address server.port = @server_port if @server_port case @action when :start case @spider when :render spider_thread = Thread.new do sleep(6) `wget -k -m -p #{server.address}:#{server.port} -directory-prefix=rendered` end when :crawl spider_thread = Thread.new do sleep(6) `wget -m --spider #{server.host}:#{server.port}` end end @server ||= Runner.adapter puts "\n==> Setup for #{self.class.mode} mode" case @server when :webrick require 'nitro/adapter/webrick' puts "==> Listening at #{server.address}:#{server.port}. [WEBRICK]" puts "==> Press Ctrl-C to shutdown; Run with --help for options.\n\n" Webrick.start(server) when :mongrel require 'nitro/adapter/mongrel' puts "==> Listening at #{server.address}:#{server.port}. [MONGREL]" puts "==> Press Ctrl-C to shutdown; Run with --help for options.\n\n" Mongrel.start(server) when :lhttpd require 'nitro/adapter/fastcgi' puts "==> Launching lighttpd (FastCGI)." `lighttpd -f conf/lhttpd_fcgi.conf` when :lhttpd_scgi require 'nitro/adapter/scgi' puts "==> Launching lighttpd (SCGI)." `lighttpd -f conf/lhttpd_scgi.conf` when :apache require 'nitro/adapter/fastcgi' puts "==> Launching apache (FastCGI)." `apachectl -d #{Dir.pwd} -f conf/apache.conf -k start` when :cgi require 'nitro/adapter/cgi' puts "==> Using standard CGI. Please look into using Fast/Scgi" when :scgi require 'nitro/adapter/scgi' SCGI.start(server) when :acgi require 'nitro/adapter/acgi' puts "==> Launching ACGI." end when :stop case @server when :webrick when :lhttpd when :apache `apachectl -d #{Dir.pwd} -f conf/apache.conf -k stop` when :acgi `public/acgi.cgi stop` end end end # :section: Utilities # Run this proccess as a daemon (UNIX only). def daemonize require 'daemons/daemonize' pwd = Dir.pwd Daemonize.daemonize(File.join(pwd, 'log/app.log')) # Restore the original pwd (daemonize sets the # pwd to '/'). Dir.chdir(pwd) # Set the logger to a file (daemonize closes the # std streams). Logger.set(Logger.new('log/app.log')) end # Attempt to load external configuration in Ruby or # YAML format. The files: # # * conf/mode.rb # * conf/mode.yaml # # are considered. def load_external_configuration(mode = :debug) # require "conf/#{mode}.rb" ruby_conf = "conf/#{mode}.rb" load ruby_conf if File.exist?(ruby_conf) # Try to configure from a yaml file. yml_conf = "conf/#{mode}.yml" Configuration.load yml_conf if File.exist?(yml_conf) end end Run = Runner end # * George Moschovitis # * James Britt