listen 3.0.8 → 3.5.1
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 +5 -5
- data/CONTRIBUTING.md +10 -3
- data/README.md +241 -70
- data/bin/listen +3 -4
- data/lib/listen/adapter/base.rb +25 -33
- data/lib/listen/adapter/bsd.rb +9 -8
- data/lib/listen/adapter/config.rb +4 -5
- data/lib/listen/adapter/darwin.rb +35 -46
- data/lib/listen/adapter/linux.rb +16 -13
- data/lib/listen/adapter/polling.rb +9 -6
- data/lib/listen/adapter/windows.rb +19 -22
- data/lib/listen/adapter.rb +25 -25
- data/lib/listen/backend.rb +7 -10
- data/lib/listen/change.rb +18 -27
- data/lib/listen/cli.rb +6 -6
- data/lib/listen/directory.rb +14 -8
- data/lib/listen/error.rb +10 -0
- data/lib/listen/event/config.rb +9 -28
- data/lib/listen/event/loop.rb +44 -67
- data/lib/listen/event/processor.rb +41 -37
- data/lib/listen/event/queue.rb +14 -18
- data/lib/listen/file.rb +16 -3
- data/lib/listen/fsm.rb +74 -72
- data/lib/listen/listener/config.rb +5 -9
- data/lib/listen/listener.rb +26 -22
- data/lib/listen/logger.rb +24 -20
- data/lib/listen/monotonic_time.rb +27 -0
- data/lib/listen/options.rb +11 -8
- data/lib/listen/queue_optimizer.rb +15 -18
- data/lib/listen/record/entry.rb +8 -4
- data/lib/listen/record/symlink_detector.rb +9 -7
- data/lib/listen/record.rb +30 -33
- data/lib/listen/silencer/controller.rb +2 -0
- data/lib/listen/silencer.rb +16 -9
- data/lib/listen/thread.rb +54 -0
- data/lib/listen/version.rb +3 -1
- data/lib/listen.rb +14 -22
- metadata +20 -28
- data/lib/listen/internals/thread_pool.rb +0 -29
data/lib/listen/record.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'thread'
|
2
4
|
require 'listen/record/entry'
|
3
5
|
require 'listen/record/symlink_detector'
|
@@ -8,14 +10,16 @@ module Listen
|
|
8
10
|
# TODO: deprecate
|
9
11
|
|
10
12
|
attr_reader :root
|
13
|
+
|
11
14
|
def initialize(directory)
|
12
15
|
@tree = _auto_hash
|
13
16
|
@root = directory.to_s
|
14
17
|
end
|
15
18
|
|
16
19
|
def add_dir(rel_path)
|
17
|
-
|
18
|
-
|
20
|
+
if ![nil, '', '.'].include?(rel_path)
|
21
|
+
@tree[rel_path] ||= {}
|
22
|
+
end
|
19
23
|
end
|
20
24
|
|
21
25
|
def update_file(rel_path, data)
|
@@ -31,30 +35,27 @@ module Listen
|
|
31
35
|
def file_data(rel_path)
|
32
36
|
dirname, basename = Pathname(rel_path).split.map(&:to_s)
|
33
37
|
if [nil, '', '.'].include? dirname
|
34
|
-
tree[basename] ||= {}
|
35
|
-
tree[basename].dup
|
38
|
+
@tree[basename] ||= {}
|
39
|
+
@tree[basename].dup
|
36
40
|
else
|
37
|
-
tree[dirname] ||= {}
|
38
|
-
tree[dirname][basename] ||= {}
|
39
|
-
tree[dirname][basename].dup
|
41
|
+
@tree[dirname] ||= {}
|
42
|
+
@tree[dirname][basename] ||= {}
|
43
|
+
@tree[dirname][basename].dup
|
40
44
|
end
|
41
45
|
end
|
42
46
|
|
43
47
|
def dir_entries(rel_path)
|
44
|
-
subtree =
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
end
|
48
|
+
subtree = if ['', '.'].include? rel_path.to_s
|
49
|
+
@tree
|
50
|
+
else
|
51
|
+
@tree[rel_path.to_s] ||= _auto_hash
|
52
|
+
@tree[rel_path.to_s]
|
53
|
+
end
|
51
54
|
|
52
|
-
|
53
|
-
subtree.each do |key, values|
|
55
|
+
subtree.transform_values do |values|
|
54
56
|
# only get data for file entries
|
55
|
-
|
57
|
+
values.key?(:mtime) ? values : {}
|
56
58
|
end
|
57
|
-
result
|
58
59
|
end
|
59
60
|
|
60
61
|
def build
|
@@ -71,31 +72,27 @@ module Listen
|
|
71
72
|
private
|
72
73
|
|
73
74
|
def _auto_hash
|
74
|
-
Hash.new { |h, k| h[k] =
|
75
|
-
end
|
76
|
-
|
77
|
-
def tree
|
78
|
-
@tree
|
75
|
+
Hash.new { |h, k| h[k] = {} }
|
79
76
|
end
|
80
77
|
|
81
78
|
def _fast_update_file(dirname, basename, data)
|
82
|
-
if [nil, '', '.'].include?
|
83
|
-
tree[basename] = (tree[basename] || {}).merge(data)
|
79
|
+
if [nil, '', '.'].include?(dirname)
|
80
|
+
@tree[basename] = (@tree[basename] || {}).merge(data)
|
84
81
|
else
|
85
|
-
tree[dirname] ||= {}
|
86
|
-
tree[dirname][basename] = (tree[dirname][basename] || {}).merge(data)
|
82
|
+
@tree[dirname] ||= {}
|
83
|
+
@tree[dirname][basename] = (@tree[dirname][basename] || {}).merge(data)
|
87
84
|
end
|
88
85
|
end
|
89
86
|
|
90
87
|
def _fast_unset_path(dirname, basename)
|
91
88
|
# this may need to be reworked to properly remove
|
92
89
|
# entries from a tree, without adding non-existing dirs to the record
|
93
|
-
if [nil, '', '.'].include?
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
tree[dirname].delete(basename)
|
90
|
+
if [nil, '', '.'].include?(dirname)
|
91
|
+
if @tree.key?(basename)
|
92
|
+
@tree.delete(basename)
|
93
|
+
end
|
94
|
+
elsif @tree.key?(dirname)
|
95
|
+
@tree[dirname].delete(basename)
|
99
96
|
end
|
100
97
|
end
|
101
98
|
|
data/lib/listen/silencer.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Listen
|
2
4
|
class Silencer
|
3
5
|
# The default list of directories that get ignored.
|
@@ -12,10 +14,10 @@ module Listen
|
|
12
14
|
| log
|
13
15
|
| tmp
|
14
16
|
|vendor/ruby
|
15
|
-
)(/|$)}x
|
17
|
+
)(/|$)}x.freeze
|
16
18
|
|
17
19
|
# The default list of files that get ignored.
|
18
|
-
DEFAULT_IGNORED_EXTENSIONS
|
20
|
+
DEFAULT_IGNORED_EXTENSIONS = %r{(?:
|
19
21
|
# Kate's tmp\/swp files
|
20
22
|
\..*\d+\.new
|
21
23
|
| \.kate-swp
|
@@ -46,11 +48,14 @@ module Listen
|
|
46
48
|
)
|
47
49
|
)
|
48
50
|
|
51
|
+
# Mutagen sync temporary files
|
52
|
+
| \.mutagen-temporary.*
|
53
|
+
|
49
54
|
# other files
|
50
55
|
| \.DS_Store
|
51
56
|
| \.tmp
|
52
57
|
| ~
|
53
|
-
)
|
58
|
+
)$}x.freeze
|
54
59
|
|
55
60
|
attr_accessor :only_patterns, :ignore_patterns
|
56
61
|
|
@@ -70,16 +75,18 @@ module Listen
|
|
70
75
|
def silenced?(relative_path, type)
|
71
76
|
path = relative_path.to_s
|
72
77
|
|
73
|
-
|
74
|
-
return true unless only_patterns.any? { |pattern| path =~ pattern }
|
75
|
-
end
|
76
|
-
|
77
|
-
ignore_patterns.any? { |pattern| path =~ pattern }
|
78
|
+
_ignore?(path) || (only_patterns && type == :file && !_only?(path))
|
78
79
|
end
|
79
80
|
|
80
81
|
private
|
81
82
|
|
82
|
-
|
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
|
83
90
|
|
84
91
|
def _init_ignores(ignores, overrides)
|
85
92
|
patterns = []
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'thread'
|
4
|
+
|
5
|
+
require_relative 'logger'
|
6
|
+
|
7
|
+
module Listen
|
8
|
+
module Thread
|
9
|
+
class << self
|
10
|
+
# Creates a new thread with the given name.
|
11
|
+
# Any exceptions raised by the thread will be logged with the thread name and complete backtrace.
|
12
|
+
# rubocop:disable Style/MultilineBlockChain
|
13
|
+
def new(name, &block)
|
14
|
+
thread_name = "listen-#{name}"
|
15
|
+
caller_stack = caller
|
16
|
+
|
17
|
+
::Thread.new do
|
18
|
+
rescue_and_log(thread_name, caller_stack: caller_stack, &block)
|
19
|
+
end.tap do |thread|
|
20
|
+
thread.name = thread_name
|
21
|
+
end
|
22
|
+
end
|
23
|
+
# rubocop:enable Style/MultilineBlockChain
|
24
|
+
|
25
|
+
def rescue_and_log(method_name, *args, caller_stack: nil)
|
26
|
+
yield(*args)
|
27
|
+
rescue => exception
|
28
|
+
_log_exception(exception, method_name, caller_stack: caller_stack)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def _log_exception(exception, thread_name, caller_stack: nil)
|
34
|
+
complete_backtrace = if caller_stack
|
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"}"
|
40
|
+
Listen.logger.error(message)
|
41
|
+
end
|
42
|
+
|
43
|
+
def _exception_with_causes(exception)
|
44
|
+
result = +"#{exception.class}: #{exception}"
|
45
|
+
if exception.cause
|
46
|
+
result << "\n"
|
47
|
+
result << "--- Caused by: ---\n"
|
48
|
+
result << _exception_with_causes(exception.cause)
|
49
|
+
end
|
50
|
+
result
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/lib/listen/version.rb
CHANGED
data/lib/listen.rb
CHANGED
@@ -1,23 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'logger'
|
4
|
+
require 'weakref'
|
2
5
|
require 'listen/logger'
|
3
6
|
require 'listen/listener'
|
4
7
|
|
5
|
-
require 'listen/internals/thread_pool'
|
6
|
-
|
7
|
-
# Always set up logging by default first time file is required
|
8
|
-
#
|
9
|
-
# NOTE: If you need to clear the logger completely, do so *after*
|
10
|
-
# requiring this file. If you need to set a custom logger,
|
11
|
-
# require the listen/logger file and set the logger before requiring
|
12
|
-
# this file.
|
13
|
-
Listen.setup_default_logger_if_unset
|
14
|
-
|
15
8
|
# Won't print anything by default because of level - unless you've set
|
16
9
|
# LISTEN_GEM_DEBUGGING or provided your own logger with a high enough level
|
17
|
-
Listen
|
18
|
-
Listen
|
10
|
+
Listen.logger.info "Listen loglevel set to: #{Listen.logger.level}"
|
11
|
+
Listen.logger.info "Listen version: #{Listen::VERSION}"
|
19
12
|
|
20
13
|
module Listen
|
14
|
+
@listeners = Queue.new
|
15
|
+
|
21
16
|
class << self
|
22
17
|
# Listens to file system modifications on a either single directory or
|
23
18
|
# multiple directories.
|
@@ -32,24 +27,21 @@ module Listen
|
|
32
27
|
# @return [Listen::Listener] the listener
|
33
28
|
#
|
34
29
|
def to(*args, &block)
|
35
|
-
@listeners ||= []
|
36
30
|
Listener.new(*args, &block).tap do |listener|
|
37
|
-
@listeners
|
31
|
+
@listeners.enq(WeakRef.new(listener))
|
38
32
|
end
|
39
33
|
end
|
40
34
|
|
41
35
|
# This is used by the `listen` binary to handle Ctrl-C
|
42
36
|
#
|
43
37
|
def stop
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
# call stop to halt the main loop
|
50
|
-
listener.stop
|
38
|
+
while (listener = @listeners.deq(true))
|
39
|
+
begin
|
40
|
+
listener.stop
|
41
|
+
rescue WeakRef::RefError
|
42
|
+
end
|
51
43
|
end
|
52
|
-
|
44
|
+
rescue ThreadError
|
53
45
|
end
|
54
46
|
end
|
55
47
|
end
|
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.
|
4
|
+
version: 3.5.1
|
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:
|
11
|
+
date: 2021-03-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rb-fsevent
|
@@ -16,20 +16,20 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0.
|
19
|
+
version: '0.10'
|
20
20
|
- - ">="
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: 0.
|
22
|
+
version: 0.10.3
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
requirements:
|
27
27
|
- - "~>"
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: '0.
|
29
|
+
version: '0.10'
|
30
30
|
- - ">="
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: 0.
|
32
|
+
version: 0.10.3
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: rb-inotify
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -39,7 +39,7 @@ dependencies:
|
|
39
39
|
version: '0.9'
|
40
40
|
- - ">="
|
41
41
|
- !ruby/object:Gem::Version
|
42
|
-
version: 0.9.
|
42
|
+
version: 0.9.10
|
43
43
|
type: :runtime
|
44
44
|
prerelease: false
|
45
45
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -49,21 +49,7 @@ dependencies:
|
|
49
49
|
version: '0.9'
|
50
50
|
- - ">="
|
51
51
|
- !ruby/object:Gem::Version
|
52
|
-
version: 0.9.
|
53
|
-
- !ruby/object:Gem::Dependency
|
54
|
-
name: bundler
|
55
|
-
requirement: !ruby/object:Gem::Requirement
|
56
|
-
requirements:
|
57
|
-
- - ">="
|
58
|
-
- !ruby/object:Gem::Version
|
59
|
-
version: 1.3.5
|
60
|
-
type: :development
|
61
|
-
prerelease: false
|
62
|
-
version_requirements: !ruby/object:Gem::Requirement
|
63
|
-
requirements:
|
64
|
-
- - ">="
|
65
|
-
- !ruby/object:Gem::Version
|
66
|
-
version: 1.3.5
|
52
|
+
version: 0.9.10
|
67
53
|
description: The Listen gem listens to file modifications and notifies you about the
|
68
54
|
changes. Works everywhere!
|
69
55
|
email: thibaud@thibaud.gg
|
@@ -90,16 +76,17 @@ files:
|
|
90
76
|
- lib/listen/change.rb
|
91
77
|
- lib/listen/cli.rb
|
92
78
|
- lib/listen/directory.rb
|
79
|
+
- lib/listen/error.rb
|
93
80
|
- lib/listen/event/config.rb
|
94
81
|
- lib/listen/event/loop.rb
|
95
82
|
- lib/listen/event/processor.rb
|
96
83
|
- lib/listen/event/queue.rb
|
97
84
|
- lib/listen/file.rb
|
98
85
|
- lib/listen/fsm.rb
|
99
|
-
- lib/listen/internals/thread_pool.rb
|
100
86
|
- lib/listen/listener.rb
|
101
87
|
- lib/listen/listener/config.rb
|
102
88
|
- lib/listen/logger.rb
|
89
|
+
- lib/listen/monotonic_time.rb
|
103
90
|
- lib/listen/options.rb
|
104
91
|
- lib/listen/queue_optimizer.rb
|
105
92
|
- lib/listen/record.rb
|
@@ -107,11 +94,18 @@ files:
|
|
107
94
|
- lib/listen/record/symlink_detector.rb
|
108
95
|
- lib/listen/silencer.rb
|
109
96
|
- lib/listen/silencer/controller.rb
|
97
|
+
- lib/listen/thread.rb
|
110
98
|
- lib/listen/version.rb
|
111
99
|
homepage: https://github.com/guard/listen
|
112
100
|
licenses:
|
113
101
|
- MIT
|
114
|
-
metadata:
|
102
|
+
metadata:
|
103
|
+
allowed_push_host: https://rubygems.org
|
104
|
+
bug_tracker_uri: https://github.com/guard/listen/issues
|
105
|
+
changelog_uri: https://github.com/guard/listen/releases
|
106
|
+
documentation_uri: https://www.rubydoc.info/gems/listen/3.5.1
|
107
|
+
homepage_uri: https://github.com/guard/listen
|
108
|
+
source_code_uri: https://github.com/guard/listen/tree/v3.5.1
|
115
109
|
post_install_message:
|
116
110
|
rdoc_options: []
|
117
111
|
require_paths:
|
@@ -120,17 +114,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
120
114
|
requirements:
|
121
115
|
- - ">="
|
122
116
|
- !ruby/object:Gem::Version
|
123
|
-
version:
|
117
|
+
version: 2.4.0
|
124
118
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
125
119
|
requirements:
|
126
120
|
- - ">="
|
127
121
|
- !ruby/object:Gem::Version
|
128
122
|
version: '0'
|
129
123
|
requirements: []
|
130
|
-
|
131
|
-
rubygems_version: 2.5.1
|
124
|
+
rubygems_version: 3.0.1
|
132
125
|
signing_key:
|
133
126
|
specification_version: 4
|
134
127
|
summary: Listen to file modifications
|
135
128
|
test_files: []
|
136
|
-
has_rdoc:
|
@@ -1,29 +0,0 @@
|
|
1
|
-
module Listen
|
2
|
-
# @private api
|
3
|
-
module Internals
|
4
|
-
module ThreadPool
|
5
|
-
def self.add(&block)
|
6
|
-
Thread.new { block.call }.tap do |th|
|
7
|
-
(@threads ||= Queue.new) << th
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
def self.stop
|
12
|
-
return unless @threads ||= nil
|
13
|
-
return if @threads.empty? # return to avoid using possibly stubbed Queue
|
14
|
-
|
15
|
-
killed = Queue.new
|
16
|
-
# You can't kill a read on a descriptor in JRuby, so let's just
|
17
|
-
# ignore running threads (listen rb-inotify waiting for disk activity
|
18
|
-
# before closing) pray threads die faster than they are created...
|
19
|
-
limit = RUBY_ENGINE == 'jruby' ? [1] : []
|
20
|
-
|
21
|
-
killed << @threads.pop.kill until @threads.empty?
|
22
|
-
until killed.empty?
|
23
|
-
th = killed.pop
|
24
|
-
th.join(*limit) unless th[:listen_blocking_read_thread]
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|