rye 0.6.6 → 0.7.0

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/CHANGES.txt CHANGED
@@ -4,13 +4,20 @@ TODO
4
4
 
5
5
  * Re-implement Rye::Rap as an Observable StringIO object for dynamic printing of output.
6
6
  * Fingerprints: ssh-keygen -l -f id_rsa_repos.pub
7
+ * Add S3 support for Rye::Box.upload / download
8
+
9
+
10
+ #### 0.7.0 (2009-05-30) #############################
11
+
12
+ * CHANGE: Rye::Box now uses unique instance variable names to encourage using
13
+ instance variables in batch command blocks.
14
+ * ADDED: Rye::Box#file_append
7
15
 
8
16
 
9
17
  #### 0.6.6 (2009-05-21) #############################
10
18
 
11
19
  * CHANGE: Key management is handled by ssh-agent again (instead of Net::SSH)
12
20
 
13
-
14
21
  #### 0.6.5 (2009-05-10) #############################
15
22
 
16
23
  * CHANGE: Default exit code is now 0 instead of -1
@@ -37,7 +44,6 @@ TODO
37
44
 
38
45
  * FIXED: I forgot to add highline to the gemspec file manifest. Cripes!
39
46
 
40
-
41
47
  #### 0.6.1 (2009-04-29) #############################
42
48
 
43
49
  * ADDED: Prints message to STDERR when passwordless login fails.
@@ -45,6 +51,7 @@ TODO
45
51
  1.5.1 is not released as a gem yet)
46
52
  * CHANGE: Cleaned examples and links in README
47
53
 
54
+
48
55
  #### 0.6.0 (2009-04-28) #############################
49
56
 
50
57
  * FIXED: handling of Process::Status ($?) in Rye.shell
data/README.rdoc CHANGED
@@ -1,4 +1,4 @@
1
- = Rye - v0.6
1
+ = Rye - v0.7
2
2
 
3
3
  Safely run SSH commands on a bunch of machines at the same time (from Ruby).
4
4
 
@@ -132,7 +132,8 @@ This list will grow. If you find one let me know!
132
132
  == Credits
133
133
 
134
134
  * Delano Mandelbaum (delano@solutious.com)
135
- * Escape, Copyright (C) 2006,2007 Tanaka Akira <akr@fsij.org>
135
+ * Escape, Copyright (C) 2006,2007 Tanaka Akira <akr@fsij.org>
136
+ * Rye::Box#instance_exec (for Ruby 1.8) Mauricio Fernandez
136
137
 
137
138
  == License
138
139
 
data/lib/rye.rb CHANGED
@@ -46,7 +46,7 @@ module Rye
46
46
  extend self
47
47
 
48
48
  unless defined?(SYSINFO)
49
- VERSION = 0.6.freeze
49
+ VERSION = 0.7.freeze
50
50
  SYSINFO = SysInfo.new.freeze
51
51
  end
52
52
 
data/lib/rye/box.rb CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  module Rye
4
4
 
5
-
6
5
  # = Rye::Box
7
6
  #
8
7
  # The Rye::Box class represents a machine. All system
@@ -30,25 +29,28 @@ module Rye
30
29
  class Box
31
30
  include Rye::Cmd
32
31
 
33
- # An instance of Net::SSH::Connection::Session
34
- attr_reader :ssh
35
-
36
- attr_reader :info
37
- attr_reader :debug
38
- attr_reader :error
39
-
40
- attr_accessor :host
41
- attr_accessor :safe
42
- attr_accessor :opts
43
-
44
- # The most recent value from Box.cd or Box.[]
45
- attr_reader :current_working_directory
46
- # The most recent valud for umask (or 0022)
47
- attr_reader :current_umask
48
-
49
- attr_writer :post_command_hook
50
- attr_writer :pre_command_hook
51
-
32
+ def host; @rye_host; end
33
+ def opts; @rye_opts; end
34
+ def safe; @rye_safe; end
35
+
36
+ def host=(val); @rye_host = val; end
37
+ def opts=(val); @rye_opts = val; end
38
+ def safe=(val); @rye_safe = val; end
39
+
40
+ # The most recent value from Box.cd or Box.[]
41
+ def current_working_directory; @rye_current_working_directory; end
42
+
43
+ # The most recent valud for umask (or 0022)
44
+ def current_umask; @rye_current_umask; end
45
+
46
+ def ssh; @rye_ssh; end
47
+ def info; @rye_info; end
48
+ def debug; @rye_debug; end
49
+ def error; @rye_error; end
50
+
51
+ def pre_command_hook=(val); @rye_pre_command_hook = val; end
52
+ def post_command_hook=(val); @rye_post_command_hook = val; end
53
+
52
54
  # * +host+ The hostname to connect to. The default is localhost.
