spin 0.7.0 → 0.7.1
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.
- data/lib/spin.rb +76 -64
- data/lib/spin/version.rb +1 -1
- metadata +3 -3
- data/lib/spin/test_process.rb +0 -21
data/lib/spin.rb
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
require 'spin/version'
|
|
2
2
|
require 'spin/hooks'
|
|
3
|
-
require 'spin/test_process'
|
|
4
3
|
require 'spin/logger'
|
|
5
4
|
require 'socket'
|
|
6
5
|
require 'tempfile' # Dir.tmpdir
|
|
@@ -17,8 +16,9 @@ module Spin
|
|
|
17
16
|
|
|
18
17
|
PUSH_FILE_SEPARATOR = '|'
|
|
19
18
|
ARGS_SEPARATOR = ' -- '
|
|
20
|
-
#
|
|
21
|
-
|
|
19
|
+
# Messages written to/read from the self-pipe queue.
|
|
20
|
+
SIGQUIT_MESSAGE = 'SIGQUIT'
|
|
21
|
+
SIGINT_MESSAGE = 'SIGINT'
|
|
22
22
|
|
|
23
23
|
class << self
|
|
24
24
|
def serve(options)
|
|
@@ -35,15 +35,66 @@ module Spin
|
|
|
35
35
|
|
|
36
36
|
open_socket do |socket|
|
|
37
37
|
preload(options) if root_path
|
|
38
|
+
self_read, self_write = IO.pipe
|
|
38
39
|
|
|
39
|
-
|
|
40
|
+
if options[:push_results]
|
|
41
|
+
logger.info "Pushing test results back to push processes"
|
|
42
|
+
else
|
|
43
|
+
trap('SIGQUIT') { sigquit_handler(self_write) }
|
|
44
|
+
end
|
|
45
|
+
trap('SIGINT') { sigint_handler(self_write) }
|
|
40
46
|
|
|
41
47
|
loop do
|
|
42
|
-
|
|
48
|
+
readable_io = ready_while do
|
|
49
|
+
IO.select([socket, self_read])[0][0]
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
if readable_io == self_read
|
|
53
|
+
# One of our signal handlers has fired
|
|
54
|
+
case readable_io.gets.strip
|
|
55
|
+
when SIGQUIT_MESSAGE
|
|
56
|
+
rerun_last_tests(options)
|
|
57
|
+
when SIGINT_MESSAGE
|
|
58
|
+
exit_server(socket)
|
|
59
|
+
end
|
|
60
|
+
else
|
|
61
|
+
# The socket must have had a new test written to it
|
|
62
|
+
run_pushed_tests(socket, options)
|
|
63
|
+
end
|
|
43
64
|
end
|
|
44
65
|
end
|
|
45
66
|
end
|
|
46
67
|
|
|
68
|
+
# This method is called when a SIGQUIT ought to be handled.
|
|
69
|
+
#
|
|
70
|
+
# Given the self-pipe +queue+, adds a SIGQUIT message to it. Message is
|
|
71
|
+
# *not* queued if the current process is not the Spin server process (i.e.
|
|
72
|
+
# it's a test process). Otherwise, more than one message would be added to
|
|
73
|
+
# the queue when Ctrl+\ is pressed.
|
|
74
|
+
#
|
|
75
|
+
def sigquit_handler(queue)
|
|
76
|
+
return unless server_process?
|
|
77
|
+
|
|
78
|
+
queue.puts(SIGQUIT_MESSAGE)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# This method is called when a SIGINT ought to be handled.
|
|
82
|
+
#
|
|
83
|
+
# Given the self-pipe +queue+, adds a SIGINT message to it. Message is
|
|
84
|
+
# *not* queued if either of these are true:
|
|
85
|
+
#
|
|
86
|
+
# 1. The current process is not the Spin server process (i.e. it's a test
|
|
87
|
+
# process). Instead, the signal is "bubbled up" by exiting.
|
|
88
|
+
#
|
|
89
|
+
# 2. The Spin server is not ready for a new command.
|
|
90
|
+
#
|
|
91
|
+
def sigint_handler(queue)
|
|
92
|
+
exit unless server_process?
|
|
93
|
+
return unless ready?
|
|
94
|
+
|
|
95
|
+
queue.puts(SIGINT_MESSAGE)
|
|
96
|
+
end
|
|
97
|
+
|
|
47
98
|
def logger
|
|
48
99
|
@logger ||= Spin::Logger.new
|
|
49
100
|
end
|
|
@@ -136,10 +187,6 @@ module Spin
|
|
|
136
187
|
end
|
|
137
188
|
|
|
138
189
|
def run_pushed_tests(socket, options)
|
|
139
|
-
rerun_last_tests_on_quit(options) unless options[:push_results]
|
|
140
|
-
|
|
141
|
-
notify_ready
|
|
142
|
-
|
|
143
190
|
# Since `spin push` reconnects each time it has new files for us we just
|
|
144
191
|
# need to accept(2) connections from it.
|
|
145
192
|
conn = socket.accept
|
|
@@ -172,36 +219,28 @@ module Spin
|
|
|
172
219
|
end
|
|
173
220
|
end
|
|
174
221
|
|
|
175
|
-
#
|
|
176
|
-
|
|
177
|
-
def rerun_last_tests_on_quit(options)
|
|
178
|
-
trap('QUIT') { sigquit_handler(options) }
|
|
179
|
-
end
|
|
180
|
-
|
|
181
|
-
# This method is called when a SIGQUIT ought to be handled.
|
|
182
|
-
def sigquit_handler(options)
|
|
183
|
-
# If the current process is not the Spin server process, ignore the
|
|
184
|
-
# signal by doing nothing.
|
|
185
|
-
return unless server_process?
|
|
186
|
-
|
|
222
|
+
# Reruns the last tests that were pushed.
|
|
223
|
+
def rerun_last_tests(options)
|
|
187
224
|
unless @last_files_ran
|
|
188
225
|
logger.fatal "Cannot rerun last tests, please push a file to Spin server first"
|
|
189
226
|
return
|
|
190
227
|
end
|
|
191
228
|
|
|
192
|
-
if test_process.alive?
|
|
193
|
-
logger.fatal "Cannot rerun last tests, test process #{test_process} still alive"
|
|
194
|
-
return
|
|
195
|
-
end
|
|
196
|
-
|
|
197
229
|
fork_and_run(@last_files_ran, nil, options.merge(:trailing_args => @last_trailing_args_used))
|
|
230
|
+
end
|
|
198
231
|
|
|
199
|
-
|
|
232
|
+
# Changes Spin server's "ready" state to +true+ while the given +block+
|
|
233
|
+
# executes. Returns the result of the +block+.
|
|
234
|
+
def ready_while(&block)
|
|
235
|
+
@ready = true
|
|
236
|
+
logger.info('Ready')
|
|
237
|
+
yield.tap { @ready = false }
|
|
200
238
|
end
|
|
201
239
|
|
|
202
|
-
#
|
|
203
|
-
|
|
204
|
-
|
|
240
|
+
# Returns Spin server's "ready" state. If +true+, this indicates that the
|
|
241
|
+
# server is available for new tests or commands.
|
|
242
|
+
def ready?
|
|
243
|
+
@ready
|
|
205
244
|
end
|
|
206
245
|
|
|
207
246
|
def preload(options)
|
|
@@ -252,38 +291,16 @@ module Spin
|
|
|
252
291
|
File.delete(file) if File.exist?(file)
|
|
253
292
|
socket = UNIXServer.open(file)
|
|
254
293
|
|
|
255
|
-
trap('SIGINT') { sigint_handler(socket) }
|
|
256
|
-
|
|
257
294
|
yield socket
|
|
258
295
|
ensure
|
|
259
296
|
File.delete(file) if file && File.exist?(file)
|
|
260
297
|
end
|
|
261
298
|
|
|
262
|
-
#
|
|
263
|
-
def
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
exit
|
|
267
|
-
|
|
268
|
-
if sigint_recently_sent?
|
|
269
|
-
socket.close
|
|
270
|
-
exit
|
|
271
|
-
else
|
|
272
|
-
set_last_sigint_sent
|
|
273
|
-
logger.info "Press Ctrl+C again (within #{SIGINT_TIME_WINDOW}s) to exit"
|
|
274
|
-
end
|
|
275
|
-
end
|
|
276
|
-
|
|
277
|
-
# Updates the timestamp when the last SIGINT was sent.
|
|
278
|
-
def set_last_sigint_sent
|
|
279
|
-
@last_sigint_sent = Time.now
|
|
280
|
-
end
|
|
281
|
-
|
|
282
|
-
# Returns +true+ if a SIGINT has been sent within the time window.
|
|
283
|
-
def sigint_recently_sent?
|
|
284
|
-
return if @last_sigint_sent.nil?
|
|
285
|
-
|
|
286
|
-
(Time.now - SIGINT_TIME_WINDOW) < @last_sigint_sent
|
|
299
|
+
# Exits the server process.
|
|
300
|
+
def exit_server(socket)
|
|
301
|
+
logger.info "Exiting"
|
|
302
|
+
socket.close
|
|
303
|
+
exit
|
|
287
304
|
end
|
|
288
305
|
|
|
289
306
|
def determine_test_framework
|
|
@@ -308,17 +325,12 @@ module Spin
|
|
|
308
325
|
path
|
|
309
326
|
end
|
|
310
327
|
|
|
311
|
-
# Returns (and caches) a TestProcess instance.
|
|
312
|
-
def test_process
|
|
313
|
-
@test_process ||= Spin::TestProcess.new
|
|
314
|
-
end
|
|
315
|
-
|
|
316
328
|
def fork_and_run(files, conn, options)
|
|
317
329
|
execute_hook(:before_fork)
|
|
318
330
|
# We fork(2) before loading the file so that our pristine preloaded
|
|
319
331
|
# environment is untouched. The child process will load whatever code it
|
|
320
332
|
# needs to, then it exits and we're back to the baseline preloaded app.
|
|
321
|
-
|
|
333
|
+
fork do
|
|
322
334
|
# To push the test results to the push process instead of having them
|
|
323
335
|
# displayed by the server, we reopen $stdout/$stderr to the open
|
|
324
336
|
# connection.
|
|
@@ -361,7 +373,7 @@ module Spin
|
|
|
361
373
|
# WAIT: We don't want the parent process handling multiple test runs at the same
|
|
362
374
|
# time because then we'd need to deal with multiple test databases, and
|
|
363
375
|
# that destroys the idea of being simple to use.
|
|
364
|
-
|
|
376
|
+
Process.wait
|
|
365
377
|
end
|
|
366
378
|
|
|
367
379
|
def socket_file
|
data/lib/spin/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: spin
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.7.
|
|
4
|
+
version: 0.7.1
|
|
5
5
|
prerelease:
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2013-
|
|
12
|
+
date: 2013-08-18 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: rake
|
|
@@ -60,7 +60,6 @@ files:
|
|
|
60
60
|
- lib/spin/cli.rb
|
|
61
61
|
- lib/spin/hooks.rb
|
|
62
62
|
- lib/spin/logger.rb
|
|
63
|
-
- lib/spin/test_process.rb
|
|
64
63
|
- lib/spin/version.rb
|
|
65
64
|
- lib/spin.rb
|
|
66
65
|
- spec/integration_spec.rb
|
|
@@ -91,3 +90,4 @@ specification_version: 3
|
|
|
91
90
|
summary: Spin preloads your Rails environment to speed up your autotest(ish) workflow.
|
|
92
91
|
test_files:
|
|
93
92
|
- spec/integration_spec.rb
|
|
93
|
+
has_rdoc:
|
data/lib/spin/test_process.rb
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
module Spin
|
|
2
|
-
class TestProcess
|
|
3
|
-
attr_accessor :pid
|
|
4
|
-
|
|
5
|
-
# Use wait(2) to block execution until the test process has finished. When
|
|
6
|
-
# finished, reset the assigned pid.
|
|
7
|
-
def wait
|
|
8
|
-
Process.wait
|
|
9
|
-
@pid = nil
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
# Returns +true+ if the test process is alive.
|
|
13
|
-
def alive?
|
|
14
|
-
!@pid.nil?
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def to_s
|
|
18
|
-
@pid.to_s
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
end
|