net-ssh-simple 1.1.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -5,3 +5,4 @@ pkg/*
5
5
  .yardoc
6
6
  coverage.data
7
7
  coverage
8
+ sync
data/README.rdoc CHANGED
@@ -55,7 +55,22 @@ Net::SSH::Simple is a simple wrapper around Net::SSH and Net::SCP.
55
55
  s.scp_ul 'example2.com', '/tmp/local_foo', '/tmp/remote_bar'
56
56
  s.scp_dl 'example3.com', '/tmp/remote_foo', '/tmp/local_bar'
57
57
  s.close
58
-
58
+
59
+ === Handling a Timeout
60
+
61
+ require 'net/ssh/simple'
62
+
63
+ # Hint: Set timeout=0 to disable, default is 60
64
+ begin
65
+ Net::SSH::Simple.sync({:timeout => 5}) do
66
+ ssh('example1.com', 'sleep 1') # I will (probably) succeed!
67
+ ssh('example2.com', 'sleep 60') # I will fail :(
68
+ end
69
+ rescue Net::SSH::Simple::Error => e
70
+ puts e.result.timed_out #=> true
71
+ end
72
+
73
+
59
74
  == Documentation
60
75
 
61
76
  See {Net::SSH::Simple}[http://rubydoc.info/gems/net-ssh-simple/Net/SSH/Simple] for more examples and full API.
data/Rakefile CHANGED
@@ -8,10 +8,16 @@ task :default => :test
8
8
  RSpec::Core::RakeTask.new("test:spec") do |t|
9
9
  t.pattern = 'spec/*.rb'
10
10
  t.rcov = false
11
- #t.rspec_opts = '-b -c -f progress'
12
- t.rspec_opts = '-b -c -f documentation'
11
+ t.rspec_opts = '-b -c -f progress --tag ~benchmark'
13
12
  end
14
13
 
14
+ RSpec::Core::RakeTask.new("test:benchmark") do |t|
15
+ t.pattern = 'spec/*.rb'
16
+ t.rcov = false
17
+ t.rspec_opts = '-b -c -f documentation --tag benchmark'
18
+ end
19
+
20
+
15
21
  namespace :test do
16
22
  task :coverage do
17
23
  require 'cover_me'
@@ -1,7 +1,7 @@
1
1
  require 'net/ssh/simple/version'
2
2
  require 'blockenspiel'
3
3
  require 'hashie'
4
+ require 'timeout'
4
5
  require 'net/ssh'
5
6
  require 'net/scp'
6
7
  require 'net/ssh/simple/core'
7
-
@@ -66,8 +66,8 @@ module Net
66
66
  # rescue Net::SSH::Simple::Error => e
67
67
  # puts "Something bad happened!"
68
68
  # puts e # Human readable error
69
- # puts e.wrapped # Original Exception from Net::SSH
70
- # puts e.context # Config that triggered the error
69
+ # puts e.wrapped # Original Exception
70
+ # puts e.result # Net::SSH::Simple::Result (partial result)
71
71
  # end
72
72
  #
73
73
  # @example
@@ -115,8 +115,8 @@ module Net
115
115
  # rescue Net::SSH::Simple::Error => e
116
116
  # puts "Something bad happened!"
117
117
  # puts e # Human readable error
118
- # puts e.wrapped # Original Exception from Net::SSH
119
- # puts e.context # Config that triggered the error
118
+ # puts e.wrapped # Original Exception
119
+ # puts e.result # Net::SSH::Simple::Result (partial result)
120
120
  # ensure
121
121
  # s.close # don't forget the clean up!
122
122
  # end
@@ -128,6 +128,27 @@ module Net
128
128
  # {:user => 'tom', :password => 'jerry', :port => 1234})
129
129
  # end
130
130
  #
131
+ # # Parameter inheritance
132
+ # Net::SSH::Simple.sync({:user => 'tom', :port => 1234}) do
133
+ # # Both commands will inherit :user and :port
134
+ # ssh('example1.com', 'echo "Hello World."', {:password => 'jerry'})
135
+ # scp_ul('example2.com', '/tmp/a', '/tmp/a', {:password => 's3cr3t'})
136
+ # end
137
+ #
138
+ # @example
139
+ # # Timeout handling
140
+ # #
141
+ # # Note: The timeout applies to each command independently.
142
+ # # Hint: Set timeout=0 to disable, default is 60
143
+ # begin
144
+ # Net::SSH::Simple.sync({:timeout => 5}) do
145
+ # ssh('example1.com', 'sleep 1') # I will (probably) succeed!
146
+ # ssh('example2.com', 'sleep 60') # I will fail :(
147
+ # end
148
+ # rescue Net::SSH::Simple::Error => e
149
+ # puts e.result.timed_out #=> true
150
+ # end
151
+ #
131
152
  # @example
132
153
  # # Using the SCP progress callback
133
154
  # Net::SSH::Simple.sync do
@@ -229,9 +250,9 @@ module Net
229
250
  # @param (see Net::SSH::Simple#ssh)
230
251
  # @raise [Net::SSH::Simple::Error]
231
252
  # @return [Net::SSH::Simple::Result] Result
232
- def self.ssh(*args)
253
+ def self.ssh(*args, &block)
233
254
  s = self.new
234
- r = s.ssh(*args)
255
+ r = s.ssh(*args, &block)
235
256
  s.close
236
257
  r
237
258
  end
@@ -297,6 +318,7 @@ module Net
297
318
  # @return [Net::SSH::Simple::Result] Result
298
319
  #
299
320
  def scp_ul(host, src, dst, opts={}, &block)
321
+ opts = @opts.merge(opts)
300
322
  scp(:upload, host, src, dst, opts, &block)
301
323
  end
302
324
 
@@ -307,12 +329,13 @@ module Net
307
329
  #
308
330
  # @param [String] host Destination hostname or ip-address
309
331
  # @param [String] cmd Shell command to execute
310
- # @param [Hash] opts Parameters for the underlying Net::SSH
332
+ # @param opts (see Net::SSH::Simple#ssh)
311
333
  # @param [Block] &block Progress callback (optional)
312
334
  # @return [Net::SSH::Simple::Result] Result
313
335
  # @see Net::SSH::Simple#scp_ul
314
336
  #
315
337
  def scp_dl(host, src, dst, opts={}, &block)
338
+ opts = @opts.merge(opts)
316
339
  scp(:download, host, src, dst, opts, &block)
317
340
  end
318
341
 
@@ -324,8 +347,8 @@ module Net
324
347
  # @return [Net::SSH::Simple::Result] Result
325
348
  # @param [String] host Destination hostname or ip-address
326
349
  # @param [String] cmd Shell command to execute
327
- # @param [Hash] opts Parameters for the underlying Net::SSH
328
350
  # @param [Block] &block Use the event-API (see example above)
351
+ # @param [Hash] opts SSH options
329
352
  # @option opts [Array] :auth_methods
330
353
  # an array of authentication methods to try
331
354
  #
@@ -399,7 +422,7 @@ module Net
399
422
  # the port to use when connecting to the remote host
400
423
  #
401
424
  # @option opts [Hash] :properties
402
- # a hash of key/value pairs to add to the new connections properties
425
+ # a hash of key/value pairs to add to the new connection's properties
403
426
  # (see Net::SSH::Connection::Session#properties)
404
427
  #
405
428
  # @option opts [String] :proxy
@@ -414,8 +437,8 @@ module Net
414
437
  # @option opts [Integer] :rekey_packet_limit
415
438
  # the max number of packets to process before rekeying
416
439
  #
417
- # @option opts [Integer] :timeout
418
- # how long to wait for the initial connection to be made
440
+ # @option opts [Integer] :timeout (60)
441
+ # connection timeout. this is enforced by Net::SSH::Simple.
419
442
  #
420
443
  # @option opts [String] :user
421
444
  # the username to log in as
@@ -434,10 +457,11 @@ module Net
434
457
  # @see http://net-ssh.github.com/ssh/v2/api/classes/Net/SSH/Config.html
435
458
  # Net::SSH documentation for the 'opts'-hash
436
459
  def ssh(host, cmd, opts={}, &block)
460
+ opts = @opts.merge(opts)
437
461
  with_session(host, opts) do |session|
438
462
  @result = Result.new(
439
- { :host => host, :cmd => cmd, :start_at => Time.new,
440
- :stdout => '' , :stderr => '' , :success => nil
463
+ { :op => :ssh, :host => host, :cmd => cmd, :start_at => Time.new,
464
+ :opts => opts, :stdout => '', :stderr => '', :success => nil
441
465
  } )
442
466
 
443
467
  channel = session.open_channel do |chan|
@@ -477,7 +501,8 @@ module Net
477
501
 
478
502
  dsl_methods false
479
503
 
480
- def initialize()
504
+ def initialize(opts={})
505
+ @opts = opts
481
506
  @sessions = {}
482
507
  @result = Result.new
483
508
  end
@@ -486,23 +511,25 @@ module Net
486
511
  # Spawn a Thread to perform a sequence of ssh/scp operations.
487
512
  #
488
513
  # @param [Block] block
514
+ # @param opts (see Net::SSH::Simple#ssh)
489
515
  # @return [Thread] Thread executing the SSH-Block.
490
516
  #
491
- def self.async(&block)
517
+ def self.async(opts={}, &block)
492
518
  Thread.new do
493
- self.sync(&block)
519
+ self.sync(opts, &block)
494
520
  end
495
521
  end
496
522
 
497
523
  #
498
524
  # Perform a sequence of ssh/scp operations.
499
525
  #
526
+ # @param opts (see Net::SSH::Simple#ssh)
500
527
  # @return [Net::SSH::Simple::Result] Result
501
528
  #
502
- def self.sync(&block)
503
- b = self.new
504
- r = Blockenspiel.invoke(block, b)
505
- b.close
529
+ def self.sync(opts={}, &block)
530
+ s = self.new(opts)
531
+ r = Blockenspiel.invoke(block, s)
532
+ s.close
506
533
  r
507
534
  end
508
535
 
@@ -519,23 +546,27 @@ module Net
519
546
  end
520
547
 
521
548
  private
522
- def with_session(host, opts, &block)
549
+ def with_session(host, opts={:timeout => 60}, &block)
523
550
  begin
524
- session = @sessions[host.hash] = @sessions[host.hash] ||\
525
- Net::SSH.start(*[host, opts[:user], opts])
526
- block.call(session)
551
+ Timeout.timeout(opts[:timeout]) do
552
+ session = @sessions[host.hash] = @sessions[host.hash] ||\
553
+ Net::SSH.start(*[host, opts[:user], opts])
554
+ block.call(session)
555
+ end
527
556
  rescue => e
528
557
  opts[:password].gsub!(/./,'*') if opts.include? :password
529
558
  @result[:exception] = e
530
- @result[:context] = [host,opts]
531
- raise Net::SSH::Simple::Error, [e, [host,opts]]
559
+ @result[:success] = false
560
+ @result[:timed_out] = true
561
+ @result[:finish_at] = Time.new
562
+ raise Net::SSH::Simple::Error, [e, [host,opts,@result]]
532
563
  end
533
564
  end
534
565
 
535
566
  def scp(mode, host, src, dst, opts={}, &block)
536
567
  @result = Result.new(
537
- { :host => host, :cmd => :scp_dl, :start_at => Time.new,
538
- :src => src , :dst => dst , :success => false
568
+ { :op => :scp, :host => host, :opts => opts, :cmd => :scp_dl,
569
+ :start_at => Time.new, :src => src, :dst => dst, :success => false
539
570
  } )
540
571
  with_session(host, opts) do |session|
541
572
  lt = 0
@@ -556,15 +587,23 @@ module Net
556
587
  # Error that occured during a Net::SSH::Simple operation.
557
588
  #
558
589
  class Error < RuntimeError
559
- # Reference to the underlying Net::SSH Exception
590
+ # Reference to the underlying Exception
560
591
  attr_reader :wrapped
561
- # The opts-hash of the operation that triggered the Error
592
+
593
+ # Context for the operation that failed, as an Array: [host, opts, result].
594
+ #
595
+ # @deprecated
596
+ # This will be removed soon, use {#result} instead!
562
597
  attr_reader :context
563
598
 
599
+ # {Net::SSH::Simple::Result} for the interrupted operation.
600
+ attr_reader :result
601
+
564
602
  def initialize(msg, e=$!)
565
603
  super(msg)
566
604
  @wrapped = e
567
605
  @context = msg[1]
606
+ @result = msg[1][2]
568
607
  end
569
608
 
570
609
  def to_s
@@ -576,9 +615,11 @@ module Net
576
615
  # Result of a Net::SSH::Simple operation.
577
616
  #
578
617
  # @attr [String] host Hostname/IP address
618
+ # @attr [Symbol] op :ssh or :scp
579
619
  # @attr [String] cmd Shell command (SSH only)
580
620
  # @attr [Time] start_at Operation start timestamp
581
621
  # @attr [Time] finish_at Operation finish timestamp
622
+ # @attr [Boolean] timed_out Set to true if the operation timed out
582
623
  # @attr [String] stdout Output to stdout (SSH only)
583
624
  # @attr [String] stderr Output to stderr (SSH only)
584
625
  # @attr [boolean] success
@@ -586,7 +627,7 @@ module Net
586
627
  # @attr [Integer] total Size of requested file (in bytes, SCP only)
587
628
  # @attr [Integer] sent Number of bytes transferred (SCP only)
588
629
  # @attr [String] exit_signal
589
- # Only present if the remote command terminates due to a signal (SSH only)
630
+ # Only present if the remote command terminated due to a signal (SSH only)
590
631
  #
591
632
  class Result < Hashie::Mash; end
592
633
  end
@@ -1,7 +1,7 @@
1
1
  module Net
2
2
  module SSH
3
3
  class Simple
4
- VERSION = "1.1.1"
4
+ VERSION = "1.2.0"
5
5
  end
6
6
  end
7
7
  end
@@ -11,14 +11,14 @@ Gem::Specification.new do |s|
11
11
  s.description = %q{Net::SSH::Simple is a simple wrapper around Net::SSH and Net::SCP.}
12
12
  s.summary = %q{SSH without the headache}
13
13
 
14
- s.rubyforge_project = "net-ssh-simple"
14
+ s.required_ruby_version = '>= 1.9.2'
15
15
 
16
16
  s.add_dependency "net-ssh", "~> 2.1.4"
17
17
  s.add_dependency "net-scp", "~> 1.0.4"
18
18
  s.add_dependency "blockenspiel", "~> 0.4.3"
19
19
  s.add_dependency "hashie", "~> 1.1.0"
20
20
 
21
- s.add_development_dependency "rake"
21
+ s.add_development_dependency "rake", "~> 0.9.2.2"
22
22
  s.add_development_dependency "rspec"
23
23
  s.add_development_dependency "cover_me"
24
24
 
@@ -17,14 +17,19 @@ require 'securerandom'
17
17
  # Port 22
18
18
  #
19
19
  # The test-suite will (over)write the following files on localhost:
20
- # /tmp/ssh_test_in{0,1,2,3,4}
21
- # /tmp/ssh_test_out{0,1,2,3,4}
20
+ # /tmp/ssh_test_in*
21
+ # /tmp/ssh_test_out*
22
22
  #
23
23
 
24
+ CONCURRENCY = 16
25
+
26
+ BENCHMARK_ITER = 10
27
+ BENCHMARK_CONCURRENCY = 128
28
+
24
29
  describe Net::SSH::Simple do
25
30
  describe "singleton" do
26
31
  before :each do
27
- (0..4).each do |i|
32
+ (0..CONCURRENCY).each do |i|
28
33
  begin
29
34
  File.unlink(File.join('/tmp', "ssh_test_in#{i}"))
30
35
  rescue; end
@@ -37,16 +42,32 @@ describe Net::SSH::Simple do
37
42
  end
38
43
  end
39
44
 
40
- it "fails gently" do
41
- lambda {
42
- Net::SSH::Simple.ssh('localhost', 'true', {:port => 0})
43
- }.should raise_error(Net::SSH::Simple::Error)
45
+ it "enforces timeout" do
46
+ raised = false
47
+ begin
48
+ r = Net::SSH::Simple.ssh('localhost', 'sleep 60', {:timeout => 1})
49
+ rescue => e
50
+ raised = true
51
+ e.to_s.should match /^execution expired @ .*/
52
+ e.result.op == :ssh
53
+ e.result.timed_out.should == true
54
+ end
55
+ raised.should == true
56
+ end
57
+
58
+ it "interprets timeout=0 as no timeout" do
59
+ Net::SSH::Simple.ssh('localhost', 'sleep 2', {:timeout => 0})
60
+ end
44
61
 
