listen 2.7.11 → 2.7.12

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.
@@ -0,0 +1,31 @@
1
+ require 'celluloid/logger'
2
+
3
+ module Listen
4
+ module Internals
5
+ module Logging
6
+ def _info(*args)
7
+ _log(:info, *args)
8
+ end
9
+
10
+ def _warn(*args)
11
+ _log(:warn, *args)
12
+ end
13
+
14
+ def _debug(*args)
15
+ _log(:debug, *args)
16
+ end
17
+
18
+ def _log(*args)
19
+ Celluloid::Logger.send(*args)
20
+ end
21
+
22
+ def _format_error(fmt)
23
+ format(fmt, $ERROR_INFO, ", Backtrace: \n" + $ERROR_POSITION * "\n")
24
+ end
25
+
26
+ def _error_exception(fmt)
27
+ _log :error, _format_error(fmt)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,19 @@
1
+ module Listen
2
+ # @private api
3
+ module Internals
4
+ # Just a wrapper for tests to avoid interfereing with Celluloid's threads
5
+ module ThreadPool
6
+ def self.add(&block)
7
+ (@threads ||= Queue.new) << Thread.new { block.call }
8
+ end
9
+
10
+ def self.stop
11
+ return unless @threads ||= nil
12
+
13
+ killed = Queue.new
14
+ killed << @threads.pop.kill until @threads.empty?
15
+ killed.pop.join until killed.empty?
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,4 +1,6 @@
1
1
  require 'pathname'
2
+
3
+ require 'listen/version'
2
4
  require 'listen/adapter'
3
5
  require 'listen/change'
4
6
  require 'listen/record'
@@ -6,6 +8,8 @@ require 'listen/silencer'
6
8
  require 'listen/queue_optimizer'
7
9
  require 'English'
8
10
 
11
+ require 'listen/internals/logging'
12
+
9
13
  module Listen
10
14
  class Listener
11
15
  include Celluloid::FSM
@@ -39,7 +43,8 @@ module Listen
39
43
  # Setup logging first
40
44
  if Celluloid.logger
41
45
  Celluloid.logger.level = _debug_level
42
- _log :info, "Celluloid loglevel set to: #{Celluloid.logger.level}"
46
+ _info "Celluloid loglevel set to: #{Celluloid.logger.level}"
47
+ _info "Listen version: #{Listen::VERSION}"
43
48
  end
44
49
 
45
50
  @silencer = Silencer.new
@@ -172,6 +177,8 @@ module Listen
172
177
 
173
178
  private
174
179
 
180
+ include Internals::Logging
181
+
175
182
  def _init_options(options = {})
176
183
  { debug: false,
177
184
  latency: nil,
@@ -239,8 +246,7 @@ module Listen
239
246
  _process_changes unless state == :paused
240
247
  end
241
248
  rescue RuntimeError
242
- Kernel.warn "[Listen warning]: Change block raised an exception: #{$!}"
243
- Kernel.warn "Backtrace:\n\t#{$@.join("\n\t")}"
249
+ Kernel.warn _format_error('exception while processing events: %s %s')
244
250
  end
245
251
 
246
252
  def _silenced?(path, type)
@@ -253,10 +259,6 @@ module Listen
253
259
  adapter.start
254
260
  end
255
261
 
256
- def _log(type, message)
257
- Celluloid::Logger.send(type, message)
258
- end
259
-
260
262
  def _adapter_class
261
263
  @adapter_class ||= Adapter.select(options)
262
264
  end
@@ -268,9 +270,7 @@ module Listen
268
270
  @last_queue_event_time = nil
269
271
 
270
272
  changes = []
271
- while !@queue.empty?
272
- changes << @queue.pop
273
- end
273
+ changes << @queue.pop until @queue.empty?
274
274
 
275
275
  return if block.nil?
276
276
 
@@ -280,7 +280,7 @@ module Listen
280
280
  block_start = Time.now.to_f
281
281
  # TODO: condition not tested, but too complex to test ATM
282
282
  block.call(*result) unless result.all?(&:empty?)
283
- _log :debug, "Callback took #{Time.now.to_f - block_start} seconds"
283
+ _debug "Callback took #{Time.now.to_f - block_start} seconds"
284
284
  end
285
285
 
286
286
  attr_reader :wait_thread
@@ -332,16 +332,16 @@ module Listen
332
332
  end
333
333
 
334
334
  def _queue_raw_change(type, dir, rel_path, options)
335
- _log :debug, "raw queue: #{[type, dir, rel_path, options].inspect}"
335
+ _debug "raw queue: #{[type, dir, rel_path, options].inspect}"
336
336
 
337
337
  unless (worker = async(:change_pool))
338
- _log :warn, 'Failed to allocate worker from change pool'
338
+ _warn 'Failed to allocate worker from change pool'
339
339
  return
340
340
  end
341
341
 
342
342
  worker.change(type, dir, rel_path, options)
343
343
  rescue RuntimeError
344
- _log :error, "#{__method__} crashed: #{$!}:#{$@.join("\n")}"
344
+ _error_exception "_queue_raw_change exception %s:\n%s:\n"
345
345
  raise
346
346
  end
347
347
  end
@@ -67,7 +67,7 @@ module Listen
67
67
 
68
68
  Celluloid::Logger.info "Record.build(): #{Time.now.to_f - start} seconds"
69
69
  rescue
70
- Celluloid::Logger.warn "build crashed: #{$!.inspect}"
70
+ Celluloid::Logger.warn "build crashed: #{$ERROR_INFO.inspect}"
71
71
  raise
72
72
  end
73
73
 
@@ -105,7 +105,7 @@ module Listen
105
105
  left = Queue.new
106
106
  left << '.'
107
107
 
108
- while !left.empty?
108
+ until left.empty?
109
109
  dirname = left.pop
110
110
  add_dir(root, dirname)
111
111
 
@@ -15,8 +15,8 @@ module Listen
15
15
  )(/|$)}x
