listen 2.7.4 → 2.7.5

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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +232 -0
  3. data/.travis.yml +6 -3
  4. data/Gemfile +9 -1
  5. data/Guardfile +6 -1
  6. data/README.md +17 -4
  7. data/lib/listen.rb +9 -4
  8. data/lib/listen/adapter.rb +5 -7
  9. data/lib/listen/adapter/base.rb +8 -5
  10. data/lib/listen/adapter/bsd.rb +58 -21
  11. data/lib/listen/adapter/darwin.rb +2 -4
  12. data/lib/listen/adapter/linux.rb +20 -10
  13. data/lib/listen/adapter/polling.rb +0 -2
  14. data/lib/listen/adapter/tcp.rb +6 -5
  15. data/lib/listen/adapter/windows.rb +8 -6
  16. data/lib/listen/change.rb +1 -2
  17. data/lib/listen/cli.rb +25 -22
  18. data/lib/listen/directory.rb +8 -6
  19. data/lib/listen/listener.rb +25 -19
  20. data/lib/listen/record.rb +4 -2
  21. data/lib/listen/silencer.rb +55 -25
  22. data/lib/listen/tcp.rb +9 -0
  23. data/lib/listen/tcp/broadcaster.rb +0 -2
  24. data/lib/listen/tcp/listener.rb +13 -8
  25. data/lib/listen/tcp/message.rb +0 -2
  26. data/lib/listen/version.rb +1 -1
  27. data/listen.gemspec +4 -3
  28. data/spec/acceptance/listen_spec.rb +190 -109
  29. data/spec/acceptance/tcp_spec.rb +28 -26
  30. data/spec/lib/listen/adapter/base_spec.rb +14 -12
  31. data/spec/lib/listen/adapter/bsd_spec.rb +5 -2
  32. data/spec/lib/listen/adapter/darwin_spec.rb +5 -2
  33. data/spec/lib/listen/adapter/linux_spec.rb +40 -25
  34. data/spec/lib/listen/adapter/polling_spec.rb +29 -14
  35. data/spec/lib/listen/adapter/tcp_spec.rb +24 -6
  36. data/spec/lib/listen/adapter/windows_spec.rb +5 -2
  37. data/spec/lib/listen/adapter_spec.rb +20 -17
  38. data/spec/lib/listen/change_spec.rb +36 -26
  39. data/spec/lib/listen/directory_spec.rb +128 -71
  40. data/spec/lib/listen/file_spec.rb +67 -34
  41. data/spec/lib/listen/listener_spec.rb +135 -105
  42. data/spec/lib/listen/record_spec.rb +32 -29
  43. data/spec/lib/listen/silencer_spec.rb +78 -56
  44. data/spec/lib/listen/tcp/broadcaster_spec.rb +3 -2
  45. data/spec/lib/listen/tcp/listener_spec.rb +17 -11
  46. data/spec/lib/listen/tcp/message_spec.rb +1 -1
  47. data/spec/lib/listen_spec.rb +18 -6
  48. data/spec/spec_helper.rb +5 -1
  49. data/spec/support/acceptance_helper.rb +3 -3
  50. data/spec/support/fixtures_helper.rb +10 -9
  51. metadata +17 -15
@@ -1,26 +1,46 @@
1
+ # Listener implementation for BSD's `kqueue`.
2
+ # @see http://www.freebsd.org/cgi/man.cgi?query=kqueue
3
+ # @see https://github.com/mat813/rb-kqueue/blob/master/lib/rb-kqueue/queue.rb
4
+ #
1
5
  module Listen
2
6
  module Adapter
3
-
4
- # Listener implementation for BSD's `kqueue`.
5
- #
6
7
  class BSD < Base
7
8
  # Watched kqueue events
8
9
  #
9
- # @see http://www.freebsd.org/cgi/man.cgi?query=kqueue
10
- # @see https://github.com/mat813/rb-kqueue/blob/master/lib/rb-kqueue/queue.rb
11
- #
12
10
  EVENTS = [:delete, :write, :extend, :attrib, :rename] # :link, :revoke
13
11
 
12
+ BSD_OS_REGEXP = /bsd|dragonfly/i
13
+
14
14
  # The message to show when wdm gem isn't available