62
+ it "fails gently" do
63
+ raised = false
45
64
  begin
46
65
  Net::SSH::Simple.ssh('localhost', 'true', {:port => 0})
47
66
  rescue => e
48
- e.to_s.should == 'Connection refused - connect(2) @ ["localhost", {:port=>0}]'
67
+ raised = true
68
+ e.to_s.should match /^Connection refused - connect\(2\).*/
49
69
  end
70
+ raised.should == true
50
71
  end
51
72
 
52
73
  it "returns a result" do
@@ -95,7 +116,7 @@ describe Net::SSH::Simple do
95
116
  before :each do
96
117
  @s = Net::SSH::Simple.new
97
118
 
98
- (0..4).each do |i|
119
+ (0..CONCURRENCY).each do |i|
99
120
  begin
100
121
  File.unlink(File.join('/tmp', "ssh_test_in#{i}"))
101
122
  rescue; end
@@ -140,6 +161,7 @@ describe Net::SSH::Simple do
140
161
  mockback.ping
141
162
  end
142
163
  r.success.should == true
164
+ r.op.should == :scp
143
165
  Digest::MD5.file('/tmp/ssh_test_in0').should == Digest::MD5.file('/tmp/ssh_test_out0')
144
166
  end
145
167
 
@@ -150,6 +172,7 @@ describe Net::SSH::Simple do
150
172
  mockback.ping
