lib/jekyll/commands/serve.rb in jekyll-3.0.5 vs lib/jekyll/commands/serve.rb in jekyll-3.1.0.pre.beta1
- old
+ new
@@ -1,151 +1,196 @@
-# -*- encoding: utf-8 -*-
module Jekyll
module Commands
class Serve < Command
-
class << self
+ COMMAND_OPTIONS = {
+ "ssl_cert" => ["--ssl-cert [CERT]", "X.509 (SSL) certificate."],
+ "host" => ["host", "-H", "--host [HOST]", "Host to bind to"],
+ "open_url" => ["-o", "--open-url", "Launch your browser with your site."],
+ "detach" => ["-B", "--detach", "Run the server in the background (detach)"],
+ "ssl_key" => ["--ssl-key [KEY]", "X.509 (SSL) Private Key."],
+ "port" => ["-P", "--port [PORT]", "Port to listen on"],
+ "baseurl" => ["-b", "--baseurl [URL]", "Base URL"],
+ "skip_initial_build" => ["skip_initial_build", "--skip-initial-build",
+ "Skips the initial site build which occurs before the server is started."]
+ }
+ #
+
def init_with_program(prog)
- prog.command(:serve) do |c|
- c.syntax 'serve [options]'
- c.description 'Serve your site locally'
- c.alias :server
- c.alias :s
+ prog.command(:serve) do |cmd|
+ cmd.description "Serve your site locally"
+ cmd.syntax "serve [options]"
+ cmd.alias :server
+ cmd.alias :s
- add_build_options(c)
+ add_build_options(cmd)
+ COMMAND_OPTIONS.each do |key, val|
+ cmd.option key, *val
+ end
- c.option 'detach', '-B', '--detach', 'Run the server in the background (detach)'
- c.option 'port', '-P', '--port [PORT]', 'Port to listen on'
- c.option 'host', '-H', '--host [HOST]', 'Host to bind to'
- c.option 'baseurl', '-b', '--baseurl [URL]', 'Base URL'
- c.option 'skip_initial_build', '--skip-initial-build', 'Skips the initial site build which occurs before the server is started.'
-
- c.action do |args, options|
- options["serving"] = true
- options["watch"] = true unless options.key?("watch")
- Jekyll::Commands::Build.process(options)
- Jekyll::Commands::Serve.process(options)
+ cmd.action do |_, opts|
+ opts["serving"] = true
+ opts["watch" ] = true unless opts.key?("watch")
+ Build.process(opts)
+ Serve.process(opts)
end
end
end
- # Boot up a WEBrick server which points to the compiled site's root.
- def process(options)
- options = configuration_from_options(options)
- destination = options['destination']
+ #
+
+ def process(opts)
+ opts = configuration_from_options(opts)
+ destination = opts["destination"]
setup(destination)
- s = WEBrick::HTTPServer.new(webrick_options(options))
- s.unmount("")
-
- s.mount(
- options['baseurl'],
- custom_file_handler,
- destination,
- file_handler_options
- )
-
- Jekyll.logger.info "Server address:", server_address(s, options)
-
- if options['detach'] # detach the server
- pid = Process.fork { s.start }
- Process.detach(pid)
- Jekyll.logger.info "Server detached with pid '#{pid}'.", "Run `pkill -f jekyll' or `kill -9 #{pid}' to stop the server."
- else # create a new server thread, then join it with current terminal
- t = Thread.new { s.start }
- trap("INT") { s.shutdown }
- t.join
- end
+ server = WEBrick::HTTPServer.new(webrick_opts(opts)).tap { |o| o.unmount("") }
+ server.mount(opts["baseurl"], Servlet, destination, file_handler_opts)
+ Jekyll.logger.info "Server address:", server_address(server, opts)
+ launch_browser server, opts if opts["open_url"]
+ boot_or_detach server, opts
end
+ # Do a base pre-setup of WEBRick so that everything is in place
+ # when we get ready to party, checking for an setting up an error page
+ # and making sure our destination exists.
+
+ private
def setup(destination)
- require 'webrick'
+ require_relative "serve/servlet"
FileUtils.mkdir_p(destination)
-
- # monkey patch WEBrick using custom 404 page (/404.html)
- if File.exist?(File.join(destination, '404.html'))
+ if File.exist?(File.join(destination, "404.html"))
WEBrick::HTTPResponse.class_eval do
def create_error_page
- @header['content-type'] = "text/html; charset=UTF-8"
- @body = IO.read(File.join(@config[:DocumentRoot], '404.html'))
+ @header["Content-Type"] = "text/html; charset=UTF-8"
+ @body = IO.read(File.join(@config[:DocumentRoot], "404.html"))
end
end
end
end
- def webrick_options(config)
+ #
+
+ private
+ def webrick_opts(opts)
opts = {
- :BindAddress => config['host'],
- :DirectoryIndex => %w(index.html index.htm index.cgi index.rhtml index.xml),
- :DocumentRoot => config['destination'],
+ :JekyllOptions => opts,
:DoNotReverseLookup => true,
:MimeTypes => mime_types,
- :Port => config['port'],
- :StartCallback => start_callback(config['detach'])
+ :DocumentRoot => opts["destination"],
+ :StartCallback => start_callback(opts["detach"]),
+ :BindAddress => opts["host"],
+ :Port => opts["port"],
+ :DirectoryIndex => %W(
+ index.htm
+ index.html
+ index.rhtml
+ index.cgi
+ index.xml
+ )
}
- if config['verbose']
- opts.merge!({
- :Logger => WEBrick::Log.new($stdout, WEBrick::Log::DEBUG)
- })
+ enable_ssl(opts)
+ enable_logging(opts)
+ opts
+ end
+
+ # Recreate NondisclosureName under utf-8 circumstance
+
+ private
+ def file_handler_opts
+ WEBrick::Config::FileHandler.merge({
+ :FancyIndexing => true,
+ :NondisclosureName => [
+ '.ht*','~*'
+ ]
+ })
+ end
+
+ #
+
+ private
+ def server_address(server, opts)
+ address = server.config[:BindAddress]
+ baseurl = "#{opts["baseurl"]}/" if opts["baseurl"]
+ port = server.config[:Port]
+
+ "http://#{address}:#{port}#{baseurl}"
+ end
+
+ #
+
+ private
+ def launch_browser(server, opts)
+ command = Utils::Platforms.windows?? "start" : Utils::Platforms.osx?? "open" : "xdg-open"
+ system command, server_address(server, opts)
+ end
+
+ # Keep in our area with a thread or detach the server as requested
+ # by the user. This method determines what we do based on what you
+ # ask us to do.
+
+ private
+ def boot_or_detach(server, opts)
+ if opts["detach"]
+ pid = Process.fork do
+ server.start
+ end
+
+ Process.detach(pid)
+ Jekyll.logger.info "Server detached with pid '#{pid}'.", \
+ "Run `pkill -f jekyll' or `kill -9 #{pid}' to stop the server."
else
- opts.merge!({
- :AccessLog => [],
- :Logger => WEBrick::Log.new([], WEBrick::Log::WARN)
- })
+ t = Thread.new { server.start }
+ trap("INT") { server.shutdown }
+ t.join
end
+ end
- opts
+ # Make the stack verbose if the user requests it.
+
+ private
+ def enable_logging(opts)
+ opts[:AccessLog] = []
+ level = WEBrick::Log.const_get(opts[:JekyllOptions]["verbose"] ? :DEBUG : :WARN)
+ opts[:Logger] = WEBrick::Log.new($stdout, level)
end
- # Custom WEBrick FileHandler servlet for serving "/file.html" at "/file"
- # when no exact match is found. This mirrors the behavior of GitHub
- # Pages and many static web server configs.
- def custom_file_handler
- Class.new WEBrick::HTTPServlet::FileHandler do
- def search_file(req, res, basename)
- if file = super
- file
- else
- super(req, res, "#{basename}.html")
- end
- end
+ # Add SSL to the stack if the user triggers --enable-ssl and they
+ # provide both types of certificates commonly needed. Raise if they
+ # forget to add one of the certificates.
+
+ private
+ def enable_ssl(opts)
+ return if !opts[:JekyllOptions]["ssl_cert"] && !opts[:JekyllOptions]["ssl_key"]
+ if !opts[:JekyllOptions]["ssl_cert"] || !opts[:JekyllOptions]["ssl_key"]
+ raise RuntimeError, "--ssl-cert or --ssl-key missing."
end
+
+ require "openssl"; require "webrick/https"
+ source_key = Jekyll.sanitized_path(opts[:JekyllOptions]["source"], opts[:JekyllOptions]["ssl_key" ])
+ source_certificate = Jekyll.sanitized_path(opts[:JekyllOptions]["source"], opts[:JekyllOptions]["ssl_cert"])
+ opts[:SSLCertificate] = OpenSSL::X509::Certificate.new(File.read(source_certificate))
+ opts[:SSLPrivateKey ] = OpenSSL::PKey::RSA.new(File.read(source_key))
+ opts[:EnableSSL] = true
end
+ private
def start_callback(detached)
unless detached
- Proc.new { Jekyll.logger.info "Server running...", "press ctrl-c to stop." }
+ proc do
+ Jekyll.logger.info("Server running...", "press ctrl-c to stop.")
+ end
end
end
+ private
def mime_types
- mime_types_file = File.expand_path('../mime.types', File.dirname(__FILE__))
- WEBrick::HTTPUtils::load_mime_types(mime_types_file)
+ file = File.expand_path('../mime.types', File.dirname(__FILE__))
+ WEBrick::HTTPUtils.load_mime_types(file)
end
-
- def server_address(server, options)
- baseurl = "#{options['baseurl']}/" if options['baseurl']
- [
- "http://",
- server.config[:BindAddress],
- ":",
- server.config[:Port],
- baseurl || ""
- ].map(&:to_s).join("")
- end
-
- # recreate NondisclosureName under utf-8 circumstance
- def file_handler_options
- WEBrick::Config::FileHandler.merge({
- :FancyIndexing => true,
- :NondisclosureName => ['.ht*','~*']
- })
- end
-
end
-
end
end
end