listen 3.3.1 → 3.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/listen +3 -4
- data/lib/listen/adapter.rb +3 -3
- data/lib/listen/adapter/base.rb +4 -4
- data/lib/listen/adapter/bsd.rb +3 -4
- data/lib/listen/adapter/config.rb +1 -4
- data/lib/listen/adapter/darwin.rb +2 -2
- data/lib/listen/adapter/linux.rb +4 -2
- data/lib/listen/adapter/polling.rb +1 -1
- data/lib/listen/adapter/windows.rb +10 -14
- data/lib/listen/change.rb +10 -19
- data/lib/listen/cli.rb +3 -4
- data/lib/listen/directory.rb +5 -7
- data/lib/listen/event/config.rb +4 -5
- data/lib/listen/event/processor.rb +8 -8
- data/lib/listen/event/queue.rb +9 -9
- data/lib/listen/file.rb +6 -0
- data/lib/listen/fsm.rb +2 -2
- data/lib/listen/listener.rb +2 -0
- data/lib/listen/listener/config.rb +2 -4
- data/lib/listen/logger.rb +13 -12
- data/lib/listen/options.rb +9 -8
- data/lib/listen/queue_optimizer.rb +7 -12
- data/lib/listen/record.rb +28 -31
- data/lib/listen/record/entry.rb +1 -1
- data/lib/listen/record/symlink_detector.rb +4 -4
- data/lib/listen/silencer.rb +10 -8
- data/lib/listen/thread.rb +14 -12
- data/lib/listen/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a573b56820a3108a7d35562e1d502da64c15f110ce755119e0a7f8dde18d76fc
|
4
|
+
data.tar.gz: 2be3e9a4e9f6e46171ccb1429fde63c07255c11923a882c63dd1c1ba8afb2ec3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 17013d995bc4e0b4a0b0b30199854960e2eb4240a21ee8329ad04be4ab3db778f908f1a583e53956f838d0bba956f6ad6133bac406aebd77caf3f400ed7d82c8
|
7
|
+
data.tar.gz: 38d254a77bbfcc28046ffd7a396cf26215bdaa95a9165f20ec1c0cd932f2e6eb88d29c5b3f4db45c6729a6f7e454ab0621c5e9959f5f70521477a8b8baa21497
|
data/bin/listen
CHANGED
@@ -1,12 +1,11 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require 'listen'
|
4
5
|
require 'listen/cli'
|
5
6
|
|
6
|
-
|
7
|
-
|
8
|
-
Signal.trap('INT') { Thread.new { Listen.stop } }
|
9
|
-
end
|
7
|
+
if !defined?(JRUBY_VERSION) && Signal.list.keys.include?('INT')
|
8
|
+
Signal.trap('INT') { Thread.new { Listen.stop } }
|
10
9
|
end
|
11
10
|
|
12
11
|
Listen::CLI.start
|
data/lib/listen/adapter.rb
CHANGED
@@ -11,7 +11,7 @@ module Listen
|
|
11
11
|
module Adapter
|
12
12
|
OPTIMIZED_ADAPTERS = [Darwin, Linux, BSD, Windows].freeze
|
13
13
|
POLLING_FALLBACK_MESSAGE = 'Listen will be polling for changes.'\
|
14
|
-
'Learn more at https://github.com/guard/listen#listen-adapters.'
|
14
|
+
'Learn more at https://github.com/guard/listen#listen-adapters.'
|
15
15
|
|
16
16
|
class << self
|
17
17
|
def select(options = {})
|
@@ -24,14 +24,14 @@ module Listen
|
|
24
24
|
Polling
|
25
25
|
rescue
|
26
26
|
Listen.logger.warn format('Adapter: failed: %s:%s', $ERROR_POSITION.inspect,
|
27
|
-
|
27
|
+
$ERROR_POSITION * "\n")
|
28
28
|
raise
|
29
29
|
end
|
30
30
|
|
31
31
|
private
|
32
32
|
|
33
33
|
def _usable_adapter_class
|
34
|
-
OPTIMIZED_ADAPTERS.
|
34
|
+
OPTIMIZED_ADAPTERS.find(&:usable?)
|
35
35
|
end
|
36
36
|
|
37
37
|
def _warn_polling_fallback(options)
|
data/lib/listen/adapter/base.rb
CHANGED
@@ -8,13 +8,11 @@ require 'listen/thread'
|
|
8
8
|
module Listen
|
9
9
|
module Adapter
|
10
10
|
class Base
|
11
|
-
attr_reader :options
|
11
|
+
attr_reader :options, :config
|
12
12
|
|
13
13
|
# TODO: only used by tests
|
14
14
|
DEFAULTS = {}.freeze
|
15
15
|
|
16
|
-
attr_reader :config
|
17
|
-
|
18
16
|
def initialize(config)
|
19
17
|
@started = false
|
20
18
|
@config = config
|
@@ -31,6 +29,7 @@ module Listen
|
|
31
29
|
end
|
32
30
|
|
33
31
|
# TODO: it's a separate method as a temporary workaround for tests
|
32
|
+
# rubocop:disable Metrics/MethodLength
|
34
33
|
def configure
|
35
34
|
if @configured
|
36
35
|
Listen.logger.warn('Adapter already configured!')
|
@@ -57,6 +56,7 @@ module Listen
|
|
57
56
|
@snapshots[dir] = snapshot
|
58
57
|
end
|
59
58
|
end
|
59
|
+
# rubocop:enable Metrics/MethodLength
|
60
60
|
|
61
61
|
def started?
|
62
62
|
@started
|
@@ -73,7 +73,7 @@ module Listen
|
|
73
73
|
@started = true
|
74
74
|
|
75
75
|
@run_thread = Listen::Thread.new("run_thread") do
|
76
|
-
@snapshots.
|
76
|
+
@snapshots.each_value do |snapshot|
|
77
77
|
_timed('Record.build()') { snapshot.record.build }
|
78
78
|
end
|
79
79
|
_run
|
data/lib/listen/adapter/bsd.rb
CHANGED
@@ -7,7 +7,7 @@
|
|
7
7
|
module Listen
|
8
8
|
module Adapter
|
9
9
|
class BSD < Base
|
10
|
-
OS_REGEXP = /bsd|dragonfly/i
|
10
|
+
OS_REGEXP = /bsd|dragonfly/i.freeze
|
11
11
|
|
12
12
|
DEFAULTS = {
|
13
13
|
events: [
|
@@ -73,8 +73,7 @@ module Listen
|
|
73
73
|
def _change(event_flags)
|
74
74
|
{ modified: [:attrib, :extend],
|
75
75
|
added: [:write],
|
76
|
-
removed: [:rename, :delete]
|
77
|
-
}.each do |change, flags|
|
76
|
+
removed: [:rename, :delete] }.each do |change, flags|
|
78
77
|
return change unless (flags & event_flags).empty?
|
79
78
|
end
|
80
79
|
nil
|
@@ -87,7 +86,7 @@ module Listen
|
|
87
86
|
def _watch_for_new_file(event)
|
88
87
|
queue = event.watcher.queue
|
89
88
|
_find(_event_path(event).to_s) do |file_path|
|
90
|
-
unless queue.watchers.
|
89
|
+
unless queue.watchers.find { |_, v| v.path == file_path.to_s }
|
91
90
|
_watch_file(file_path, queue)
|
92
91
|
end
|
93
92
|
end
|
@@ -5,10 +5,7 @@ require 'pathname'
|
|
5
5
|
module Listen
|
6
6
|
module Adapter
|
7
7
|
class Config
|
8
|
-
attr_reader :directories
|
9
|
-
attr_reader :silencer
|
10
|
-
attr_reader :queue
|
11
|
-
attr_reader :adapter_options
|
8
|
+
attr_reader :directories, :silencer, :queue, :adapter_options
|
12
9
|
|
13
10
|
def initialize(directories, queue, silencer, adapter_options)
|
14
11
|
# Default to current directory if no directories are supplied
|
@@ -7,7 +7,7 @@ module Listen
|
|
7
7
|
# Adapter implementation for Mac OS X `FSEvents`.
|
8
8
|
#
|
9
9
|
class Darwin < Base
|
10
|
-
OS_REGEXP = /darwin(?<major_version>(1|2)\d+)/i
|
10
|
+
OS_REGEXP = /darwin(?<major_version>(1|2)\d+)/i.freeze
|
11
11
|
|
12
12
|
# The default delay between checking for changes.
|
13
13
|
DEFAULTS = { latency: 0.1 }.freeze
|
@@ -51,7 +51,7 @@ module Listen
|
|
51
51
|
|
52
52
|
def _process_changes(dirs)
|
53
53
|
dirs.each do |dir|
|
54
|
-
dir = Pathname.new(dir.sub(%r{
|
54
|
+
dir = Pathname.new(dir.sub(%r{/$}, ''))
|
55
55
|
|
56
56
|
@callbacks.each do |watched_dir, callback|
|
57
57
|
if watched_dir.eql?(dir) || Listen::Directory.ascendant_of?(watched_dir, dir)
|
data/lib/listen/adapter/linux.rb
CHANGED
@@ -4,7 +4,7 @@ module Listen
|
|
4
4
|
module Adapter
|
5
5
|
# @see https://github.com/nex3/rb-inotify
|
6
6
|
class Linux < Base
|
7
|
-
OS_REGEXP = /linux/i
|
7
|
+
OS_REGEXP = /linux/i.freeze
|
8
8
|
|
9
9
|
DEFAULTS = {
|
10
10
|
events: [
|
@@ -22,7 +22,7 @@ module Listen
|
|
22
22
|
private
|
23
23
|
|
24
24
|
WIKI_URL = 'https://github.com/guard/listen'\
|
25
|
-
'/wiki/Increasing-the-amount-of-inotify-watchers'
|
25
|
+
'/wiki/Increasing-the-amount-of-inotify-watchers'
|
26
26
|
|
27
27
|
INOTIFY_LIMIT_MESSAGE = <<-EOS.gsub(/^\s*/, '')
|
28
28
|
FATAL: Listen error: unable to monitor directories for changes.
|
@@ -41,6 +41,7 @@ module Listen
|
|
41
41
|
@worker.run
|
42
42
|
end
|
43
43
|
|
44
|
+
# rubocop:disable Metrics/MethodLength
|
44
45
|
def _process_event(dir, event)
|
45
46
|
# NOTE: avoid using event.absolute_name since new API
|
46
47
|
# will need to have a custom recursion implemented
|
@@ -73,6 +74,7 @@ module Listen
|
|
73
74
|
|
74
75
|
_queue_change(:file, dir, rel_path, params)
|
75
76
|
end
|
77
|
+
# rubocop:enable Metrics/MethodLength
|
76
78
|
|
77
79
|
def _skip_event?(event)
|
78
80
|
# Event on root directory
|
@@ -5,7 +5,7 @@ module Listen
|
|
5
5
|
# Adapter implementation for Windows `wdm`.
|
6
6
|
#
|
7
7
|
class Windows < Base
|
8
|
-
OS_REGEXP = /mswin|mingw|cygwin/i
|
8
|
+
OS_REGEXP = /mswin|mingw|cygwin/i.freeze
|
9
9
|
|
10
10
|
BUNDLER_DECLARE_GEM = <<-EOS.gsub(/^ {6}/, '')
|
11
11
|
Please add the following to your Gemfile to avoid polling for changes:
|
@@ -18,7 +18,7 @@ module Listen
|
|
18
18
|
true
|
19
19
|
rescue LoadError
|
20
20
|
Listen.logger.debug format('wdm - load failed: %s:%s', $ERROR_INFO,
|
21
|
-
|
21
|
+
$ERROR_POSITION * "\n")
|
22
22
|
|
23
23
|
Kernel.warn BUNDLER_DECLARE_GEM
|
24
24
|
false
|
@@ -38,8 +38,7 @@ module Listen
|
|
38
38
|
yield([:dir, change])
|
39
39
|
end
|
40
40
|
|
41
|
-
|
42
|
-
@worker.watch_recursively(dir.to_s, *events) do |change|
|
41
|
+
@worker.watch_recursively(dir.to_s, :attributes, :last_write) do |change|
|
43
42
|
yield([:attr, change])
|
44
43
|
end
|
45
44
|
end
|
@@ -48,6 +47,7 @@ module Listen
|
|
48
47
|
@worker.run!
|
49
48
|
end
|
50
49
|
|
50
|
+
# rubocop:disable Metrics/MethodLength
|
51
51
|
def _process_event(dir, event)
|
52
52
|
Listen.logger.debug "wdm - callback: #{event.inspect}"
|
53
53
|
|
@@ -67,10 +67,11 @@ module Listen
|
|
67
67
|
_queue_change(:file, dir, rel_path, options)
|
68
68
|
end
|
69
69
|
when :dir
|
70
|
-
|
70
|
+
case change.type
|
71
|
+
when :removed
|
71
72
|
# TODO: check if watched dir?
|
72
73
|
_queue_change(:dir, dir, Pathname(rel_path).dirname.to_s, {})
|
73
|
-
|
74
|
+
when :added
|
74
75
|
_queue_change(:dir, dir, rel_path, {})
|
75
76
|
# do nothing - changed directory means either:
|
76
77
|
# - removed subdirs (handled above)
|
@@ -80,20 +81,15 @@ module Listen
|
|
80
81
|
# so what's left?
|
81
82
|
end
|
82
83
|
end
|
83
|
-
rescue
|
84
|
-
details = event.inspect
|
85
|
-
Listen.logger.error format('wdm - callback (%s): %s:%s', details, $ERROR_INFO,
|
86
|
-
$ERROR_POSITION * "\n")
|
87
|
-
raise
|
88
84
|
end
|
85
|
+
# rubocop:enable Metrics/MethodLength
|
89
86
|
|
90
87
|
def _change(type)
|
91
88
|
{ modified: [:modified, :attrib], # TODO: is attrib really passed?
|
92
89
|
added: [:added, :renamed_new_file],
|
93
|
-
removed: [:removed, :renamed_old_file] }.
|
94
|
-
|
90
|
+
removed: [:removed, :renamed_old_file] }.find do |change, types|
|
91
|
+
types.include?(type) and break change
|
95
92
|
end
|
96
|
-
nil
|
97
93
|
end
|
98
94
|
end
|
99
95
|
end
|
data/lib/listen/change.rb
CHANGED
@@ -30,13 +30,16 @@ module Listen
|
|
30
30
|
end
|
31
31
|
|
32
32
|
# Invalidate some part of the snapshot/record (dir, file, subtree, etc.)
|
33
|
+
# rubocop:disable Metrics/MethodLength
|
34
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
35
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
33
36
|
def invalidate(type, rel_path, options)
|
34
37
|
watched_dir = Pathname.new(record.root)
|
35
38
|
|
36
39
|
change = options[:change]
|
37
40
|
cookie = options[:cookie]
|
38
41
|
|
39
|
-
if !cookie && config.silenced?(rel_path, type)
|
42
|
+
if !cookie && @config.silenced?(rel_path, type)
|
40
43
|
Listen.logger.debug { "(silenced): #{rel_path.inspect}" }
|
41
44
|
return
|
42
45
|
end
|
@@ -50,29 +53,17 @@ module Listen
|
|
50
53
|
|
51
54
|
if change
|
52
55
|
options = cookie ? { cookie: cookie } : {}
|
53
|
-
config.queue(type, change, watched_dir, rel_path, options)
|
56
|
+
@config.queue(type, change, watched_dir, rel_path, options)
|
54
57
|
elsif type == :dir
|
55
58
|
# NOTE: POSSIBLE RECURSION
|
56
59
|
# TODO: fix - use a queue instead
|
57
60
|
Directory.scan(self, rel_path, options)
|
58
|
-
|
59
|
-
|
60
|
-
return if !change || options[:silence]
|
61
|
-
config.queue(:file, change, watched_dir, rel_path)
|
61
|
+
elsif (change = File.change(record, rel_path)) && !options[:silence]
|
62
|
+
@config.queue(:file, change, watched_dir, rel_path)
|
62
63
|
end
|
63
|
-
rescue RuntimeError => ex
|
64
|
-
msg = format(
|
65
|
-
'%s#%s crashed %s:%s',
|
66
|
-
self.class,
|
67
|
-
__method__,
|
68
|
-
exinspect,
|
69
|
-
ex.backtrace * "\n")
|
70
|
-
Listen.logger.error(msg)
|
71
|
-
raise
|
72
64
|
end
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
attr_reader :config
|
65
|
+
# rubocop:enable Metrics/MethodLength
|
66
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
67
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
77
68
|
end
|
78
69
|
end
|
data/lib/listen/cli.rb
CHANGED
@@ -35,6 +35,7 @@ module Listen
|
|
35
35
|
|
36
36
|
class Forwarder
|
37
37
|
attr_reader :logger
|
38
|
+
|
38
39
|
def initialize(options)
|
39
40
|
@options = options
|
40
41
|
@logger = ::Logger.new(STDOUT, level: ::Logger::INFO)
|
@@ -43,6 +44,7 @@ module Listen
|
|
43
44
|
|
44
45
|
def start
|
45
46
|
logger.info 'Starting listen...'
|
47
|
+
|
46
48
|
directory = @options[:directory]
|
47
49
|
relative = @options[:relative]
|
48
50
|
callback = proc do |modified, added, removed|
|
@@ -53,10 +55,7 @@ module Listen
|
|
53
55
|
end
|
54
56
|
end
|
55
57
|
|
56
|
-
listener = Listen.to(
|
57
|
-
directory,
|
58
|
-
relative: relative,
|
59
|
-
&callback)
|
58
|
+
listener = Listen.to(directory, relative: relative, &callback)
|
60
59
|
|
61
60
|
listener.start
|
62
61
|
|
data/lib/listen/directory.rb
CHANGED
@@ -5,6 +5,7 @@ require 'set'
|
|
5
5
|
module Listen
|
6
6
|
# TODO: refactor (turn it into a normal object, cache the stat, etc)
|
7
7
|
class Directory
|
8
|
+
# rubocop:disable Metrics/MethodLength
|
8
9
|
def self.scan(snapshot, rel_path, options)
|
9
10
|
record = snapshot.record
|
10
11
|
dir = Pathname.new(record.root)
|
@@ -38,22 +39,19 @@ module Listen
|
|
38
39
|
previous = previous.reject { |entry, _| current.include? path + entry }
|
39
40
|
|
40
41
|
_async_changes(snapshot, Pathname.new(rel_path), previous, options)
|
41
|
-
|
42
42
|
rescue Errno::ENOENT, Errno::EHOSTDOWN
|
43
43
|
record.unset_path(rel_path)
|
44
44
|
_async_changes(snapshot, Pathname.new(rel_path), previous, options)
|
45
|
-
|
46
45
|
rescue Errno::ENOTDIR
|
47
46
|
# TODO: path not tested
|
48
47
|
record.unset_path(rel_path)
|
49
48
|
_async_changes(snapshot, path, previous, options)
|
50
49
|
_change(snapshot, :file, rel_path, options)
|
51
50
|
rescue
|
52
|
-
Listen.logger.warn
|
53
|
-
format('scan DIED: %s:%s', $ERROR_INFO, $ERROR_POSITION * "\n")
|
54
|
-
end
|
51
|
+
Listen.logger.warn { format('scan DIED: %s:%s', $ERROR_INFO, $ERROR_POSITION * "\n") }
|
55
52
|
raise
|
56
53
|
end
|
54
|
+
# rubocop:enable Metrics/MethodLength
|
57
55
|
|
58
56
|
def self.ascendant_of?(base, other)
|
59
57
|
other.ascend do |ascendant|
|
@@ -88,8 +86,8 @@ module Listen
|
|
88
86
|
# https://github.com/jruby/jruby/issues/3840
|
89
87
|
exists = path.exist?
|
90
88
|
directory = path.directory?
|
91
|
-
|
92
|
-
|
89
|
+
exists && !directory and raise Errno::ENOTDIR, path.to_s
|
90
|
+
path.children
|
93
91
|
end
|
94
92
|
end
|
95
93
|
end
|
data/lib/listen/event/config.rb
CHANGED
@@ -3,16 +3,15 @@
|
|
3
3
|
module Listen
|
4
4
|
module Event
|
5
5
|
class Config
|
6
|
-
attr_reader :listener
|
7
|
-
attr_reader :event_queue
|
8
|
-
attr_reader :min_delay_between_events
|
6
|
+
attr_reader :listener, :event_queue, :min_delay_between_events
|
9
7
|
|
10
8
|
def initialize(
|
11
9
|
listener,
|
12
10
|
event_queue,
|
13
11
|
queue_optimizer,
|
14
12
|
wait_for_delay,
|
15
|
-
&block
|
13
|
+
&block
|
14
|
+
)
|
16
15
|
|
17
16
|
@listener = listener
|
18
17
|
@event_queue = event_queue
|
@@ -26,7 +25,7 @@ module Listen
|
|
26
25
|
end
|
27
26
|
|
28
27
|
def call(*args)
|
29
|
-
@block
|
28
|
+
@block&.call(*args)
|
30
29
|
end
|
31
30
|
|
32
31
|
def timestamp
|
@@ -51,10 +51,10 @@ module Listen
|
|
51
51
|
end
|
52
52
|
|
53
53
|
def _check_stopped
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
54
|
+
if @listener.stopped?
|
55
|
+
_flush_wakeup_reasons
|
56
|
+
raise Stopped
|
57
|
+
end
|
58
58
|
end
|
59
59
|
|
60
60
|
def _sleep(seconds)
|
@@ -70,22 +70,22 @@ module Listen
|
|
70
70
|
end
|
71
71
|
|
72
72
|
def _remember_time_of_first_unprocessed_event
|
73
|
-
@
|
73
|
+
@_remember_time_of_first_unprocessed_event ||= _timestamp
|
74
74
|
end
|
75
75
|
|
76
76
|
def _reset_no_unprocessed_events
|
77
|
-
@
|
77
|
+
@_remember_time_of_first_unprocessed_event = nil
|
78
78
|
end
|
79
79
|
|
80
80
|
def _deadline
|
81
|
-
@
|
81
|
+
@_remember_time_of_first_unprocessed_event + @latency
|
82
82
|
end
|
83
83
|
|
84
84
|
# blocks until event is popped
|
85
85
|
# returns the event or `nil` when the event_queue is closed
|
86
86
|
def _wait_until_events
|
87
87
|
config.event_queue.pop.tap do |_event|
|
88
|
-
@
|
88
|
+
@_remember_time_of_first_unprocessed_event ||= _timestamp
|
89
89
|
end
|
90
90
|
end
|
91
91
|
|
data/lib/listen/event/queue.rb
CHANGED
@@ -30,21 +30,21 @@ module Listen
|
|
30
30
|
fail "Invalid change: #{change.inspect}" unless change.is_a?(Symbol)
|
31
31
|
fail "Invalid path: #{path.inspect}" unless path.is_a?(String)
|
32
32
|
|
33
|
-
dir =
|
34
|
-
|
33
|
+
dir = if @config.relative?
|
34
|
+
_safe_relative_from_cwd(dir)
|
35
|
+
else
|
36
|
+
dir
|
37
|
+
end
|
38
|
+
@event_queue << [type, change, dir, path, options]
|
35
39
|
end
|
36
40
|
|
37
|
-
delegate empty?:
|
38
|
-
delegate pop:
|
39
|
-
delegate close:
|
41
|
+
delegate empty?: :@event_queue
|
42
|
+
delegate pop: :@event_queue
|
43
|
+
delegate close: :@event_queue
|
40
44
|
|
41
45
|
private
|
42
46
|
|
43
|
-
attr_reader :event_queue
|
44
|
-
attr_reader :config
|
45
|
-
|
46
47
|
def _safe_relative_from_cwd(dir)
|
47
|
-
return dir unless config.relative?
|
48
48
|
dir.relative_path_from(Pathname.pwd)
|
49
49
|
rescue ArgumentError
|
50
50
|
dir
|
data/lib/listen/file.rb
CHANGED
@@ -4,6 +4,9 @@ require 'digest/md5'
|
|
4
4
|
|
5
5
|
module Listen
|
6
6
|
class File
|
7
|
+
# rubocop:disable Metrics/MethodLength
|
8
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
9
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
7
10
|
def self.change(record, rel_path)
|
8
11
|
path = Pathname.new(record.root) + rel_path
|
9
12
|
lstat = path.lstat
|
@@ -74,6 +77,9 @@ module Listen
|
|
74
77
|
Listen.logger.debug "lstat failed for: #{rel_path} (#{$ERROR_INFO})"
|
75
78
|
raise
|
76
79
|
end
|
80
|
+
# rubocop:enable Metrics/MethodLength
|
81
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
82
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
77
83
|
|
78
84
|
def self.inaccurate_mac_time?(stat)
|
79
85
|
# 'mac' means Modified/Accessed/Created
|
data/lib/listen/fsm.rb
CHANGED
data/lib/listen/listener.rb
CHANGED
@@ -33,6 +33,7 @@ module Listen
|
|
33
33
|
# @yieldparam [Array<String>] added the list of added files
|
34
34
|
# @yieldparam [Array<String>] removed the list of removed files
|
35
35
|
#
|
36
|
+
# rubocop:disable Metrics/MethodLength
|
36
37
|
def initialize(*dirs, &block)
|
37
38
|
options = dirs.last.is_a?(Hash) ? dirs.pop : {}
|
38
39
|
|
@@ -60,6 +61,7 @@ module Listen
|
|
60
61
|
|
61
62
|
initialize_fsm
|
62
63
|
end
|
64
|
+
# rubocop:enable Metrics/MethodLength
|
63
65
|
|
64
66
|
start_state :initializing
|
65
67
|
|
@@ -25,9 +25,7 @@ module Listen
|
|
25
25
|
@relative
|
26
26
|
end
|
27
27
|
|
28
|
-
attr_reader :min_delay_between_events
|
29
|
-
|
30
|
-
attr_reader :silencer_rules
|
28
|
+
attr_reader :min_delay_between_events, :silencer_rules
|
31
29
|
|
32
30
|
def adapter_instance_options(klass)
|
33
31
|
valid_keys = klass.const_get('DEFAULTS').keys
|
@@ -35,7 +33,7 @@ module Listen
|
|
35
33
|
end
|
36
34
|
|
37
35
|
def adapter_select_options
|
38
|
-
valid_keys = %w
|
36
|
+
valid_keys = %w[force_polling polling_fallback_message].map(&:to_sym)
|
39
37
|
Hash[@options.select { |key, _| valid_keys.include?(key) }]
|
40
38
|
end
|
41
39
|
end
|
data/lib/listen/logger.rb
CHANGED
@@ -16,18 +16,19 @@ module Listen
|
|
16
16
|
private
|
17
17
|
|
18
18
|
def default_logger
|
19
|
-
level =
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
19
|
+
level =
|
20
|
+
case ENV['LISTEN_GEM_DEBUGGING'].to_s
|
21
|
+
when /debug|2/i
|
22
|
+
::Logger::DEBUG
|
23
|
+
when /info|true|yes|1/i
|
24
|
+
::Logger::INFO
|
25
|
+
when /warn/i
|
26
|
+
::Logger::WARN
|
27
|
+
when /fatal/i
|
28
|
+
::Logger::FATAL
|
29
|
+
else
|
30
|
+
::Logger::ERROR
|
31
|
+
end
|
31
32
|
|
32
33
|
::Logger.new(STDERR, level: level)
|
33
34
|
end
|
data/lib/listen/options.rb
CHANGED
@@ -5,21 +5,22 @@ module Listen
|
|
5
5
|
def initialize(opts, defaults)
|
6
6
|
@options = {}
|
7
7
|
given_options = opts.dup
|
8
|
-
defaults.
|
8
|
+
defaults.each_key do |key|
|
9
9
|
@options[key] = given_options.delete(key) || defaults[key]
|
10
10
|
end
|
11
11
|
|
12
|
-
|
12
|
+
given_options.empty? or raise ArgumentError, "Unknown options: #{given_options.inspect}"
|
13
|
+
end
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
15
|
+
# rubocop:disable Lint/MissingSuper
|
16
|
+
def respond_to_missing?(name, *_)
|
17
|
+
@options.has_key?(name)
|
17
18
|
end
|
18
19
|
|
19
20
|
def method_missing(name, *_)
|
20
|
-
|
21
|
-
|
22
|
-
fail NameError, msg
|
21
|
+
respond_to_missing?(name) or raise NameError, "Bad option: #{name.inspect} (valid:#{@options.keys.inspect})"
|
22
|
+
@options[name]
|
23
23
|
end
|
24
|
+
# rubocop:enable Lint/MissingSuper
|
24
25
|
end
|
25
26
|
end
|
@@ -62,7 +62,7 @@ module Listen
|
|
62
62
|
actions << :added if actions.delete(:moved_to)
|
63
63
|
actions << :removed if actions.delete(:moved_from)
|
64
64
|
|
65
|
-
modified = actions.
|
65
|
+
modified = actions.find { |x| x == :modified }
|
66
66
|
_calculate_add_remove_difference(actions, path, modified)
|
67
67
|
end
|
68
68
|
|
@@ -91,10 +91,8 @@ module Listen
|
|
91
91
|
def _reinterpret_related_changes(cookies)
|
92
92
|
table = { moved_to: :added, moved_from: :removed }
|
93
93
|
cookies.flat_map do |_, changes|
|
94
|
-
|
95
|
-
|
96
|
-
to_dir, to_file = data
|
97
|
-
[[:modified, to_dir, to_file]]
|
94
|
+
if (editor_modified = editor_modified?(changes))
|
95
|
+
[[:modified, *editor_modified]]
|
98
96
|
else
|
99
97
|
not_silenced = changes.reject do |type, _, _, path, _|
|
100
98
|
config.silenced?(Pathname(path), type)
|
@@ -106,7 +104,7 @@ module Listen
|
|
106
104
|
end
|
107
105
|
end
|
108
106
|
|
109
|
-
def
|
107
|
+
def editor_modified?(changes)
|
110
108
|
return unless changes.size == 2
|
111
109
|
|
112
110
|
from_type = from = nil
|
@@ -118,17 +116,14 @@ module Listen
|
|
118
116
|
from_type, _from_change, _, from, = data
|
119
117
|
when :moved_to
|
120
118
|
to_type, _to_change, to_dir, to, = data
|
121
|
-
else
|
122
|
-
return nil
|
123
119
|
end
|
124
120
|
end
|
125
121
|
|
126
|
-
return unless from && to
|
127
|
-
|
128
122
|
# Expect an ignored moved_from and non-ignored moved_to
|
129
123
|
# to qualify as an "editor modify"
|
130
|
-
|
131
|
-
|
124
|
+
if from && to && config.silenced?(Pathname(from), from_type) && !config.silenced?(Pathname(to), to_type)
|
125
|
+
[to_dir, to]
|
126
|
+
end
|
132
127
|
end
|
133
128
|
end
|
134
129
|
end
|
data/lib/listen/record.rb
CHANGED
@@ -10,14 +10,16 @@ module Listen
|
|
10
10
|
# TODO: deprecate
|
11
11
|
|
12
12
|
attr_reader :root
|
13
|
+
|
13
14
|
def initialize(directory)
|
14
15
|
@tree = _auto_hash
|
15
16
|
@root = directory.to_s
|
16
17
|
end
|
17
18
|
|
18
19
|
def add_dir(rel_path)
|
19
|
-
|
20
|
-
|
20
|
+
if ![nil, '', '.'].include?(rel_path)
|
21
|
+
@tree[rel_path] ||= {}
|
22
|
+
end
|
21
23
|
end
|
22
24
|
|
23
25
|
def update_file(rel_path, data)
|
@@ -33,33 +35,30 @@ module Listen
|
|
33
35
|
def file_data(rel_path)
|
34
36
|
dirname, basename = Pathname(rel_path).split.map(&:to_s)
|
35
37
|
if [nil, '', '.'].include? dirname
|
36
|
-
tree[basename] ||= {}
|
37
|
-
tree[basename].dup
|
38
|
+
@tree[basename] ||= {}
|
39
|
+
@tree[basename].dup
|
38
40
|
else
|
39
|
-
tree[dirname] ||= {}
|
40
|
-
tree[dirname][basename] ||= {}
|
41
|
-
tree[dirname][basename].dup
|
41
|
+
@tree[dirname] ||= {}
|
42
|
+
@tree[dirname][basename] ||= {}
|
43
|
+
@tree[dirname][basename].dup
|
42
44
|
end
|
43
45
|
end
|
44
46
|
|
45
47
|
def dir_entries(rel_path)
|
46
|
-
subtree =
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
end
|
48
|
+
subtree = if [nil, '', '.'].include? rel_path.to_s
|
49
|
+
@tree
|
50
|
+
else
|
51
|
+
_sub_tree(rel_path)
|
52
|
+
end
|
52
53
|
|
53
|
-
|
54
|
-
subtree.each do |key, values|
|
54
|
+
subtree.transform_values do |values|
|
55
55
|
# only get data for file entries
|
56
|
-
|
56
|
+
values.key?(:mtime) ? values : {}
|
57
57
|
end
|
58
|
-
result
|
59
58
|
end
|
60
59
|
|
61
60
|
def _sub_tree(rel_path)
|
62
|
-
tree.each_with_object({}) do |(path, meta), result|
|
61
|
+
@tree.each_with_object({}) do |(path, meta), result|
|
63
62
|
next unless path.start_with?(rel_path)
|
64
63
|
|
65
64
|
if path == rel_path
|
@@ -85,29 +84,27 @@ module Listen
|
|
85
84
|
private
|
86
85
|
|
87
86
|
def _auto_hash
|
88
|
-
Hash.new { |h, k| h[k] =
|
87
|
+
Hash.new { |h, k| h[k] = {} }
|
89
88
|
end
|
90
89
|
|
91
|
-
attr_reader :tree
|
92
|
-
|
93
90
|
def _fast_update_file(dirname, basename, data)
|
94
|
-
if [nil, '', '.'].include?
|
95
|
-
tree[basename] = (tree[basename] || {}).merge(data)
|
91
|
+
if [nil, '', '.'].include?(dirname)
|
92
|
+
@tree[basename] = (@tree[basename] || {}).merge(data)
|
96
93
|
else
|
97
|
-
tree[dirname] ||= {}
|
98
|
-
tree[dirname][basename] = (tree[dirname][basename] || {}).merge(data)
|
94
|
+
@tree[dirname] ||= {}
|
95
|
+
@tree[dirname][basename] = (@tree[dirname][basename] || {}).merge(data)
|
99
96
|
end
|
100
97
|
end
|
101
98
|
|
102
99
|
def _fast_unset_path(dirname, basename)
|
103
100
|
# this may need to be reworked to properly remove
|
104
101
|
# entries from a tree, without adding non-existing dirs to the record
|
105
|
-
if [nil, '', '.'].include?
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
tree[dirname].delete(basename)
|
102
|
+
if [nil, '', '.'].include?(dirname)
|
103
|
+
if @tree.key?(basename)
|
104
|
+
@tree.delete(basename)
|
105
|
+
end
|
106
|
+
elsif @tree.key?(dirname)
|
107
|
+
@tree[dirname].delete(basename)
|
111
108
|
end
|
112
109
|
end
|
113
110
|
|
data/lib/listen/record/entry.rb
CHANGED
@@ -6,9 +6,9 @@ module Listen
|
|
6
6
|
# @private api
|
7
7
|
class Record
|
8
8
|
class SymlinkDetector
|
9
|
-
WIKI = 'https://github.com/guard/listen/wiki/Duplicate-directory-errors'
|
9
|
+
WIKI = 'https://github.com/guard/listen/wiki/Duplicate-directory-errors'
|
10
10
|
|
11
|
-
SYMLINK_LOOP_ERROR = <<-EOS
|
11
|
+
SYMLINK_LOOP_ERROR = <<-EOS
|
12
12
|
** ERROR: directory is already being watched! **
|
13
13
|
|
14
14
|
Directory: %s
|
@@ -33,8 +33,8 @@ module Listen
|
|
33
33
|
private
|
34
34
|
|
35
35
|
def _fail(symlinked, real_path)
|
36
|
-
|
37
|
-
|
36
|
+
warn(format(SYMLINK_LOOP_ERROR, symlinked, real_path))
|
37
|
+
raise Error, 'Failed due to looped symlinks'
|
38
38
|
end
|
39
39
|
end
|
40
40
|
end
|
data/lib/listen/silencer.rb
CHANGED
@@ -14,7 +14,7 @@ module Listen
|
|
14
14
|
| log
|
15
15
|
| tmp
|
16
16
|
|vendor/ruby
|
17
|
-
)(/|$)}x
|
17
|
+
)(/|$)}x.freeze
|
18
18
|
|
19
19
|
# The default list of files that get ignored.
|
20
20
|
DEFAULT_IGNORED_EXTENSIONS = %r{(?:
|
@@ -55,7 +55,7 @@ module Listen
|
|
55
55
|
| \.DS_Store
|
56
56
|
| \.tmp
|
57
57
|
| ~
|
58
|
-
)$}x
|
58
|
+
)$}x.freeze
|
59
59
|
|
60
60
|
attr_accessor :only_patterns, :ignore_patterns
|
61
61
|
|
@@ -75,16 +75,18 @@ module Listen
|
|
75
75
|
def silenced?(relative_path, type)
|
76
76
|
path = relative_path.to_s
|
77
77
|
|
78
|
-
|
79
|
-
return true unless only_patterns.any? { |pattern| path =~ pattern }
|
80
|
-
end
|
81
|
-
|
82
|
-
ignore_patterns.any? { |pattern| path =~ pattern }
|
78
|
+
_ignore?(path) || (only_patterns && type == :file && !_only?(path))
|
83
79
|
end
|
84
80
|
|
85
81
|
private
|
86
82
|
|
87
|
-
|
83
|
+
def _ignore?(path)
|
84
|
+
ignore_patterns.any? { |pattern| path =~ pattern }
|
85
|
+
end
|
86
|
+
|
87
|
+
def _only?(path)
|
88
|
+
only_patterns.any? { |pattern| path =~ pattern }
|
89
|
+
end
|
88
90
|
|
89
91
|
def _init_ignores(ignores, overrides)
|
90
92
|
patterns = []
|
data/lib/listen/thread.rb
CHANGED
@@ -9,6 +9,7 @@ module Listen
|
|
9
9
|
class << self
|
10
10
|
# Creates a new thread with the given name.
|
11
11
|
# Any exceptions raised by the thread will be logged with the thread name and complete backtrace.
|
12
|
+
# rubocop:disable Style/MultilineBlockChain
|
12
13
|
def new(name, &block)
|
13
14
|
thread_name = "listen-#{name}"
|
14
15
|
caller_stack = caller
|
@@ -19,31 +20,32 @@ module Listen
|
|
19
20
|
thread.name = thread_name
|
20
21
|
end
|
21
22
|
end
|
23
|
+
# rubocop:enable Style/MultilineBlockChain
|
22
24
|
|
23
25
|
def rescue_and_log(method_name, *args, caller_stack: nil)
|
24
26
|
yield(*args)
|
25
|
-
rescue Exception =>
|
26
|
-
_log_exception(
|
27
|
+
rescue Exception => exception # rubocop:disable Lint/RescueException
|
28
|
+
_log_exception(exception, method_name, caller_stack: caller_stack)
|
27
29
|
end
|
28
30
|
|
29
31
|
private
|
30
32
|
|
31
|
-
def _log_exception(
|
33
|
+
def _log_exception(exception, thread_name, caller_stack: nil)
|
32
34
|
complete_backtrace = if caller_stack
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
message = "Exception rescued in #{thread_name}:\n#{_exception_with_causes(
|
35
|
+
[*exception.backtrace, "--- Thread.new ---", *caller_stack]
|
36
|
+
else
|
37
|
+
exception.backtrace
|
38
|
+
end
|
39
|
+
message = "Exception rescued in #{thread_name}:\n#{_exception_with_causes(exception)}\n#{complete_backtrace * "\n"}"
|
38
40
|
Listen.logger.error(message)
|
39
41
|
end
|
40
42
|
|
41
|
-
def _exception_with_causes(
|
42
|
-
result = +"#{
|
43
|
-
if
|
43
|
+
def _exception_with_causes(exception)
|
44
|
+
result = +"#{exception.class}: #{exception}"
|
45
|
+
if exception.cause
|
44
46
|
result << "\n"
|
45
47
|
result << "--- Caused by: ---\n"
|
46
|
-
result << _exception_with_causes(
|
48
|
+
result << _exception_with_causes(exception.cause)
|
47
49
|
end
|
48
50
|
result
|
49
51
|
end
|
data/lib/listen/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: listen
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.3.
|
4
|
+
version: 3.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thibaud Guillaume-Gentil
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-11-
|
11
|
+
date: 2020-11-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rb-fsevent
|
@@ -51,7 +51,7 @@ dependencies:
|
|
51
51
|
- !ruby/object:Gem::Version
|
52
52
|
version: 0.9.10
|
53
53
|
description: The Listen gem listens to file modifications and notifies you about the
|
54
|
-
|
54
|
+
changes. Works everywhere!
|
55
55
|
email: thibaud@thibaud.gg
|
56
56
|
executables:
|
57
57
|
- listen
|