151
173
  end
152
174
  r.success.should == true
175
+ r.op.should == :scp
153
176
  Digest::MD5.file('/tmp/ssh_test_in0').should == Digest::MD5.file('/tmp/ssh_test_out0')
154
177
  end
155
178
  end
@@ -211,7 +234,7 @@ describe Net::SSH::Simple do
211
234
 
212
235
  describe "asynchronous block syntax" do
213
236
  before :each do
214
- (0..4).each do |i|
237
+ (0..CONCURRENCY).each do |i|
215
238
  begin
216
239
  File.unlink(File.join('/tmp', "ssh_test_in#{i}"))
217
240
  rescue; end
@@ -226,7 +249,7 @@ describe Net::SSH::Simple do
226
249
 
227
250
  it "copes with a little concurrency" do
228
251
  t = []
229
- (0..4).each do |i|
252
+ (0..CONCURRENCY).each do |i|
230
253
  t[i] = Net::SSH::Simple.async do
231
254
  mockback = mock(:progress_callback)
232
255
  mockback.should_receive(:ping).at_least(:once)
@@ -245,13 +268,47 @@ describe Net::SSH::Simple do
245
268
  end
246
269
  end
247
270
 
248
- (0..4).each do |i|
271
+ (0..CONCURRENCY).each do |i|
249
272
  r = t[i].value
