listen 2.7.6 → 2.7.7
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 +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?
|