rspec-interactive 0.9.7 → 0.9.10

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: 19e7c3fad7abad85f3523490ddfcfd3d6091e042d99fd940c6a9a19991e7dc06
4
- data.tar.gz: 02d25e506765d4f0c40b8b3e64ae751f6da34e06af9e845830bdc05071fc8112
3
+ metadata.gz: 1e00d8b9955bf056a3967733d54b89fdece90829b006b7d831de803670e33295
4
+ data.tar.gz: a5494e1160b97aa0b6c3e883e8457c5a6e6c2c54df1f26cd4d96c1ef15a4bbee
5
5
  SHA512:
6
- metadata.gz: 89b49ff9d0e888b8304e0c70a2fded4dd780381750fed960af5f282246accc6ae6d52eb71c5402d2be31bfb9a827c64e04cffcb7f4935d12d97e3d632843a8bf
7
- data.tar.gz: 36320560582c44d1459e0590aa469f56e70b5411d8c3c88a499ca9f46c5075163aa3778869f65bb5cfd85dc3fc7dd196fff65c87733b5b0057352353583215c6
6
+ metadata.gz: be9f403faf9fbfa42e38b0a07c70a4a338bc45cc6d9dc679e262653d3bc0a72d4ee1e15341b1693db3b51b0d2436da71b54525d22066fddd02d71a658c3ffb04
7
+ data.tar.gz: 0f9c77f7d09b008164bf802fa5507b46d6bb43de0d37e5b8aadc414751d919dc9347bf37262b65503e617259e9414a41d6c2e8fa082f77c8328790177b21fad0
data/Gemfile.lock CHANGED
@@ -1,8 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rspec-interactive (0.9.6)
5
- listen
4
+ rspec-interactive (0.9.9)
6
5
  pry
7
6
  rspec-core
8
7
  rspec-teamcity (= 1.0.0)
@@ -12,11 +11,7 @@ GEM
12
11
  specs:
13
12
  coderay (1.1.3)
14
13
  diff-lcs (1.4.4)
15
- ffi (1.15.5)
16
14
  ffi (1.15.5-java)
17
- listen (3.7.1)
18
- rb-fsevent (~> 0.10, >= 0.10.3)
19
- rb-inotify (~> 0.9, >= 0.9.10)
20
15
  method_source (1.0.0)
21
16
  pry (0.14.1)
22
17
  coderay (~> 1.1)
@@ -25,9 +20,6 @@ GEM
25
20
  coderay (~> 1.1)
26
21
  method_source (~> 1.0)
27
22
  spoon (~> 0.0)
28
- rb-fsevent (0.11.1)
29
- rb-inotify (0.10.1)
30
- ffi (~> 1.0)
31
23
  rspec (3.9.0)
32
24
  rspec-core (~> 3.9.0)
33
25
  rspec-expectations (~> 3.9.0)
@@ -17,6 +17,13 @@ module RSpec
17
17
  @client.print(str.to_s + "\n")
18
18
  end
19
19
 
20
+ def flush
21
+ end
22
+
23
+ def closed?
24
+ @client.closed?
25
+ end
26
+
20
27
  def string
21
28
  @output
22
29
  end
@@ -1,52 +1,13 @@
1
1
  module RSpec
2
2
  module Interactive
3
3
  class Stdio
4
- def self.capture2(stdout:, stderr:)
4
+ def self.capture(stdout:, stderr:)
5
5
  old_stdout, old_stderr = $stdout, $stderr
6
6
  $stdout, $stderr = stdout, stderr
7
7
  yield
8
8
  ensure
9
9
  $stdout, $stderr = old_stdout, old_stderr
10
10
  end