16
16
 
17
17
  # The default list of files that get ignored.
18
- DEFAULT_IGNORED_EXTENSIONS = %r{(?:
19
- # Kate's tmp/swp files
18
+ DEFAULT_IGNORED_EXTENSIONS = /(?:
19
+ # Kate's tmp\/swp files
20
20
  \..*\d+\.new
21
21
  | \.kate-swp
22
22
 
@@ -36,7 +36,7 @@ module Listen
36
36
  | \.DS_Store
37
37
  | \.tmp
38
38
  | ~
39
- )$}x
39
+ )$/x
40
40
 
41
41
  attr_accessor :only_patterns, :ignore_patterns
42
42
 
@@ -16,10 +16,12 @@ module Listen
16
16
  #
17
17
  def initialize(host, port)
18
18
  @sockets = []
19
- _log :debug, "Broadcaster: starting tcp server: #{host}:#{port}"
19
+ _log :debug, format('Broadcaster: tcp server listening on: %s:%s',
20
+ host, port)
20
21
  @server = TCPServer.new(host, port)
21
22
  rescue
22
- _log :error, "Broadcaster.initialize: #{$!.inspect}:#{$@.join("\n")}"
23
+ _log :error, format('Broadcaster.initialize: %s:%s', $ERROR_INFO,
24
+ $ERROR_POSITION * "\n")
23
25
  raise
24
26
  end
25
27
 
@@ -48,13 +50,14 @@ module Listen
48
50
 
49
51
  # Continuously accept and handle incoming connections
50
52
  def run
51
- while socket = @server.accept
53
+ while (socket = @server.accept)
52
54
  @sockets << socket
53
55
  end
54
56
  rescue Celluloid::Task::TerminatedError
55
- _log :debug, "TCP adapter was terminated: #{$!.inspect}"
57
+ _log :debug, "TCP adapter was terminated: #{$ERROR_INFO}"
56
58
  rescue
57
- _log :error, "Broadcaster.run: #{$!.inspect}:#{$@.join("\n")}"
59
+ _log :error, format('Broadcaster.run: %s:%s', $ERROR_INFO,
60
+ $ERROR_POSITION * "\n")
58
61
  raise
59
62
  end
60
63
 
@@ -1,3 +1,3 @@
1
1
  module Listen
2
- VERSION = '2.7.11'
2
+ VERSION = '2.7.12'
3
3
  end
@@ -14,8 +14,8 @@ Gem::Specification.new do |s|
14
14
  s.description = 'The Listen gem listens to file modifications and '\
15
15
  'notifies you about the changes. Works everywhere!'
16
16
 
