middleman/middleman-core/lib/middleman-core/preview_server.rb

213 lines
5.5 KiB
Ruby
Raw Normal View History

require 'webrick'
2012-10-13 22:12:47 +02:00
require 'middleman-core/meta_pages'
require 'middleman-core/logger'
require 'middleman-core/rack'
2014-07-02 20:05:57 +02:00
# rubocop:disable GlobalVars
module Middleman
module PreviewServer
DEFAULT_PORT = 4567
class << self
extend Forwardable
attr_reader :app, :host, :port
def_delegator :app, :logger
# 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
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'}"
@initialized ||= false
2014-07-02 19:11:52 +02:00
return if @initialized
@initialized = true
2014-07-02 19:11:52 +02:00
register_signal_handlers
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')
2014-07-02 19:11:52 +02:00
loop do
@webrick.start
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
end
end
end
# Detach the current Middleman::Application instance
# @return [void]
def stop
begin
logger.info '== The Middleman is shutting down'
rescue
# if the user closed their terminal STDOUT/STDERR won't exist
end
unmount_instance
end
# Simply stop, then start the server
# @return [void]
def reload
logger.info '== The Middleman is reloading'
begin
app = new_app
2014-04-29 19:50:21 +02:00
rescue => e
logger.error "Error reloading Middleman: #{e}\n#{e.backtrace.join("\n")}"
logger.info '== The Middleman is still running the application from before the error'
return
end
2012-09-13 19:13:57 +02:00
unmount_instance
mount_instance(app)
logger.info '== The Middleman has reloaded'
end
# Stop the current instance, exit Webrick
# @return [void]
def shutdown
stop
@webrick.shutdown
end
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
::Middleman::Logger.singleton(
opts[:debug] ? 0 : 1,
opts[:instrumenting] || false
)
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
end
# Add in the meta pages application
meta_app = Middleman::MetaPages::Application.new(app)
app.map '/__middleman' do
run meta_app
end
app
2012-09-13 19:13:57 +02:00
end
# Trap some interupt signals and shut down smoothly
# @return [void]
def register_signal_handlers
%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
end
end
end
# Initialize webrick
# @return [void]
def setup_webrick(is_logging)
http_opts = {
2014-04-29 19:50:21 +02:00
BindAddress: host,
Port: port,
AccessLog: [],
DoNotReverseLookup: true
}
if is_logging
http_opts[:Logger] = FilteredWebrickLog.new
else
http_opts[:Logger] = ::WEBrick::Log.new(nil, 0)
end
2012-09-13 19:13:57 +02:00
begin
::WEBrick::HTTPServer.new(http_opts)
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
end
# Attach a new Middleman::Application instance
# @param [Middleman::Application] app
# @return [void]
def mount_instance(app)
@app = app
@webrick ||= setup_webrick(@options[:debug] || false)
rack_app = ::Middleman::Rack.new(@app).to_app
@webrick.mount '/', ::Rack::Handler::WEBrick, rack_app
end
# Detach the current Middleman::Application instance
# @return [void]
def unmount_instance
@webrick.unmount '/'
2014-07-16 03:01:45 +02:00
@app.shutdown!
2014-07-16 03:01:45 +02:00
@app = nil
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
end
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.}
end
end
end
end