rye 0.7.4 → 0.7.5

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.
@@ -7,6 +7,16 @@ TODO
7
7
  * Add S3 support for Rye::Box.upload / download
8
8
 
9
9
 
10
+ #### 0.7.5 (2009-06-14) #############################
11
+
12
+ * FIXED: Rye::Set methods were not accepting or passing blocks.
13
+ * ADDED: Rye::Set#user and Rye::Set#opts methods
14
+ * ADDED: Rye::Box#nickname
15
+ * ADDED: exception hooks for Rye::Box.
16
+ * CHANGE: Rye::Set method missing now forwards to Rye::Box
17
+ methods instead of Rye::Cmd
18
+
19
+
10
20
  #### 0.7.4 (2009-06-04) #############################
11
21
 
12
22
  * FIXED: Bug in Rye::Box#interactive_ssh related to instance variable renaming from 0.7.0.
data/lib/rye.rb CHANGED
@@ -63,6 +63,9 @@ module Rye
63
63
  class NoHost < RuntimeError; end
64
64
  class NotConnected < RuntimeError; end
65
65
  class CommandNotFound < RuntimeError; end
66
+ class NoPty < RuntimeError
67
+ def message; "Could not obtain pty (i.e. an interactive ssh session)"; end
68
+ end
66
69
  class CommandError < RuntimeError
67
70
  attr_reader :rap
68
71
  # * +rap+ a Rye::Rap object
@@ -34,9 +34,17 @@ module Rye
34
34
  def safe; @rye_safe; end
35
35
  def user; (@rye_opts || {})[:user]; end
36
36
 
37
+ # A storage area +@rye_stash+
38
+ def stash; @rye_stash; end
39
+ def nickname; @rye_nickname || host; end
40
+
37
41
  def host=(val); @rye_host = val; end
38
42
  def opts=(val); @rye_opts = val; end
39
43
 
44
+ # Returns the storage area +@rye_stash+
45
+ def stash=(val); @rye_stash = val; end
46
+ def nickname=(val); @rye_nickname = val; end
47
+
40
48
  def enable_safe_mode; @rye_safe = true; end
41
49
  def disable_safe_mode; @rye_safe = false; end
42
50
 
@@ -45,14 +53,15 @@ module Rye
45
53
 
46
54
  # The most recent valud for umask (or 0022)
47
55
  def current_umask; @rye_current_umask; end
48
-
49
- def ssh; @rye_ssh; end
56
+
50
57
  def info; @rye_info; end
51
58
  def debug; @rye_debug; end
52
59
  def error; @rye_error; end
53
60
 
54
61
  def pre_command_hook=(val); @rye_pre_command_hook = val; end
55
62
  def post_command_hook=(val); @rye_post_command_hook = val; end
63
+ # A Hash. The keys are exception classes, the values are Procs to execute
64
+ def exception_hook=(val); @rye_exception_hook = val; end
56
65
 
57
66
  # * +host+ The hostname to connect to. The default is localhost.
58
67
  # * +opts+ a hash of optional arguments.
@@ -72,6 +81,7 @@ module Rye
72
81
  # Net::SSH.start that is not already mentioned above.
73
82
  #
74
83
  def initialize(host='localhost', opts={})
84
+ @rye_exception_hook = {}
75
85
  @rye_host = host
76
86
 
77
87
  # These opts are use by Rye::Box and also passed to Net::SSH
@@ -222,7 +232,7 @@ module Rye
222
232
  debug "ssh-add stdout: #{ret.stdout}"
223
233
  debug "ssh-add stderr: #{ret.stderr}"
224
234
  end
225
- self #MUST RETURN itself
235
+ self # MUST RETURN self
226
236
  end
227
237
  alias :add_key :add_keys
228
238
 
@@ -279,8 +289,8 @@ module Rye
279
289
  def to_s; '%s@rye_%s' % [user, @rye_host]; end
280
290
 
281
291
  def inspect