11
-
12
- def self.capture(stdout:, stderr:)
13
- raise ArgumentError, 'missing block' unless block_given?
14
-
15
- old_stdout, old_stderr = STDOUT.dup, STDERR.dup
16
-
17
- IO.pipe do |stdout_read, stdout_write|
18
- IO.pipe do |stderr_read, stderr_write|
19
- STDOUT.reopen(stdout_write)
20
- STDERR.reopen(stderr_write)
21
-
22
- stdout_write.close
23
- stderr_write.close
24
-
25
- stdout_thread = Thread.new do
26
- while line = stdout_read.gets do
27
- stdout.print(line)
28
- end
29
- end
30
-
31
- stderr_thread = Thread.new do
32
- while line = stderr_read.gets do
33
- stderr.print(line)
34
- end
35
- end
36
-
37
- begin
38
- yield
39
- ensure
40
- # TODO: should the threads be killed here?
41
- STDOUT.reopen old_stdout
42
- STDERR.reopen old_stderr
43
- end
44
-
45
- stdout_thread.join
46
- stderr_thread.join
47
- end
48
- end
49
- end
50
11
  end
51
12
  end
52
13
  end
@@ -18,6 +18,13 @@ module RSpec
18
18
  def print(str = "")
19
19
  @string += str.to_s
20
20
  end
21
+
22
+ def flush
23
+ end
24
+
25
+ def closed?
26
+ @client.closed?
27
+ end
21
28
  end
22
29
  end
23
30
  end
@@ -0,0 +1,33 @@
1
+ module RSpec
2
+ module Interactive
3
+ class ThreadedOutput
4
+ attr_reader :string
5
+
6
+ def initialize(thread_map:, default:)
7
+ @thread_map = thread_map
8
+ @default = default
9
+ @string = ''
10
+ end
11
+
12
+ def write(name, str = "")
13
+ (@thread_map[Thread.current] || @default).write(name, str)
14
+ end
15
+
16
+ def puts(str = "")
17
+ (@thread_map[Thread.current] || @default).puts(str)
18
+ end
19
+
20
+ def print(str = "")
21
+ (@thread_map[Thread.current] || @default).puts(str)
22
+ end
23
+
24
+ def flush
25
+ (@thread_map[Thread.current] || @default).flush
26
+ end
27
+
28
+ def closed?
29
+ (@thread_map[Thread.current] || @default).closed?
30
+ end
31
+ end
32
+ end
33
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RSpec
4
4
  module Interactive
5
- VERSION = "0.9.7"
5
+ VERSION = "0.9.10"
6
6
  end
7
7
  end
@@ -1,5 +1,5 @@
1
+ require 'find'
1
2
  require 'json'
2
- require 'listen'
3
3
  require 'pry'
4
4
  require 'readline'
5
5
  require 'rspec/core'
@@ -19,6 +19,7 @@ require 'rspec-interactive/rubo_cop_command'
19
19
  require 'rspec-interactive/runner'
20
20
  require 'rspec-interactive/stdio'
21
21
  require 'rspec-interactive/string_output'
22
+ require 'rspec-interactive/threaded_output'
22
23
 
23
24
  module RSpec
24
25
  module Interactive
@@ -46,8 +47,7 @@ module RSpec
46
47
  @history_file = history_file
47
48
  @updated_files = []
48
49
  @stty_save = %x`stty -g`.chomp
49
- @file_change_mutex = Mutex.new
50
- @command_mutex = Mutex.new
50
+ @rspec_mutex = Mutex.new
51
51
  @output_stream = output_stream
52
52
  @input_stream = input_stream
53
53
  @error_stream = error_stream
@@ -59,28 +59,45 @@ module RSpec
59
59
  check_rails
60
60
  maybe_trap_interrupt
61
61
  configure_pry
62
+ configure_watched_files
62
63
 
63
64
  @startup_thread = Thread.start do
64
- @config_cache.record_configuration { @configuration.configure_rspec.call }
65
- start_file_watcher
66
-
65
+ Thread.current.report_on_exception = false
67
66
  if server
68
67
  @server_thread = Thread.start do
69
68
  server = TCPServer.new port
70
69
 