15
15
  #
16
16
  BUNDLER_DECLARE_GEM = <<-EOS.gsub(/^ {6}/, '')
17
17
  Please add the following to your Gemfile to avoid polling for changes:
18
18
  require 'rbconfig'
19
- gem 'rb-kqueue', '>= 0.2' if RbConfig::CONFIG['target_os'] =~ /freebsd/i
19
+ if RbConfig::CONFIG['target_os'] =~ #{BSD_OS_REGEXP}
20
+ gem 'rb-kqueue', '>= 0.2'
21
+
22
+ # Base versions have known conflicts/bugs
23
+ # Even master branches may not work...
24
+ gem 'ffi', github: 'carpetsmoker/ffi', ref: 'ac63e07f7'
25
+ gem 'celluloid', github: 'celluloid/celluloid', ref: '7fdef04'
26
+ end
27
+ EOS
28
+
29
+ BSD_EXPERIMENTAL = <<-EOS.gsub(/^ {6}/, '')
30
+ NOTE *BSD SUPPORT IS EXPERIMENTAL!
31
+
32
+ In fact, it likely WONT WORK!!!!
33
+
34
+ (see: https://github.com/guard/listen/issues/220)
35
+
36
+ If you're brave enough, feel free to suggest pull requests and
37
+ experiment on your own. For help, browse existing issues marked 'bsd'
38
+ for clues, tips and workaround.
20
39
  EOS
21
40
 
22
41
  def self.usable?
23
- if RbConfig::CONFIG['target_os'] =~ /freebsd/i
42
+ if RbConfig::CONFIG['target_os'] =~ BSD_OS_REGEXP
43
+ Kernel.warn BSD_EXPERIMENTAL
24
44
  require 'rb-kqueue'
25
45
  require 'find'
26
46
  true
@@ -32,7 +52,7 @@ module Listen
32
52
 
33
53
  def start
34
54
  worker = _init_worker
35
- Thread.new { worker.poll }
55
+ Thread.new { worker.run }
36
56
  end
37
57
 
38
58
  private
@@ -45,27 +65,38 @@ module Listen
45
65
  def _init_worker
46
66
  KQueue::Queue.new.tap do |queue|
47
67
  _directories_path.each do |path|
48
- Find.find(path) { |file_path| _watch_file(file_path, queue) }
68
+ # use Record to make a snapshot of dir, so we
69
+ # can detect new files
70
+ _find(path) { |file_path| _watch_file(file_path, queue) }
49
71
  end
50
72
  end
51
73
  end
52
74
 
53
75
  def _worker_callback
54
76
  lambda do |event|
55
- _notify_change(_event_path(event), type: 'File', change: _change(event.flags))
77
+ change = _change(event.flags)
78
+ path = _event_path(event)
79
+ if path.directory?
80
+ # Force dir content tracking to kick in, or we won't have
81
+ # names of added files
82
+ _notify_change(path, type: 'Directory', recursive: true)
83
+ else
84
+ _notify_change(path, type: 'File', change: change)
85
+ end
56
86
 
57
- # If it is a directory, and it has a write flag, it means a
58
- # file has been added so find out which and deal with it.
59
- # No need to check for removed files, kqueue will forget them
60
- # when the vfs does.
61
- _watch_for_new_file(event) if _new_file_added?(event)
87
+ # If it is a directory, and it has a write flag, it means a
88
+ # file has been added so find out which and deal with it.
89
+ # No need to check for removed files, kqueue will forget them
90
+ # when the vfs does.
91
+ _watch_for_new_file(event) if _new_file_added?(event)
62
92
  end
63
93
  end
64
94
 
65
95
  def _change(event_flags)
66
96
  { modified: [:attrib, :extend],
67
97
  added: [:write],
68
- removed: [:rename, :delete] }.each do |change, flags|
98
+ removed: [:rename, :delete]
99
+ }.each do |change, flags|
69
100
  return change unless (flags & event_flags).empty?
70
101
  end
71
102
  nil
@@ -76,20 +107,26 @@ module Listen
76
107
  end
77
108
 
78
109
  def _new_file_added?(event)
