listen 3.9.0 → 3.10.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b365e353c2a0dc2a64459faa2c30a9b472130637b5fb4f50977c07adb2c6fd0c
4
- data.tar.gz: 82d72d4f26f25a7fd1e285fbebe66fffcee246999696313a4f19997ce2017ef5
3
+ metadata.gz: 67245b3e45ef5fa6fec5fb54a2b8af298c98caf521cea53ab29cc6b9fd15565f
4
+ data.tar.gz: ff8ca5d435fc3c409f845a0fbada5d3e7ce606d4a5962e9b07912245d08b7540
5
5
  SHA512:
6
- metadata.gz: f52228164dce447a048dea3e04268909004e17f0b40788495f58f9afc9a9a9f3a0207fd0acb541d0cffe0be78836a10f652acf6ff418cea9ea119708eaec0b83
7
- data.tar.gz: ee91854777075dc80f4cbcff3e507f4ca162aabe37fa11709b145184ada246efd0401ba89a50de8008c2ca7345d0dd08d20bbad7c6d9272004ad3581e74abca5
6
+ metadata.gz: 448354fa9e581471cfa7888f6478c439c9e2e0d1dcd9351adf962847f629efaea060cc629512e48f663119e7431b5e63d956df0cb24e5275a4827eff8544dbcc
7
+ data.tar.gz: e76261c0062d5655db30e316ebbbf4b0405c4321c19044ceae27743449ae92449ecb139650dec91ab6bf9999d0a40d748ca2d8760d9952aa886a02e0fac405b6
data/README.md CHANGED
@@ -25,7 +25,7 @@ The `listen` gem listens to file modifications and notifies you about the change
25
25
  * Support for plugins planned for future.