17
- s.files = `git ls-files`.split($/)
18
- s.test_files = s.files.grep(%r{^spec/})
17
+ s.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
18
+ s.test_files = s.files.grep(/^spec\//)
19
19
  s.executable = 'listen'
20
20
  s.require_path = 'lib'
21
21
 
@@ -23,8 +23,7 @@ describe 'Listen' do
23
23
 
24
24
  it 'warns the backtrace' do
25
25
  expect(Kernel).to receive(:warn).
26
- with('[Listen warning]: Change block raised an exception: foo')
27
- expect(Kernel).to receive(:warn).with(/^Backtrace:.*/)
26
+ with(/exception while processing events: foo .*Backtrace:/)
28
27
  wrapper.listen { touch 'file.rb' }
29
28
  end
30
29
  end
@@ -6,7 +6,10 @@ describe Listen::Listener do
6
6
  let(:broadcast_options) { { forward_to: port } }
7
7
  let(:paths) { Pathname.new(Dir.pwd) }
8
8
 
9
- around { |example| fixtures { example.run } }
9
+ around do |example|
10
+ fixtures { example.run }
11
+ Listen.stop
12
+ end
10
13
 
11
14
  modes = if !windows? || Celluloid::VERSION > '0.15.2'
12
15
  [:recipient, :broadcaster]
@@ -1,5 +1,8 @@
1
1
  require 'spec_helper'
2
2
 
3
+ # This is just so stubs work
4
+ require 'rb-fsevent'
5
+
3
6
  require 'listen/adapter/darwin'
4
7
 
5
8
  include Listen
@@ -34,4 +37,109 @@ describe Adapter::Darwin do
34
37
  it { should eq 1234 }
35
38
  end
36
39
  end
40
+
41
+ describe 'multiple dirs' do
42
+ subject do
43
+ dirs = config.keys.map { |p| Pathname(p.to_s) }
44
+ described_class.new(directories: dirs)
45
+ end
46
+
47
+ let(:foo1) { double('foo1') }
48
+ let(:foo2) { double('foo2') }
49
+ let(:foo3) { double('foo3') }
50
+
51
+ before do
52
+ allow(FSEvent).to receive(:new).and_return(*config.values, nil)
53
+ config.each do |dir, obj|
54
+ allow(obj).to receive(:watch).with(dir.to_s, latency: 0.1)
55
+ end
56
+ subject.configure
57
+ end
58
+
59
+ describe 'configuration' do
60
+ context 'with 1 directory' do
61
+ let(:config) { { dir1: foo1 } }
62
+
63
+ it 'configures directory' do
64
+ expect(foo1).to have_received(:watch).with('dir1', latency: 0.1)
65
+ end
66
+ end
67
+
68
+ context 'with 2 directories' do
69
+ let(:config) { { dir1: foo1, dir2: foo2 } }
70
+
71
+ it 'configures directories' do
72
+ expect(foo1).to have_received(:watch).with('dir1', latency: 0.1)
73
+ expect(foo2).to have_received(:watch).with('dir2', latency: 0.1)
74
+ end
75
+ end
76
+
77
+ context 'with 3 directories' do
78
+ let(:config) { { dir1: foo1, dir2: foo2, dir3: foo3 } }
79
+
80
+ it 'configures directories' do
81
+ expect(foo1).to have_received(:watch).with('dir1', latency: 0.1)
82
+ expect(foo2).to have_received(:watch).with('dir2', latency: 0.1)
83
+ expect(foo3).to have_received(:watch).with('dir3', latency: 0.1)
84
+ end
85
+ end
86
+ end
87
+
88
+ describe 'running threads' do
89
+ let(:running) { [] }
90
+
91
+ before do
92
+ started = Queue.new
93
+ threads = Queue.new
94
+ left = Queue.new
95
+
96
+ # NOTE: Travis has a hard time creating threads on OSX
97
+ thread_start_overhead = 3
98
+ max_test_time = 3 * thread_start_overhead
99
+ block_time = max_test_time + thread_start_overhead
100
+
101
+ config.each do |name, obj|
102
+ left << name # anything, we're just counting
103
+ allow(obj).to receive(:run).once do
104
+ threads << Thread.current
105
+ started << name
106
+ left.pop
107
+ sleep block_time
108
+ end
109
+ end
110
+
111
+ Timeout.timeout(max_test_time) do
112
+ subject.start
113
+ running << started.pop until left.empty?
114
+ end
115
+
116
+ running << started.pop until started.empty?
117
+
118
+ killed = Queue.new
119
+ killed << threads.pop.kill until threads.empty?
120
+ killed.pop.join until killed.empty?
121
+ end
122
+
123
+ context 'with 1 directory' do
124
+ let(:config) { { dir1: foo1 } }
125
+ it 'runs all the workers without blocking' do
126
+ expect(running.sort).to eq(config.keys)
127
+ end
128
+ end
129
+
130
+ context 'with 2 directories' do
131
+ let(:config) { { dir1: foo1, dir2: foo2 } }
132
+ it 'runs all the workers without blocking' do
133
+ expect(running.sort).to eq(config.keys)
134
+ end
135
+ end
136
+
137
+ context 'with 3 directories' do
138
+ let(:config) { { dir1: foo1, dir2: foo2, dir3: foo3 } }
139
+ it 'runs all the workers without blocking' do
140
+ expect(running.sort).to eq(config.keys)
141
+ end
142
+ end
143
+ end
144
+ end
37
145
  end
@@ -26,6 +26,7 @@ describe Adapter::Polling do
26
26
  t = Thread.new { subject.start }
27
27
  sleep 0.25
28
28
  t.kill
29
+ t.join
29
30
  end
30
31
  end
31
32
 
@@ -6,7 +6,7 @@ describe Listen::File do
6
6
  Listen::Record,
7
7
  add_dir: true,
8
8
  update_file: true,
9
- unset_path: true,
9
+ unset_path: true
10
10
  )