79
- File.directory?(event.watcher.path) && event.flags.include?(:write)
110
+ ::File.directory?(event.watcher.path) && event.flags.include?(:write)
80
111
  end
81
112
 
82
113
  def _watch_for_new_file(event)
83
114
  queue = event.watcher.queue
84
- Find.find(path) do |file_path|
85
- _watch_file(file_path, queue) unless queue.watchers.detect { |k,v| v.path == file.to_s }
115
+ _find(_event_path(event).to_s) do |file_path|
116
+ unless queue.watchers.detect { |_, v| v.path == file_path.to_s }
117
+ _watch_file(file_path, queue)
118
+ end
86
119
  end
87
120
  end
88
121
 
89
122
  def _watch_file(path, queue)
90
123
  queue.watch_file(path, *EVENTS, &_worker_callback)
91
124
  end
92
- end
93
125
 
126
+ # Quick rubocop workaround
127
+ def _find(*paths)
128
+ Find.send(:find, *paths)
129
+ end
130
+ end
94
131
  end
95
132
  end
@@ -1,10 +1,8 @@
1
1
  module Listen
2
2
  module Adapter
3
-
4
3
  # Adapter implementation for Mac OS X `FSEvents`.
5
4
  #
6
5
  class Darwin < Base
7
-
8
6
  def self.usable?
9
7
  RbConfig::CONFIG['target_os'] =~ /darwin(1.+)?$/i
10
8
  end
@@ -27,7 +25,8 @@ module Listen
27
25
  def _init_worker
28
26
  FSEvent.new.tap do |worker|
29
27
  worker.watch(_directories_path, latency: _latency) do |changes|
30
- _changes_path(changes).each { |path| _notify_change(path, type: 'Dir') }
28
+ paths = _changes_path(changes)
29
+ paths.each { |path| _notify_change(path, type: 'Dir') }
31
30
  end
32
31
  end
33
32
  end
@@ -39,6 +38,5 @@ module Listen
39
38
  end
40
39
  end
41
40
  end
42
-
43
41
  end
44
42
  end
@@ -1,22 +1,24 @@
1
1
  module Listen
2
2
  module Adapter
3
-
4
3
  # Listener implementation for Linux `inotify`.
5
4
  #
6
5
  class Linux < Base
7
6
  # Watched inotify events
8
7
  #
9
8
  # @see http://www.tin.org/bin/man.cgi?section=7&topic=inotify
10
- # @see https://github.com/nex3/rb-inotify/blob/master/lib/rb-inotify/notifier.rb#L99-L177
9
+ # @see https://github.com/nex3/rb-inotify
11
10
  #
12
11
  EVENTS = [:recursive, :attrib, :create, :delete, :move, :close_write]
13
12
 
14
13
  # The message to show when the limit of inotify watchers is not enough
15
14
  #
15
+ WIKI_URL = 'https://github.com/guard/listen'\
16
+ '/wiki/Increasing-the-amount-of-inotify-watchers'
17
+
16
18
  INOTIFY_LIMIT_MESSAGE = <<-EOS.gsub(/^\s*/, '')
17
19
  FATAL: Listen error: unable to monitor directories for changes.
18
20
 
19
- Please head to https://github.com/guard/listen/wiki/Increasing-the-amount-of-inotify-watchers
21
+ Please head to #{WIKI_URL}
20
22
  for information on how to solve this issue.
21
23
  EOS
22
24
 
@@ -47,7 +49,9 @@ module Listen
47
49
  #
48
50
  def _init_worker
49
51
  INotify::Notifier.new.tap do |worker|
50
- _directories_path.each { |path| worker.watch(path, *EVENTS, &_worker_callback) }
52
+ _directories_path.each do |path|
53
+ worker.watch(path, *EVENTS, &_worker_callback)
54
+ end
51
55
  end
52
56
  end
53
57
 
@@ -58,24 +62,25 @@ module Listen
58
62
  path = _event_path(event)
59
63
  cookie_opts = event.cookie.zero? ? {} : { cookie: event.cookie }
60
64
 
61
- Celluloid.logger.info "listen: inotify event: #{event.flags.inspect}: #{event.name}"
65
+ _log(event)
62
66
 
63
67
  if _dir_event?(event)
