Class: Listen::Adapter::BSD

Inherits:
Base
  • Object
show all
Defined in:
lib/listen/adapter/bsd.rb

Constant Summary collapse

OS_REGEXP =
/bsd|dragonfly/i
EVENTS =

:link, :revoke

[:delete, :write, :extend, :attrib, :rename]
BUNDLER_DECLARE_GEM =
<<-EOS.gsub(/^ {6}/, '')
  Please add the following to your Gemfile to avoid polling for changes:
    require 'rbconfig'
    if RbConfig::CONFIG['target_os'] =~ #{OS_REGEXP}
      gem 'rb-kqueue', '>= 0.2'

      # Base versions have known conflicts/bugs
      # Even master branches may not work...
      gem 'ffi', github: 'carpetsmoker/ffi', ref: 'ac63e07f7'
      gem 'celluloid', github: 'celluloid/celluloid', ref: '7fdef04'
    end
EOS
BSD_EXPERIMENTAL =
<<-EOS.gsub(/^ {6}/, '')
  NOTE *BSD SUPPORT IS EXPERIMENTAL!

  In fact, it likely WONT WORK!!!!

  (see: https://github.com/guard/listen/issues/220)

  If you're brave enough, feel free to suggest pull requests and
  experiment on your own. For help, browse existing issues marked 'bsd'
  for clues, tips and workaround.
EOS

Instance Attribute Summary

Attributes inherited from Base

#listener

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Base

#_directories, #_log, #_notify_change, #initialize, local_fs?, #start

Constructor Details

This class inherits a constructor from Listen::Adapter::Base

Class Method Details

.usable?Boolean

Returns:

  • (Boolean)


37
38
39
40
41
42
43
44
45
46
# File 'lib/listen/adapter/bsd.rb', line 37

def self.usable?
  return false unless super
  Kernel.warn BSD_EXPERIMENTAL
  require 'rb-kqueue'
  require 'find'
  true
rescue LoadError
  Kernel.warn BUNDLER_DECLARE_GEM
  false
end

Instance Method Details

#_change(event_flags) ⇒ Object (private)



82
83
84
85
86
87
88
89
90
# File 'lib/listen/adapter/bsd.rb', line 82

def _change(event_flags)
  { modified: [:attrib, :extend],
    added:    [:write],
    removed:  [:rename, :delete]
  }.each do |change, flags|
    return change unless (flags & event_flags).empty?
  end
  nil
end

#_configureObject (private)



50
51
52
53
54
55
56
57
# File 'lib/listen/adapter/bsd.rb', line 50

def _configure
  @worker = KQueue::Queue.new
  _directories.each do |path|
    # use Record to make a snapshot of dir, so we
    # can detect new files
    _find(path.to_s) { |file_path| _watch_file(file_path, @worker) }
  end
end

#_event_path(event) ⇒ Object (private)



92
93
94
# File 'lib/listen/adapter/bsd.rb', line 92

def _event_path(event)
  Pathname.new(event.watcher.path)
end

#_find(*paths) ⇒ Object (private)

Quick rubocop workaround



110
111
112
# File 'lib/listen/adapter/bsd.rb', line 110

def _find(*paths)
  Find.send(:find, *paths)
end

#_runObject (private)



59
60
61
# File 'lib/listen/adapter/bsd.rb', line 59

def _run
  @worker.run
end

#_watch_file(path, queue) ⇒ Object (private)



105
106
107
# File 'lib/listen/adapter/bsd.rb', line 105

def _watch_file(path, queue)
  queue.watch_file(path, *EVENTS, &_worker_callback)
end

#_watch_for_new_file(event) ⇒ Object (private)



96
97
98
99
100
101
102
103
# File 'lib/listen/adapter/bsd.rb', line 96

def _watch_for_new_file(event)
  queue = event.watcher.queue
  _find(_event_path(event).to_s) do |file_path|
    unless queue.watchers.detect { |_, v| v.path == file_path.to_s }
      _watch_file(file_path, queue)
    end
  end
end

#_worker_callbackObject (private)



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/listen/adapter/bsd.rb', line 63

def _worker_callback
  lambda do |event|
    path = _event_path(event)
    if path.directory?
      # Force dir content tracking to kick in, or we won't have
      # names of added files
      _notify_change(:dir, path, recursive: true)
    else
      _notify_change(:file, path, change: _change(event.flags))
    end

    # If it is a directory, and it has a write flag, it means a
    # file has been added so find out which and deal with it.
    # No need to check for removed files, kqueue will forget them
    # when the vfs does.
    _watch_for_new_file(event) if path.directory?
  end
end