From 37171795913bf0a9378560e3469b9f8aa1d88156 Mon Sep 17 00:00:00 2001 From: Thibaud Guillaume-Gentil Date: Tue, 30 Aug 2011 21:13:51 +0200 Subject: [PATCH] Refactor new interactor/listener mechanic now it's look pretty. Specs still need some love :) --- lib/guard.rb | 102 ++++++++++++++++++--------------- lib/guard/interactor.rb | 87 ++++++---------------------- lib/guard/listener.rb | 41 ++++++++++++- lib/guard/listeners/linux.rb | 1 - lib/guard/listeners/windows.rb | 1 - 5 files changed, 112 insertions(+), 120 deletions(-) diff --git a/lib/guard.rb b/lib/guard.rb index dcfb1e4..4d2594c 100644 --- a/lib/guard.rb +++ b/lib/guard.rb @@ -9,15 +9,14 @@ module Guard autoload :Notifier, 'guard/notifier' class << self - attr_accessor :options, :guards, :listener, :interactor_thread + attr_accessor :options, :guards, :interactor, :listener # initialize this singleton def setup(options = {}) - @options = options - @listener = Listener.select_and_init(@options[:watchdir] ? File.expand_path(@options[:watchdir]) : Dir.pwd) - @guards = [] - @locked = false - @files = [] + @options = options + @guards = [] + @interactor = Interactor.new + @listener = Listener.select_and_init(@options[:watchdir] ? File.expand_path(@options[:watchdir]) : Dir.pwd) @options[:notify] && ENV["GUARD_NOTIFY"] != 'false' ? Notifier.turn_on : Notifier.turn_off @@ -28,48 +27,69 @@ module Guard end def start(options = {}) - # Interactor.init_signal_traps - setup(options) Dsl.evaluate_guardfile(options) - listener.on_change do |files| - Dsl.reevaluate_guardfile if Watcher.match_guardfile?(files) - - @files += files if Watcher.match_files?(guards, files) - end - UI.info "Guard is now watching at '#{listener.directory}'" guards.each { |guard| supervised_task(guard, :start) } - Interactor.listen - Thread.new do - loop do - if @files != [] && !@listener_locked - files = @files.dup - @files.clear - run { run_on_change_for_all_guards(files) } - end - end - end + interactor.start listener.start end - def run_on_change_for_all_guards(files) - guards.each do |guard| - paths = Watcher.match_files(guard, files) - unless paths.empty? - UI.debug "#{guard.class.name}#run_on_change with #{paths.inspect}" - supervised_task(guard, :run_on_change, paths) + def stop + UI.info "Bye bye...", :reset => true + listener.stop + guards.each { |guard| supervised_task(guard, :stop) } + abort + end + + def reload + run do + guards.each { |guard| supervised_task(guard, :reload) } + end + end + + def run_all + run do + guards.each { |guard| supervised_task(guard, :run_all) } + end + end + + def pause + if listener.locked + UI.info "Un-paused files modification listening", :reset => true + listener.clear_changed_files + listener.unlock + else + UI.info "Paused files modification listening", :reset => true + listener.lock + end + end + + def run_on_change(files) + run do + guards.each do |guard| + paths = Watcher.match_files(guard, files) + unless paths.empty? + UI.debug "#{guard.class.name}#run_on_change with #{paths.inspect}" + supervised_task(guard, :run_on_change, paths) + end end end + end - # Reparse the whole directory to catch new files modified during the guards run - # new_modified_files = listener.modified_files([listener.directory], :all => true) - # if !new_modified_files.empty? && Watcher.match_files?(guards, new_modified_files) - # run { run_on_change_for_all_guards(new_modified_files) } - # end + def run + listener.lock + interactor.lock + UI.clear if options[:clear] + begin + yield + rescue Interrupt + end + interactor.unlock + listener.unlock end # Let a guard execute its task but @@ -84,18 +104,6 @@ module Guard return ex end - def run - @listener_locked = true - Interactor.lock - UI.clear if options[:clear] - # begin - yield - # rescue Interrupt - # end - Interactor.unlock - @listener_locked = false - end - def add_guard(name, watchers = [], options = {}) if name.downcase == 'ego' UI.deprecation("Guard::Ego is now part of Guard. You can remove it from your Guardfile.") diff --git a/lib/guard/interactor.rb b/lib/guard/interactor.rb index eb0a46f..c44184e 100644 --- a/lib/guard/interactor.rb +++ b/lib/guard/interactor.rb @@ -1,29 +1,25 @@ module Guard - module Interactor - extend self + class Interactor - @@locked = false + def initialize + @locked = false + end - def listen + def start return if ENV["GUARD_ENV"] == 'test' Thread.new do loop do - if (entry = $stdin.gets) && !@@locked + if (entry = $stdin.gets) && !@locked entry.gsub! /\n/, '' case entry - when 'quit', 'exit', 'q', 'e' - UI.info "Bye bye...", :reset => true - ::Guard.listener.stop - ::Guard.guards.each { |guard| ::Guard.supervised_task(guard, :stop) } - abort + when 'stop', 'quit', 'exit', 's', 'q', 'e' + ::Guard.stop when 'reload', 'r', 'z' - ::Guard.run do - ::Guard.guards.each { |guard| ::Guard.supervised_task(guard, :reload) } - end - else # run_all - ::Guard.run do - ::Guard.guards.each { |guard| ::Guard.supervised_task(guard, :run_all) } - end + ::Guard.reload + when 'pause', 'p' + ::Guard.pause + else + ::Guard.run_all end end end @@ -31,59 +27,12 @@ module Guard end def lock - @@locked = true - end - def unlock - @@locked = false + @locked = true + end + + def unlock + @locked = false end - # def run_all - # ::Guard.run do - # ::Guard.guards.each { |guard| ::Guard.supervised_task(guard, :run_all) } - # end - # end - # - # def stop - # UI.info "Bye bye...", :reset => true - # ::Guard.listener.stop - # ::Guard.guards.each { |guard| ::Guard.supervised_task(guard, :stop) } - # abort - # end - # - # def reload - # ::Guard.run do - # ::Guard.guards.each { |guard| ::Guard.supervised_task(guard, :reload) } - # end - # end - # - # def self.init_signal_traps - # # Run all (Ctrl-\) - # if Signal.list.has_key?('QUIT') - # Signal.trap('QUIT') do - # run_all - # end - # else - # UI.info "Your system doesn't support QUIT signal, so Ctrl-\\ (Run all) won't work" - # end - # - # # Stop (Ctrl-C) - # if Signal.list.has_key?('INT') - # Signal.trap('INT') do - # stop - # end - # else - # UI.info "Your system doesn't support INT signal, so Ctrl-C (Stop) won't work" - # end - # - # # Reload (Ctrl-Z) - # if Signal.list.has_key?('TSTP') - # Signal.trap('TSTP') do - # reload - # end - # else - # UI.info "Your system doesn't support TSTP signal, so Ctrl-Z (Reload) won't work" - # end - # - # end end end diff --git a/lib/guard/listener.rb b/lib/guard/listener.rb index 1a8eeaf..6adaa9c 100644 --- a/lib/guard/listener.rb +++ b/lib/guard/listener.rb @@ -9,8 +9,8 @@ module Guard autoload :Polling, 'guard/listeners/polling' class Listener - - attr_reader :directory + + attr_reader :directory, :locked def self.select_and_init(*a) if mac? && Darwin.usable? @@ -29,16 +29,53 @@ module Guard @directory = directory.to_s @sha1_checksums_hash = {} @relativize_paths = options.fetch(:relativize_paths, true) + @changed_files = [] + @locked = false update_last_event + start_reactor + end + + def start_reactor + Thread.new do + loop do + if @changed_files != [] && !@locked + changed_files = @changed_files.dup + clear_changed_files + ::Guard.run_on_change(changed_files) + else + sleep 0.1 + end + end + end end def start + on_change do |files| + if Watcher.match_guardfile?(files) + Dsl.reevaluate_guardfile + end + if Watcher.match_files?(::Guard.guards, files) + @changed_files += files + end + end watch(@directory) end def stop end + def lock + @locked = true + end + + def unlock + @locked = false + end + + def clear_changed_files + @changed_files.clear + end + def on_change(&callback) @callback = callback end diff --git a/lib/guard/listeners/linux.rb b/lib/guard/listeners/linux.rb index 5c9e46f..ed85d8a 100644 --- a/lib/guard/listeners/linux.rb +++ b/lib/guard/listeners/linux.rb @@ -3,7 +3,6 @@ module Guard def initialize(*) super - @inotify = INotify::Notifier.new @files = [] @latency = 0.5 diff --git a/lib/guard/listeners/windows.rb b/lib/guard/listeners/windows.rb index f6ca03a..1f74d14 100644 --- a/lib/guard/listeners/windows.rb +++ b/lib/guard/listeners/windows.rb @@ -3,7 +3,6 @@ module Guard def initialize(*) super - @fchange = FChange::Notifier.new end