2013-12-28 01:26:31 +01:00
require 'webrick'
2012-10-13 22:12:47 +02:00
require 'middleman-core/meta_pages'
2013-12-31 23:41:17 +01:00
require 'middleman-core/logger'
2014-07-05 21:14:58 +02:00
require 'middleman-core/rack'
2012-07-09 09:16:13 +02:00
2014-07-02 20:05:57 +02:00
# rubocop:disable GlobalVars
2012-05-20 01:49:44 +02:00
module Middleman
module PreviewServer
DEFAULT_PORT = 4567
2012-08-14 00:39:06 +02:00
2012-05-20 01:49:44 +02:00
class << self
2014-07-05 20:17:41 +02:00
extend Forwardable
2012-11-11 03:16:47 +01:00
attr_reader :app , :host , :port
2014-07-05 20:17:41 +02:00
def_delegator :app , :logger
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 = { } )
2014-07-14 22:19:34 +02:00
@options = opts . dup . freeze
2014-04-14 19:34:53 +02:00
@host = @options [ :host ] || '0.0.0.0'
2012-09-13 19:13:57 +02:00
@port = @options [ :port ] || DEFAULT_PORT
2012-08-14 00:39:06 +02:00
2013-10-20 04:39:10 +02:00
mount_instance ( new_app )
2014-03-12 10:05:43 +01:00
logger . info " == The Middleman is standing watch at #{ uri } "
logger . info " == Inspect your site configuration at #{ uri + '__middleman' } "
2012-05-20 08:17:13 +02:00
@initialized || = false
2014-07-02 19:11:52 +02:00
return if @initialized
@initialized = true
2012-08-14 00:39:06 +02:00
2014-07-02 19:11:52 +02:00
register_signal_handlers
2012-08-14 00:39:06 +02:00
2014-07-02 19:11:52 +02:00
# Save the last-used @options so it may be re-used when
# reloading later on.
:: Middleman :: Profiling . report ( 'server_start' )
2012-07-19 07:10:02 +02:00
2014-07-02 19:11:52 +02:00
loop do
@webrick . start
2013-03-03 21:31:42 +01:00
2014-07-02 19:11:52 +02:00
# $mm_shutdown is set by the signal handler
if $mm_shutdown
shutdown
exit
elsif $mm_reload
$mm_reload = false
reload
2013-03-03 21:31:42 +01:00
end
2012-05-20 01:49:44 +02:00
end
end
# Detach the current Middleman::Application instance
# @return [void]
def stop
2012-09-28 08:02:59 +02:00
begin
2013-12-28 01:26:31 +01:00
logger . info '== The Middleman is shutting down'
2012-09-28 08:02:59 +02:00
rescue
# if the user closed their terminal STDOUT/STDERR won't exist
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
2013-12-28 01:26:31 +01:00
logger . info '== The Middleman is reloading'
2012-11-11 03:16:47 +01:00
2013-10-20 04:39:10 +02:00
begin
app = new_app
2014-04-29 19:50:21 +02:00
rescue = > e
2013-10-20 04:39:10 +02:00
logger . error " Error reloading Middleman: #{ e } \n #{ e . backtrace . join ( " \n " ) } "
2013-12-28 01:26:31 +01:00
logger . info '== The Middleman is still running the application from before the error'
2013-10-20 04:39:10 +02:00
return
end
2012-09-13 19:13:57 +02:00
unmount_instance
2013-10-20 04:39:10 +02:00
mount_instance ( app )
2012-11-11 03:16:47 +01:00
2013-12-28 01:26:31 +01:00
logger . info '== The Middleman has reloaded'
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
2014-04-29 19:50:21 +02:00
private
2014-04-29 19:44:24 +02:00
2012-09-13 19:13:57 +02:00
def new_app
2014-07-14 22:19:34 +02:00
opts = @options
2014-07-05 22:41:59 +02:00
:: Middleman :: Logger . singleton (
opts [ :debug ] ? 0 : 1 ,
opts [ :instrumenting ] || false
)
2014-07-05 21:14:58 +02:00
app = :: Middleman :: Application . new do
config [ :environment ] = opts [ :environment ] . to_sym if opts [ :environment ]
2014-07-16 03:01:45 +02:00
config [ :watcher_disable ] = opts [ :disable_watcher ]
config [ :watcher_force_polling ] = opts [ :force_polling ]
config [ :watcher_latency ] = opts [ :latency ]
ready do
match_against = [
%r{ ^config \ .rb$ } ,
%r{ ^environments/[^ \ .](.*) \ .rb$ } ,
%r{ ^lib/[^ \ .](.*) \ .rb$ } ,
%r{ ^ #{ @app . config [ :helpers_dir ] } /[^ \ .](.*) \ .rb$ }
]
# config.rb
files . watch :reload ,
path : root ,
ignored : proc { | file |
match_against . none? { | m | file [ :relative_path ] . to_s . match ( m ) }
}
end
end
app . files . changed :reload do
$mm_reload = true
@webrick . stop
2014-07-05 21:14:58 +02:00
end
2013-04-13 07:48:56 +02:00
# Add in the meta pages application
2014-07-05 21:14:58 +02:00
meta_app = Middleman :: MetaPages :: Application . new ( app )
app . map '/__middleman' do
2013-04-13 07:48:56 +02:00
run meta_app
end
2014-07-05 21:14:58 +02:00
app
2012-09-13 19:13:57 +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 |
2014-07-02 19:11:52 +02:00
next unless Signal . list [ sig ]
Signal . trap ( sig ) do
# Do as little work as possible in the signal context
$mm_shutdown = true
2014-07-02 20:05:57 +02:00
2014-07-02 19:11:52 +02:00
@webrick . stop
2012-09-28 08:02:59 +02:00
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 = {
2014-04-29 19:50:21 +02:00
BindAddress : host ,
Port : port ,
AccessLog : [ ] ,
DoNotReverseLookup : true
2012-05-20 01:49:44 +02:00
}
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 )
2013-04-06 23:48:00 +02:00
rescue Errno :: EADDRINUSE
2014-04-29 19:50:21 +02:00
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 } "
2012-09-13 19:13:57 +02:00
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]
2013-10-20 04:39:10 +02:00
def mount_instance ( app )
@app = app
2012-09-28 08:02:59 +02:00
2012-11-11 03:16:47 +01:00
@webrick || = setup_webrick ( @options [ :debug ] || false )
2014-07-05 21:14:58 +02:00
rack_app = :: Middleman :: Rack . new ( @app ) . to_app
2013-12-28 01:26:31 +01:00
@webrick . mount '/' , :: Rack :: Handler :: WEBrick , 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
2013-12-28 01:26:31 +01:00
@webrick . unmount '/'
2012-05-20 01:49:44 +02:00
2014-07-16 03:01:45 +02:00
@app . shutdown!
2012-11-11 03:16:47 +01:00
2014-07-16 03:01:45 +02:00
@app = nil
2012-05-20 01:49:44 +02:00
end
2014-03-12 10:05:43 +01:00
# Returns the URI the preview server will run on
# @return [URI]
def uri
host = ( @host == '0.0.0.0' ) ? 'localhost' : @host
URI ( " http:// #{ host } : #{ @port } " )
end
2012-05-20 01:49:44 +02:00
end
2012-07-09 09:16:13 +02:00
class FilteredWebrickLog < :: WEBrick :: Log
def log ( level , data )
2014-07-02 19:11:52 +02:00
super ( level , data ) unless data =~ %r{ Could not determine content-length of response body. }
2012-07-09 09:16:13 +02:00
end
end
2012-05-20 01:49:44 +02:00
end
2012-05-20 08:05:06 +02:00
end