listen 3.3.0.pre.2 → 3.3.3
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/README.md +105 -61
- 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 +5 -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/loop.rb +1 -4
- data/lib/listen/event/processor.rb +14 -10
- 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 +22 -15
- data/lib/listen/version.rb +1 -1
- metadata +11 -5
@@ -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
|
data/lib/listen/event/loop.rb
CHANGED
@@ -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
|
|
@@ -114,8 +114,12 @@ module Listen
|
|
114
114
|
return if result.all?(&:empty?)
|
115
115
|
|
116
116
|
block_start = _timestamp
|
117
|
-
|
118
|
-
Listen.
|
117
|
+
exception_note = " (exception)"
|
118
|
+
::Listen::Thread.rescue_and_log('_process_changes') do
|
119
|
+
config.call(*result)
|
120
|
+
exception_note = nil
|
121
|
+
end
|
122
|
+
Listen.logger.debug "Callback#{exception_note} took #{_timestamp - block_start} sec"
|
119
123
|
end
|
120
124
|
|
121
125
|
attr_reader :config
|
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
|