listen 0.7.3 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +70 -35
- data/README.md +93 -76
- data/lib/listen.rb +34 -19
- data/lib/listen/adapter.rb +179 -81
- data/lib/listen/adapters/bsd.rb +27 -64
- data/lib/listen/adapters/darwin.rb +21 -58
- data/lib/listen/adapters/linux.rb +23 -55
- data/lib/listen/adapters/polling.rb +25 -34
- data/lib/listen/adapters/windows.rb +50 -46
- data/lib/listen/directory_record.rb +88 -58
- data/lib/listen/listener.rb +111 -37
- data/lib/listen/multi_listener.rb +5 -133
- data/lib/listen/turnstile.rb +9 -5
- data/lib/listen/version.rb +1 -1
- metadata +69 -22
- data/lib/listen/dependency_manager.rb +0 -126
data/lib/listen.rb
CHANGED
@@ -1,24 +1,21 @@
|
|
1
|
-
|
1
|
+
require 'listen/turnstile'
|
2
|
+
require 'listen/listener'
|
3
|
+
require 'listen/multi_listener'
|
4
|
+
require 'listen/directory_record'
|
5
|
+
require 'listen/adapter'
|
2
6
|
|
3
|
-
|
4
|
-
autoload :Listener, 'listen/listener'
|
5
|
-
autoload :MultiListener, 'listen/multi_listener'
|
6
|
-
autoload :DirectoryRecord, 'listen/directory_record'
|
7
|
-
autoload :DependencyManager, 'listen/dependency_manager'
|
8
|
-
autoload :Adapter, 'listen/adapter'
|
7
|
+
module Listen
|
9
8
|
|
10
9
|
module Adapters
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
autoload :Windows, 'listen/adapters/windows'
|
15
|
-
autoload :Polling, 'listen/adapters/polling'
|
10
|
+
Adapter::ADAPTERS.each do |adapter|
|
11
|
+
require "listen/adapters/#{adapter.downcase}"
|
12
|
+
end
|
16
13
|
end
|
17
14
|
|
18
|
-
# Listens to
|
15
|
+
# Listens to file system modifications on a either single directory or multiple directories.
|
16
|
+
# When calling this method, the current thread is not blocked.
|
19
17
|
#
|
20
18
|
# @param (see Listen::Listener#new)
|
21
|
-
# @param (see Listen::MultiListener#new)
|
22
19
|
#
|
23
20
|
# @yield [modified, added, removed] the changed files
|
24
21
|
# @yieldparam [Array<String>] modified the list of modified files
|
@@ -28,13 +25,31 @@ module Listen
|
|
28
25
|
# @return [Listen::Listener] the file listener if no block given
|
29
26
|
#
|
30
27
|
def self.to(*args, &block)
|
31
|
-
listener =
|
32
|
-
Listener.new(*args, &block)
|
33
|
-
else
|
34
|
-
MultiListener.new(*args, &block)
|
35
|
-
end
|
28
|
+
listener = _init_listener(*args, &block)
|
36
29
|
|
37
30
|
block ? listener.start : listener
|
38
31
|
end
|
39
32
|
|
33
|
+
# Listens to file system modifications on a either single directory or multiple directories.
|
34
|
+
# When calling this method, the current thread is blocked.
|
35
|
+
#
|
36
|
+
# @param (see Listen::Listener#new)
|
37
|
+
#
|
38
|
+
# @yield [modified, added, removed] the changed files
|
39
|
+
# @yieldparam [Array<String>] modified the list of modified files
|
40
|
+
# @yieldparam [Array<String>] added the list of added files
|
41
|
+
# @yieldparam [Array<String>] removed the list of removed files
|
42
|
+
#
|
43
|
+
# @since 1.0.0
|
44
|
+
#
|
45
|
+
def self.to!(*args, &block)
|
46
|
+
_init_listener(*args, &block).start!
|
47
|
+
end
|
48
|
+
|
49
|
+
# @private
|
50
|
+
#
|
51
|
+
def self._init_listener(*args, &block)
|
52
|
+
Listener.new(*args, &block)
|
53
|
+
end
|
54
|
+
|
40
55
|
end
|
data/lib/listen/adapter.rb
CHANGED
@@ -5,19 +5,25 @@ require 'fileutils'
|
|
5
5
|
|
6
6
|
module Listen
|
7
7
|
class Adapter
|
8
|
-
attr_accessor :directories, :
|
8
|
+
attr_accessor :directories, :callback, :stopped, :paused,
|
9
|
+
:mutex, :changed_directories, :turnstile, :latency,
|
10
|
+
:worker, :worker_thread, :poller_thread
|
11
|
+
|
12
|
+
# The list of existing optimized adapters.
|
13
|
+
OPTIMIZED_ADAPTERS = %w[Darwin Linux BSD Windows]
|
14
|
+
|
15
|
+
# The list of existing fallback adapters.
|
16
|
+
FALLBACK_ADAPTERS = %w[Polling]
|
17
|
+
|
18
|
+
# The list of all existing adapters.
|
19
|
+
ADAPTERS = OPTIMIZED_ADAPTERS + FALLBACK_ADAPTERS
|
9
20
|
|
10
21
|
# The default delay between checking for changes.
|
11
22
|
DEFAULT_LATENCY = 0.25
|
12
23
|
|
13
|
-
# The default warning message when there is a missing dependency.
|
14
|
-
MISSING_DEPENDENCY_MESSAGE = <<-EOS.gsub(/^\s*/, '')
|
15
|
-
For a better performance, it's recommended that you satisfy the missing dependency.
|
16
|
-
EOS
|
17
|
-
|
18
24
|
# The default warning message when falling back to polling adapter.
|
19
25
|
POLLING_FALLBACK_MESSAGE = <<-EOS.gsub(/^\s*/, '')
|
20
|
-
Listen will be polling changes. Learn more at https://github.com/guard/listen#polling-fallback.
|
26
|
+
Listen will be polling for changes. Learn more at https://github.com/guard/listen#polling-fallback.
|
21
27
|
EOS
|
22
28
|
|
23
29
|
# Selects the appropriate adapter implementation for the
|
@@ -29,36 +35,23 @@ module Listen
|
|
29
35
|
# @option options [String, Boolean] polling_fallback_message to change polling fallback message or remove it
|
30
36
|
# @option options [Float] latency the delay between checking for changes in seconds
|
31
37
|
#
|
32
|
-
# @yield [
|
33
|
-
# @yieldparam [Array<String>]
|
34
|
-
# @yieldparam [Hash] options callback options (like :
|
38
|
+
# @yield [changed_directories, options] callback the callback called when a change happens
|
39
|
+
# @yieldparam [Array<String>] changed_directories the changed directories
|
40
|
+
# @yieldparam [Hash] options callback options (like recursive: true)
|
35
41
|
#
|
36
42
|
# @return [Listen::Adapter] the chosen adapter
|
37
43
|
#
|
38
44
|
def self.select_and_initialize(directories, options = {}, &callback)
|
39
45
|
return Adapters::Polling.new(directories, options, &callback) if options.delete(:force_polling)
|
40
46
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
return Adapters::Darwin.new(directories, options, &callback)
|
46
|
-
elsif Adapters::Linux.usable_and_works?(directories, options)
|
47
|
-
return Adapters::Linux.new(directories, options, &callback)
|
48
|
-
elsif Adapters::BSD.usable_and_works?(directories, options)
|
49
|
-
return Adapters::BSD.new(directories, options, &callback)
|
50
|
-
elsif Adapters::Windows.usable_and_works?(directories, options)
|
51
|
-
return Adapters::Windows.new(directories, options, &callback)
|
47
|
+
OPTIMIZED_ADAPTERS.each do |adapter|
|
48
|
+
namespaced_adapter = Adapters.const_get(adapter)
|
49
|
+
if namespaced_adapter.send(:usable_and_works?, directories, options)
|
50
|
+
return namespaced_adapter.new(directories, options, &callback)
|
52
51
|
end
|
53
|
-
rescue DependencyManager::Error => e
|
54
|
-
warning += e.message + "\n" + MISSING_DEPENDENCY_MESSAGE
|
55
|
-
end
|
56
|
-
|
57
|
-
unless options[:polling_fallback_message] == false
|
58
|
-
warning += options[:polling_fallback_message] || POLLING_FALLBACK_MESSAGE
|
59
|
-
Kernel.warn "[Listen warning]:\n" + warning.gsub(/^(.*)/, ' \1')
|
60
52
|
end
|
61
53
|
|
54
|
+
self.warn_polling_fallback(options)
|
62
55
|
Adapters::Polling.new(directories, options, &callback)
|
63
56
|
end
|
64
57
|
|
@@ -67,97 +60,145 @@ module Listen
|
|
67
60
|
# @param [String, Array<String>] directories the directories to watch
|
68
61
|
# @param [Hash] options the adapter options
|
69
62
|
# @option options [Float] latency the delay between checking for changes in seconds
|
70
|
-
# @option options [Boolean] report_changes whether or not to automatically report changes (run the callback)
|
71
63
|
#
|
72
|
-
# @yield [
|
73
|
-
# @yieldparam [Array<String>]
|
74
|
-
# @yieldparam [Hash] options callback options (like :
|
64
|
+
# @yield [changed_directories, options] callback Callback called when a change happens
|
65
|
+
# @yieldparam [Array<String>] changed_directories the changed directories
|
66
|
+
# @yieldparam [Hash] options callback options (like recursive: true)
|
75
67
|
#
|
76
68
|
# @return [Listen::Adapter] the adapter
|
77
69
|
#
|
78
70
|
def initialize(directories, options = {}, &callback)
|
79
|
-
@directories
|
80
|
-
@callback
|
81
|
-
@
|
82
|
-
@
|
83
|
-
@
|
84
|
-
@
|
85
|
-
@
|
86
|
-
@latency
|
87
|
-
@
|
71
|
+
@directories = Array(directories)
|
72
|
+
@callback = callback
|
73
|
+
@stopped = true
|
74
|
+
@paused = false
|
75
|
+
@mutex = Mutex.new
|
76
|
+
@changed_directories = Set.new
|
77
|
+
@turnstile = Turnstile.new
|
78
|
+
@latency = options.fetch(:latency, default_latency)
|
79
|
+
@worker = initialize_worker
|
88
80
|
end
|
89
81
|
|
90
|
-
# Starts the adapter.
|
82
|
+
# Starts the adapter and don't block the current thread.
|
91
83
|
#
|
92
84
|
# @param [Boolean] blocking whether or not to block the current thread after starting
|
93
85
|
#
|
94
|
-
def start
|
95
|
-
|
86
|
+
def start
|
87
|
+
mutex.synchronize do
|
88
|
+
return unless stopped
|
89
|
+
@stopped = false
|
90
|
+
end
|
91
|
+
|
92
|
+
start_worker
|
93
|
+
start_poller
|
94
|
+
end
|
95
|
+
|
96
|
+
# Starts the adapter and block the current thread.
|
97
|
+
#
|
98
|
+
# @since 1.0.0
|
99
|
+
#
|
100
|
+
def start!
|
101
|
+
start
|
102
|
+
blocking_thread.join
|
96
103
|
end
|
97
104
|
|
98
105
|
# Stops the adapter.
|
99
106
|
#
|
100
107
|
def stop
|
101
|
-
|
102
|
-
|
108
|
+
mutex.synchronize do
|
109
|
+
return if stopped
|
110
|
+
@stopped = true
|
111
|
+
turnstile.signal # ensure no thread is blocked
|
112
|
+
end
|
113
|
+
|
114
|
+
worker.stop if worker
|
115
|
+
Thread.kill(worker_thread) if worker_thread
|
116
|
+
poller_thread.join if poller_thread
|
117
|
+
end
|
118
|
+
|
119
|
+
# Pauses the adapter.
|
120
|
+
#
|
121
|
+
def pause
|
122
|
+
@paused = true
|
103
123
|
end
|
104
124
|
|
105
|
-
#
|
125
|
+
# Unpauses the adapter.
|
126
|
+
#
|
127
|
+
def unpause
|
128
|
+
@paused = false
|
129
|
+
end
|
130
|
+
|
131
|
+
# Returns whether the adapter is started or not.
|
106
132
|
#
|
107
133
|
# @return [Boolean] whether the adapter is started or not
|
108
134
|
#
|
109
135
|
def started?
|
110
|
-
|
136
|
+
!stopped
|
137
|
+
end
|
138
|
+
|
139
|
+
# Returns whether the adapter is paused or not.
|
140
|
+
#
|
141
|
+
# @return [Boolean] whether the adapter is paused or not
|
142
|
+
#
|
143
|
+
def paused?
|
144
|
+
paused
|
111
145
|
end
|
112
146
|
|
113
147
|
# Blocks the main thread until the poll thread
|
114
148
|
# runs the callback.
|
115
149
|
#
|
116
150
|
def wait_for_callback
|
117
|
-
|
151
|
+
turnstile.wait unless paused
|
118
152
|
end
|
119
153
|
|
120
154
|
# Blocks the main thread until N changes are
|
121
155
|
# detected.
|
122
156
|
#
|
123
|
-
def wait_for_changes(
|
157
|
+
def wait_for_changes(threshold = 0)
|
124
158
|
changes = 0
|
125
159
|
|
126
160
|
loop do
|
127
|
-
|
161
|
+
mutex.synchronize { changes = changed_directories.size }
|
128
162
|
|
129
|
-
return if
|
130
|
-
return if changes >=
|
163
|
+
return if paused || stopped
|
164
|
+
return if changes >= threshold
|
131
165
|
|
132
|
-
sleep(
|
166
|
+
sleep(latency)
|
133
167
|
end
|
134
168
|
end
|
135
169
|
|
136
|
-
# Checks if the adapter is usable on the current OS.
|
137
|
-
#
|
138
|
-
# @return [Boolean] whether usable or not
|
139
|
-
#
|
140
|
-
def self.usable?
|
141
|
-
load_depenencies
|
142
|
-
dependencies_loaded?
|
143
|
-
end
|
144
|
-
|
145
170
|
# Checks if the adapter is usable and works on the current OS.
|
146
171
|
#
|
147
172
|
# @param [String, Array<String>] directories the directories to watch
|
148
173
|
# @param [Hash] options the adapter options
|
149
174
|
# @option options [Float] latency the delay between checking for changes in seconds
|
150
175
|
#
|
151
|
-
# @return [Boolean] whether usable and work or not
|
176
|
+
# @return [Boolean] whether the adapter is usable and work or not
|
152
177
|
#
|
153
178
|
def self.usable_and_works?(directories, options = {})
|
154
179
|
usable? && Array(directories).all? { |d| works?(d, options) }
|
155
180
|
end
|
156
181
|
|
182
|
+
# Checks if the adapter is usable on target OS.
|
183
|
+
#
|
184
|
+
# @return [Boolean] whether usable or not
|
185
|
+
#
|
186
|
+
def self.usable?
|
187
|
+
load_dependency if RbConfig::CONFIG['target_os'] =~ target_os_regex
|
188
|
+
end
|
189
|
+
|
190
|
+
# Load the adapter gem
|
191
|
+
#
|
192
|
+
# @return [Boolean] whether required or not
|
193
|
+
#
|
194
|
+
def self.load_dependency
|
195
|
+
@loaded ||= require adapter_gem
|
196
|
+
end
|
197
|
+
|
157
198
|
# Runs a tests to determine if the adapter can actually pick up
|
158
199
|
# changes in a given directory and returns the result.
|
159
200
|
#
|
160
|
-
# @note This test takes some time depending the adapter latency.
|
201
|
+
# @note This test takes some time depending on the adapter latency.
|
161
202
|
#
|
162
203
|
# @param [String, Pathname] directory the directory to watch
|
163
204
|
# @param [Hash] options the adapter options
|
@@ -166,11 +207,11 @@ module Listen
|
|
166
207
|
# @return [Boolean] whether the adapter works or not
|
167
208
|
#
|
168
209
|
def self.works?(directory, options = {})
|
169
|
-
work
|
210
|
+
work = false
|
170
211
|
test_file = "#{directory}/.listen_test"
|
171
|
-
callback
|
172
|
-
adapter
|
173
|
-
adapter.start
|
212
|
+
callback = lambda { |*| work = true }
|
213
|
+
adapter = self.new(directory, options, &callback)
|
214
|
+
adapter.start
|
174
215
|
|
175
216
|
FileUtils.touch(test_file)
|
176
217
|
|
@@ -180,7 +221,7 @@ module Listen
|
|
180
221
|
work
|
181
222
|
ensure
|
182
223
|
Thread.kill(t) if t
|
183
|
-
FileUtils.rm(test_file
|
224
|
+
FileUtils.rm(test_file, :force => true)
|
184
225
|
adapter.stop if adapter && adapter.started?
|
185
226
|
end
|
186
227
|
|
@@ -189,24 +230,81 @@ module Listen
|
|
189
230
|
def report_changes
|
190
231
|
changed_dirs = nil
|
191
232
|
|
192
|
-
|
193
|
-
return if @
|
194
|
-
changed_dirs = @
|
195
|
-
@
|
233
|
+
mutex.synchronize do
|
234
|
+
return if @changed_directories.empty?
|
235
|
+
changed_dirs = @changed_directories.to_a
|
236
|
+
@changed_directories.clear
|
196
237
|
end
|
197
238
|
|
198
|
-
|
199
|
-
|
239
|
+
callback.call(changed_dirs, {})
|
240
|
+
turnstile.signal
|
200
241
|
end
|
201
242
|
|
202
243
|
private
|
203
244
|
|
204
|
-
#
|
205
|
-
#
|
245
|
+
# The default delay between checking for changes.
|
246
|
+
#
|
247
|
+
# @note This method can be overriden on a per-adapter basis.
|
248
|
+
#
|
249
|
+
def default_latency
|
250
|
+
DEFAULT_LATENCY
|
251
|
+
end
|
252
|
+
|
253
|
+
# The thread on which the main thread should wait
|
254
|
+
# when the adapter has been started in blocking mode.
|
255
|
+
#
|
256
|
+
# @note This method can be overriden on a per-adapter basis.
|
257
|
+
#
|
258
|
+
def blocking_thread
|
259
|
+
worker_thread
|
260
|
+
end
|
261
|
+
|
262
|
+
# Initialize the adpater' specific worker.
|
263
|
+
#
|
264
|
+
# @note Each adapter must override this method
|
265
|
+
# to initialize its own @worker.
|
266
|
+
#
|
267
|
+
def initialize_worker
|
268
|
+
nil
|
269
|
+
end
|
270
|
+
|
271
|
+
# Should start the worker in a new thread.
|
272
|
+
#
|
273
|
+
# @note Each adapter must override this method
|
274
|
+
# to start its worker on a new @worker_thread thread.
|
275
|
+
#
|
276
|
+
def start_worker
|
277
|
+
raise NotImplementedError, "#{self.class} cannot respond to: #{__method__}"
|
278
|
+
end
|
279
|
+
|
280
|
+
# This method starts a new thread which poll for changes detected by
|
281
|
+
# the adapter and report them back to the user.
|
282
|
+
#
|
283
|
+
def start_poller
|
284
|
+
@poller_thread = Thread.new { poll_changed_directories }
|
285
|
+
end
|
286
|
+
|
287
|
+
# Warn of polling fallback unless the :polling_fallback_message
|
288
|
+
# has been set to false.
|
289
|
+
#
|
290
|
+
# @param [String] warning an existing warning message
|
291
|
+
# @param [Hash] options the adapter options
|
292
|
+
# @option options [Boolean] polling_fallback_message to change polling fallback message or remove it
|
293
|
+
#
|
294
|
+
def self.warn_polling_fallback(options)
|
295
|
+
return if options[:polling_fallback_message] == false
|
296
|
+
|
297
|
+
warning = options[:polling_fallback_message] || POLLING_FALLBACK_MESSAGE
|
298
|
+
Kernel.warn "[Listen warning]:\n#{warning.gsub(/^(.*)/, ' \1')}"
|
299
|
+
end
|
300
|
+
|
301
|
+
# Polls changed directories and reports them back when there are changes.
|
302
|
+
#
|
303
|
+
# @note This method can be overriden on a per-adapter basis.
|
206
304
|
#
|
207
|
-
def
|
208
|
-
until
|
209
|
-
sleep(
|
305
|
+
def poll_changed_directories
|
306
|
+
until stopped
|
307
|
+
sleep(latency)
|
210
308
|
report_changes
|
211
309
|
end
|
212
310
|
end
|
data/lib/listen/adapters/bsd.rb
CHANGED
@@ -4,68 +4,15 @@ module Listen
|
|
4
4
|
# Listener implementation for BSD's `kqueue`.
|
5
5
|
#
|
6
6
|
class BSD < Adapter
|
7
|
-
extend DependencyManager
|
8
|
-
|
9
|
-
# Declare the adapter's dependencies
|
10
|
-
dependency 'rb-kqueue', '~> 0.2'
|
11
|
-
|
12
7
|
# Watched kqueue events
|
13
8
|
#
|
14
9
|
# @see http://www.freebsd.org/cgi/man.cgi?query=kqueue
|
15
10
|
# @see https://github.com/nex3/rb-kqueue/blob/master/lib/rb-kqueue/queue.rb
|
16
11
|
#
|
17
|
-
EVENTS = [
|
18
|
-
|
19
|
-
# Initializes the Adapter. See {Listen::Adapter#initialize} for
|
20
|
-
# more info.
|
21
|
-
#
|
22
|
-
def initialize(directories, options = {}, &callback)
|
23
|
-
super
|
24
|
-
@kqueue = init_kqueue
|
25
|
-
end
|
26
|
-
|
27
|
-
# Starts the adapter.
|
28
|
-
#
|
29
|
-
# @param [Boolean] blocking whether or not to block the current thread after starting
|
30
|
-
#
|
31
|
-
def start(blocking = true)
|
32
|
-
@mutex.synchronize do
|
33
|
-
return if @stop == false
|
34
|
-
super
|
35
|
-
end
|
36
|
-
|
37
|
-
@kqueue_thread = Thread.new do
|
38
|
-
until @stop
|
39
|
-
@kqueue.poll
|
40
|
-
sleep(@latency)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
@poll_thread = Thread.new { poll_changed_dirs } if @report_changes
|
44
|
-
|
45
|
-
@kqueue_thread.join if blocking
|
46
|
-
end
|
47
|
-
|
48
|
-
# Stops the adapter.
|
49
|
-
#
|
50
|
-
def stop
|
51
|
-
@mutex.synchronize do
|
52
|
-
return if @stop == true
|
53
|
-
super
|
54
|
-
end
|
55
|
-
|
56
|
-
@kqueue.stop
|
57
|
-
Thread.kill(@kqueue_thread) if @kqueue_thread
|
58
|
-
@poll_thread.join if @poll_thread
|
59
|
-
end
|
12
|
+
EVENTS = [:delete, :write, :extend, :attrib, :link, :rename, :revoke]
|
60
13
|
|
61
|
-
|
62
|
-
|
63
|
-
# @return [Boolean] whether usable or not
|
64
|
-
#
|
65
|
-
def self.usable?
|
66
|
-
return false unless RbConfig::CONFIG['target_os'] =~ /freebsd/i
|
67
|
-
super
|
68
|
-
end
|
14
|
+
def self.target_os_regex; /freebsd/i; end
|
15
|
+
def self.adapter_gem; 'rb-kqueue'; end
|
69
16
|
|
70
17
|
private
|
71
18
|
|
@@ -74,24 +21,26 @@ module Listen
|
|
74
21
|
#
|
75
22
|
# @return [INotify::Notifier] initialized kqueue
|
76
23
|
#
|
77
|
-
|
24
|
+
# @see Listen::Adapter#initialize_worker
|
25
|
+
#
|
26
|
+
def initialize_worker
|
78
27
|
require 'find'
|
79
28
|
|
80
29
|
callback = lambda do |event|
|
81
30
|
path = event.watcher.path
|
82
|
-
|
31
|
+
mutex.synchronize do
|
83
32
|
# kqueue watches everything, but Listen only needs the
|
84
33
|
# directory where stuffs happens.
|
85
|
-
@
|
34
|
+
@changed_directories << (File.directory?(path) ? path : File.dirname(path))
|
86
35
|
|
87
36
|
# If it is a directory, and it has a write flag, it means a
|
88
37
|
# file has been added so find out which and deal with it.
|
89
|
-
# No need to check for removed
|
90
|
-
# when the vfs does
|
91
|
-
if File.directory?(path) &&
|
38
|
+
# No need to check for removed files, kqueue will forget them
|
39
|
+
# when the vfs does.
|
40
|
+
if File.directory?(path) && event.flags.include?(:write)
|
92
41
|
queue = event.watcher.queue
|
93
42
|
Find.find(path) do |file|
|
94
|
-
unless queue.watchers.detect {|k,v| v.path == file.to_s}
|
43
|
+
unless queue.watchers.detect { |k,v| v.path == file.to_s }
|
95
44
|
queue.watch_file(file, *EVENTS, &callback)
|
96
45
|
end
|
97
46
|
end
|
@@ -100,13 +49,27 @@ module Listen
|
|
100
49
|
end
|
101
50
|
|
102
51
|
KQueue::Queue.new.tap do |queue|
|
103
|
-
|
52
|
+
directories.each do |directory|
|
104
53
|
Find.find(directory) do |path|
|
105
54
|
queue.watch_file(path, *EVENTS, &callback)
|
106
55
|
end
|
107
56
|
end
|
108
57
|
end
|
109
58
|
end
|
59
|
+
|
60
|
+
# Starts the worker in a new thread.
|
61
|
+
#
|
62
|
+
# @see Listen::Adapter#start_worker
|
63
|
+
#
|
64
|
+
def start_worker
|
65
|
+
@worker_thread = Thread.new do
|
66
|
+
until stopped
|
67
|
+
worker.poll
|
68
|
+
sleep(latency)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
110
72
|
end
|
73
|
+
|
111
74
|
end
|
112
75
|
end
|