rspec-interactive 0.9.7 → 0.9.10

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