-
Notifications
You must be signed in to change notification settings - Fork 247
/
linux.rb
108 lines (89 loc) · 3.06 KB
/
linux.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# frozen_string_literal: true
module Listen
module Adapter
# @see https://github.com/nex3/rb-inotify
class Linux < Base
OS_REGEXP = /linux/i
DEFAULTS = {
events: [
:recursive,
:attrib,
:create,
:modify,
:delete,
:move,
:close_write
],
wait_for_delay: 0.1
}.freeze
private
README_URL = 'https://github.com/guard/listen'\
'/blob/master/README.md#increasing-the-amount-of-inotify-watchers'
def _configure(directory, &callback)
require 'rb-inotify'
@worker ||= ::INotify::Notifier.new
@worker.watch(directory.to_s, *options.events, &callback)
rescue Errno::ENOSPC
raise ::Listen::Error::INotifyMaxWatchesExceeded, <<~EOS
Unable to monitor directories for changes because iNotify max watches exceeded. See #{README_URL} .
EOS
end
def _run
@worker.run
end
# rubocop:disable Metrics/MethodLength
def _process_event(dir, 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
rel_path = path.relative_path_from(dir).to_s
Listen.logger.debug { "inotify: #{rel_path} (#{event.flags.inspect})" }
if /1|true/ =~ ENV['LISTEN_GEM_SIMULATE_FSEVENT']
if (event.flags & [:moved_to, :moved_from]) || _dir_event?(event)
rel_path = path.dirname.relative_path_from(dir).to_s
end
_queue_change(:dir, dir, rel_path, {})
return
end
return if _skip_event?(event)
cookie_params = event.cookie.zero? ? {} : { cookie: event.cookie }
# NOTE: don't pass options to force rescanning the directory, so we can
# detect moving/deleting a whole tree
if _dir_event?(event)
_queue_change(:dir, dir, rel_path, cookie_params)
return
end
params = cookie_params.merge(change: _change(event.flags))
_queue_change(:file, dir, rel_path, params)
end
# rubocop:enable Metrics/MethodLength
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
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
def _dir_event?(event)
event.flags.include?(:isdir)
end
def _stop
@worker&.close
super
end
end
end
end