53
55
  # * +opts+ a hash of optional arguments.
54
56
  #
@@ -67,10 +69,10 @@ module Rye
67
69
  # Net::SSH.start that is not already mentioned above.
68
70
  #
69
71
  def initialize(host='localhost', opts={})
70
- @host = host
72
+ @rye_host = host
71
73
 
72
74
  # These opts are use by Rye::Box and also passed to Net::SSH
73
- @opts = {
75
+ @rye_opts = {
74
76
  :user => Rye.sysinfo.user,
75
77
  :safe => true,
76
78
  :port => 22,
@@ -85,33 +87,33 @@ module Rye
85
87
  # if disconnect has already been called explicitly.
86
88
  at_exit { self.disconnect }
87
89
 
88
- # @opts gets sent to Net::SSH so we need to remove the keys
90
+ # @rye_opts gets sent to Net::SSH so we need to remove the keys
89
91
  # that are not meant for it.
90
- @safe, @debug = @opts.delete(:safe), @opts.delete(:debug)
91
- @info, @error = @opts.delete(:info), @opts.delete(:error)
92
- @getenv = {} if @opts.delete(:getenv) # Enable getenv with a hash
92
+ @rye_safe, @rye_debug = @rye_opts.delete(:safe), @rye_opts.delete(:debug)
93
+ @rye_info, @rye_error = @rye_opts.delete(:info), @rye_opts.delete(:error)
94
+ @rye_getenv = {} if @rye_opts.delete(:getenv) # Enable getenv with a hash
93
95
 
94
96
  # Just in case someone sends a true value rather than IO object
95
- @debug = STDERR if @debug == true
96
- @error = STDERR if @error == true
97
- @info = STDOUT if @info == true
97
+ @rye_debug = STDERR if @rye_debug == true
98
+ @rye_error = STDERR if @rye_error == true
99
+ @rye_info = STDOUT if @rye_info == true
98
100
 
99
- @opts[:logger] = Logger.new(@debug) if @debug # Enable Net::SSH debugging
100
- @opts[:paranoid] = true unless @opts[:safe] == false # See Net::SSH.start
101
+ @rye_opts[:logger] = Logger.new(@rye_debug) if @rye_debug # Enable Net::SSH debugging
102
+ @rye_opts[:paranoid] = true unless @rye_opts[:safe] == false # See Net::SSH.start
101
103
 
102
- # Add the given private keys to the keychain that will be used for @host
103
- add_keys(@opts[:keys])
104
+ # Add the given private keys to the keychain that will be used for @rye_host
105
+ add_keys(@rye_opts[:keys])
104
106
 
105
107
  # We don't want Net::SSH to handle the keypairs. This may change
106
108
  # but for we're letting ssh-agent do it.
107
109
  # TODO: Check if this should ot should not be enabled.
108
- @opts.delete(:keys)
110
+ @rye_opts.delete(:keys)
109
111
 
110
112
  # From: capistrano/lib/capistrano/cli.rb
111
113
  STDOUT.sync = true # so that Net::SSH prompts show up
112
114
 
113
115
  debug "ssh-agent info: #{Rye.sshagent_info.inspect}"
114
- debug @opts.inspect
116
+ debug @rye_opts.inspect
115
117
 
116
118
  end
117
119
 
@@ -135,61 +137,61 @@ module Rye
135
137
  # rbox.pwd # => /usr/bin ($ cd /usr/bin && pwd)
136
138
  #
137
139
  def [](key=nil)
138
- @current_working_directory = key
140
+ @rye_current_working_directory = key
139
141
  self
140
142
  end
141
143
  # Like [] except it returns an empty Rye::Rap object to mimick
142
144
  # a regular command method. Call with nil key (or no arg) to
143
145
  # reset.
144
146
  def cd(key=nil)
145
- @current_working_directory = key
147
+ @rye_current_working_directory = key
146
148
  ret = Rye::Rap.new(self)
147
149
  end
148
150
 
149
151
  # Change the current umask (sort of -- works the same way as cd)
150
152
  # The default umask is 0022
151
153
  def umask=(val='0022')
152
- @current_umask = val
154
+ @rye_current_umask = val
153
155
  self
154
156
  end
155
157
 
156
158
 
157
- # Open an SSH session with +@host+. This called automatically
159
+ # Open an SSH session with +@rye_host+. This called automatically
158
160
  # when you the first comamnd is run if it's not already connected.
159
- # Raises a Rye::NoHost exception if +@host+ is not specified.
161
+ # Raises a Rye::NoHost exception if +@rye_host+ is not specified.
160
162
  # Will attempt a password login up to 3 times if the initial
161
163
  # authentication fails.
162
164
  # * +reconnect+ Disconnect first if already connected. The default
163
165
  # is true. When set to false, connect will do nothing if already
164
166
  # connected.
165
167
  def connect(reconnect=true)
166
- raise Rye::NoHost unless @host
167
- return if @ssh && !reconnect
168
- disconnect if @ssh
169
- debug "Opening connection to #{@host} as #{@opts[:user]}"
168
+ raise Rye::NoHost unless @rye_host
169
+ return if @rye_ssh && !reconnect
170
+ disconnect if @rye_ssh
171
+ debug "Opening connection to #{@rye_host} as #{@rye_opts[:user]}"
170
172
  highline = HighLine.new # Used for password prompt
171
173
  retried = 0
172
174
 
173
175
  begin
174
- @ssh = Net::SSH.start(@host, @opts[:user], @opts || {})
176
+ @rye_ssh = Net::SSH.start(@rye_host, @rye_opts[:user], @rye_opts || {})
175
177
  rescue Net::SSH::HostKeyMismatch => ex
176
178
  STDERR.puts ex.message
177
179
  STDERR.puts "NOTE: EC2 instances generate new SSH keys on first boot."
178
- print "\a" if @info # Ring the bell
180
+ print "\a" if @rye_info # Ring the bell
179
181
  if highline.ask("Continue? ").strip.match(/\Ay|yes|sure|ya\z/i)
180
- @opts[:paranoid] = false
182
+ @rye_opts[:paranoid] = false
181
183
  retry
182
184
  else
183
185
  raise Net::SSH::HostKeyMismatch
184
186
  end
185
187
  rescue Net::SSH::AuthenticationFailed => ex
186
- print "\a" if retried == 0 && @info # Ring the bell once
188
+ print "\a" if retried == 0 && @rye_info # Ring the bell once
187
189
  retried += 1
188
190
  if STDIN.tty? && retried <= 3
189
- STDERR.puts "Passwordless login failed for #{@opts[:user]}"
190
- @opts[:password] = highline.ask("Password: ") { |q| q.echo = '' }
191
- @opts[:auth_methods] ||= []
192
- @opts[:auth_methods] << 'password'
191
+ STDERR.puts "Passwordless login failed for #{@rye_opts[:user]}"
192
+ @rye_opts[:password] = highline.ask("Password: ") { |q| q.echo = '' }
193
+ @rye_opts[:auth_methods] ||= []
194
+ @rye_opts[:auth_methods] << 'password'
193
195
  retry
194
196
  else
195
197
  raise Net::SSH::AuthenticationFailed
@@ -198,9 +200,9 @@ module Rye
198
200
 
199
201
  # We add :auth_methods (a Net::SSH joint) to force asking for a
200
202
  # password if the initial (key-based) authentication fails. We
201
- # need to delete the key from @opts otherwise it lingers until
203
+ # need to delete the key from @rye_opts otherwise it lingers until
202
204
  # the next connection (if we switch_user is called for example).
203
- @opts.delete :auth_methods if @opts.has_key?(:auth_methods)
205
+ @rye_opts.delete :auth_methods if @rye_opts.has_key?(:auth_methods)
204
206
 
205
207
  self
206
208
  end
@@ -213,20 +215,20 @@ module Rye
213
215
  # and a new one is opened for the given user.
214
216
  def switch_user(newuser)
215
217
  return if newuser.to_s == self.user.to_s
216
- @opts ||= {}
217
- @opts[:user] = newuser
218
+ @rye_opts ||= {}
219
+ @rye_opts[:user] = newuser
218
220
  disconnect
219
221
  connect
220
222
  end
221
223
 
222
224
 
223
- # Close the SSH session with +@host+. This is called
225
+ # Close the SSH session with +@rye_host+. This is called
224
226
  # automatically at exit if the connection is open.
225
227
  def disconnect
226
- return unless @ssh && !@ssh.closed?
227
- @ssh.loop(0.1) { @ssh.busy? }
228
- debug "Closing connection to #{@ssh.host}"
229
- @ssh.close
228
+ return unless @rye_ssh && !@rye_ssh.closed?
229
+ @rye_ssh.loop(0.1) { @rye_ssh.busy? }
230
+ debug "Closing connection to #{@rye_ssh.host}"
231
+ @rye_ssh.close
230
232
  end
231
233
 
232
234
 
@@ -239,7 +241,7 @@ module Rye
239
241
  def interactive_ssh(run=true)
240
242
  debug "interactive_ssh with keys: #{Rye.keys.inspect}"
241
243
  run = false unless STDIN.tty?
242
- cmd = Rye.prepare_command("ssh", "#{@opts[:user]}@#{@host}")
244
+ cmd = Rye.prepare_command("ssh", "#{@rye_opts[:user]}@rye_#{@rye_host}")
243
245
  return cmd unless run
244
246
  system(cmd)
245
247
  end
@@ -260,44 +262,79 @@ module Rye
260
262
  end
261
263
  alias :add_key :add_keys
262
264
 
265
+ # Return the value of uname in lowercase
266
+ # This is a temporary fix. We can use SysInfo for this, upload
267
+ # it, execute it directly, parse the output.
268
+ def ostype
269
+ return @rye_ostype if @rye_ostype # simple cache
270
+ os = self.uname.first rescue nil
271
+ os ||= 'unknown'
272
+ os &&= os.downcase
273
+ @rye_ostype = os
274
+ end
275
+
276
+ # Returns the hash containing the parsed output of "env" on the
277
+ # remote machine. If the initialize option +:getenv+ was set to
278
+ # false, this will return an empty hash.
279
+ # This is a lazy loaded method so it fetches the remote envvars
280
+ # the first time this method is called.
281
+ #
282
+ # puts rbox.getenv['HOME'] # => "/home/gloria" (remote)
283
+ #
284
+ # NOTE: This method should not raise an exception under normal
285
+ # circumstances.
286
+ #
287
+ def getenv
288
+ if @rye_getenv && @rye_getenv.empty? && self.can?(:env)
289
+ env = self.env rescue []
290
+ env.each do |nv|
291
+ # Parse "GLORIA_HOME=/gloria/lives/here" into a name/value
292
+ # pair. The regexp ensures we split only at the 1st = sign
293
+ n, v = nv.scan(/\A([\w_-]+?)=(.+)\z/).flatten
294
+ @rye_getenv[n] = v
295
+ end
296
+ end
297
+ @rye_getenv
298
+ end
299
+
263
300
  # Add an environment variable. +n+ and +v+ are the name and value.
264
301
  # Returns the instance of Rye::Box
265
302
  def setenv(n, v)
266
303
  debug "Adding env: #{n}=#{v}"
267
- debug "prev value: #{@getenv[n]}"
268
- @getenv[n] = v
269
- (@current_environment_variables ||= {})[n] = v
304
+ debug "prev value: #{@rye_getenv[n]}"
305
+ @rye_getenv[n] = v
306
+ (@rye_current_environment_variables ||= {})[n] = v
270
307
  self
271
308
  end
272
309
  alias :add_env :setenv # deprecated?
273
310
 
274
311
  # The name of the user that opened the SSH connection
275
- def user; (@opts || {})[:user]; end
312
+ def user; (@rye_opts || {})[:user]; end
276
313
 
277
314
  # See Rye.keys
278
315
  def keys; Rye.keys; end
279
316
 
280
- # Returns +user@host+
281
- def to_s; '%s@%s' % [user, @host]; end
317
+ # Returns +user@rye_host+
318
+ def to_s; '%s@rye_%s' % [user, @rye_host]; end
282
319
 
283
320
  def inspect
284
321
  %q{#<%s:%s cwd=%s umask=%s env=%s safe=%s opts=%s>} %
285
322
  [self.class.to_s, self.host,
286
- @current_working_directory, @current_umask,
287
- (@current_environment_variables || '').inspect,
323
+ @rye_current_working_directory, @rye_current_umask,
324
+ (@rye_current_environment_variables || '').inspect,
288
325
  self.safe, self.opts.inspect]
289
326
  end
290
327
 
291
328
  # Compares itself with the +other+ box. If the hostnames
292
329
  # are the same, this will return true. Otherwise false.
293
330
  def ==(other)
294
- @host == other.host
331
+ @rye_host == other.host
295
332
  end
296
333
 
297
334
  # Returns the host SSH keys for this box
298
335
  def host_key
299
- raise "No host" unless @host
300
- Rye.remote_host_keys(@host)
336
+ raise "No host" unless @rye_host
337
+ Rye.remote_host_keys(@rye_host)
301
338
  end
302
339
 
303
340
  # Uses the output of "useradd -D" to determine the default home
@@ -305,10 +342,10 @@ module Rye
305
342
  # home directory. Currently used only by authorize_keys_remote.
306
343
  def guess_user_home(other_user=nil)
307
344
  this_user = other_user || opts[:user]
308
- @guessed_homes ||= {}
345
+ @rye_guessed_homes ||= {}
309
346
 
310
347
  # A simple cache.
311
- return @guessed_homes[this_user] if @guessed_homes.has_key?(this_user)
348
+ return @rye_guessed_homes[this_user] if @rye_guessed_homes.has_key?(this_user)
312
349
 
313
350
  # Some junk to determine where user home directories are by default.
314
351
  # We're relying on the command "useradd -D" so this may not work on
@@ -337,7 +374,7 @@ module Rye
337
374
  end
338
375
  end
339
376
 
340
- @guessed_homes[this_user] = "#{user_defaults['HOME']}/#{this_user}"
377
+ @rye_guessed_homes[this_user] = "#{user_defaults['HOME']}/#{this_user}"
341
378
  end
342
379
 
343
380
  # Copy the local public keys (as specified by Rye.keys) to
@@ -439,8 +476,8 @@ module Rye
439
476
  # with three arguments: command name, an Array of arguments, user name
440
477
  #
441
478
  def pre_command_hook(&block)
442
- @pre_command_hook = block if block
443
- @pre_command_hook
479
+ @rye_pre_command_hook = block if block
480
+ @rye_pre_command_hook
444
481
  end
445
482
 
446
483
  # Execute a block in the context of an instance of Rye::Box.
@@ -455,8 +492,25 @@ module Rye
455
492
  # rbox.batch(&block)
456
493
  #
457
494
  #
458
- def batch(&block)
459
- instance_eval &block
495
+ def batch(*args, &block)
496
+ self.instance_exec *args, &block
497
+ end
498
+
499
+ # instance_exec for Ruby 1.8 written by Mauricio Fernandez
500
+ # http://eigenclass.org/hiki/instance_exec
501
+ if RUBY_VERSION =~ /1.8/
502
+ module InstanceExecHelper; end
503
+ include InstanceExecHelper
504
+ def instance_exec(*args, &block) # !> method redefined; discarding old instance_exec
505
+ mname = "__instance_exec_#{Thread.current.object_id.abs}_#{object_id.abs}"
506
+ InstanceExecHelper.module_eval{ define_method(mname, &block) }
507
+ begin
508
+ ret = send(mname, *args)
509
+ ensure
510
+ InstanceExecHelper.module_eval{ undef_method(mname) } rescue nil
511
+ end
512
+ ret
513
+ end
460
514
  end
461
515
 
462
516
  # Supply a block to be called after every command. It's called
@@ -467,23 +521,23 @@ module Rye
467
521
  # behavior) so the block needs to check the Rye::Rap object to
468
522
  # determine whether an exception should be raised.
469
523
  def post_command_hook(&block)
470
- @post_command_hook = block if block
471
- @post_command_hook
524
+ @rye_post_command_hook = block if block
525
+ @rye_post_command_hook
472
526
  end
473
527
 
474
528
 
475
529
  private
476
530
 
477
- def debug(msg="unknown debug msg"); @debug.puts msg if @debug; end
478
- def error(msg="unknown error msg"); @error.puts msg if @error; end
479
- def pinfo(msg="unknown info msg"); @info.print msg if @info; end
480
- def info(msg="unknown info msg"); @info.puts msg if @info; end
531
+ def debug(msg="unknown debug msg"); @rye_debug.puts msg if @rye_debug; end
532
+ def error(msg="unknown error msg"); @rye_error.puts msg if @rye_error; end
533
+ def pinfo(msg="unknown info msg"); @rye_info.print msg if @rye_info; end
534
+ def info(msg="unknown info msg"); @rye_info.puts msg if @rye_info; end
481
535
 
482
536
  # Add the current environment variables to the beginning of +cmd+
483
537
  def prepend_env(cmd)
484
- return cmd unless @current_environment_variables.is_a?(Hash)
538
+ return cmd unless @rye_current_environment_variables.is_a?(Hash)
485
539
  env = ''
486
- @current_environment_variables.each_pair do |n,v|
540
+ @rye_current_environment_variables.each_pair do |n,v|
487
541
  env << "export #{n}=#{Escape.shell_single_word(v)}; "
488
542
  end
489
543
  [env, cmd].join(' ')
@@ -513,22 +567,22 @@ module Rye
513
567
 
514
568
  cmd, args = prep_args(*args)
515
569
 
516
- connect if !@ssh || @ssh.closed?
517
- raise Rye::NotConnected, @host unless @ssh && !@ssh.closed?
570
+ connect if !@rye_ssh || @rye_ssh.closed?
571
+ raise Rye::NotConnected, @rye_host unless @rye_ssh && !@rye_ssh.closed?
518
572
 
519
- cmd_clean = Rye.escape(@safe, cmd, args)
573
+ cmd_clean = Rye.escape(@rye_safe, cmd, args)
520
574
  cmd_clean = prepend_env(cmd_clean)
521
575
 
522
576
  # Add the current working directory before the command if supplied.
523
577
  # The command will otherwise run in the user's home directory.
524
- if @current_working_directory
525
- cwd = Rye.escape(@safe, 'cd', @current_working_directory)
578
+ if @rye_current_working_directory
579
+ cwd = Rye.escape(@rye_safe, 'cd', @rye_current_working_directory)
526
580
  cmd_clean = [cwd, cmd_clean].join(' && ')
527
581
  end
528
582
 
529
583
  # ditto (same explanation as cwd)
530
- if @current_umask
531
- cwd = Rye.escape(@safe, 'umask', @current_umask)
584
+ if @rye_current_umask
585
+ cwd = Rye.escape(@rye_safe, 'umask', @rye_current_umask)
532
586
  cmd_clean = [cwd, cmd_clean].join(' && ')
533
587
  end
534
588
 
@@ -536,8 +590,8 @@ module Rye
536
590
  info "COMMAND: #{cmd_clean}"
537
591
  debug "Executing: %s" % cmd_clean
538
592
 
539
- if @pre_command_hook.is_a?(Proc)
540
- @pre_command_hook.call(cmd, args, opts[:user])
593
+ if @rye_pre_command_hook.is_a?(Proc)
594
+ @rye_pre_command_hook.call(cmd, args, opts[:user])
541
595
  end
542
596
 
543
597
  ## NOTE: Do not raise a CommandNotFound exception in this method.
@@ -558,8 +612,8 @@ module Rye
558
612
  rap.exit_signal = esignal
559
613
  rap.cmd = cmd
560
614
 
561
- if @post_command_hook.is_a?(Proc)
562
- @post_command_hook.call(rap)
615
+ if @rye_post_command_hook.is_a?(Proc)
616
+ @rye_post_command_hook.call(rap)
563
617
  else
564
618
  # It seems a convention for various commands to return -1
565
619
  # when something only mildly concerning happens. ls even
@@ -623,7 +677,7 @@ module Rye
623
677
  #end
624
678
  end
625
679
 
626
- channel = @ssh.exec(command, &block)
680
+ channel = @rye_ssh.exec(command, &block)
627
681
  channel.wait # block until we get a response
628
682
 
629
683
  channel[:exit_code] = 0 if channel[:exit_code] == nil
@@ -655,8 +709,8 @@ module Rye
655
709
  raise "Must be one of: upload, download"
656
710
  end
657
711
 
658
- if @current_working_directory
659
- info "CWD (#{@current_working_directory})"
712
+ if @rye_current_working_directory
713
+ info "CWD (#{@rye_current_working_directory})"
660
714
  end
661
715
 
662
716
  files = [files].flatten.compact || []
@@ -674,7 +728,7 @@ module Rye
674
728
  raise "Cannot upload to a StringIO object"
675
729
  end
676
730
 
677
- # Fail early. We check the
731
+ # Fail early. We check whether the StringIO object is available to read
678
732
  files.each do |file|
679
733
  if file.is_a?(StringIO)
680
734
  raise "Cannot download a StringIO object" if direction == :download
@@ -694,13 +748,13 @@ module Rye
694
748
  self.mkdir(:p, other) unless self.file_exists?(other)
695
749
  end
696
750
 
697
- Net::SCP.start(@host, @opts[:user], @opts || {}) do |scp|
751
+ Net::SCP.start(@rye_host, @rye_opts[:user], @rye_opts || {}) do |scp|
698
752
  transfers = []
699
753
  files.each do |file|
700
754
  debug file.to_s
701
755
  transfers << scp.send(direction, file, other) do |ch, n, s, t|
702
756
  pinfo "#{n}: #{s}/#{t}b\r" # update line: "file: sent/total"
703
- @info.flush if @info # make sure every line is printed
757
+ @rye_info.flush if @rye_info # make sure every line is printed
704
758
  end
705
759
  end
706
760
  transfers.each { |t| t.wait } # Run file transfers in parallel
data/lib/rye/cmd.rb CHANGED
@@ -98,6 +98,24 @@ module Rye;
98
98
  # NOTE: Changes to current working directory with +cd+ or +[]+ are ignored.
99
99
  def download(*files); net_scp_transfer!(:download, *files); end
100
100
 
101
+
102
+ def file_append(filepath, newcontent, backup=false)
103
+ if self.file_exists?(filepath) && backup
104
+ self.cp filepath, "#{filepath}-previous"
105
+ end
106
+
107
+ file_content = self.download filepath
108
+ file_content ||= StringIO.new
109
+ if newcontent.is_a?(StringIO)
110
+ newcontent.rewind
111
+ file_content.puts newcontent.read
112
+ else
113
+ file_content.puts newcontent
114
+ end
115
+
116
+ self.upload file_content, filepath
117
+ end
118
+
101
119
  # Does a remote path exist?
102
120
  def file_exists?(path)
103
121
  begin
@@ -109,41 +127,6 @@ module Rye;
109
127
  # But on OSX exit code is 1. This is why we look at STDERR.
110
128
  ret.stderr.empty?
111
129
  end
112
-
113
- # Return the value of uname in lowercase
114
- # This is a temporary fix. We can use SysInfo for this, upload
115
- # it, execute it directly, parse the output.
116
- def ostype
117
- return @ostype if @ostype # simple cache
118
- os = self.uname.first rescue nil
119
- os ||= 'unknown'
120
- os &&= os.downcase
121
- @ostype = os
122
- end
123
-
124
- # Returns the hash containing the parsed output of "env" on the
125
- # remote machine. If the initialize option +:getenv+ was set to
126
- # false, this will return an empty hash.
127
- # This is a lazy loaded method so it fetches the remote envvars
128
- # the first time this method is called.
129
- #
130
- # puts rbox.getenv['HOME'] # => "/home/gloria" (remote)
131
- #
132
- # NOTE: This method should not raise an exception under normal
133
- # circumstances.
134
- #
135
- def getenv
136
- if @getenv && @getenv.empty? && self.can?(:env)
137
- env = self.env rescue []
138
- env.each do |nv|
139
- # Parse "GLORIA_HOME=/gloria/lives/here" into a name/value
140
- # pair. The regexp ensures we split only at the 1st = sign
141
- n, v = nv.scan(/\A([\w_-]+?)=(.+)\z/).flatten
142
- @getenv[n] = v
143
- end
144
- end
145
- @getenv
146
- end
147
130
 
148
131
  # Returns an Array of system commands available over SSH
149
132
  def can
data/rye.gemspec CHANGED
@@ -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.6.6"
4
+ s.version = "0.7.0"
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.6.6
4
+ version: 0.7.0
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-05-21 00:00:00 -04:00
12
+ date: 2009-05-30 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -123,7 +123,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
123
123
  requirements: []
124
124
 
125
125
  rubyforge_project: rye
126
- rubygems_version: 1.3.2
126
+ rubygems_version: 1.3.3
127
127
  signing_key:
128
128
  specification_version: 2
129
129
  summary: "Rye: Safely run SSH commands on a bunch of machines at the same time (from Ruby)."