250
273
  r.stdout.should == "hello #{i}\n"
251
274
  Digest::MD5.file("/tmp/ssh_test_in#{i}").should == Digest::MD5.file("/tmp/ssh_test_out#{i}")
252
275
  end
253
276
  end
254
277
 
278
+ it "doesn't break under high concurrency", :benchmark => true do
279
+ iter = 0
280
+ (0..BENCHMARK_ITER).each do
281
+ iter += 1
282
+ t = []
283
+ (0..BENCHMARK_CONCURRENCY).each do |i|
284
+ #t[i] = Net::SSH::Simple.async(:verbose=>Logger::DEBUG) do
285
+ t[i] = Net::SSH::Simple.async do
286
+ mockback = mock(:progress_callback)
287
+ mockback.should_receive(:ping).at_least(:once)
288
+ r = nil
289
+ if 0 == i % 2
290
+ r = scp_dl('localhost', "/tmp/ssh_test_in#{i}", "/tmp/ssh_test_out#{i}") do |sent,total|
291
+ mockback.ping
292
+ end
293
+ else
294
+ r = scp_ul('localhost', "/tmp/ssh_test_in#{i}", "/tmp/ssh_test_out#{i}") do |sent,total|
295
+ mockback.ping
296
+ end
297
+ end
298
+ r.success.should == true
299
+ ssh('localhost', "echo hello #{i}")
300
+ end
301
+ end
302
+
303
+ (0..BENCHMARK_CONCURRENCY).each do |i|
304
+ r = t[i].value
305
+ r.stdout.should == "hello #{i}\n"
306
+ Digest::MD5.file("/tmp/ssh_test_in#{i}").should == Digest::MD5.file("/tmp/ssh_test_out#{i}")
307
+ end
308
+ puts "#{iter}/#{BENCHMARK_ITER}"
309
+ end
310
+ end
311
+
255
312
  it "handles signals" do
