rubygems-test 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
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 => spec.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, thr|
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
- begin
209
- handles.each { |io| io.readpartial(16384, buf) } if handles
210
- rescue EOFError, IOError
211
- next
212
- end
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
- unless RUBY_VERSION =~ /^1.8/
220
- exit_status = thr.value
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
- if RUBY_VERSION =~ /^1.8/
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 => spec.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
- - 2
9
- version: 0.1.2
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-16 00:00:00 -05:00
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