2012-07-09 09:16:13 +02:00
require " webrick "
2012-05-20 01:49:44 +02:00
module Middleman
module PreviewServer
2012-08-14 00:39:06 +02:00
2012-11-11 03:16:47 +01:00
DEFAULT_HOST = '0.0.0.0'
2012-05-20 01:49:44 +02:00
DEFAULT_PORT = 4567
2012-08-14 00:39:06 +02:00
2012-05-20 01:49:44 +02:00
class << self
2012-11-11 03:16:47 +01:00
attr_reader :app , :host , :port
2012-07-15 20:04:45 +02:00
delegate :logger , :to = > :app
2012-08-14 00:39:06 +02:00
2012-05-20 01:49:44 +02:00
# Start an instance of Middleman::Application
# @return [void]
2012-09-13 19:13:57 +02:00
def start ( opts = { } )
@options = opts
2012-11-11 03:16:47 +01:00
@host = @options [ :host ] || DEFAULT_HOST
2012-09-13 19:13:57 +02:00
@port = @options [ :port ] || DEFAULT_PORT
2012-08-14 00:39:06 +02:00
2012-09-13 19:13:57 +02:00
mount_instance
2012-11-11 03:16:47 +01:00
logger . info " == The Middleman is standing watch at http:// #{ host } : #{ port } "
2012-05-20 08:17:13 +02:00
@initialized || = false
unless @initialized
@initialized = true
2012-08-14 00:39:06 +02:00
2012-09-28 08:02:59 +02:00
register_signal_handlers
2012-08-14 00:39:06 +02:00
2012-09-13 19:13:57 +02:00
# Save the last-used @options so it may be re-used when
2012-06-16 00:20:40 +02:00
# reloading later on.
2012-07-19 07:10:02 +02:00
:: Middleman :: Profiling . report ( " server_start " )
2012-05-20 01:49:44 +02:00
@webrick . start
end
end
# Detach the current Middleman::Application instance
# @return [void]
def stop
2012-09-28 08:02:59 +02:00
begin
logger . info " == The Middleman is shutting down "
rescue
# if the user closed their terminal STDOUT/STDERR won't exist
end
2012-06-28 08:27:27 +02:00
if @listener
@listener . stop
@listener = nil
end
2012-05-20 01:49:44 +02:00
unmount_instance
end
2012-08-14 00:39:06 +02:00
2012-05-20 01:49:44 +02:00
# Simply stop, then start the server
# @return [void]
def reload
2012-09-13 19:13:57 +02:00
logger . info " == The Middleman is reloading "
2012-11-11 03:16:47 +01:00
2012-09-13 19:13:57 +02:00
unmount_instance
mount_instance
2012-11-11 03:16:47 +01:00
logger . info " == The Middleman is standing watch at http:// #{ host } : #{ port } "
2012-05-20 01:49:44 +02:00
end
# Stop the current instance, exit Webrick
# @return [void]
def shutdown
stop
@webrick . shutdown
end
2012-08-14 00:39:06 +02:00
2012-05-20 01:49:44 +02:00
private
2012-09-13 19:13:57 +02:00
def new_app
opts = @options
@app = :: Middleman :: Application . server . inst do
if opts [ :environment ]
2012-10-14 04:54:55 +02:00
config [ :environment ] = opts [ :environment ] . to_sym
2012-09-13 19:13:57 +02:00
end
2012-11-11 03:16:47 +01:00
2012-09-13 19:13:57 +02:00
logger ( opts [ :debug ] ? 0 : 1 , opts [ :instrumenting ] || false )
end
end
2012-08-14 00:39:06 +02:00
2012-05-20 01:49:44 +02:00
def start_file_watcher
2012-09-13 19:51:16 +02:00
return if @options [ :" disable-watcher " ]
2012-11-11 03:16:47 +01:00
2012-09-13 19:51:16 +02:00
first_run = ! @listener
2012-11-11 03:16:47 +01:00
2012-09-13 19:51:16 +02:00
if first_run
# Watcher Library
require " listen "
@listener = Listen . to ( Dir . pwd , :relative_paths = > true )
end
2012-11-11 03:16:47 +01:00
2012-06-28 08:27:27 +02:00
@listener . change do | modified , added , removed |
2012-05-20 01:49:44 +02:00
added_and_modified = ( modified + added )
2012-09-13 19:51:16 +02:00
# See if the changed file is config.rb or lib/*.rb
if needs_to_reload? ( added_and_modified ) || needs_to_reload? ( removed )
reload
else
2012-05-20 08:05:06 +02:00
added_and_modified . each do | path |
2012-09-13 19:13:57 +02:00
app . files . did_change ( path )
2012-05-20 01:49:44 +02:00
end
removed . each do | path |
2012-09-13 19:13:57 +02:00
app . files . did_delete ( path )
2012-05-20 01:49:44 +02:00
end
end
end
2012-08-14 00:39:06 +02:00
2012-05-20 01:49:44 +02:00
# Don't block this thread
2012-09-13 19:51:16 +02:00
@listener . start ( false ) if first_run
2012-05-20 01:49:44 +02:00
end
2012-08-14 00:39:06 +02:00
2012-09-28 08:02:59 +02:00
# Trap some interupt signals and shut down smoothly
2012-05-20 01:49:44 +02:00
# @return [void]
def register_signal_handlers
2012-09-28 08:02:59 +02:00
%w( INT HUP TERM QUIT ) . each do | sig |
if Signal . list [ sig ]
Signal . trap ( sig ) do
shutdown
exit
end
end
end
2012-05-20 01:49:44 +02:00
end
2012-08-14 00:39:06 +02:00
# Initialize webrick
2012-05-20 01:49:44 +02:00
# @return [void]
2012-11-11 03:16:47 +01:00
def setup_webrick ( is_logging )
2012-05-20 01:49:44 +02:00
http_opts = {
2012-11-11 03:16:47 +01:00
:BindAddress = > host ,
2012-09-13 19:13:57 +02:00
:Port = > port ,
2012-05-20 01:49:44 +02:00
:AccessLog = > [ ]
}
2012-08-14 00:39:06 +02:00
2012-07-09 09:16:13 +02:00
if is_logging
http_opts [ :Logger ] = FilteredWebrickLog . new
else
http_opts [ :Logger ] = :: WEBrick :: Log . new ( nil , 0 )
2012-05-20 01:49:44 +02:00
end
2012-08-14 00:39:06 +02:00
2012-09-13 19:13:57 +02:00
begin
:: WEBrick :: HTTPServer . new ( http_opts )
rescue Errno :: EADDRINUSE = > e
logger . error " == Port #{ port } is unavailable. Either close the instance of Middleman already running on #{ port } or start this Middleman on a new port with: --port= #{ port . to_i + 1 } "
exit ( 1 )
end
2012-05-20 01:49:44 +02:00
end
2012-08-14 00:39:06 +02:00
2012-05-20 01:49:44 +02:00
# Attach a new Middleman::Application instance
# @param [Middleman::Application] app
# @return [void]
2012-09-13 19:13:57 +02:00
def mount_instance
2012-09-28 08:02:59 +02:00
@app = new_app
2012-11-11 03:16:47 +01:00
@webrick || = setup_webrick ( @options [ :debug ] || false )
2012-09-13 19:51:16 +02:00
start_file_watcher
2012-11-11 03:16:47 +01:00
2012-09-13 19:13:57 +02:00
@webrick . mount " / " , :: Rack :: Handler :: WEBrick , app . class . to_rack_app
2012-05-20 01:49:44 +02:00
end
2012-08-14 00:39:06 +02:00
2012-05-20 01:49:44 +02:00
# Detach the current Middleman::Application instance
# @return [void]
def unmount_instance
@webrick . unmount " / "
@app = nil
end
# Whether the passed files are config.rb, lib/*.rb or helpers
# @param [Array<String>] paths Array of paths to check
# @return [Boolean] Whether the server needs to reload
def needs_to_reload? ( paths )
2012-09-13 19:13:57 +02:00
match_against = [
%r{ ^config \ .rb } ,
%r{ ^lib/^[^ \ .](.*) \ .rb$ } ,
%r{ ^helpers/^[^ \ .](.*)_helper \ .rb$ }
]
2012-11-11 03:16:47 +01:00
2012-09-13 19:13:57 +02:00
if @options [ :reload_paths ]
@options [ :reload_paths ] . split ( ',' ) . each do | part |
match_against << %r{ ^ #{ part } }
end
end
2012-11-11 03:16:47 +01:00
2012-05-20 01:49:44 +02:00
paths . any? do | path |
2012-09-13 19:13:57 +02:00
match_against . any? do | matcher |
path . match ( matcher )
end
2012-05-20 01:49:44 +02:00
end
end
end
2012-07-09 09:16:13 +02:00
class FilteredWebrickLog < :: WEBrick :: Log
def log ( level , data )
unless data =~ %r{ Could not determine content-length of response body. }
super ( level , data )
end
end
end
2012-05-20 01:49:44 +02:00
end
2012-05-20 08:05:06 +02:00
end