256
313
  victim = Net::SSH::Simple.async do
257
314
  begin
@@ -269,11 +326,151 @@ describe Net::SSH::Simple do
269
326
  k.success.should == true
270
327
 
271
328
  v = victim.value
272
- v.to_s.should == 'Killed by SIGTERM @ ["localhost", {}]'
329
+ v.to_s.should match /Killed by SIGTERM @ .*/
330
+ end
331
+ end
332
+
333
+ describe "parameter inheritance" do
334
+ it "works with instance syntax" do
335
+ s = Net::SSH::Simple.new({:timeout => 7})
336
+ r = s.ssh('localhost', 'date', {:rekey_packet_limit => 42})
337
+ r.op.should == :ssh
338
+ r.opts[:timeout].should == 7
339
+ r.opts[:rekey_packet_limit].should == 42
340
+
341
+ r = s.scp_dl('localhost', '/tmp/ssh_test_in0', '/tmp/ssh_test_out0',
342
+ {:rekey_packet_limit => 42})
343
+ r.op.should == :scp
344
+ r.opts[:timeout].should == 7
345
+ r.opts[:rekey_packet_limit].should == 42
346
+
347
+ r = s.scp_ul('localhost', '/tmp/ssh_test_in0', '/tmp/ssh_test_out0',
348
+ {:rekey_packet_limit => 42})
349
+ r.op.should == :scp
350
+ r.opts[:timeout].should == 7
351
+ r.opts[:rekey_packet_limit].should == 42
352
+
353
+ s.close
354
+ end
355
+
356
+ it "works with synchronous block syntax" do
357
+ r = Net::SSH::Simple.sync({:timeout => 7}) do
358
+ r = ssh('localhost', 'date', {:rekey_packet_limit => 42})
359
+ r.opts[:timeout].should == 7
360
+ r.opts[:rekey_packet_limit].should == 42
361
+
362
+ r = scp_ul('localhost', '/tmp/ssh_test_in0', '/tmp/ssh_test_out0',
363
+ {:rekey_packet_limit => 42})
364
+ r.opts[:timeout].should == 7
365
+ r.opts[:rekey_packet_limit].should == 42
366
+
367
+ r = scp_dl('localhost', '/tmp/ssh_test_in0', '/tmp/ssh_test_out0',
368
+ {:rekey_packet_limit => 42})
369
+ r.opts[:timeout].should == 7
370
+ r.opts[:rekey_packet_limit].should == 42
371
+ end
372
+ end
373
+
374
+ it "works with asynchronous block syntax" do
375
+ t = Net::SSH::Simple.async({:timeout => 7}) do
376
+ r = ssh('localhost', 'date', {:rekey_packet_limit => 42})
377
+ r.opts[:timeout].should == 7
378
+ r.opts[:rekey_packet_limit].should == 42
379
+
380
+ r = scp_ul('localhost', '/tmp/ssh_test_in0', '/tmp/ssh_test_out0',
381
+ {:rekey_packet_limit => 42})
382
+ r.opts[:timeout].should == 7
383
+ r.opts[:rekey_packet_limit].should == 42
384
+
385
+ r = scp_dl('localhost', '/tmp/ssh_test_in0', '/tmp/ssh_test_out0',
386
+ {:rekey_packet_limit => 42})
387
+ r.opts[:timeout].should == 7
388
+ r.opts[:rekey_packet_limit].should == 42
389
+ :happy
390
+ end
391
+ t.value.should == :happy
273
392
  end
