listen 2.7.11 → 2.7.12

Sign up to get free protection for your applications and to get access to all the features.
@@ -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