26
26
  * TCP functionality was removed in `listen` [3.0.0](https://github.com/guard/listen/releases/tag/v3.0.0) ([#319](https://github.com/guard/listen/issues/319), [#218](https://github.com/guard/listen/issues/218)). There are plans to extract this feature to separate gems ([#258](https://github.com/guard/listen/issues/258)), until this is finished, you can use by locking the `listen` gem to version `'~> 2.10'`.
27
27
  * Some filesystems won't work without polling (VM/Vagrant Shared folders, NFS, Samba, sshfs, etc.).
28
- * Windows and \*BSD adapter aren't continuously and automatically tested.
28
+ * \*BSD adapter isn't continuously and automatically tested.
29
29
  * OSX adapter has some performance limitations ([#342](https://github.com/guard/listen/issues/342)).
30
30
  * Listeners do not notify across forked processes, if you wish for multiple processes to receive change notifications you must [listen inside of each process](https://github.com/guard/listen/issues/398#issuecomment-223957952).
31
31
 
@@ -135,8 +135,6 @@ sleep
135
135
 
136
136
  Note: `:ignore` regexp patterns are evaluated against relative paths.
137
137
 
138
- Note: Ignoring paths does not improve performance, except when Polling ([#274](https://github.com/guard/listen/issues/274)).
139
-
140
138
  ### Only
141
139
 
142
140
  `Listen` watches all files (less the ignored ones) by default. If you want to only listen to a specific type of file (i.e., just `.rb` extension), you should use the `only` option/method.
@@ -265,7 +263,7 @@ If you are on Windows, it's recommended to use the [`wdm`](https://github.com/Ma
265
263
  Please add the following to your Gemfile:
266
264
 
267
265
  ```ruby
268
- gem 'wdm', '>= 0.1.0', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
266
+ gem 'wdm', '>= 0.1.0'
269
267
  ```
270
268
 
271
269
  ### On \*BSD
@@ -275,11 +273,7 @@ If you are on \*BSD you can try to use the [`rb-kqueue`](https://github.com/mat8
275
273
  Please add the following to your Gemfile:
276
274
 
277
275
  ```ruby
278
- require 'rbconfig'
279
- if RbConfig::CONFIG['target_os'] =~ /bsd|dragonfly/i
280
- gem 'rb-kqueue', '>= 0.2'
281
- end
282
-
276
+ gem 'rb-kqueue', '>= 0.2'
283
277
  ```
284
278
 
285
279
  ### Getting the [polling fallback message](#options)?
@@ -357,6 +351,9 @@ $ sudo sysctl -p
357
351
  ```
358
352
  You may also need to pay attention to the values of `max_queued_events` and `max_user_instances` if Listen keeps on complaining.
359
353
 
354
+ While 524,288 is the maximum number of files that can be watched. Each file watch [takes up 1,080 bytes](https://stackoverflow.com/a/7091897/1156119) on a 64-bit system, so assuming that all 524,288 watches are consumed, that allocates around 540 MiB.
355
+ If you're in an environment that is particularly memory-constrained, consider to specify a lower number.
356
+
360
357
  #### More info
361
358
  Man page for [inotify(7)](https://linux.die.net/man/7/inotify).
362
359
  Blog post: [limit of inotify](https://blog.sorah.jp/2012/01/24/inotify-limitation).
@@ -431,7 +428,7 @@ When in doubt, `LISTEN_GEM_DEBUGGING=debug` can help discover the actual events
431
428
  Pull requests are very welcome! Please try to follow these simple rules if applicable:
432
429
 
433
430
  * Please create a topic branch for every separate change you make.
434
- * Make sure your patches are well tested. All specs must pass on [Travis CI](https://travis-ci.org/guard/listen).
431
+ * Make sure your patches are well tested. All specs must pass on [CI](https://github.com/guard/listen/actions?workflow=Development).
435
432
  * Update the [Yard](http://yardoc.org/) documentation.
436
433
  * Update the [README](https://github.com/guard/listen/blob/master/README.md).
437
434
  * Please **do not change** the version number.
@@ -88,7 +88,7 @@ module Listen
88
88
  private
89
89
 
90
90
  def _stop
91
- @run_thread&.kill
91
+ @run_thread&.kill&.join
92
92
  @run_thread = nil
93
93
  end
94
94
 
@@ -7,7 +7,7 @@
7
7
  module Listen
8
8
  module Adapter
9
9
  class BSD < Base
10
- OS_REGEXP = /bsd|dragonfly/i.freeze
10
+ OS_REGEXP = /bsd|dragonfly/i
11
11
 
12
12
  DEFAULTS = {
13
13
  events: [
@@ -22,10 +22,7 @@ module Listen
22
22
 
23
23
  BUNDLER_DECLARE_GEM = <<-EOS.gsub(/^ {6}/, '')
24
24
  Please add the following to your Gemfile to avoid polling for changes:
25
- require 'rbconfig'
26
- if RbConfig::CONFIG['target_os'] =~ /#{OS_REGEXP}/
27
- gem 'rb-kqueue', '>= 0.2'
28
- end
25
+ gem 'rb-kqueue', '>= 0.2'
29
26
  EOS
30
27
 
31
28
  def self.usable?
@@ -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.freeze
10
+ OS_REGEXP = /darwin(?<major_version>(1|2)\d+)/i
11
11
 
12
12
  # The default delay between checking for changes.
13
13
  DEFAULTS = { latency: 0.1 }.freeze
@@ -69,7 +69,7 @@ module Listen
69
69
  end
70
70
 
71
71
  def _stop
72
- @worker_thread&.kill
72
+ @worker_thread&.kill&.join
73
73
  super
74
74
  end
75
75
  end
@@ -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.freeze
7
+ OS_REGEXP = /linux/i
8
8
 
9
9
  DEFAULTS = {
10
10
  events: [
@@ -60,7 +60,7 @@ module Listen
60
60
 
61
61
  cookie_params = event.cookie.zero? ? {} : { cookie: event.cookie }
62
62
 
63
- # Note: don't pass options to force rescanning the directory, so we can
63
+ # NOTE: don't pass options to force rescanning the directory, so we can
64
64
  # detect moving/deleting a whole tree
65
65
  if _dir_event?(event)
66
66
  _queue_change(:dir, dir, rel_path, cookie_params)
@@ -8,7 +8,7 @@ module Listen
8
8
  # file IO than the other implementations.
9
9
  #
10
10
  class Polling < Base
11
- OS_REGEXP = //.freeze # match every OS
11
+ OS_REGEXP = // # match every OS
12
12
 
13
13
  DEFAULTS = { latency: 1.0, wait_for_delay: 0.05 }.freeze
14
14
 
@@ -5,11 +5,11 @@ module Listen
5
5
  # Adapter implementation for Windows `wdm`.
6
6
  #
7
7
  class Windows < Base
8
- OS_REGEXP = /mswin|mingw|cygwin/i.freeze
8
+ OS_REGEXP = /mswin|mingw|cygwin/i
9
9
 
10
10
  BUNDLER_DECLARE_GEM = <<-EOS.gsub(/^ {6}/, '')
11
11
  Please add the following to your Gemfile to avoid polling for changes:
12
- gem 'wdm', '>= 0.1.0' if Gem.win_platform?
12
+ gem 'wdm', '>= 0.1.0'
13
13
  EOS
14
14
 
15
15
  def self.usable?
@@ -18,7 +18,8 @@ module Listen
18
18
  Listen.logger.debug 'Adapter: considering polling ...'
19
19
  return Polling if options[:force_polling]
20
20
  Listen.logger.debug 'Adapter: considering optimized backend...'
21
- return _usable_adapter_class if _usable_adapter_class
21
+ adapter_class = _usable_adapter_class
22
+ return adapter_class if adapter_class
22
23
  Listen.logger.debug 'Adapter: falling back to polling...'
23
24
  _warn_polling_fallback(options)
24
25
  Polling
data/lib/listen/change.rb CHANGED
@@ -55,9 +55,7 @@ module Listen
55
55
  options = cookie ? { cookie: cookie } : {}
56
56
  @config.queue(type, change, watched_dir, rel_path, options)
57
57
  elsif type == :dir
58
- # NOTE: POSSIBLE RECURSION
59
- # TODO: fix - use a queue instead
60
- Directory.scan(self, rel_path, options)
58
+ _scan_directory(rel_path, options)
61
59
  elsif (change = File.change(record, rel_path)) && !options[:silence]
62
60
  @config.queue(:file, change, watched_dir, rel_path)
63
61
  end
@@ -65,5 +63,25 @@ module Listen
65
63
  # rubocop:enable Metrics/MethodLength
66
64
  # rubocop:enable Metrics/CyclomaticComplexity
67
65
  # rubocop:enable Metrics/PerceivedComplexity
66
+
67
+ private
68
+
69
+ def _scan_directory(rel_path, options)
70
+ @directory_scan_queue ||= []
71
+ @directory_scan_queue << [rel_path, options]
72
+ return if @scanning_directories
73
+
74
+ _drain_directory_scan_queue
75
+ end
76
+
77
+ def _drain_directory_scan_queue
78
+ @scanning_directories = true
79
+ @directory_scan_queue.each do |path, options|
80
+ Directory.scan(self, path, options)
81
+ end
82
+ ensure
83
+ @directory_scan_queue.clear
84
+ @scanning_directories = false
85
+ end
68
86
  end
69
87
  end
@@ -5,6 +5,8 @@ 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
+ MAX_RESCAN_ATTEMPTS = 5
9
+
8
10
  # rubocop:disable Metrics/MethodLength
9
11
  def self.scan(snapshot, rel_path, options)
10
12
  record = snapshot.record
@@ -23,6 +25,8 @@ module Listen
23
25
  rel_path, options.inspect, previous.inspect, current.inspect)
24
26
  end
25
27
 
28
+ rescan_attempts = 0
29
+ full_path = nil
26
30
  begin
27
31
  current.each do |full_path|
28
32
  type = ::File.lstat(full_path.to_s).directory? ? :dir : :file
@@ -31,8 +35,16 @@ module Listen
31
35
  end
32
36
  rescue Errno::ENOENT
33
37
  # The directory changed meanwhile, so rescan it
34
- current = Set.new(_children(path))
35
- retry
38
+ rescan_attempts += 1
39
+ if rescan_attempts <= MAX_RESCAN_ATTEMPTS
40
+ current = Set.new(_children(path))
41
+ retry
42
+ end
43
+
44
+ current.delete(full_path)
45
+ Listen.logger.debug do
46
+ "scan remained unstable after #{MAX_RESCAN_ATTEMPTS} rescans: #{path}"
47
+ end
36
48
  end
37
49
 
38
50
  # TODO: this is not tested properly
@@ -48,7 +60,9 @@ module Listen
48
60
  _async_changes(snapshot, path, previous, options)
49
61
  _change(snapshot, :file, rel_path, options)
50
62
  rescue
51
- Listen.logger.warn { format('scan DIED: %s:%s', $ERROR_INFO, $ERROR_POSITION * "\n") }
63
+ Listen.logger.warn do
64
+ "scan DIED: #{$ERROR_INFO}:#{$ERROR_POSITION * "\n"}"
65
+ end
52
66
  raise
53
67
  end
54
68
  # rubocop:enable Metrics/MethodLength
@@ -12,7 +12,6 @@ module Listen
12
12
  wait_for_delay,
13
13
  &block
14
14
  )
15
-
16
15
  @listener = listener
17
16
  @event_queue = event_queue
18
17
  @queue_optimizer = queue_optimizer
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'thread'
4
-
5
3
  require 'timeout'
6
4
  require 'listen/event/processor'
7
5
  require 'listen/thread'
@@ -85,11 +85,13 @@ module Listen
85
85
 
86
86
  # blocks until event is popped
87
87
  # returns the event or `nil` when the event_queue is closed
88
+ # rubocop:disable Naming/MemoizedInstanceVariableName
88
89
  def _wait_until_events
89
90
  config.event_queue.pop.tap do |_event|
90
91
  @_remember_time_of_first_unprocessed_event ||= MonotonicTime.now
91
92
  end
92
93
  end
94
+ # rubocop:enable Naming/MemoizedInstanceVariableName
93
95
 
94
96
  def _flush_wakeup_reasons
95
97
  until @reasons.empty?
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'thread'
4
-
5
3
  require 'forwardable'
6
4
 
7
5
  module Listen
data/lib/listen/fsm.rb CHANGED
@@ -2,8 +2,6 @@
2
2
 
3
3
  # Code copied from https://github.com/celluloid/celluloid-fsm
4
4
 
5
- require 'thread'
6
-
7
5
  module Listen
8
6
  module FSM
9
7
  # Included hook to extend class methods
@@ -38,7 +36,7 @@ module Listen
38
36
  end
39
37
  end
40
38
 
41
- # Note: including classes must call initialize_fsm from their initialize method.
39
+ # NOTE: including classes must call initialize_fsm from their initialize method.
42
40
  def initialize_fsm
43
41
  @fsm_initialized = true
44
42
  @state = self.class.start_state
data/lib/listen/logger.rb CHANGED
@@ -46,7 +46,7 @@ module Listen
46
46
 
47
47
  ::Logger.new(STDERR, level: level)
48
48
  end
49
-
49
+
50
50
  def adapter_warn_behavior_callback(message)
51
51
  if adapter_warn_behavior.respond_to?(:call)
52
52
  case behavior = adapter_warn_behavior.call(message)
@@ -12,7 +12,6 @@ module Listen
12
12
  given_options.empty? or raise ArgumentError, "Unknown options: #{given_options.inspect}"
13
13
  end
14
14
 
15
- # rubocop:disable Lint/MissingSuper
16
15
  def respond_to_missing?(name, *_)
17
16
  @options.has_key?(name)
18
17
  end
@@ -21,6 +20,5 @@ module Listen
21
20
  respond_to_missing?(name) or raise NameError, "Bad option: #{name.inspect} (valid:#{@options.keys.inspect})"
22
21
  @options[name]
23
22
  end
24
- # rubocop:enable Lint/MissingSuper
25
23
  end
26
24
  end
@@ -9,7 +9,7 @@ module Listen
9
9
  class SymlinkDetector
10
10
  README_URL = 'https://github.com/guard/listen/blob/master/README.md'
11
11
 
12
- SYMLINK_LOOP_ERROR = <<-EOS
12
+ SYMLINK_LOOP_ERROR = <<-EOS.freeze
13
13
  ** ERROR: directory is already being watched! **
14
14
 
15
15
  Directory: %s
data/lib/listen/record.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'thread'
4
3
  require 'listen/record/entry'
5
4
  require 'listen/record/symlink_detector'
6
5
 
@@ -73,7 +72,7 @@ module Listen
73
72
  private
74
73
 
75
74
  def empty_dirname?(dirname)
76
- dirname == '.' || dirname == ''
75
+ ['.', ''].include?(dirname)
77
76
  end
78
77
 
79
78
  def reset_tree
@@ -17,16 +17,21 @@ module Listen
17
17
  end
18
18
 
19
19
  def append_ignores(*regexps)
20
- prev_ignores = Array(@prev_silencer_options[:ignore])
21
- _reconfigure_silencer(ignore: [prev_ignores + regexps])
20
+ opts = @prev_silencer_options.dup
21
+ opts[:ignore] = [opts[:ignore], regexps]
22
+ _reconfigure_silencer(opts)
22
23
  end
23
24
 
24
25
  def replace_with_bang_ignores(regexps)
25
- _reconfigure_silencer(ignore!: regexps)
26
+ opts = @prev_silencer_options.dup
27
+ opts.delete(:ignore)
28
+ opts[:ignore!] = regexps
29
+ _reconfigure_silencer(opts)
26
30
  end
27
31
 
28
32
  def replace_with_only(regexps)
29
- _reconfigure_silencer(only: regexps)
33
+ opts = @prev_silencer_options.merge(only: regexps)
34
+ _reconfigure_silencer(opts)
30
35
  end
31
36
 
32
37
  private
@@ -18,7 +18,7 @@ module Listen
18
18
  # emacs temp files
19
19
  | \#.+\#
20
20
  | \.\#.+
21
- )(/|\z)}x.freeze
21
+ )(/|\z)}x
22
22
 
23
23
  # The default list of files that get ignored.
24
24
  DEFAULT_IGNORED_EXTENSIONS = %r{(?:
@@ -59,7 +59,7 @@ module Listen
59
59
  | \.DS_Store
60
60
  | \.tmp
61
61
  | ~
62
- )\z}x.freeze
62
+ )\z}x
63
63
 
64
64
  # TODO: deprecate these mutators; use attr_reader instead
65
65
  attr_accessor :only_patterns, :ignore_patterns
@@ -75,7 +75,7 @@ module Listen
75
75
  end
76
76
 
77
77
  def silenced?(relative_path, type)
78
- path = relative_path.to_s # in case it is a Pathname
78
+ path = relative_path.to_s # in case it is a Pathname
79
79
 
80
80
  _ignore?(path) || (only_patterns && type == :file && !_only?(path))
81
81
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Listen
4
- VERSION = '3.9.0'
4
+ VERSION = '3.10.1'
5
5
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: listen
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.9.0
4
+ version: 3.10.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: 2024-02-24 00:00:00.000000000 Z
11
+ date: 2026-10-01 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: logger
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: rb-fsevent
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -103,9 +117,9 @@ metadata:
103
117
  allowed_push_host: https://rubygems.org
104
118
  bug_tracker_uri: https://github.com/guard/listen/issues
105
119
  changelog_uri: https://github.com/guard/listen/releases
106
- documentation_uri: https://www.rubydoc.info/gems/listen/3.9.0
120
+ documentation_uri: https://www.rubydoc.info/gems/listen/3.10.1
107
121
  homepage_uri: https://github.com/guard/listen
108
- source_code_uri: https://github.com/guard/listen/tree/v3.9.0
122
+ source_code_uri: https://github.com/guard/listen/tree/v3.10.1
109
123
  post_install_message:
110
124
  rdoc_options: []
111
125
  require_paths:
@@ -121,7 +135,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
121
135
  - !ruby/object:Gem::Version
122
136
  version: '0'
123
137
  requirements: []
124
- rubygems_version: 3.4.6
138
+ rubygems_version: 3.4.19
125
139
  signing_key:
126
140
  specification_version: 4
127
141
  summary: Listen to file modifications