Class: Listen::Adapter::Linux

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

Overview

Listener implementation for Linux inotify.

Constant Summary collapse

OS_REGEXP =
/linux/i
EVENTS =
[:recursive, :attrib, :create, :delete, :move, :close_write]
WIKI_URL =
'https://github.com/guard/listen'\
'/wiki/Increasing-the-amount-of-inotify-watchers'
INOTIFY_LIMIT_MESSAGE =
<<-EOS.gsub(/^\s*/, '')
  FATAL: Listen error: unable to monitor directories for changes.

  Please head to #{WIKI_URL}
  for information on how to solve this issue.
EOS

Instance Attribute Summary

Attributes inherited from Base

#listener

Instance Method Summary collapse

Methods inherited from Base

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

Constructor Details

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

Instance Method Details

#_callbackObject (private)



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/listen/adapter/linux.rb', line 40

def _callback
  lambda do |event|
    # NOTE: avoid using event.absolute_name since new API
    # will need to have a custom recursion implemented
    # to properly match events to configured directories
    path = Pathname.new(event.watcher.path) + event.name

    _log :debug, "inotify: #{event.name} #{path} (#{event.flags.inspect})"

    if /1|true/ =~ ENV['LISTEN_GEM_SIMULATE_FSEVENT']
      if (event.flags & [:moved_to, :moved_from]) || _dir_event?(event)
        _notify_change(:dir, path.dirname)
      else
        _notify_change(:dir, path)
      end
    else
      next if _skip_event?(event)
      cookie_opts = event.cookie.zero? ? {} : { cookie: event.cookie }
      if _dir_event?(event)
        _notify_change(:dir, path, cookie_opts)
      else
        options = { change: _change(event.flags) }
        _notify_change(:file, path, options.merge(cookie_opts))
      end
    end
  end
end

#_change(event_flags) ⇒ Object (private)



78
79
80
81
82
83
84
85
86
87
# File 'lib/listen/adapter/linux.rb', line 78

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

#_configureObject (private)



23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/listen/adapter/linux.rb', line 23

def _configure
  require 'rb-inotify'
  @worker = INotify::Notifier.new
  _directories.each do |path|
    @worker.watch(path.to_s, *EVENTS, &_callback)
  end
rescue Errno::ENOSPC
  # workaround - Celluloid catches abort and prints nothing
  STDERR.puts INOTIFY_LIMIT_MESSAGE
  STDERR.flush
  abort(INOTIFY_LIMIT_MESSAGE)
end

#_dir_event?(event) ⇒ Boolean (private)

Returns:

  • (Boolean)


89
90
91
# File 'lib/listen/adapter/linux.rb', line 89

def _dir_event?(event)
  event.flags.include?(:isdir)
end

#_runObject (private)



36
37
38
# File 'lib/listen/adapter/linux.rb', line 36

def _run
  @worker.run
end

#_skip_event?(event) ⇒ Boolean (private)

Returns:

  • (Boolean)


68
69
70
71
72
73
74
75
76
# File 'lib/listen/adapter/linux.rb', line 68

def _skip_event?(event)
  # Event on root directory
  return true if event.name == ''
  # INotify reports changes to files inside directories as events
  # on the directories themselves too.
  #
  # @see http://linux.die.net/man/7/inotify
  _dir_event?(event) && (event.flags & [:close, :modify]).any?
end