274
393
  end
275
394
 
276
395
  describe "event api" do
396
+ it "works with singleton syntax" do
397
+ mockie = mock(:callbacks)
398
+ mockie.should_receive(:start).once.ordered
399
+ mockie.should_receive(:finish).once.ordered
400
+ r = Net::SSH::Simple.ssh('localhost', '/bin/sh') do |e,c,d|
401
+ case e
402
+ when :start
403
+ mockie.start()
404
+ c.send_data("echo 'hello stdout'\n")
405
+ c.eof!
406
+ when :finish
407
+ mockie.finish()
408
+ end
409
+ end
410
+ r.stdout.should == "hello stdout\n"
411
+ r.stderr.should == ''
412
+ end
413
+
414
+ it "works with instance syntax" do
415
+ mockie = mock(:callbacks)
416
+ mockie.should_receive(:start).once.ordered
417
+ mockie.should_receive(:finish).once.ordered
418
+ s = Net::SSH::Simple.new
419
+ r = s.ssh('localhost', '/bin/sh') do |e,c,d|
420
+ case e
421
+ when :start
422
+ mockie.start()
423
+ c.send_data("echo 'hello stdout'\n")
424
+ c.eof!
425
+ when :finish
426
+ mockie.finish()
427
+ end
428
+ end
429
+ r.stdout.should == "hello stdout\n"
430
+ r.stderr.should == ''
431
+ end
432
+
433
+ it "works with synchronous block syntax" do
434
+ mockie = mock(:callbacks)
435
+ mockie.should_receive(:start).once.ordered
436
+ mockie.should_receive(:finish).once.ordered
437
+ r = Net::SSH::Simple.sync do
438
+ ssh('localhost', '/bin/sh') do |e,c,d|
439
+ case e
440
+ when :start
441
+ mockie.start()
442
+ c.send_data("echo 'hello stdout'\n")
443
+ c.eof!
444
+ when :finish
445
+ mockie.finish()
446
+ end
447
+ end
448
+ end
449
+ r.stdout.should == "hello stdout\n"
450
+ r.stderr.should == ''
451
+ end
452
+
453
+ it "works with asynchronous block syntax" do
454
+ t = Net::SSH::Simple.async do
455
+ mockie = mock(:callbacks)
456
+ mockie.should_receive(:start).once.ordered
457
+ mockie.should_receive(:finish).once.ordered
458
+ ssh('localhost', '/bin/sh') do |e,c,d|
459
+ case e
460
+ when :start
461
+ mockie.start()
462
+ c.send_data("echo 'hello stdout'\n")
463
+ c.eof!
464
+ when :finish
465
+ mockie.finish()
466
+ end
467
+ end
468
+ end
469
+ r = t.value
470
+ r.stdout.should == "hello stdout\n"
471
+ r.stderr.should == ''
472
+ end
473
+
277
474
  it "handles long stdin->stdout pipe" do
