rf-web/vendor/bundle/gems/jekyll-watch-2.2.1/lib/jekyll/watcher.rb
2019-10-21 10:18:17 +02:00

138 lines
4.0 KiB
Ruby

# frozen_string_literal: true
require "listen"
module Jekyll
module Watcher
extend self
# Public: Continuously watch for file changes and rebuild the site
# whenever a change is detected.
#
# If the optional site argument is populated, that site instance will be
# reused and the options Hash ignored. Otherwise, a new site instance will
# be instantiated from the options Hash and used.
#
# options - A Hash containing the site configuration
# site - The current site instance (populated starting with Jekyll 3.2)
# (optional, default: nil)
#
# Returns nothing.
def watch(options, site = nil)
ENV["LISTEN_GEM_DEBUGGING"] ||= "1" if options["verbose"]
site ||= Jekyll::Site.new(options)
listener = build_listener(site, options)
listener.start
Jekyll.logger.info "Auto-regeneration:", "enabled for '#{options["source"]}'"
unless options["serving"]
trap("INT") do
listener.stop
Jekyll.logger.info "", "Halting auto-regeneration."
exit 0
end
sleep_forever
end
rescue ThreadError
# You pressed Ctrl-C, oh my!
end
private
def build_listener(site, options)
Listen.to(
options["source"],
:ignore => listen_ignore_paths(options),
:force_polling => options["force_polling"],
&listen_handler(site)
)
end
def listen_handler(site)
proc do |modified, added, removed|
t = Time.now
c = modified + added + removed
n = c.length
Jekyll.logger.info "Regenerating:",
"#{n} file(s) changed at #{t.strftime("%Y-%m-%d %H:%M:%S")}"
c.each { |path| Jekyll.logger.info "", path["#{site.source}/".length..-1] }
process(site, t)
end
end
def normalize_encoding(obj, desired_encoding)
case obj
when Array
obj.map { |entry| entry.encode!(desired_encoding, entry.encoding) }
when String
obj.encode!(desired_encoding, obj.encoding)
end
end
def custom_excludes(options)
Array(options["exclude"]).map { |e| Jekyll.sanitized_path(options["source"], e) }
end
def config_files(options)
%w(yml yaml toml).map do |ext|
Jekyll.sanitized_path(options["source"], "_config.#{ext}")
end
end
def to_exclude(options)
[
config_files(options),
options["destination"],
custom_excludes(options),
].flatten
end
# Paths to ignore for the watch option
#
# options - A Hash of options passed to the command
#
# Returns a list of relative paths from source that should be ignored
def listen_ignore_paths(options)
source = Pathname.new(options["source"]).expand_path
paths = to_exclude(options)
paths.map do |p|
absolute_path = Pathname.new(normalize_encoding(p, options["source"].encoding)).expand_path
next unless absolute_path.exist?
begin
relative_path = absolute_path.relative_path_from(source).to_s
relative_path = File.join(relative_path, "") if absolute_path.directory?
unless relative_path.start_with?("../")
path_to_ignore = %r!^#{Regexp.escape(relative_path)}!
Jekyll.logger.debug "Watcher:", "Ignoring #{path_to_ignore}"
path_to_ignore
end
rescue ArgumentError
# Could not find a relative path
end
end.compact + [%r!^\.jekyll\-metadata!]
end
def sleep_forever
loop { sleep 1000 }
end
def process(site, time)
begin
site.process
Jekyll.logger.info "", "...done in #{Time.now - time} seconds."
rescue StandardError => e
Jekyll.logger.warn "Error:", e.message
Jekyll.logger.warn "Error:", "Run jekyll build --trace for more information."
end
Jekyll.logger.info ""
end
end
end