64
- _notify_change(path, { type: 'Dir'}.merge(cookie_opts))
68
+ _notify_change(path, { type: 'Dir' }.merge(cookie_opts))
65
69
  else
66
- _notify_change(path, { type: 'File', change: _change(event.flags)}.merge(cookie_opts))
70
+ options = { type: 'File', change: _change(event.flags) }
71
+ _notify_change(path, options.merge(cookie_opts))
67
72
  end
68
73
  end
69
74
  end
70
75
 
71
76
  def _skip_event?(event)
72
77
  # Event on root directory
73
- return true if event.name == ""
78
+ return true if event.name == ''
74
79
  # INotify reports changes to files inside directories as events
75
80
  # on the directories themselves too.
76
81
  #
77
82
  # @see http://linux.die.net/man/7/inotify
78
- return true if _dir_event?(event) && (event.flags & [:close, :modify]).any?
83
+ _dir_event?(event) && (event.flags & [:close, :modify]).any?
79
84
  end
80
85
 
81
86
  def _change(event_flags)
@@ -96,7 +101,12 @@ module Listen
96
101
  def _event_path(event)
97
102
  Pathname.new(event.absolute_name)
98
103
  end
99
- end
100
104
 
105
+ def _log(event)
106
+ name = event.name
107
+ flags = event.flags.inspect
108
+ Celluloid.logger.info "inotify event: #{flags}: #{name}"
109
+ end
110
+ end
101
111
  end
102
112
  end
@@ -1,6 +1,5 @@
1
1
  module Listen
2
2
  module Adapter
3
-
4
3
  # Polling Adapter that works cross-platform and
5
4
  # has no dependencies. This is the adapter that
6
5
  # uses the most CPU processing power and has higher
@@ -44,6 +43,5 @@ module Listen
44
43
  sleep(nap_time) if nap_time > 0
45
44
  end
46
45
  end
47
-
48
46
  end
49
47
  end
@@ -2,7 +2,6 @@ require 'celluloid/io'
2
2
 
3
3
  module Listen
4
4
  module Adapter
5
-
6
5
  # Adapter to receive file system modifications over TCP
7
6
  class TCP < Base
8
7
  include Celluloid::IO
@@ -18,7 +17,7 @@ module Listen
18
17
  # Initializes and starts a Celluloid::IO-powered TCP-recipient
19
18
  def start
20
19
  @socket = TCPSocket.new(listener.host, listener.port)
21
- @buffer = String.new
20
+ @buffer = ''
22
21
  run
23
22
  end
24
23
 
@@ -36,7 +35,7 @@ module Listen
36
35
 
37
36
  # Continuously receive and asynchronously handle data
38
37
  def run
39
- while data = @socket.recv(RECEIVE_WINDOW)
38
+ while (data = @socket.recv(RECEIVE_WINDOW))
40
39
  async.handle_data(data)
41
40
  end
42
41
  end
@@ -44,7 +43,7 @@ module Listen
44
43
  # Buffers incoming data and handles messages accordingly
45
44
  def handle_data(data)
46
45
  @buffer << data
47
- while message = Listen::TCP::Message.from_buffer(@buffer)
46
+ while (message = Listen::TCP::Message.from_buffer(@buffer))
48
47
  handle_message(message)
49
48
  end
50
49
  end
@@ -58,7 +57,9 @@ module Listen
58
57
  end
59
58
  end
60
59
 
60
+ def self.local_fs?
61
+ false
62
+ end
61
63
  end
62
-
63
64
  end
64
65
  end
@@ -1,16 +1,16 @@
1
1
  module Listen
2
2
  module Adapter
3
-
4
3
  # Adapter implementation for Windows `wdm`.
5
4
  #
6
5
  class Windows < Base
7
-
8
6
  # The message to show when wdm gem isn't available
9
7
  #
10
8
  BUNDLER_DECLARE_GEM = <<-EOS.gsub(/^ {6}/, '')
11
9
  Please add the following to your Gemfile to avoid polling for changes:
12
10
  require 'rbconfig'