278
475
  mockie = mock(:callbacks)
279
476
  mockie.should_receive(:start).once.ordered
@@ -414,7 +611,7 @@ describe Net::SSH::Simple do
414
611
  k.success.should == true
415
612
 
416
613
  v = victim.value
417
- v.to_s.should == 'Killed by SIGTERM @ ["localhost", {}]'
614
+ v.to_s.should match /Killed by SIGTERM @ .*/
418
615
  end
419
616
 
420
617
  it "handles signals (:no_raise)" do
metadata CHANGED
@@ -1,131 +1,100 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: net-ssh-simple
3
- version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 1
7
- - 1
8
- - 1
9
- version: 1.1.1
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.2.0
5
+ prerelease:
10
6
  platform: ruby
11
- authors:
7
+ authors:
12
8
  - Moe
13
9
  autorequire:
14
10
  bindir: bin
15
11
  cert_chain: []
16
-
17
- date: 2011-10-25 00:00:00 +02:00
18
- default_executable:
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
12
+ date: 2011-10-25 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
21
15
  name: net-ssh
22
- requirement: &id001 !ruby/object:Gem::Requirement
16
+ requirement: &7024800 !ruby/object:Gem::Requirement
23
17
  none: false
24
- requirements:
18
+ requirements:
25
19
  - - ~>
26
- - !ruby/object:Gem::Version
27
- segments:
28
- - 2
29
- - 1
30
- - 4
20
+ - !ruby/object:Gem::Version
31
21
  version: 2.1.4
32
22
  type: :runtime
33
23
  prerelease: false
34
- version_requirements: *id001
35
- - !ruby/object:Gem::Dependency
24
+ version_requirements: *7024800
25
+ - !ruby/object:Gem::Dependency
36
26
  name: net-scp
37
- requirement: &id002 !ruby/object:Gem::Requirement
27
+ requirement: &7024140 !ruby/object:Gem::Requirement
38
28
  none: false
39
- requirements:
29
+ requirements:
40
30
  - - ~>
41
- - !ruby/object:Gem::Version
42
- segments:
43
- - 1
44
- - 0
45
- - 4
31
+ - !ruby/object:Gem::Version
46
32
  version: 1.0.4
47
33
  type: :runtime
48
34
  prerelease: false
49
- version_requirements: *id002
50
- - !ruby/object:Gem::Dependency
35
+ version_requirements: *7024140
36
+ - !ruby/object:Gem::Dependency
51
37
  name: blockenspiel
52
- requirement: &id003 !ruby/object:Gem::Requirement
38
+ requirement: &7023480 !ruby/object:Gem::Requirement
53
39
  none: false
54
- requirements:
40
+ requirements:
55
41
  - - ~>
56
- - !ruby/object:Gem::Version
57
- segments:
58
- - 0
59
- - 4
60
- - 3
42
+ - !ruby/object:Gem::Version
61
43
  version: 0.4.3
62
44
  type: :runtime
63
45
  prerelease: false
64
- version_requirements: *id003
65
- - !ruby/object:Gem::Dependency
46
+ version_requirements: *7023480
47
+ - !ruby/object:Gem::Dependency
66
48
  name: hashie