71
- while client = server.accept
72
- request = client.gets
73
- args = Shellwords.split(request)
74
- rspec_for_server(client, args)
75
- client.close
70
+ while true
71
+ break unless client = server.accept
72
+ begin
73
+ request = client.gets
74
+ args = Shellwords.split(request)
75
+ rspec_for_server(client, args)
76
+ rescue StandardError => e
77
+ # It would be nice to log to the client here but it might be
78
+ # disconnected or disconnect before we successfully write. Any
79
+ # error here is unexpected so just log to the console.
80
+ @output_stream.puts
81
+ @output_stream.puts 'error handling client request'
82
+ log_exception(@output_stream, e)
83
+ ensure
84
+ client.close
85
+ end
76
86
  end
77
87
  end
78
88
  end
89
+
90
+ @startup_output = StringOutput.new
91
+ output = ThreadedOutput.new(thread_map: { Thread.current => @startup_output }, default: @output_stream)
92
+
93
+ Stdio.capture(stdout: output, stderr: output) do
94
+ @config_cache.record_configuration { @configuration.configure_rspec.call }
95
+ end
79
96
  end
80
97
 
81
98
  Pry.start
82
- @listener.stop if @listener
83
99
  @server_thread.exit if @server_thread
100
+ @startup_thread.exit if @startup_thread
84
101
  0
85
102
  end
86
103
 
@@ -113,18 +130,6 @@ module RSpec
113
130
  end
114
131
  end
115
132
 
116
- def self.start_file_watcher
117
- return if @configuration.watch_dirs.empty?
118
-
119
- # Only polling seems to work in Docker.
120
- @listener = Listen.to(*@configuration.watch_dirs, only: /\.rb$/, force_polling: true) do |modified, added|
121
- @file_change_mutex.synchronize do
122
- @updated_files.concat(added + modified)
123
- end
124
- end
125
- @listener.start
126
- end
127
-
128
133
  def self.configure_pry
129
134
  # Set up IO.
130
135
  Pry.config.input = Readline
@@ -138,19 +143,16 @@ module RSpec
138
143
  Pry.config.history_file = @history_file
139
144
  end
140
145
 
141
- def self.refresh
142
- @file_change_mutex.synchronize do
143
- @updated_files.uniq.each do |filename|
144
- @output_stream.puts "changed: #{filename}"
145
- trace = TracePoint.new(:class) do |tp|
146
- @configuration.on_class_load.call(tp.self)
147
- end
148
- trace.enable
149
- load filename
150
- trace.disable
151
- @output_stream.puts
146
+ def self.refresh(output: @output_stream)
147
+ get_updated_files.each do |filename|
148
+ output.puts "changed: #{filename}"
149
+ trace = TracePoint.new(:class) do |tp|
150
+ @configuration.on_class_load.call(tp.self)
152
151
  end
153
- @updated_files.clear
152
+ trace.enable
153
+ load filename
154
+ trace.disable
155
+ output.puts
154
156
  end
155
157
  @configuration.refresh.call
156
158
  end
@@ -177,51 +179,60 @@ module RSpec
177
179
  end
178
180
 
179
181
  def self.rspec(args)
180
- @runner = RSpec::Interactive::Runner.new(parse_args(args))
182
+ @rspec_mutex.synchronize do
183
+ begin
184
+ @runner = RSpec::Interactive::Runner.new(parse_args(args))
181
185
 
182
- refresh
186
+ refresh
183
187
 
184
- # Stop saving history in case a new Pry session is started for debugging.
185
- Pry.config.history_save = false
188
+ # Stop saving history in case a new Pry session is started for debugging.
189
+ Pry.config.history_save = false
186
190
 
187
- # RSpec::Interactive-specific RSpec configuration
188
- RSpec.configure do |config|
189
- config.error_stream = @error_stream
190
- config.output_stream = @output_stream
191
- config.start_time = RSpec::Core::Time.now
192
- end
191
+ # RSpec::Interactive-specific RSpec configuration
192
+ RSpec.configure do |config|
193
+ config.error_stream = @error_stream
194
+ config.output_stream = @output_stream
195
+ config.start_time = RSpec::Core::Time.now
196
+ end
193
197
 
