diff --git a/lib/vendor/fssm/fssm.rb b/lib/vendor/fssm/fssm.rb index e2709279..058cbf3c 100644 --- a/lib/vendor/fssm/fssm.rb +++ b/lib/vendor/fssm/fssm.rb @@ -12,15 +12,7 @@ module FSSM def monitor(*args, &block) monitor = FSSM::Monitor.new - context = args.empty? ? monitor : monitor.path(*args) - - if block_given? - if block.arity == 1 - block.call(context) - else - context.instance_eval(&block) - end - end + FSSM::Support.use_block(args.empty? ? monitor : monitor.path(*args), block) monitor.run end @@ -33,7 +25,8 @@ require 'fssm/pathname' require 'fssm/support' require 'fssm/tree' require 'fssm/path' -require 'fssm/state' +require 'fssm/state/directory' +require 'fssm/state/file' require 'fssm/monitor' require "fssm/backends/#{FSSM::Support.backend.downcase}" diff --git a/lib/vendor/fssm/fssm/backends/fsevents.rb b/lib/vendor/fssm/fssm/backends/fsevents.rb index bb33c598..800cebd1 100644 --- a/lib/vendor/fssm/fssm/backends/fsevents.rb +++ b/lib/vendor/fssm/fssm/backends/fsevents.rb @@ -7,18 +7,17 @@ module FSSM::Backends @fsevents = [] end - def add_path(path, preload=true) - handler = FSSM::State.new(path) - @handlers["#{path}"] = handler + def add_handler(handler, preload=true) + @handlers[handler.path.to_s] = handler - fsevent = Rucola::FSEvents.new("#{path}", {:latency => 0.5}) do |events| + fsevent = Rucola::FSEvents.new(handler.path.to_s, {:latency => 0.5}) do |events| events.each do |event| handler.refresh(event.path) end end fsevent.create_stream - handler.refresh(path.to_pathname, true) if preload + handler.refresh(nil, true) if preload fsevent.start @fsevents << fsevent end diff --git a/lib/vendor/fssm/fssm/backends/inotify.rb b/lib/vendor/fssm/fssm/backends/inotify.rb index 5a9736f0..dc9079cf 100644 --- a/lib/vendor/fssm/fssm/backends/inotify.rb +++ b/lib/vendor/fssm/fssm/backends/inotify.rb @@ -4,14 +4,12 @@ module FSSM::Backends @notifier = INotify::Notifier.new end - def add_path(path, preload=true) - handler = FSSM::State.new(path) - - @notifier.watch(path.to_s, :all_events) do |event| + def add_handler(handler, preload=true) + @notifier.watch(handler.path.to_s, :all_events) do |event| handler.refresh(event.name) end - handler.refresh(path.to_pathname, true) if preload + handler.refresh(nil, true) if preload end def run diff --git a/lib/vendor/fssm/fssm/backends/polling.rb b/lib/vendor/fssm/fssm/backends/polling.rb index f80dc168..083cf07b 100644 --- a/lib/vendor/fssm/fssm/backends/polling.rb +++ b/lib/vendor/fssm/fssm/backends/polling.rb @@ -5,9 +5,8 @@ module FSSM::Backends @latency = options[:latency] || 1.5 end - def add_path(path, preload=true) - handler = FSSM::State.new(path) - handler.refresh(path.to_pathname, true) if preload + def add_handler(handler, preload=true) + handler.refresh(nil, true) if preload @handlers << handler end diff --git a/lib/vendor/fssm/fssm/monitor.rb b/lib/vendor/fssm/fssm/monitor.rb index b7cd0f99..d7f7468d 100644 --- a/lib/vendor/fssm/fssm/monitor.rb +++ b/lib/vendor/fssm/fssm/monitor.rb @@ -6,16 +6,17 @@ class FSSM::Monitor def path(*args, &block) path = FSSM::Path.new(*args) + FSSM::Support.use_block(path, block) - if block_given? - if block.arity == 1 - block.call(path) - else - path.instance_eval(&block) - end - end + @backend.add_handler(FSSM::State::Directory.new(path)) + path + end - @backend.add_path(path) + def file(*args, &block) + path = FSSM::Path.new(*args) + FSSM::Support.use_block(path, block) + + @backend.add_handler(FSSM::State::File.new(path)) path end diff --git a/lib/vendor/fssm/fssm/path.rb b/lib/vendor/fssm/fssm/path.rb index 1264809c..101dd103 100644 --- a/lib/vendor/fssm/fssm/path.rb +++ b/lib/vendor/fssm/fssm/path.rb @@ -81,7 +81,7 @@ class FSSM::Path def set_path(path) path = FSSM::Pathname.for(path) - raise FSSM::FileNotFoundError, "#{path}" unless path.exist? + raise FSSM::FileNotFoundError, "No such file or directory - #{path}" unless path.exist? @path = path.expand_path end diff --git a/lib/vendor/fssm/fssm/state.rb b/lib/vendor/fssm/fssm/state.rb deleted file mode 100644 index e22ef878..00000000 --- a/lib/vendor/fssm/fssm/state.rb +++ /dev/null @@ -1,54 +0,0 @@ -require 'yaml' -class FSSM::State - def initialize(path) - @path = path - @cache = FSSM::Tree::Cache.new - end - - def refresh(base=nil, skip_callbacks=false) - previous, current = recache(base || @path.to_pathname) - - unless skip_callbacks - deleted(previous, current) - created(previous, current) - modified(previous, current) - end - end - - private - - def created(previous, current) - (current.keys - previous.keys).each {|created| @path.create(created)} - end - - def deleted(previous, current) - (previous.keys - current.keys).each {|deleted| @path.delete(deleted)} - end - - def modified(previous, current) - (current.keys & previous.keys).each do |file| - @path.update(file) if (current[file] <=> previous[file]) != 0 - end - end - - def recache(base) - base = FSSM::Pathname.for(base) - previous = @cache.files - snapshot(base) - current = @cache.files - [previous, current] - end - - def snapshot(base) - base = FSSM::Pathname.for(base) - @cache.unset(base) - @path.glob.each {|glob| add_glob(base, glob)} - end - - def add_glob(base, glob) - FSSM::Pathname.glob(base.join(glob).to_s).each do |fn| - @cache.set(fn) - end - end - -end diff --git a/lib/vendor/fssm/fssm/state/directory.rb b/lib/vendor/fssm/fssm/state/directory.rb new file mode 100644 index 00000000..de701e6a --- /dev/null +++ b/lib/vendor/fssm/fssm/state/directory.rb @@ -0,0 +1,57 @@ +module FSSM::State + class Directory + attr_reader :path + + def initialize(path) + @path = path + @cache = FSSM::Tree::Cache.new + end + + def refresh(base=nil, skip_callbacks=false) + previous, current = recache(base || @path.to_pathname) + + unless skip_callbacks + deleted(previous, current) + created(previous, current) + modified(previous, current) + end + end + + private + + def created(previous, current) + (current.keys - previous.keys).each {|created| @path.create(created)} + end + + def deleted(previous, current) + (previous.keys - current.keys).each {|deleted| @path.delete(deleted)} + end + + def modified(previous, current) + (current.keys & previous.keys).each do |file| + @path.update(file) if (current[file] <=> previous[file]) != 0 + end + end + + def recache(base) + base = FSSM::Pathname.for(base) + previous = @cache.files + snapshot(base) + current = @cache.files + [previous, current] + end + + def snapshot(base) + base = FSSM::Pathname.for(base) + @cache.unset(base) + @path.glob.each {|glob| add_glob(base, glob)} + end + + def add_glob(base, glob) + FSSM::Pathname.glob(base.join(glob).to_s).each do |fn| + @cache.set(fn) + end + end + + end +end diff --git a/lib/vendor/fssm/fssm/state/file.rb b/lib/vendor/fssm/fssm/state/file.rb new file mode 100644 index 00000000..ec601f81 --- /dev/null +++ b/lib/vendor/fssm/fssm/state/file.rb @@ -0,0 +1,24 @@ +module FSSM::State + class File + attr_reader :path + + def initialize(path) + @path = path + end + + def refresh(base=nil, skip_callbacks=false) + base ||= @path.to_pathname + used_to_exist, @exists = @exists, base.exists? + # this handles bad symlinks without failing. why handle bad symlinks at + # all? well, we could still be interested in their creation and deletion. + old_mtime, @mtime = @mtime, base.symlink? ? Time.at(0) : base.mtime if @exists + + unless skip_callbacks + @path.delete(@path.to_s) if used_to_exist && !@exists + @path.create(@path.to_s) if !used_to_exist && @exists + @path.update(@path.to_s) if used_to_exist && @exists && old_mtime != @mtime + end + end + + end +end diff --git a/lib/vendor/fssm/fssm/support.rb b/lib/vendor/fssm/fssm/support.rb index 8e2b8850..4aa7b486 100644 --- a/lib/vendor/fssm/fssm/support.rb +++ b/lib/vendor/fssm/fssm/support.rb @@ -37,15 +37,23 @@ module FSSM::Support end def rb_inotify? - begin - require 'rubygems' - gem 'rb-inotify', '>= 0.3.0' + found = begin require 'rb-inotify' - true - rescue LoadError, Gem::LoadError - STDERR.puts("Warning: Unable to load rb-inotify >= 0.3.0. Inotify will be unavailable.") + INotify::Notifier.ancestors.include?(IO) + rescue LoadError false end + STDERR.puts("Warning: Unable to load rb-inotify >= 0.3.0. Inotify will be unavailable.") unless found + found + end + + def use_block(context, block) + return if block.nil? + if block.arity == 1 + block.call(context) + else + context.instance_eval(&block) + end end end