13
- gem 'wdm', '>= 0.1.0' if RbConfig::CONFIG['target_os'] =~ /mswin|mingw|cygwin/i
11
+ if RbConfig::CONFIG['target_os'] =~ /mswin|mingw|cygwin/i
12
+ gem 'wdm', '>= 0.1.0'
13
+ end
14
14
  EOS
15
15
 
16
16
  def self.usable?
@@ -37,13 +37,16 @@ module Listen
37
37
  #
38
38
  def _init_worker
39
39
  WDM::Monitor.new.tap do |worker|
40
- _directories_path.each { |path| worker.watch_recursively(path, &_worker_callback) }
40
+ _directories_path.each do |path|
41
+ worker.watch_recursively(path, &_worker_callback)
42
+ end
41
43
  end
42
44
  end
43
45
 
44
46
  def _worker_callback
45
47
  lambda do |change|
46
- _notify_change(_path(change.path), type: 'File', change: _change(change.type))
48
+ options = { type: 'File', change: _change(change.type) }
49
+ _notify_change(_path(change.path), options)
47
50
  end
48
51
  end
49
52
 
@@ -60,6 +63,5 @@ module Listen
60
63
  nil
61
64
  end
62
65
  end
63
-
64
66
  end
65
67
  end
data/lib/listen/change.rb CHANGED
@@ -16,7 +16,7 @@ module Listen
16
16
  cookie = options[:cookie]
17
17
 
18
18
  unless cookie
19
- #TODO: remove silencing here (it's done later)
19
+ # TODO: remove silencing here (it's done later)
20
20
  return if _silencer.silenced?(path, options[:type])
21
21
  end
22
22
 
@@ -47,6 +47,5 @@ module Listen
47
47
  def _silencer
48
48
  listener.registry[:silencer]
49
49
  end
50
-
51
50
  end
52
51
  end
data/lib/listen/cli.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'thor'
2
2
  require 'listen'
3
+ require 'logger'
3
4
 
4
5
  module Listen
5
6
  class CLI < Thor
@@ -8,44 +9,46 @@ module Listen
8
9
  desc 'start', 'Starts Listen'
9
10
 
10
11
  class_option :verbose,
11
- type: :boolean,
12
- default: false,
13
- aliases: '-v',
14
- banner: 'Verbose'
12
+ type: :boolean,
13
+ default: false,
14
+ aliases: '-v',
15
+ banner: 'Verbose'
15
16
 
16
17
  class_option :forward,
17
- type: :string,
18
- default: '127.0.0.1:4000',
19
- aliases: '-f',
20
- banner: 'The address to forward filesystem events'
18
+ type: :string,
19
+ default: '127.0.0.1:4000',
20
+ aliases: '-f',
21
+ banner: 'The address to forward filesystem events'
21
22
 
22
23
  class_option :directory,
23
- type: :string,
24
- default: '.',
25
- aliases: '-d',
26
- banner: 'The directory to listen to'
27
-
28
-
29
- def start
30
- Listen::Forwarder.new(options).start
31
- end
24
+ type: :string,
25
+ default: '.',
26
+ aliases: '-d',
27
+ banner: 'The directory to listen to'
32
28
 
29
+ def start
30
+ Listen::Forwarder.new(options).start
31
+ end
33
32
  end
34
33
 
35
34
  class Forwarder
35
+ attr_reader :logger
36
36
  def initialize(options)
37
37
  @options = options
38
+ @logger = Logger.new(STDOUT)
39
+ @logger.level = Logger::INFO
40
+ @logger.formatter = proc { |_, _, _, msg| "#{msg}\n" }
38
41
  end
39
42
 
40
43
  def start
41
- puts "Starting listen..."
44
+ logger.info 'Starting listen...'
42
45
  address = @options[:forward]
43
46
  directory = @options[:directory]
44
- callback = Proc.new do |modified, added, removed|
47
+ callback = proc do |modified, added, removed|
45
48
  if @options[:verbose]
46
- puts "+ #{added}" unless added.empty?
47
- puts "- #{removed}" unless removed.empty?
48
- puts "> #{modified}" unless modified.empty?
49
+ logger.info "+ #{added}" unless added.empty?
50
+ logger.info "- #{removed}" unless removed.empty?
51
+ logger.info "> #{modified}" unless modified.empty?
49
52
  end
50
53
  end
51
54