listen 2.7.6 → 2.7.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +0 -0
- data/.rspec +0 -0
- data/.rubocop.yml +0 -0
- data/.travis.yml +0 -0
- data/.yardopts +0 -0
- data/CHANGELOG.md +0 -0
- data/CONTRIBUTING.md +0 -0
- data/Gemfile +2 -0
- data/Guardfile +2 -0
- data/LICENSE.txt +0 -0
- data/README.md +0 -0
- data/Rakefile +0 -0
- data/lib/listen.rb +0 -0
- data/lib/listen/adapter.rb +0 -0
- data/lib/listen/adapter/base.rb +47 -21
- data/lib/listen/adapter/bsd.rb +31 -25
- data/lib/listen/adapter/darwin.rb +13 -12
- data/lib/listen/adapter/linux.rb +45 -36
- data/lib/listen/adapter/polling.rb +12 -7
- data/lib/listen/adapter/tcp.rb +9 -4
- data/lib/listen/adapter/windows.rb +46 -58
- data/lib/listen/change.rb +12 -8
- data/lib/listen/cli.rb +0 -0
- data/lib/listen/directory.rb +30 -22
- data/lib/listen/file.rb +9 -8
- data/lib/listen/listener.rb +35 -12
- data/lib/listen/options.rb +23 -0
- data/lib/listen/queue_optimizer.rb +23 -13
- data/lib/listen/record.rb +98 -21
- data/lib/listen/silencer.rb +21 -40
- data/lib/listen/tcp.rb +0 -0
- data/lib/listen/tcp/broadcaster.rb +0 -0
- data/lib/listen/tcp/message.rb +0 -0
- data/lib/listen/version.rb +1 -1
- data/listen.gemspec +0 -0
- data/spec/acceptance/listen_spec.rb +0 -0
- data/spec/acceptance/tcp_spec.rb +0 -0
- data/spec/lib/listen/adapter/base_spec.rb +17 -16
- data/spec/lib/listen/adapter/bsd_spec.rb +0 -0
- data/spec/lib/listen/adapter/darwin_spec.rb +11 -4
- data/spec/lib/listen/adapter/linux_spec.rb +20 -29
- data/spec/lib/listen/adapter/polling_spec.rb +15 -13
- data/spec/lib/listen/adapter/tcp_spec.rb +6 -3
- data/spec/lib/listen/adapter/windows_spec.rb +0 -0
- data/spec/lib/listen/adapter_spec.rb +0 -0
- data/spec/lib/listen/change_spec.rb +21 -27
- data/spec/lib/listen/directory_spec.rb +60 -42
- data/spec/lib/listen/file_spec.rb +16 -20
- data/spec/lib/listen/listener_spec.rb +136 -99
- data/spec/lib/listen/record_spec.rb +205 -62
- data/spec/lib/listen/silencer_spec.rb +44 -114
- data/spec/lib/listen/tcp/broadcaster_spec.rb +0 -0
- data/spec/lib/listen/tcp/listener_spec.rb +8 -5
- data/spec/lib/listen/tcp/message_spec.rb +0 -0
- data/spec/lib/listen_spec.rb +0 -0
- data/spec/spec_helper.rb +0 -0
- data/spec/support/acceptance_helper.rb +15 -4
- data/spec/support/fixtures_helper.rb +0 -0
- data/spec/support/platform_helper.rb +0 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e6d5e368c0d42f2b677a88efcd2b983eb1551278
|
4
|
+
data.tar.gz: 656135661cb4e2c2bd82c9acdbf9d0779a1c707a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d3b07e9530ffa906cf9cc1413dba58b990dc5e720e7c42f4364ac84790e47c43d10bfa5aa5afcbe43e360e1f6c459a5f7ffb15f7dc20ef8467127c6d1c8c93de
|
7
|
+
data.tar.gz: c6e078178e2879ec66de6c54a52542aa973d9de372edda0c8e74356d7fd1377330f569ef8ae73bf61b4f09962fe341d53dec6201bfdd4261275163fcdfb1a035
|
data/.gitignore
CHANGED
File without changes
|
data/.rspec
CHANGED
File without changes
|
data/.rubocop.yml
CHANGED
File without changes
|
data/.travis.yml
CHANGED
File without changes
|
data/.yardopts
CHANGED
File without changes
|
data/CHANGELOG.md
CHANGED
File without changes
|
data/CONTRIBUTING.md
CHANGED
File without changes
|
data/Gemfile
CHANGED
data/Guardfile
CHANGED
data/LICENSE.txt
CHANGED
File without changes
|
data/README.md
CHANGED
File without changes
|
data/Rakefile
CHANGED
File without changes
|
data/lib/listen.rb
CHANGED
File without changes
|
data/lib/listen/adapter.rb
CHANGED
File without changes
|
data/lib/listen/adapter/base.rb
CHANGED
@@ -1,19 +1,58 @@
|
|
1
|
+
require 'listen/options'
|
2
|
+
|
1
3
|
module Listen
|
2
4
|
module Adapter
|
3
5
|
class Base
|
4
6
|
include Celluloid
|
5
7
|
|
6
|
-
|
8
|
+
attr_reader :options
|
9
|
+
|
10
|
+
# TODO: only used by tests
|
11
|
+
DEFAULTS = {}
|
12
|
+
|
13
|
+
def initialize(opts)
|
14
|
+
@configured = nil
|
15
|
+
options = opts.dup
|
16
|
+
@mq = options.delete(:mq)
|
17
|
+
@directories = options.delete(:directories)
|
18
|
+
|
19
|
+
Array(@directories).each do |dir|
|
20
|
+
next if dir.is_a?(Pathname)
|
21
|
+
fail ArgumentError, "not a Pathname: #{dir.inspect}"
|
22
|
+
end
|
23
|
+
|
24
|
+
# TODO: actually use this in every adapter
|
25
|
+
@recursion = options.delete(:recursion)
|
26
|
+
@recursion = true if @recursion.nil?
|
7
27
|
|
8
|
-
|
9
|
-
@
|
28
|
+
defaults = self.class.const_get('DEFAULTS')
|
29
|
+
@options = Listen::Options.new(options, defaults)
|
10
30
|
rescue
|
11
31
|
_log :error, "adapter config failed: #{$!}:#{$@.join("\n")}"
|
12
32
|
raise
|
13
33
|
end
|
14
34
|
|
35
|
+
# TODO: it's a separate method as a temporary workaround for tests
|
36
|
+
def configure
|
37
|
+
return if @configured
|
38
|
+
@configured = true
|
39
|
+
|
40
|
+
@callbacks ||= {}
|
41
|
+
@directories.each do |dir|
|
42
|
+
unless dir.is_a?(Pathname)
|
43
|
+
fail ArgumentError, "not a Pathname: #{dir.inspect}"
|
44
|
+
end
|
45
|
+
|
46
|
+
callback = @callbacks[dir] || lambda do |event|
|
47
|
+
_process_event(dir, event)
|
48
|
+
end
|
49
|
+
@callbacks[dir] = callback
|
50
|
+
_configure(dir, &callback)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
15
54
|
def start
|
16
|
-
|
55
|
+
configure
|
17
56
|
Thread.new do
|
18
57
|
begin
|
19
58
|
_run
|
@@ -34,23 +73,10 @@ module Listen
|
|
34
73
|
|
35
74
|
private
|
36
75
|
|
37
|
-
def
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
listener.directories
|
42
|
-
end
|
43
|
-
|
44
|
-
def _notify_change(type, path, options = {})
|
45
|
-
unless (worker = listener.async(:change_pool))
|
46
|
-
_log :warn, 'Failed to allocate worker from change pool'
|
47
|
-
return
|
48
|
-
end
|
49
|
-
|
50
|
-
worker.change(type, path, options)
|
51
|
-
rescue RuntimeError
|
52
|
-
_log :error, "_notify_change crashed: #{$!}:#{$@.join("\n")}"
|
53
|
-
raise
|
76
|
+
def _queue_change(type, dir, rel_path, options)
|
77
|
+
# TODO: temporary workaround to remove dependency on Change through
|
78
|
+
# Celluloid in tests
|
79
|
+
@mq.send(:_queue_raw_change, type, dir, rel_path, options)
|
54
80
|
end
|
55
81
|
|
56
82
|
def _log(type, message)
|
data/lib/listen/adapter/bsd.rb
CHANGED
@@ -7,7 +7,16 @@ module Listen
|
|
7
7
|
class BSD < Base
|
8
8
|
OS_REGEXP = /bsd|dragonfly/i
|
9
9
|
|
10
|
-
|
10
|
+
DEFAULTS = {
|
11
|
+
events: [
|
12
|
+
:delete,
|
13
|
+
:write,
|
14
|
+
:extend,
|
15
|
+
:attrib,
|
16
|
+
:rename
|
17
|
+
# :link, :revoke
|
18
|
+
]
|
19
|
+
}
|
11
20
|
|
12
21
|
BUNDLER_DECLARE_GEM = <<-EOS.gsub(/^ {6}/, '')
|
13
22
|
Please add the following to your Gemfile to avoid polling for changes:
|
@@ -47,36 +56,33 @@ module Listen
|
|
47
56
|
|
48
57
|
private
|
49
58
|
|
50
|
-
def _configure
|
51
|
-
@worker
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
_find(path.to_s) { |file_path| _watch_file(file_path, @worker) }
|
56
|
-
end
|
59
|
+
def _configure(directory, &_callback)
|
60
|
+
@worker ||= KQueue::Queue.new
|
61
|
+
# use Record to make a snapshot of dir, so we
|
62
|
+
# can detect new files
|
63
|
+
_find(directory.to_s) { |path| _watch_file(path, @worker) }
|
57
64
|
end
|
58
65
|
|
59
66
|
def _run
|
60
67
|
@worker.run
|
61
68
|
end
|
62
69
|
|
63
|
-
def
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
end
|
73
|
-
|
74
|
-
# If it is a directory, and it has a write flag, it means a
|
75
|
-
# file has been added so find out which and deal with it.
|
76
|
-
# No need to check for removed files, kqueue will forget them
|
77
|
-
# when the vfs does.
|
78
|
-
_watch_for_new_file(event) if path.directory?
|
70
|
+
def _process_event(dir, event)
|
71
|
+
full_path = _event_path(event)
|
72
|
+
if full_path.directory?
|
73
|
+
# Force dir content tracking to kick in, or we won't have
|
74
|
+
# names of added files
|
75
|
+
_queue_change(:dir, dir, '.', recursive: true)
|
76
|
+
else
|
77
|
+
path = full_path.relative_path_from(dir)
|
78
|
+
_queue_change(:file, dir, path, change: _change(event.flags))
|
79
79
|
end
|
80
|
+
|
81
|
+
# If it is a directory, and it has a write flag, it means a
|
82
|
+
# file has been added so find out which and deal with it.
|
83
|
+
# No need to check for removed files, kqueue will forget them
|
84
|
+
# when the vfs does.
|
85
|
+
_watch_for_new_file(event) if path.directory?
|
80
86
|
end
|
81
87
|
|
82
88
|
def _change(event_flags)
|
@@ -103,7 +109,7 @@ module Listen
|
|
103
109
|
end
|
104
110
|
|
105
111
|
def _watch_file(path, queue)
|
106
|
-
queue.watch_file(path, *
|
112
|
+
queue.watch_file(path, *options.events, &_worker_callback)
|
107
113
|
end
|
108
114
|
|
109
115
|
# Quick rubocop workaround
|
@@ -6,28 +6,29 @@ module Listen
|
|
6
6
|
OS_REGEXP = /darwin(1.+)?$/i
|
7
7
|
|
8
8
|
# The default delay between checking for changes.
|
9
|
-
|
9
|
+
DEFAULTS = { latency: 0.1 }
|
10
10
|
|
11
11
|
private
|
12
12
|
|
13
|
-
def _configure
|
13
|
+
def _configure(dir, &callback)
|
14
14
|
require 'rb-fsevent'
|
15
|
-
@worker
|
16
|
-
|
17
|
-
|
18
|
-
new_path = Pathname.new(path.sub(/\/$/, ''))
|
19
|
-
_log :debug, "fsevent: #{new_path}"
|
20
|
-
_notify_change(:dir, new_path)
|
21
|
-
end
|
22
|
-
end
|
15
|
+
@worker ||= FSEvent.new
|
16
|
+
opts = { latency: options.latency }
|
17
|
+
@worker.watch(dir.to_s, opts, &callback)
|
23
18
|
end
|
24
19
|
|
25
20
|
def _run
|
26
21
|
@worker.run
|
27
22
|
end
|
28
23
|
|
29
|
-
def
|
30
|
-
|
24
|
+
def _process_event(dir, event)
|
25
|
+
event.each do |path|
|
26
|
+
new_path = Pathname.new(path.sub(/\/$/, ''))
|
27
|
+
_log :debug, "fsevent: #{new_path}"
|
28
|
+
# TODO: does this preserve symlinks?
|
29
|
+
rel_path = new_path.relative_path_from(dir).to_s
|
30
|
+
_queue_change(:dir, dir, rel_path, recursive: true)
|
31
|
+
end
|
31
32
|
end
|
32
33
|
end
|
33
34
|
end
|
data/lib/listen/adapter/linux.rb
CHANGED
@@ -1,31 +1,34 @@
|
|
1
1
|
module Listen
|
2
2
|
module Adapter
|
3
|
-
# Listener implementation for Linux `inotify`.
|
4
3
|
# @see https://github.com/nex3/rb-inotify
|
5
|
-
#
|
6
4
|
class Linux < Base
|
7
5
|
OS_REGEXP = /linux/i
|
8
6
|
|
9
|
-
|
7
|
+
DEFAULTS = {
|
8
|
+
events: [
|
9
|
+
:recursive,
|
10
|
+
:attrib,
|
11
|
+
:create,
|
12
|
+
:delete,
|
13
|
+
:move,
|
14
|
+
:close_write
|
15
|
+
]
|
16
|
+
}
|
17
|
+
|
18
|
+
private
|
10
19
|
|
11
20
|
WIKI_URL = 'https://github.com/guard/listen'\
|
12
21
|
'/wiki/Increasing-the-amount-of-inotify-watchers'
|
13
22
|
|
14
23
|
INOTIFY_LIMIT_MESSAGE = <<-EOS.gsub(/^\s*/, '')
|
15
24
|
FATAL: Listen error: unable to monitor directories for changes.
|
16
|
-
|
17
|
-
Please head to #{WIKI_URL}
|
18
|
-
for information on how to solve this issue.
|
25
|
+
Visit #{WIKI_URL} for info on how to fix this.
|
19
26
|
EOS
|
20
27
|
|
21
|
-
|
22
|
-
|
23
|
-
def _configure
|
28
|
+
def _configure(directory, &callback)
|
24
29
|
require 'rb-inotify'
|
25
|
-
@worker
|
26
|
-
|
27
|
-
@worker.watch(path.to_s, *EVENTS, &_callback)
|
28
|
-
end
|
30
|
+
@worker ||= INotify::Notifier.new
|
31
|
+
@worker.watch(directory.to_s, *options.events, &callback)
|
29
32
|
rescue Errno::ENOSPC
|
30
33
|
# workaround - Celluloid catches abort and prints nothing
|
31
34
|
STDERR.puts INOTIFY_LIMIT_MESSAGE
|
@@ -37,32 +40,38 @@ module Listen
|
|
37
40
|
@worker.run
|
38
41
|
end
|
39
42
|
|
40
|
-
def
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
else
|
53
|
-
_notify_change(:dir, path)
|
54
|
-
end
|
43
|
+
def _process_event(dir, event)
|
44
|
+
# NOTE: avoid using event.absolute_name since new API
|
45
|
+
# will need to have a custom recursion implemented
|
46
|
+
# to properly match events to configured directories
|
47
|
+
path = Pathname.new(event.watcher.path) + event.name
|
48
|
+
rel_path = path.relative_path_from(dir).to_s
|
49
|
+
|
50
|
+
_log :debug, "inotify: #{rel_path} (#{event.flags.inspect})"
|
51
|
+
|
52
|
+
if /1|true/ =~ ENV['LISTEN_GEM_SIMULATE_FSEVENT']
|
53
|
+
if (event.flags & [:moved_to, :moved_from]) || _dir_event?(event)
|
54
|
+
_queue_change(:dir, dir, Pathname(rel_path).dirname, {})
|
55
55
|
else
|
56
|
-
|
57
|
-
cookie_opts = event.cookie.zero? ? {} : { cookie: event.cookie }
|
58
|
-
if _dir_event?(event)
|
59
|
-
_notify_change(:dir, path, cookie_opts)
|
60
|
-
else
|
61
|
-
options = { change: _change(event.flags) }
|
62
|
-
_notify_change(:file, path, options.merge(cookie_opts))
|
63
|
-
end
|
56
|
+
_queue_change(:dir, dir, rel_path, {})
|
64
57
|
end
|
58
|
+
return
|
65
59
|
end
|
60
|
+
|
61
|
+
return if _skip_event?(event)
|
62
|
+
|
63
|
+
cookie_params = event.cookie.zero? ? {} : { cookie: event.cookie }
|
64
|
+
|
65
|
+
# Note: don't pass options to force rescanning the directory, so we can
|
66
|
+
# detect moving/deleting a whole tree
|
67
|
+
if _dir_event?(event)
|
68
|
+
_queue_change(:dir, dir, rel_path, cookie_params)
|
69
|
+
return
|
70
|
+
end
|
71
|
+
|
72
|
+
params = cookie_params.merge(change: _change(event.flags))
|
73
|
+
|
74
|
+
_queue_change(:file, dir, rel_path, params)
|
66
75
|
end
|
67
76
|
|
68
77
|
def _skip_event?(event)
|
@@ -6,26 +6,31 @@ module Listen
|
|
6
6
|
# file IO than the other implementations.
|
7
7
|
#
|
8
8
|
class Polling < Base
|
9
|
-
OS_REGEXP = // # match
|
9
|
+
OS_REGEXP = // # match every OS
|
10
10
|
|
11
|
-
|
11
|
+
DEFAULTS = { latency: 1.0 }
|
12
12
|
|
13
13
|
private
|
14
14
|
|
15
|
-
def
|
16
|
-
|
15
|
+
def _configure(_, &callback)
|
16
|
+
@polling_callbacks ||= []
|
17
|
+
@polling_callbacks << callback
|
17
18
|
end
|
18
19
|
|
19
20
|
def _run
|
20
21
|
loop do
|
21
22
|
start = Time.now.to_f
|
22
|
-
|
23
|
-
|
24
|
-
nap_time =
|
23
|
+
@polling_callbacks.each do |callback|
|
24
|
+
callback.call(nil)
|
25
|
+
nap_time = options.latency - (Time.now.to_f - start)
|
25
26
|
sleep(nap_time) if nap_time > 0
|
26
27
|
end
|
27
28
|
end
|
28
29
|
end
|
30
|
+
|
31
|
+
def _process_event(dir, _)
|
32
|
+
_queue_change(:dir, dir, '.', recursive: true)
|
33
|
+
end
|
29
34
|
end
|
30
35
|
end
|
31
36
|
end
|
data/lib/listen/adapter/tcp.rb
CHANGED
@@ -9,15 +9,19 @@ module Listen
|
|
9
9
|
OS_REGEXP = // # match any
|
10
10
|
|
11
11
|
include Celluloid::IO
|
12
|
-
|
13
12
|
finalizer :finalize
|
14
13
|
|
14
|
+
DEFAULTS = {
|
15
|
+
host: 'localhost',
|
16
|
+
port: '4000'
|
17
|
+
}
|
18
|
+
|
15
19
|
attr_reader :buffer, :socket
|
16
20
|
|
17
21
|
# Initializes and starts a Celluloid::IO-powered TCP-recipient
|
18
22
|
def start
|
19
23
|
attempts = 3
|
20
|
-
@socket = TCPSocket.new(
|
24
|
+
@socket = TCPSocket.new(options.host, options.port)
|
21
25
|
@buffer = ''
|
22
26
|
async.run
|
23
27
|
rescue Celluloid::Task::TerminatedError
|
@@ -66,8 +70,9 @@ module Listen
|
|
66
70
|
|
67
71
|
# Handles incoming message by notifying of path changes
|
68
72
|
def handle_message(message)
|
69
|
-
type,
|
70
|
-
|
73
|
+
type, change, dir, path, _ = message.object
|
74
|
+
_log :debug, "TCP message: #{[type, change, dir, path].inspect}"
|
75
|
+
_queue_change(type.to_sym, Pathname(dir), path, change: change.to_sym)
|
71
76
|
end
|
72
77
|
|
73
78
|
def self.local_fs?
|