Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 56 additions & 23 deletions lib/jekyll/watcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,25 +43,34 @@ def watch(options, site = nil)
private

def build_listener(site, options)
ignore_regexps, ignore_paths = listen_ignore_paths(options)

Listen.to(
options["source"],
:ignore => listen_ignore_paths(options),
:ignore => ignore_regexps,
:force_polling => options["force_polling"],
&listen_handler(site)
&listen_handler(site, ignore_paths)
)
end

def listen_handler(site)
def listen_handler(site, ignore_paths)
proc do |modified, added, removed|
t = Time.now
modified = strip_ignore_paths(modified, ignore_paths)
added = strip_ignore_paths(added, ignore_paths)
removed = strip_ignore_paths(removed, ignore_paths)

c = modified + added + removed
n = c.length

Jekyll.logger.info "Regenerating:",
"#{n} file(s) changed at #{t.strftime("%Y-%m-%d %H:%M:%S")}"
unless c.empty?
t = Time.now
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)
c.each { |path| Jekyll.logger.info "", path["#{site.source}/".length..-1] }
process(site, t)
end
end
end

Expand All @@ -74,6 +83,10 @@ def normalize_encoding(obj, desired_encoding)
end
end

# paths that user specified to be excluded in their _config.yml file.
# could be nil, a single string or an array of strings.
#
# Returns an array of paths joined to the src directory.
def custom_excludes(options)
Array(options["exclude"]).map { |e| Jekyll.sanitized_path(options["source"], e) }
end
Expand All @@ -89,34 +102,54 @@ def to_exclude(options)
config_files(options),
options["destination"],
custom_excludes(options),
].flatten
].flat_map { |e| normalize_encoding(e, options["source"].encoding) }
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
# Returns a tuple where the first entry is a list of regular
# expressions relating to exact (existing) files to
# ignore and the second is a list of fnmatch patterns
# to ignore.
def listen_ignore_paths(options)
source = Pathname.new(options["source"]).expand_path
paths = to_exclude(options)
exclusion_fnmatch_paths = []

paths.map do |p|
absolute_path = Pathname.new(normalize_encoding(p, options["source"].encoding)).expand_path
next unless absolute_path.exist?
exclusion_regexps = to_exclude(options).map do |path|
# convert to absolute path from the source directory
absolute_path = Pathname.new(path).expand_path
relative_path = absolute_path.relative_path_from(source).to_s

begin
relative_path = absolute_path.relative_path_from(source).to_s
if absolute_path.exist?
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

begin
next if relative_path.start_with?("../")

%r!^#{Regexp.escape(relative_path)}!.tap do |pattern|
Jekyll.logger.debug "Watcher:", "Ignoring #{pattern}"
end
rescue ArgumentError
# Could not find a relative path
end
rescue ArgumentError
# Could not find a relative path
else
# maybe wildcard, or just a file that doesn't exist.
nil.tap { exclusion_fnmatch_paths << relative_path }
end
end.compact + [%r!^\.jekyll\-metadata!]

[exclusion_regexps, exclusion_fnmatch_paths]
end

# remove any paths from PATHS which're matched to by some fnmatch
# pattern in IGNORE_PATTERNS
def strip_ignore_paths(paths, ignore_patterns)
paths.select do |path|
# true when every patten in ignore_patterns does not match to path.
ignore_patterns.find { |pattern| File.fnmatch?(pattern, path) }.nil?
end
end

def sleep_forever
Expand Down
3 changes: 2 additions & 1 deletion spec/watcher_spec.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# coding: utf-8
require "spec_helper"

describe(Jekyll::Watcher) do
Expand Down Expand Up @@ -97,7 +98,7 @@
end

context "#listen_ignore_paths" do
let(:ignored) { subject.send(:listen_ignore_paths, options) }
let(:ignored) { subject.send(:listen_ignore_paths, options)[0] }
let(:metadata_path) { Jekyll.sanitized_path(options["source"], ".jekyll-metadata") }

before(:each) { FileUtils.touch(metadata_path) }
Expand Down