lib/vegas/runner.rb in vegas-0.1.2 vs lib/vegas/runner.rb in vegas-0.1.3
- old
+ new
@@ -4,116 +4,132 @@
if Vegas::WINDOWS
begin
require 'win32/process'
rescue
- puts "Sorry, in order to use Vegas on Windows you need the win32-process gem:\n gem install win32-process"
+ puts "Sorry, in order to use Vegas on Windows you need the win32-process gem:\n " +
+ "gem install win32-process"
end
end
module Vegas
class Runner
- attr_reader :app, :app_name, :rack_handler, :port, :host, :options, :args
-
+ attr_reader :app, :app_name, :filesystem_friendly_app_name, :quoted_app_name,
+ :rack_handler, :port, :host, :options, :args
+
ROOT_DIR = File.expand_path(File.join('~', '.vegas'))
PORT = 5678
HOST = WINDOWS ? 'localhost' : '0.0.0.0'
-
+
def initialize(app, app_name, set_options = {}, runtime_args = ARGV, &block)
- # initialize
- @app = app
- @app_name = app_name
- @options = set_options || {}
- @runtime_args = runtime_args
+ @options = set_options || {}
+
self.class.logger.level = options[:debug] ? Logger::DEBUG : Logger::INFO
-
- @rack_handler = @app.respond_to?(:detect_rack_handler) ?
- @app.send(:detect_rack_handler) : Rack::Handler.get('thin')
+ @app = app
+ @app_name = app_name
+
+ @filesystem_friendly_app_name = @app_name.gsub(/\W+/, "_")
+ @quoted_app_name = "'#{app_name}'"
+
+ @runtime_args = runtime_args
+ @rack_handler = setup_rack_handler
+
# load options from opt parser
@args = define_options do |opts|
if block_given?
opts.separator ''
- opts.separator "#{app_name} options:"
+ opts.separator "#{quoted_app_name} options:"
yield(self, opts, app)
end
end
- # Call before run if before_run is a Proc
- if before_run = options.delete(:before_run) and
- before_run.is_a?(Proc)
+ # Handle :before_run hook
+ if (before_run = options.delete(:before_run)).respond_to?(:call)
before_run.call(self)
end
- # set app options
+ # Set app options
@host = options[:host] || HOST
- if @app.respond_to?(:set)
- @app.set(options)
- @app.set(:vegas, self)
+
+ if app.respond_to?(:set)
+ app.set(options)
+ app.set(:vegas, self)
end
- # initialize app dir
+
+ # Make sure app dir is setup
FileUtils.mkdir_p(app_dir)
- return if options[:start] === false
+
+ return if options[:start] == false
+
# evaluate the launch_path
- path = if options[:launch_path] && options[:launch_path].respond_to?(:call)
+ path = if options[:launch_path].respond_to?(:call)
options[:launch_path].call(self)
else
options[:launch_path]
end
+
start(path)
end
def app_dir
- File.join(ROOT_DIR, app_name)
+ File.join(ROOT_DIR, filesystem_friendly_app_name)
end
def pid_file
- File.join(app_dir, "#{app_name}.pid")
+ File.join(app_dir, "#{filesystem_friendly_app_name}.pid")
end
def url_file
- File.join(app_dir, "#{app_name}.url")
+ File.join(app_dir, "#{filesystem_friendly_app_name}.url")
end
def url
"http://#{host}:#{port}"
end
def log_file
- File.join(app_dir, "#{app_name}.log")
+ File.join(app_dir, "#{filesystem_friendly_app_name}.log")
end
def start(path = nil)
logger.info "Running with Windows Settings" if WINDOWS
- logger.info "Starting #{app_name}"
+ logger.info "Starting #{quoted_app_name}"
begin
check_for_running(path)
find_port
write_url
launch!(url, path)
- daemonize! unless options[:foreground]
+ daemonize! unless options[:foreground]
run!
rescue RuntimeError => e
- logger.warn "There was an error starting #{app_name}: #{e}"
+ logger.warn "There was an error starting #{quoted_app_name}: #{e}"
exit
end
end
def find_port
if @port = options[:port]
- if !port_open?
+ announce_port_attempted
+
+ unless port_open?
logger.warn "Port #{port} is already in use. Please try another or don't use -P, for auto-port"
end
else
@port = PORT
- logger.info "Trying to start #{app_name} on Port #{port}"
- while !port_open?
+ announce_port_attempted
+
+ until port_open?
@port += 1
- logger.info "Trying to start #{app_name} on Port #{port}"
+ announce_port_attempted
end
end
end
+
+ def announce_port_attempted
+ logger.info "Trying to start #{quoted_app_name} on port #{port}"
+ end
def port_open?(check_url = nil)
begin
open(check_url || url)
false
@@ -128,23 +144,25 @@
def check_for_running(path = nil)
if File.exists?(pid_file) && File.exists?(url_file)
running_url = File.read(url_file)
if !port_open?(running_url)
- logger.warn "#{app_name} is already running at #{running_url}"
+ logger.warn "#{quoted_app_name} is already running at #{running_url}"
launch!(running_url, path)
exit!
end
end
end
def run!
+ logger.info "Running with Rack handler: #{@rack_handler.inspect}"
+
rack_handler.run app, :Host => host, :Port => port do |server|
trap(kill_command) do
## Use thins' hard #stop! if available, otherwise just #stop
server.respond_to?(:stop!) ? server.stop! : server.stop
- logger.info "#{app_name} received INT ... stopping"
+ logger.info "#{quoted_app_name} received INT ... stopping"
delete_pid!
end
end
end
@@ -183,15 +201,15 @@
logger.warn "pid not found at #{pid_file} : #{e}"
end
def status
if File.exists?(pid_file)
- logger.info "#{app_name} running"
+ logger.info "#{quoted_app_name} running"
logger.info "PID #{File.read(pid_file)}"
logger.info "URL #{File.read(url_file)}" if File.exists?(url_file)
else
- logger.info "#{app_name} not running!"
+ logger.info "#{quoted_app_name} not running!"
end
end
# Loads a config file at config_path and evals it in the context of the @app.
def load_config_file(config_path)
@@ -199,15 +217,15 @@
config = File.read(config_path)
# trim off anything after __END__
config.sub!(/^__END__\n.*/, '')
@app.module_eval(config)
end
-
+
def self.logger=(logger)
@logger = logger
end
-
+
def self.logger
@logger ||= LOGGER if defined?(LOGGER)
if !@logger
@logger = Logger.new(STDOUT)
@logger.formatter = Proc.new {|s, t, n, msg| "[#{t}] #{msg}\n"}
@@ -217,15 +235,49 @@
end
def logger
self.class.logger
end
-
- private
+
+ private
+ def setup_rack_handler
+ # First try to set Rack handler via a special hook we honor
+ @rack_handler = if @app.respond_to?(:detect_rack_handler)
+ @app.detect_rack_handler
+
+ # If they aren't using our hook, try to use their @app.server settings
+ elsif @app.respond_to?(:server) and @app.server
+ # If :server isn't set, it returns an array of possibilities,
+ # sorted from most to least preferable.
+ if @app.server.is_a?(Array)
+ handler = nil
+ @app.server.each do |server|
+ begin
+ handler = Rack::Handler.get(server)
+ break
+ rescue NameError => e
+ next
+ end
+ end
+ handler
+
+ # :server might be set explicitly to a single option like "mongrel"
+ else
+ Rack::Handler.get(@app.server)
+ end
+
+ # If all else fails, we'll use Thin
+ else
+ Rack::Handler::Thin
+ end
+ end
+
def define_options
OptionParser.new("", 24, ' ') do |opts|
- opts.banner = "Usage: #{app_name} [options]"
+ # TODO instead of app_name, we should determine the name of the script
+ # used to invoke Vegas and use that here
+ opts.banner = "Usage: your_executable_name [options]"
opts.separator ""
opts.separator "Vegas options:"
opts.on("-s", "--server SERVER", "serve using SERVER (thin/mongrel/webrick)") { |s|
@@ -276,10 +328,10 @@
exit
end
opts.on_tail("--version", "Show version") do
if app.respond_to?(:version)
- puts "#{app_name} #{app.version}"
+ puts "#{quoted_app_name} #{app.version}"
end
puts "rack #{Rack::VERSION.join('.')}"
puts "sinatra #{Sinatra::VERSION}" if defined?(Sinatra)
puts "vegas #{Vegas::VERSION}"
exit