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 +4 -4
- data/Gemfile.lock +1 -9
- data/lib/rspec-interactive/client_output.rb +7 -0
- data/lib/rspec-interactive/stdio.rb +1 -40
- data/lib/rspec-interactive/string_output.rb +7 -0
- data/lib/rspec-interactive/threaded_output.rb +33 -0
- data/lib/rspec-interactive/version.rb +1 -1
- data/lib/rspec-interactive.rb +140 -77
- data/rspec-interactive.gemspec +0 -1
- data/runner/rspec-interactive-run +8 -4
- metadata +3 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1e00d8b9955bf056a3967733d54b89fdece90829b006b7d831de803670e33295
|
4
|
+
data.tar.gz: a5494e1160b97aa0b6c3e883e8457c5a6e6c2c54df1f26cd4d96c1ef15a4bbee
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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)
|
@@ -1,52 +1,13 @@
|
|
1
1
|
module RSpec
|
2
2
|
module Interactive
|
3
3
|
class Stdio
|
4
|
-
def self.
|
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
|
@@ -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
|
data/lib/rspec-interactive.rb
CHANGED
@@ -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
|
-
@
|
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
|
-
|
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
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
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
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
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
|
-
|
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
|
-
@
|
182
|
+
@rspec_mutex.synchronize do
|
183
|
+
begin
|
184
|
+
@runner = RSpec::Interactive::Runner.new(parse_args(args))
|
181
185
|
|
182
|
-
|
186
|
+
refresh
|
183
187
|
|
184
|
-
|
185
|
-
|
188
|
+
# Stop saving history in case a new Pry session is started for debugging.
|
189
|
+
Pry.config.history_save = false
|
186
190
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
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
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
+
# Run.
|
199
|
+
@runner.run
|
200
|
+
ensure
|
201
|
+
@runner = nil
|
198
202
|
|
199
|
-
|
200
|
-
|
203
|
+
# Reenable history
|
204
|
+
Pry.config.history_save = true
|
201
205
|
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
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
|
-
@
|
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
|
-
|
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 =
|
224
|
-
config.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
|
-
|
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?
|
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
|
-
@
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
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
|
data/rspec-interactive.gemspec
CHANGED
@@ -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
|
-
|
28
|
-
|
29
|
-
|
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.
|
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-
|
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
|