282
- %q{#<%s:%s cwd=%s umask=%s env=%s safe=%s opts=%s>} %
283
- [self.class.to_s, self.host,
292
+ %q{#<%s:%s name=%s cwd=%s umask=%s env=%s safe=%s opts=%s>} %
293
+ [self.class.to_s, self.host, self.nickname,
284
294
  @rye_current_working_directory, @rye_current_umask,
285
295
  (@rye_current_environment_variables || '').inspect,
286
296
  self.safe, self.opts.inspect]
@@ -424,7 +434,9 @@ module Rye
424
434
  # A handler for undefined commands.
425
435
  # Raises Rye::CommandNotFound exception.
426
436
  def method_missing(meth, *args, &block)
427
- raise Rye::CommandNotFound, "#{meth.to_s}"
437
+ ex = Rye::CommandNotFound.new(meth.to_s)
438
+ raise ex unless @rye_exception_hook.has_key? ex.class
439
+ @rye_exception_hook[Rye::CommandNotFound].call ex
428
440
  end
429
441
 
430
442
  # Returns the command an arguments as a String.
@@ -444,6 +456,27 @@ module Rye
444
456
  @rye_pre_command_hook
445
457
  end
446
458
 
459
+ # Supply a block to be called whenever there's an Exception. It's called
460
+ # with 1 argument: the exception class. If the exception block returns
461
+ # :retry, the command will be executed again.
462
+ #
463
+ # e.g.
464
+ # rbox.exception_hook(CommandNotFound) do |ex|
465
+ # STDERR.puts "An error occurred: #{ex.class}"
466
+ # choice = Annoy.get_user_input('(S)kip (R)etry (A)bort: ')
467
+ # if choice == 'R'
468
+ # :retry
469
+ # elsif choice == 'S'
470
+ # # do nothing
471
+ # else
472
+ # exit # !
473
+ # end
474
+ # end
475
+ def exception_hook(klass, &block)
476
+ @rye_exception_hook[klass] = block if block
477
+ @rye_exception_hook[klass]
478
+ end
479
+
447
480
  # Execute a block in the context of an instance of Rye::Box.
448
481
  #
449
482
  # rbox = Rye::Box.new
@@ -622,12 +655,11 @@ module Rye
622
655
  cmd_clean = [cwd, cmd_clean].join(' && ')
623
656
  end
624
657
 
625
-
626
658
  info "COMMAND: #{cmd_clean}"
627
659
  debug "Executing: %s" % cmd_clean
628
660
 
629
661
  if @rye_pre_command_hook.is_a?(Proc)
630
- @rye_pre_command_hook.call(cmd, args, user, host)
662
+ @rye_pre_command_hook.call(cmd, args, user, host, nickname)
631
663
  end
632
664
 
633
665
  ## NOTE: Do not raise a CommandNotFound exception in this method.
@@ -639,25 +671,30 @@ module Rye
639
671
  # this is good enough for now.
640
672
  ## raise Rye::CommandNotFound unless self.can?(cmd)
641
673
 
642
- stdout, stderr, ecode, esignal = net_ssh_exec!(cmd_clean)
643
-
644
- rap = Rye::Rap.new(self)
645
- rap.add_stdout(stdout || '')
646
- rap.add_stderr(stderr || '')
647
- rap.add_exit_code(ecode)
648
- rap.exit_signal = esignal
649
- rap.cmd = cmd
650
-
651
- if @rye_post_command_hook.is_a?(Proc)
652
- @rye_post_command_hook.call(rap)
653
- else
674
+ begin
675
+ stdout, stderr, ecode, esignal = net_ssh_exec!(cmd_clean)
676
+
677
+ rap = Rye::Rap.new(self)
678
+ rap.add_stdout(stdout || '')
679
+ rap.add_stderr(stderr || '')
680
+ rap.add_exit_code(ecode)
681
+ rap.exit_signal = esignal
682
+ rap.cmd = cmd
683
+
654
684
  # It seems a convention for various commands to return -1
655
685
  # when something only mildly concerning happens. ls even
656
686
  # returns -1 for apparently no reason sometimes. In any
657
687
  # case, the real errors are the ones greater than zero
658
688
  raise Rye::CommandError.new(rap) if ecode > 0
689
+
690
+ rescue Exception => ex
691
+ raise ex unless @rye_exception_hook.has_key? ex.class
692
+ ret = @rye_exception_hook[ex.class].call(ex)
693
+ retry if ret == :retry
659
694
  end
660
695
 
696
+ @rye_post_command_hook.call(rap) if @rye_post_command_hook.is_a?(Proc)
697
+
661
698
  rap
662
699
  end
663
700
  alias :cmd :run_command
@@ -722,7 +759,7 @@ module Rye
722
759
 
723
760
  channel.wait # block until we get a response
724
761
  channel.request_pty do |ch, success|
725
- raise "Could not obtain pty (i.e. an interactive ssh session)" if !success
762
+ raise Rye::NoPty if !success
726
763
  end
727
764
 
728
765
  channel[:exit_code] = 0 if channel[:exit_code] == nil
@@ -67,6 +67,7 @@ module Rye;
67
67
  def chown(*args); cmd('chown', args); end
68
68
  def unzip(*args); cmd('unzip', args); end
69
69
  def bzip2(*args); cmd('bzip2', args); end
70
+ def which(*args); cmd('which', args); end
70
71
 
71
72
  def umount(*args); cmd("umount", args); end
72
73
  def uptime(*args); cmd("uptime", args); end
@@ -42,6 +42,9 @@ module Rye
42
42
  add_keys(@opts[:keys])
43
43
  end
44
44
 
45
+ def opts; @opts; end
46
+ def user; (@opts || {})[:user]; end
47
+
45
48
  # * +boxes+ one or more boxes. Rye::Box objects will be added directly
46
49
  # to the set. Hostnames will be used to create new instances of Rye::Box
47
50
  # and those will be added to the list.
@@ -97,7 +100,12 @@ module Rye
97
100
  run_command(:cd, key)
98
101
  self
99
102
  end
100
-
103
+
104
+ # Are there any boxes in this set?
105
+ def empty?
106
+ @boxes.nil? || @boxes.empty?
107
+ end
108
+
101
109
  # Catches calls to Rye::Box commands. If +meth+ is the name of an
102
110
  # instance method defined in Rye::Cmd then we call it against all
103
111
  # the boxes in +@boxes+. Otherwise this method raises a
@@ -105,33 +113,32 @@ module Rye
105
113
  # exception if this set has no boxes defined.
106
114
  #
107
115
  # Returns a Rye::Rap object containing the responses from each Rye::Box.
108
- def method_missing(meth, *args)
116
+ def method_missing(meth, *args, &block)
109
117
  # Ruby 1.8 populates Module.instance_methods with Strings. 1.9 uses Symbols.
110
118
  meth = (Rye.sysinfo.ruby[1] == 8) ? meth.to_s : meth.to_sym
111
119
  raise Rye::NoBoxes if @boxes.empty?
112
- raise Rye::CommandNotFound, meth.to_s unless Rye::Cmd.instance_methods.member?(meth)
113
- run_command(meth, *args)
120
+ raise Rye::CommandNotFound, meth.to_s unless Rye::Box.instance_methods.member?(meth)
121
+ run_command(meth, *args, &block)
114
122
  end
115
123
 
116
124
  private
117
125
 
118
126
  # Determines whether to call the serial or parallel method, then calls it.
119
- def run_command(meth, *args)
127
+ def run_command(meth, *args, &block)
120
128
  runner = @parallel ? :run_command_parallel : :run_command_serial
121
- self.send(runner, meth, *args)
129
+ self.send(runner, meth, *args, &block)
122
130
  end
123
131
 
124
132
 
125
133
  # Run the command on all boxes in parallel
126
- def run_command_parallel(meth, *args)
127
- p @boxes
134
+ def run_command_parallel(meth, *args, &block)
128
135
  debug "P: #{meth} on #{@boxes.size} boxes (#{@boxes.collect {|b| b.host }.join(', ')})"
129
136
  threads = []
130
137
 
131
138
  raps = Rye::Rap.new(self)
132
139
  (@boxes || []).each do |box|
133
140
  threads << Thread.new do
134
- Thread.current[:rap] = box.send(meth, *args) # Store the result in the thread
141
+ Thread.current[:rap] = box.send(meth, *args, &block) # Store the result in the thread
135
142
  end
136
143
  end
137
144
 
@@ -148,11 +155,11 @@ module Rye
148
155
 
149
156
 
150
157
  # Run the command on all boxes in serial
151
- def run_command_serial(meth, *args)
158
+ def run_command_serial(meth, *args, &block)
152
159
  debug "S: #{meth} on #{@boxes.size} boxes (#{@boxes.collect {|b| b.host }.join(', ')})"
153
160
  raps = Rye::Rap.new(self)
154
161
  (@boxes || []).each do |box|
155
- raps << box.send(meth, *args)
162
+ raps << box.send(meth, *args, &block)
156
163
  end
157
164
  raps
158
165
  end
@@ -1,7 +1,7 @@
1
1
  @spec = Gem::Specification.new do |s|
2
2
  s.name = "rye"
3
3
  s.rubyforge_project = "rye"
4
- s.version = "0.7.4"
4
+ s.version = "0.7.5"
5
5
  s.summary = "Rye: Safely run SSH commands on a bunch of machines at the same time (from Ruby)."
6
6
  s.description = s.summary
7
7
  s.author = "Delano Mandelbaum"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rye
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.4
4
+ version: 0.7.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Delano Mandelbaum
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-06-04 00:00:00 -04:00
12
+ date: 2009-06-13 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency