From 8fe25a695897a04e11356494437f50b67f0c643e Mon Sep 17 00:00:00 2001 From: Dmitry Chestnykh Date: Mon, 30 Sep 2013 03:10:57 +0200 Subject: [PATCH 1/4] Replace directory_watcher with listen. Directory_watcher consumed ~25% CPU on big Jekyll projects (depending on the number of watched files), since it polled for changes every second. Listen is easier on CPU, as it uses directory change notifications provided by OS (currently OS X and Linux), falling back to polling when they are not available. --- jekyll.gemspec | 2 +- lib/jekyll/commands/build.rb | 17 ++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/jekyll.gemspec b/jekyll.gemspec index f726d4d1..f9b46f73 100644 --- a/jekyll.gemspec +++ b/jekyll.gemspec @@ -25,7 +25,7 @@ Gem::Specification.new do |s| s.add_runtime_dependency('liquid', "~> 2.5.2") s.add_runtime_dependency('classifier', "~> 1.3") - s.add_runtime_dependency('directory_watcher', "~> 1.4.1") + s.add_runtime_dependency('listen', "~> 1.3.1") s.add_runtime_dependency('maruku', "~> 0.5") s.add_runtime_dependency('pygments.rb', "~> 0.5.0") s.add_runtime_dependency('commander', "~> 4.1.3") diff --git a/lib/jekyll/commands/build.rb b/lib/jekyll/commands/build.rb index fe49b54b..901806c7 100644 --- a/lib/jekyll/commands/build.rb +++ b/lib/jekyll/commands/build.rb @@ -31,25 +31,24 @@ module Jekyll # # Returns nothing. def self.watch(site, options) - require 'directory_watcher' + require 'listen' + require 'pathname' source = options['source'] - destination = options['destination'] + destination = Pathname.new(options['destination']) + .relative_path_from(Pathname.new(source)) + .to_path Jekyll.logger.info "Auto-regeneration:", "enabled" - dw = DirectoryWatcher.new(source, :glob => self.globs(source, destination), :pre_load => true) - dw.interval = 1 - - dw.add_observer do |*args| + Listen.to(source, :ignore => %r{#{Regexp.escape(destination)}}) do |modified, added, removed| t = Time.now.strftime("%Y-%m-%d %H:%M:%S") - print Jekyll.logger.formatted_topic("Regenerating:") + "#{args.size} files at #{t} " + n = modified.length + added.length + removed.length + print Jekyll.logger.formatted_topic("Regenerating:") + "#{n} files at #{t} " self.process_site(site) puts "...done." end - dw.start - unless options['serving'] trap("INT") do puts " Halting auto-regeneration." From dfaf1f45cc5c587a210ccb5c8ecc701fca3aa236 Mon Sep 17 00:00:00 2001 From: Dmitry Chestnykh Date: Mon, 30 Sep 2013 05:11:15 +0200 Subject: [PATCH 2/4] Remove require 'pathname': already included. --- lib/jekyll/commands/build.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/jekyll/commands/build.rb b/lib/jekyll/commands/build.rb index 901806c7..79ab11bb 100644 --- a/lib/jekyll/commands/build.rb +++ b/lib/jekyll/commands/build.rb @@ -32,7 +32,6 @@ module Jekyll # Returns nothing. def self.watch(site, options) require 'listen' - require 'pathname' source = options['source'] destination = Pathname.new(options['destination']) From 58cab6b0505504dc567f9385ad1d451219bcf08d Mon Sep 17 00:00:00 2001 From: Dmitry Chestnykh Date: Mon, 30 Sep 2013 05:55:38 +0200 Subject: [PATCH 3/4] Handle destinations outside of source. --- lib/jekyll/commands/build.rb | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/jekyll/commands/build.rb b/lib/jekyll/commands/build.rb index 79ab11bb..dd5fc967 100644 --- a/lib/jekyll/commands/build.rb +++ b/lib/jekyll/commands/build.rb @@ -34,13 +34,20 @@ module Jekyll require 'listen' source = options['source'] - destination = Pathname.new(options['destination']) - .relative_path_from(Pathname.new(source)) - .to_path + destination = options['destination'] + + begin + ignored = Regexp.new(Regexp.escape(Pathname.new(destination) + .relative_path_from(Pathname.new(source)) + .to_path)) + rescue ArgumentError + # Destination is outside the source, no need to ignore it. + ignored = nil + end Jekyll.logger.info "Auto-regeneration:", "enabled" - Listen.to(source, :ignore => %r{#{Regexp.escape(destination)}}) do |modified, added, removed| + Listen.to(source, :ignore => ignored) do |modified, added, removed| t = Time.now.strftime("%Y-%m-%d %H:%M:%S") n = modified.length + added.length + removed.length print Jekyll.logger.formatted_topic("Regenerating:") + "#{n} files at #{t} " From 12ba0a541c552bd6d836be0c4256f9aea2bb9cff Mon Sep 17 00:00:00 2001 From: Dmitry Chestnykh Date: Fri, 18 Oct 2013 11:04:54 +0200 Subject: [PATCH 4/4] Update listen to ~> 2.0. --- jekyll.gemspec | 2 +- lib/jekyll/commands/build.rb | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/jekyll.gemspec b/jekyll.gemspec index f9b46f73..4923aed2 100644 --- a/jekyll.gemspec +++ b/jekyll.gemspec @@ -25,7 +25,7 @@ Gem::Specification.new do |s| s.add_runtime_dependency('liquid', "~> 2.5.2") s.add_runtime_dependency('classifier', "~> 1.3") - s.add_runtime_dependency('listen', "~> 1.3.1") + s.add_runtime_dependency('listen', "~> 2.0") s.add_runtime_dependency('maruku', "~> 0.5") s.add_runtime_dependency('pygments.rb', "~> 0.5.0") s.add_runtime_dependency('commander', "~> 4.1.3") diff --git a/lib/jekyll/commands/build.rb b/lib/jekyll/commands/build.rb index dd5fc967..56fe90e6 100644 --- a/lib/jekyll/commands/build.rb +++ b/lib/jekyll/commands/build.rb @@ -47,16 +47,18 @@ module Jekyll Jekyll.logger.info "Auto-regeneration:", "enabled" - Listen.to(source, :ignore => ignored) do |modified, added, removed| + listener = Listen.to(source, ignore: ignored) do |modified, added, removed| t = Time.now.strftime("%Y-%m-%d %H:%M:%S") n = modified.length + added.length + removed.length print Jekyll.logger.formatted_topic("Regenerating:") + "#{n} files at #{t} " self.process_site(site) puts "...done." end + listener.start unless options['serving'] trap("INT") do + listener.stop puts " Halting auto-regeneration." exit 0 end