194
- # Run.
195
- @runner.run
196
- ensure
197
- @runner = nil
198
+ # Run.
199
+ @runner.run
200
+ ensure
201
+ @runner = nil
198
202
 
199
- # Reenable history
200
- Pry.config.history_save = true
203
+ # Reenable history
204
+ Pry.config.history_save = true
201
205
 
202
- # Reset
203
- RSpec.clear_examples
204
- RSpec.reset
205
- @config_cache.replay_configuration
206
+ # Reset
207
+ RSpec.clear_examples
208
+ RSpec.reset
209
+ @config_cache.replay_configuration
210
+ end
211
+ end
206
212
  end
207
213
 
208
214
  def self.rspec_for_server(client, args)
209
- @command_mutex.synchronize do
210
- output = ClientOutput.new(client)
215
+ @rspec_mutex.synchronize do
211
216
  disable_pry = ENV['DISABLE_PRY']
217
+ output = ClientOutput.new(client)
218
+
219
+ ENV['TEAMCITY_RAKE_RUNNER_DEBUG_OUTPUT_CAPTURER_ENABLED'] = 'false'
220
+ Rake::TeamCity::RunnerCommon.class_variable_set(:@@original_stdout, output)
221
+
222
+ return unless await_startup(output: output)
212
223
 
213
224
  Stdio.capture(stdout: output, stderr: output) do
214
225
  # Prevent the debugger from being used. The server isn't interactive.
215
226
  ENV['DISABLE_PRY'] = 'true'
216
227
 
217
- @runner = RSpec::Interactive::Runner.new(parse_args(args))
228
+ runner = RSpec::Interactive::Runner.new(parse_args(args))
218
229
 
219
- refresh
230
+ refresh(output: output)
220
231
 
221
232
  # RSpec::Interactive-specific RSpec configuration
222
233
  RSpec.configure do |config|
223
- config.error_stream = @error_stream
224
- config.output_stream = @output_stream
234
+ config.error_stream = output
235
+ config.output_stream = output
225
236
  config.start_time = RSpec::Core::Time.now
226
237
  end
227
238
 
@@ -237,14 +248,17 @@ module RSpec
237
248
  RSpec.configuration.formatter = Spec::Runner::Formatter::TeamcityFormatter
238
249
 
239
250
  # Run.
240
- @runner.run
251
+ runner.run
252
+ rescue Errno::EPIPE, IOError
253
+ # Don't care.
241
254
  ensure
242
- @runner = nil
243
255
  ENV['DISABLE_PRY'] = disable_pry
256
+ runner = nil
244
257
 
245
258
  # Reset
246
259
  RSpec.clear_examples
247
260
  RSpec.reset
261
+
248
262
  @config_cache.replay_configuration
249
263
  end
250
264
  end
@@ -259,23 +273,72 @@ module RSpec
259
273
  end
260
274
 
261
275
  def self.eval(line, options, &block)
262
- if line.nil? || Thread.current.thread_variable_get('holding_lock')
276
+ return yield if line.nil? # EOF
277
+ return yield if line.empty? # blank line
278
+
279
+ if await_startup
263
280
  yield
264
281
  else