11
11
  end
12
12
 
@@ -116,17 +116,17 @@ describe Listen::File do
116
116
  let(:record_mtime) { stat_mtime.to_f }
117
117
 
118
118
  context 'with accurate stat times' do
119
- let(:stat_mtime) { Time.at(1401235714.123) }
120
- let(:stat_atime) { Time.at(1401235714.123) }
121
- let(:stat_ctime) { Time.at(1401235714.123) }
119
+ let(:stat_mtime) { Time.at(1_401_235_714.123) }
120
+ let(:stat_atime) { Time.at(1_401_235_714.123) }
121
+ let(:stat_ctime) { Time.at(1_401_235_714.123) }
122
122
  let(:record_mtime) { stat_mtime.to_f }
123
123
  it { should be_nil }
124
124
  end
125
125
 
126
126
  context 'with inaccurate stat times' do
127
- let(:stat_mtime) { Time.at(1401235714.0) }
128
- let(:stat_atime) { Time.at(1401235714.0) }
129
- let(:stat_ctime) { Time.at(1401235714.0) }
127
+ let(:stat_mtime) { Time.at(1_401_235_714.0) }
128
+ let(:stat_atime) { Time.at(1_401_235_714.0) }
129
+ let(:stat_ctime) { Time.at(1_401_235_714.0) }
130
130
 
131
131
  let(:record_mtime) { stat_mtime.to_f }
132
132
 
@@ -135,7 +135,7 @@ describe Listen::File do
135
135
 
136
136
  # NOTE: if real mtime is ???14.99, the
137
137
  # saved mtime is ???14.0
138
- let(:now) { Time.at(1401235716.00) }
138
+ let(:now) { Time.at(1_401_235_716.00) }
139
139
  it { should be_nil }
140
140
  end
141
141
 
@@ -144,17 +144,17 @@ describe Listen::File do
144
144
  # so saved mtime at ???14.0 means it could be
145
145
  # ???14.999, so ???15.999 could still be within 1 second
146
146
  # range
147
- let(:now) { Time.at(1401235715.999999) }
147
+ let(:now) { Time.at(1_401_235_715.999999) }
148
148
 
149
149
  before { allow(Time).to receive(:now) { now } }
150
150
 
151
151
  context 'without available md5' do
152
152
  let(:md5) { fail Errno::ENOENT }
153
153
 
154
- # Treat is as an ignored file, because chances are ... ...
154
+ # Treat it as a removed file, because chances are ...
155
155
  # whatever is listening for changes won't be able to deal
156
156
  # with the file either (e.g. because of permissions)
157
- it { should be nil }
157
+ it { should be :removed }
158
158
 
159
159
  it 'should not unset record' do
160
160
  expect(async_record).to_not receive(:unset_path)
@@ -229,23 +229,23 @@ describe Listen::File do
229
229
  subject { Listen::File.inaccurate_mac_time?(stat) }
230
230
 
231
231
  context 'with no accurate times' do
232
- let(:mtime) { Time.at(1234567.0) }
233
- let(:atime) { Time.at(1234567.0) }
234
- let(:ctime) { Time.at(1234567.0) }
232
+ let(:mtime) { Time.at(1_234_567.0) }
233
+ let(:atime) { Time.at(1_234_567.0) }
234
+ let(:ctime) { Time.at(1_234_567.0) }
235
235
  it { should be_truthy }
236
236
  end
237
237
 
238
238
  context 'with all accurate times' do
239
- let(:mtime) { Time.at(1234567.89) }
240
- let(:atime) { Time.at(1234567.89) }
241
- let(:ctime) { Time.at(1234567.89) }
239
+ let(:mtime) { Time.at(1_234_567.89) }
240
+ let(:atime) { Time.at(1_234_567.89) }
241
+ let(:ctime) { Time.at(1_234_567.89) }
242
242
  it { should be_falsey }
243
243
  end
244
244
 
245
245
  context 'with one accurate time' do
246
- let(:mtime) { Time.at(1234567.0) }
247
- let(:atime) { Time.at(1234567.89) }
248
- let(:ctime) { Time.at(1234567.0) }
246
+ let(:mtime) { Time.at(1_234_567.0) }
247
+ let(:atime) { Time.at(1_234_567.89) }
248
+ let(:ctime) { Time.at(1_234_567.0) }
249
249
  it { should be_falsey }
250
250
  end
251
251
  end