67
- requirement: &id004 !ruby/object:Gem::Requirement
49
+ requirement: &7022900 !ruby/object:Gem::Requirement
68
50
  none: false
69
- requirements:
51
+ requirements:
70
52
  - - ~>
71
- - !ruby/object:Gem::Version
72
- segments:
73
- - 1
74
- - 1
75
- - 0
53
+ - !ruby/object:Gem::Version
76
54
  version: 1.1.0
77
55
  type: :runtime
78
56
  prerelease: false
79
- version_requirements: *id004
80
- - !ruby/object:Gem::Dependency
57
+ version_requirements: *7022900
58
+ - !ruby/object:Gem::Dependency
81
59
  name: rake
82
- requirement: &id005 !ruby/object:Gem::Requirement
60
+ requirement: &7022240 !ruby/object:Gem::Requirement
83
61
  none: false
84
- requirements:
85
- - - ">="
86
- - !ruby/object:Gem::Version
87
- segments:
88
- - 0
89
- version: "0"
62
+ requirements:
63
+ - - ~>
64
+ - !ruby/object:Gem::Version
65
+ version: 0.9.2.2
90
66
  type: :development
91
67
  prerelease: false
92
- version_requirements: *id005
93
- - !ruby/object:Gem::Dependency
68
+ version_requirements: *7022240
69
+ - !ruby/object:Gem::Dependency
94
70
  name: rspec
95
- requirement: &id006 !ruby/object:Gem::Requirement
71
+ requirement: &7021660 !ruby/object:Gem::Requirement
96
72
  none: false
97
- requirements:
98
- - - ">="
99
- - !ruby/object:Gem::Version
100
- segments:
101
- - 0
102
- version: "0"
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
103
77
  type: :development
104
78
  prerelease: false
105
- version_requirements: *id006
106
- - !ruby/object:Gem::Dependency
79
+ version_requirements: *7021660
80
+ - !ruby/object:Gem::Dependency
107
81
  name: cover_me
108
- requirement: &id007 !ruby/object:Gem::Requirement
82
+ requirement: &7020960 !ruby/object:Gem::Requirement
109
83
  none: false
110
- requirements:
111
- - - ">="
112
- - !ruby/object:Gem::Version
113
- segments:
114
- - 0
115
- version: "0"
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
116
88
  type: :development
117
89
  prerelease: false
118
- version_requirements: *id007
90
+ version_requirements: *7020960
119
91
  description: Net::SSH::Simple is a simple wrapper around Net::SSH and Net::SCP.
120
- email:
92
+ email:
121
93
  - moe@busyloop.net
122
94
  executables: []
123
-
124
95
  extensions: []
125
-
126
96
  extra_rdoc_files: []
127
-
128
- files:
97
+ files:
129
98
  - .gitignore
130
99
  - Gemfile
131
100
  - README.rdoc
@@ -135,39 +104,31 @@ files:
135
104
  - lib/net/ssh/simple/version.rb
136
105
  - net-ssh-simple.gemspec
137
106
  - spec/net-ssh-simple.rb
138
- has_rdoc: true
139
107
  homepage: https://github.com/busyloop/net-ssh-simple
140
108
  licenses: []
141
-
142
109
  post_install_message:
143
110
  rdoc_options: []
144
-
145
- require_paths:
111
+ require_paths:
146
112
  - lib
147
- required_ruby_version: !ruby/object:Gem::Requirement
113
+ required_ruby_version: !ruby/object:Gem::Requirement
148
114
  none: false
149
- requirements:
150
- - - ">="
151
- - !ruby/object:Gem::Version
152
- hash: 4391388084429679989
153
- segments:
154
- - 0
155
- version: "0"
156
- required_rubygems_version: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ! '>='
117
+ - !ruby/object:Gem::Version
118
+ version: 1.9.2
119
+ required_rubygems_version: !ruby/object:Gem::Requirement
157
120
  none: false
158
- requirements:
159
- - - ">="
160
- - !ruby/object:Gem::Version
161
- hash: 4391388084429679989
162
- segments:
121
+ requirements:
122
+ - - ! '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ segments:
163
126
  - 0
164
- version: "0"
127
+ hash: 2238180045890726956
165
128
  requirements: []
166
-
167
- rubyforge_project: net-ssh-simple
168
- rubygems_version: 1.3.7
129
+ rubyforge_project:
130
+ rubygems_version: 1.8.10
169
131
  signing_key:
170
132
  specification_version: 3
171
133
  summary: SSH without the headache
172
134
  test_files: []
173
-