265
- @command_mutex.synchronize do
266
- Thread.current.thread_variable_set('holding_lock', true)
267
- if @startup_thread
268
- if @startup_thread.alive?
269
- @output_stream.puts 'waiting for configure_rspec...'
270
- end
271
- @startup_thread.join
272
- @startup_thread = nil
273
- end
274
- yield
275
- ensure
276
- Thread.current.thread_variable_set('holding_lock', false)
282
+ @output_stream.puts
283
+ true
284
+ end
285
+ end
286
+
287
+ def self.await_startup(output: @output_stream)
288
+ return true unless @startup_thread
289
+
290
+ if @startup_thread.alive?
291
+ output.puts 'waiting for configure_rspec...'
292
+ end
293
+
294
+ begin
295
+ @startup_thread.join
296
+ @startup_thread = nil
297
+ print_startup_output(output: output)
298
+ true
299
+ rescue Interrupt
300
+ false
301
+ rescue StandardError => e
302
+ print_startup_output(output: output)
303
+ output.puts 'configure_rspec failed'
304
+ log_exception(output, e)
305
+ false
306
+ end
307
+ end
308
+
309
+ def self.log_exception(output, e)
310
+ output.puts "#{e.backtrace[0]}: #{e.message} (#{e.class})"
311
+ e.backtrace[1..-1].each { |b| output.puts "\t#{b}" }
312
+ end
313
+
314
+ def self.print_startup_output(output: @output_stream)
315
+ return if @startup_output.nil? || @startup_output.string.empty?
316
+
317
+ output.puts(@startup_output.string)
318
+ @startup_output = nil
319
+ end
320
+
321
+ def self.configure_watched_files
322
+ @watched_files = get_watched_files
323
+ end
324
+
325
+ def self.get_watched_files
326
+ return Set.new if @configuration.watch_dirs.empty?
327
+ entries = Find.find(*@configuration.watch_dirs).flat_map do |file|
328
+ if FileTest.file?(file)
329
+ [[file, File.mtime(file).to_i]]
330
+ else
331
+ []
277
332
  end
278
333
  end
334
+ entries.to_set
335
+ end
336
+
337
+ def self.get_updated_files
338
+ new_watched_files = get_watched_files
339
+ difference = new_watched_files - @watched_files
340
+ @watched_files = new_watched_files
341
+ difference.map(&:first)
279
342
  end
280
343
  end
281
344
  end
@@ -27,6 +27,5 @@ Gem::Specification.new do |spec|
27
27
 
28
28
  spec.add_dependency 'rspec-core'
29
29
  spec.add_dependency 'rspec-teamcity', '1.0.0'
30
- spec.add_dependency 'listen'
31
30
  spec.add_dependency 'pry'
32
31
  end
@@ -24,8 +24,12 @@ parser = OptionParser.new do |opts|
24
24
  end.parse
25
25
 
26
26
  server = TCPSocket.open(@options[:host], @options[:port])
27
- server.puts ARGV.map{ |arg| Shellwords.escape arg }.join(' ')
28
- while response = server.gets do
29
- puts response
27
+ begin
28
+ server.puts ARGV.map{ |arg| Shellwords.escape arg }.join(' ')
29
+ server.close_write
30
+ while response = server.gets do
31
+ puts response
32
+ end
33
+ ensure
34
+ server.close
30
35
  end
31
- server.close
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-interactive
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.7
4
+ version: 0.9.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Dower
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-02-26 00:00:00.000000000 Z
11
+ date: 2022-02-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec-core
@@ -38,20 +38,6 @@ dependencies:
38
38
  - - '='
39
39
  - !ruby/object:Gem::Version
40
40
  version: 1.0.0
41
- - !ruby/object:Gem::Dependency
42
- name: listen
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: '0'
48
- type: :runtime
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: '0'
55
41
  - !ruby/object:Gem::Dependency
56
42
  name: pry
57
43
  requirement: !ruby/object:Gem::Requirement
@@ -103,6 +89,7 @@ files:
103
89
  - lib/rspec-interactive/runner.rb
104
90
  - lib/rspec-interactive/stdio.rb
105
91
  - lib/rspec-interactive/string_output.rb
92
+ - lib/rspec-interactive/threaded_output.rb
106
93
  - lib/rspec-interactive/version.rb
107
94
  - lib/teamcity/spec/runner/formatter/teamcity/formatter.rb
108
95
  - rspec-interactive.gemspec