rubygems-test 0.1.2 → 0.1.3
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/gems/test-gem-0.0.0.gem +0 -0
- data/lib/open4.rb +401 -0
- data/lib/rubygems/commands/test_command.rb +21 -18
- data/test/test_execute.rb +1 -2
- metadata +4 -3
data/gems/test-gem-0.0.0.gem
CHANGED
Binary file
|
data/lib/open4.rb
ADDED
@@ -0,0 +1,401 @@
|
|
1
|
+
# vim: ts=2:sw=2:sts=2:et:fdm=marker
|
2
|
+
require 'fcntl'
|
3
|
+
require 'timeout'
|
4
|
+
require 'thread'
|
5
|
+
|
6
|
+
module Open4
|
7
|
+
#--{{{
|
8
|
+
VERSION = '1.0.1'
|
9
|
+
def self.version() VERSION end
|
10
|
+
|
11
|
+
class Error < ::StandardError; end
|
12
|
+
|
13
|
+
def popen4(*cmd, &b)
|
14
|
+
#--{{{
|
15
|
+
pw, pr, pe, ps = IO.pipe, IO.pipe, IO.pipe, IO.pipe
|
16
|
+
|
17
|
+
verbose = $VERBOSE
|
18
|
+
begin
|
19
|
+
$VERBOSE = nil
|
20
|
+
ps.first.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
21
|
+
ps.last.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
22
|
+
|
23
|
+
cid = fork {
|
24
|
+
pw.last.close
|
25
|
+
STDIN.reopen pw.first
|
26
|
+
pw.first.close
|
27
|
+
|
28
|
+
pr.first.close
|
29
|
+
STDOUT.reopen pr.last
|
30
|
+
pr.last.close
|
31
|
+
|
32
|
+
pe.first.close
|
33
|
+
STDERR.reopen pe.last
|
34
|
+
pe.last.close
|
35
|
+
|
36
|
+
STDOUT.sync = STDERR.sync = true
|
37
|
+
|
38
|
+
begin
|
39
|
+
exec(*cmd)
|
40
|
+
raise 'forty-two'
|
41
|
+
rescue Exception => e
|
42
|
+
Marshal.dump(e, ps.last)
|
43
|
+
ps.last.flush
|
44
|
+
end
|
45
|
+
ps.last.close unless (ps.last.closed?)
|
46
|
+
exit!
|
47
|
+
}
|
48
|
+
ensure
|
49
|
+
$VERBOSE = verbose
|
50
|
+
end
|
51
|
+
|
52
|
+
[pw.first, pr.last, pe.last, ps.last].each{|fd| fd.close}
|
53
|
+
|
54
|
+
begin
|
55
|
+
e = Marshal.load ps.first
|
56
|
+
raise(Exception === e ? e : "unknown failure!")
|
57
|
+
rescue EOFError # If we get an EOF error, then the exec was successful
|
58
|
+
42
|
59
|
+
ensure
|
60
|
+
ps.first.close
|
61
|
+
end
|
62
|
+
|
63
|
+
pw.last.sync = true
|
64
|
+
|
65
|
+
pi = [pw.last, pr.first, pe.first]
|
66
|
+
|
67
|
+
if b
|
68
|
+
begin
|
69
|
+
b[cid, *pi]
|
70
|
+
Process.waitpid2(cid).last
|
71
|
+
ensure
|
72
|
+
pi.each{|fd| fd.close unless fd.closed?}
|
73
|
+
end
|
74
|
+
else
|
75
|
+
[cid, pw.last, pr.first, pe.first]
|
76
|
+
end
|
77
|
+
#--}}}
|
78
|
+
end
|
79
|
+
alias open4 popen4
|
80
|
+
module_function :popen4
|
81
|
+
module_function :open4
|
82
|
+
|
83
|
+
class SpawnError < Error
|
84
|
+
#--{{{
|
85
|
+
attr 'cmd'
|
86
|
+
attr 'status'
|
87
|
+
attr 'signals'
|
88
|
+
def exitstatus
|
89
|
+
@status.exitstatus
|
90
|
+
end
|
91
|
+
def initialize cmd, status
|
92
|
+
@cmd, @status = cmd, status
|
93
|
+
@signals = {}
|
94
|
+
if status.signaled?
|
95
|
+
@signals['termsig'] = status.termsig
|
96
|
+
@signals['stopsig'] = status.stopsig
|
97
|
+
end
|
98
|
+
sigs = @signals.map{|k,v| "#{ k }:#{ v.inspect }"}.join(' ')
|
99
|
+
super "cmd <#{ cmd }> failed with status <#{ exitstatus.inspect }> signals <#{ sigs }>"
|
100
|
+
end
|
101
|
+
#--}}}
|
102
|
+
end
|
103
|
+
|
104
|
+
class ThreadEnsemble
|
105
|
+
#--{{{
|
106
|
+
attr 'threads'
|
107
|
+
|
108
|
+
def initialize cid
|
109
|
+
@cid, @threads, @argv, @done, @running = cid, [], [], Queue.new, false
|
110
|
+
@killed = false
|
111
|
+
end
|
112
|
+
|
113
|
+
def add_thread *a, &b
|
114
|
+
@running ? raise : (@argv << [a, b])
|
115
|
+
end
|
116
|
+
|
117
|
+
#
|
118
|
+
# take down process more nicely
|
119
|
+
#
|
120
|
+
def killall
|
121
|
+
c = Thread.critical
|
122
|
+
return nil if @killed
|
123
|
+
Thread.critical = true
|
124
|
+
(@threads - [Thread.current]).each{|t| t.kill rescue nil}
|
125
|
+
@killed = true
|
126
|
+
ensure
|
127
|
+
Thread.critical = c
|
128
|
+
end
|
129
|
+
|
130
|
+
def run
|
131
|
+
@running = true
|
132
|
+
|
133
|
+
begin
|
134
|
+
@argv.each do |a, b|
|
135
|
+
@threads << Thread.new(*a) do |*a|
|
136
|
+
begin
|
137
|
+
b[*a]
|
138
|
+
ensure
|
139
|
+
killall rescue nil if $!
|
140
|
+
@done.push Thread.current
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
rescue
|
145
|
+
killall
|
146
|
+
raise
|
147
|
+
ensure
|
148
|
+
all_done
|
149
|
+
end
|
150
|
+
|
151
|
+
@threads.map{|t| t.value}
|
152
|
+
end
|
153
|
+
|
154
|
+
def all_done
|
155
|
+
@threads.size.times{ @done.pop }
|
156
|
+
end
|
157
|
+
#--}}}
|
158
|
+
end
|
159
|
+
|
160
|
+
def to timeout = nil
|
161
|
+
#--{{{
|
162
|
+
Timeout.timeout(timeout){ yield }
|
163
|
+
#--}}}
|
164
|
+
end
|
165
|
+
module_function :to
|
166
|
+
|
167
|
+
def new_thread *a, &b
|
168
|
+
#--{{{
|
169
|
+
cur = Thread.current
|
170
|
+
Thread.new(*a) do |*a|
|
171
|
+
begin
|
172
|
+
b[*a]
|
173
|
+
rescue Exception => e
|
174
|
+
cur.raise e
|
175
|
+
end
|
176
|
+
end
|
177
|
+
#--}}}
|
178
|
+
end
|
179
|
+
module_function :new_thread
|
180
|
+
|
181
|
+
def getopts opts = {}
|
182
|
+
#--{{{
|
183
|
+
lambda do |*args|
|
184
|
+
keys, default, ignored = args
|
185
|
+
catch('opt') do
|
186
|
+
[keys].flatten.each do |key|
|
187
|
+
[key, key.to_s, key.to_s.intern].each do |key|
|
188
|
+
throw 'opt', opts[key] if opts.has_key?(key)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
default
|
192
|
+
end
|
193
|
+
end
|
194
|
+
#--}}}
|
195
|
+
end
|
196
|
+
module_function :getopts
|
197
|
+
|
198
|
+
def relay src, dst = nil, t = nil
|
199
|
+
#--{{{
|
200
|
+
send_dst =
|
201
|
+
if dst.respond_to?(:call)
|
202
|
+
lambda{|buf| dst.call(buf)}
|
203
|
+
else
|
204
|
+
lambda{|buf| dst << buf}
|
205
|
+
end
|
206
|
+
|
207
|
+
unless src.nil?
|
208
|
+
if src.respond_to? :gets
|
209
|
+
while buf = to(t){ src.gets }
|
210
|
+
send_dst[buf]
|
211
|
+
end
|
212
|
+
|
213
|
+
elsif src.respond_to? :each
|
214
|
+
q = Queue.new
|
215
|
+
th = nil
|
216
|
+
|
217
|
+
timer_set = lambda do |t|
|
218
|
+
th = new_thread{ to(t){ q.pop } }
|
219
|
+
end
|
220
|
+
|
221
|
+
timer_cancel = lambda do |t|
|
222
|
+
th.kill if th rescue nil
|
223
|
+
end
|
224
|
+
|
225
|
+
timer_set[t]
|
226
|
+
begin
|
227
|
+
src.each do |buf|
|
228
|
+
timer_cancel[t]
|
229
|
+
send_dst[buf]
|
230
|
+
timer_set[t]
|
231
|
+
end
|
232
|
+
ensure
|
233
|
+
timer_cancel[t]
|
234
|
+
end
|
235
|
+
|
236
|
+
elsif src.respond_to? :read
|
237
|
+
buf = to(t){ src.read }
|
238
|
+
send_dst[buf]
|
239
|
+
|
240
|
+
else
|
241
|
+
buf = to(t){ src.to_s }
|
242
|
+
send_dst[buf]
|
243
|
+
end
|
244
|
+
end
|
245
|
+
#--}}}
|
246
|
+
end
|
247
|
+
module_function :relay
|
248
|
+
|
249
|
+
def spawn arg, *argv
|
250
|
+
#--{{{
|
251
|
+
argv.unshift(arg)
|
252
|
+
opts = ((argv.size > 1 and Hash === argv.last) ? argv.pop : {})
|
253
|
+
argv.flatten!
|
254
|
+
cmd = argv.join(' ')
|
255
|
+
|
256
|
+
|
257
|
+
getopt = getopts opts
|
258
|
+
|
259
|
+
ignore_exit_failure = getopt[ 'ignore_exit_failure', getopt['quiet', false] ]
|
260
|
+
ignore_exec_failure = getopt[ 'ignore_exec_failure', !getopt['raise', true] ]
|
261
|
+
exitstatus = getopt[ %w( exitstatus exit_status status ) ]
|
262
|
+
stdin = getopt[ %w( stdin in i 0 ) << 0 ]
|
263
|
+
stdout = getopt[ %w( stdout out o 1 ) << 1 ]
|
264
|
+
stderr = getopt[ %w( stderr err e 2 ) << 2 ]
|
265
|
+
pid = getopt[ 'pid' ]
|
266
|
+
timeout = getopt[ %w( timeout spawn_timeout ) ]
|
267
|
+
stdin_timeout = getopt[ %w( stdin_timeout ) ]
|
268
|
+
stdout_timeout = getopt[ %w( stdout_timeout io_timeout ) ]
|
269
|
+
stderr_timeout = getopt[ %w( stderr_timeout ) ]
|
270
|
+
status = getopt[ %w( status ) ]
|
271
|
+
cwd = getopt[ %w( cwd dir ) ]
|
272
|
+
|
273
|
+
exitstatus =
|
274
|
+
case exitstatus
|
275
|
+
when TrueClass, FalseClass
|
276
|
+
ignore_exit_failure = true if exitstatus
|
277
|
+
[0]
|
278
|
+
else
|
279
|
+
[*(exitstatus || 0)].map{|i| Integer i}
|
280
|
+
end
|
281
|
+
|
282
|
+
stdin ||= '' if stdin_timeout
|
283
|
+
stdout ||= '' if stdout_timeout
|
284
|
+
stderr ||= '' if stderr_timeout
|
285
|
+
|
286
|
+
started = false
|
287
|
+
|
288
|
+
status =
|
289
|
+
begin
|
290
|
+
chdir(cwd) do
|
291
|
+
Timeout::timeout(timeout) do
|
292
|
+
popen4(*argv) do |c, i, o, e|
|
293
|
+
started = true
|
294
|
+
|
295
|
+
%w( replace pid= << push update ).each do |msg|
|
296
|
+
break(pid.send(msg, c)) if pid.respond_to? msg
|
297
|
+
end
|
298
|
+
|
299
|
+
te = ThreadEnsemble.new c
|
300
|
+
|
301
|
+
te.add_thread(i, stdin) do |i, stdin|
|
302
|
+
relay stdin, i, stdin_timeout
|
303
|
+
i.close rescue nil
|
304
|
+
end
|
305
|
+
|
306
|
+
te.add_thread(o, stdout) do |o, stdout|
|
307
|
+
relay o, stdout, stdout_timeout
|
308
|
+
end
|
309
|
+
|
310
|
+
te.add_thread(e, stderr) do |o, stderr|
|
311
|
+
relay e, stderr, stderr_timeout
|
312
|
+
end
|
313
|
+
|
314
|
+
te.run
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
rescue
|
319
|
+
raise unless(not started and ignore_exec_failure)
|
320
|
+
end
|
321
|
+
|
322
|
+
raise SpawnError.new(cmd, status) unless
|
323
|
+
(ignore_exit_failure or (status.nil? and ignore_exec_failure) or exitstatus.include?(status.exitstatus))
|
324
|
+
|
325
|
+
status
|
326
|
+
#--}}}
|
327
|
+
end
|
328
|
+
module_function :spawn
|
329
|
+
|
330
|
+
def chdir cwd, &block
|
331
|
+
return(block.call Dir.pwd) unless cwd
|
332
|
+
Dir.chdir cwd, &block
|
333
|
+
end
|
334
|
+
module_function :chdir
|
335
|
+
|
336
|
+
def background arg, *argv
|
337
|
+
#--{{{
|
338
|
+
require 'thread'
|
339
|
+
q = Queue.new
|
340
|
+
opts = { 'pid' => q, :pid => q }
|
341
|
+
case argv.last
|
342
|
+
when Hash
|
343
|
+
argv.last.update opts
|
344
|
+
else
|
345
|
+
argv.push opts
|
346
|
+
end
|
347
|
+
thread = Thread.new(arg, argv){|arg, argv| spawn arg, *argv}
|
348
|
+
sc = class << thread; self; end
|
349
|
+
sc.module_eval {
|
350
|
+
define_method(:pid){ @pid ||= q.pop }
|
351
|
+
define_method(:spawn_status){ @spawn_status ||= value }
|
352
|
+
define_method(:exitstatus){ @exitstatus ||= spawn_status.exitstatus }
|
353
|
+
}
|
354
|
+
thread
|
355
|
+
#--}}}
|
356
|
+
end
|
357
|
+
alias bg background
|
358
|
+
module_function :background
|
359
|
+
module_function :bg
|
360
|
+
|
361
|
+
def maim pid, opts = {}
|
362
|
+
#--{{{
|
363
|
+
getopt = getopts opts
|
364
|
+
sigs = getopt[ 'signals', %w(SIGTERM SIGQUIT SIGKILL) ]
|
365
|
+
suspend = getopt[ 'suspend', 4 ]
|
366
|
+
pid = Integer pid
|
367
|
+
existed = false
|
368
|
+
sigs.each do |sig|
|
369
|
+
begin
|
370
|
+
Process.kill sig, pid
|
371
|
+
existed = true
|
372
|
+
rescue Errno::ESRCH
|
373
|
+
return(existed ? nil : true)
|
374
|
+
end
|
375
|
+
return true unless alive? pid
|
376
|
+
sleep suspend
|
377
|
+
return true unless alive? pid
|
378
|
+
end
|
379
|
+
return(not alive?(pid))
|
380
|
+
#--}}}
|
381
|
+
end
|
382
|
+
module_function :maim
|
383
|
+
|
384
|
+
def alive pid
|
385
|
+
#--{{{
|
386
|
+
pid = Integer pid
|
387
|
+
begin
|
388
|
+
Process.kill 0, pid
|
389
|
+
true
|
390
|
+
rescue Errno::ESRCH
|
391
|
+
false
|
392
|
+
end
|
393
|
+
#--}}}
|
394
|
+
end
|
395
|
+
alias alive? alive
|
396
|
+
module_function :alive
|
397
|
+
module_function :'alive?'
|
398
|
+
#--}}}
|
399
|
+
end
|
400
|
+
|
401
|
+
def open4(*cmd, &b) cmd.size == 0 ? Open4 : Open4::popen4(*cmd, &b) end
|
@@ -7,7 +7,6 @@ require 'fileutils'
|
|
7
7
|
require 'pathname'
|
8
8
|
require 'rbconfig'
|
9
9
|
require 'yaml'
|
10
|
-
require 'open3'
|
11
10
|
require 'net/http'
|
12
11
|
require 'uri'
|
13
12
|
require 'ostruct'
|
@@ -174,7 +173,7 @@ class Gem::Commands::TestCommand < Gem::Command
|
|
174
173
|
:release => spec.version.release.to_s,
|
175
174
|
:prerelease => spec.version.prerelease?
|
176
175
|
},
|
177
|
-
:platform =>
|
176
|
+
:platform => (Kernel.const_get("RUBY_ENGINE") rescue "ruby"),
|
178
177
|
:ruby_version => RUBY_VERSION,
|
179
178
|
:result => result,
|
180
179
|
:test_output => output
|
@@ -195,7 +194,7 @@ class Gem::Commands::TestCommand < Gem::Command
|
|
195
194
|
exit_status = nil
|
196
195
|
|
197
196
|
if spec.files.include?(".gemtest")
|
198
|
-
open_proc = proc do |stdin, stdout, stderr
|
197
|
+
open_proc = proc do |pid, stdin, stdout, stderr|
|
199
198
|
loop do
|
200
199
|
if stdout.eof? and stderr.eof?
|
201
200
|
break
|
@@ -205,28 +204,32 @@ class Gem::Commands::TestCommand < Gem::Command
|
|
205
204
|
|
206
205
|
handles, _, _ = IO.select([stdout, stderr].reject { |x| x.closed? || x.eof? }, nil, nil, 0.1)
|
207
206
|
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
207
|
+
handles.each do |io|
|
208
|
+
begin
|
209
|
+
io.readpartial(16384, buf)
|
210
|
+
rescue EOFError, IOError
|
211
|
+
next
|
212
|
+
end
|
213
|
+
end if handles
|
213
214
|
|
214
215
|
output += buf
|
215
216
|
|
216
217
|
print buf
|
217
218
|
end
|
219
|
+
end
|
218
220
|
|
219
|
-
|
220
|
-
|
221
|
+
# jruby stuffs it under IO, so we'll use that if it's available
|
222
|
+
# XXX I'm fairly sure that JRuby's gems don't support plugins, so this is
|
223
|
+
# left untested.
|
224
|
+
klass =
|
225
|
+
if IO.respond_to?(:open4)
|
226
|
+
IO
|
227
|
+
else
|
228
|
+
require 'open4'
|
229
|
+
Open4
|
221
230
|
end
|
222
|
-
end
|
223
231
|
|
224
|
-
|
225
|
-
Open3.popen3(rake_path, "test", '--trace', &open_proc)
|
226
|
-
exit_status = $?
|
227
|
-
else
|
228
|
-
Open3.popen3(rake_path, "test", '--trace', &open_proc)
|
229
|
-
end
|
232
|
+
exit_status = klass.popen4(rake_path, "test", '--trace', &open_proc)
|
230
233
|
|
231
234
|
if config["upload_results"] or
|
232
235
|
(!config.has_key?("upload_results") and ask_yes_no("Upload these results to rubygems.org?", true))
|
@@ -239,7 +242,7 @@ class Gem::Commands::TestCommand < Gem::Command
|
|
239
242
|
|
240
243
|
FileUtils.chdir(pwd)
|
241
244
|
|
242
|
-
raise Gem::TestError
|
245
|
+
raise Gem::TestError, "something"
|
243
246
|
end
|
244
247
|
else
|
245
248
|
alert_warning "This gem has no tests! Please contact the author to gain testing and reporting!"
|
data/test/test_execute.rb
CHANGED
@@ -78,11 +78,10 @@ class TestExecute < Test::Unit::TestCase
|
|
78
78
|
:release => spec.version.release.to_s,
|
79
79
|
:prerelease => spec.version.prerelease?
|
80
80
|
},
|
81
|
-
:platform =>
|
81
|
+
:platform => (Kernel.const_get("RUBY_ENGINE") rescue "ruby"),
|
82
82
|
:test_output => output
|
83
83
|
}
|
84
84
|
|
85
|
-
|
86
85
|
assert_equal YAML.load(@test.gather_results(spec, output, true)), hash
|
87
86
|
end
|
88
87
|
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
version: 0.1.
|
8
|
+
- 3
|
9
|
+
version: 0.1.3
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Erik Hollensbe
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-12-
|
18
|
+
date: 2010-12-17 00:00:00 -05:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -47,6 +47,7 @@ files:
|
|
47
47
|
- gems/template.gemspec
|
48
48
|
- gems/test-gem-0.0.0.gem
|
49
49
|
- gems/test/test_pass.rb
|
50
|
+
- lib/open4.rb
|
50
51
|
- lib/rubygems/commands/test_command.rb
|
51
52
|
- lib/rubygems/on_install_test.rb
|
52
53
|
- lib/rubygems_plugin.rb
|