rye 0.7.6 → 0.8.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
@@ -7,6 +7,18 @@ TODO
7
7
  * Add S3 support for Rye::Box.upload / download
8
8
 
9
9
 
10
+ #### 0.8.0 (2009-06-21) #############################
11
+
12
+ * FIXED: safely and unsafely (Rye::Box) now return the block return value
13
+ * ADDED: Rye::Set#parallel and Rye::Set#parallel= methods
14
+ * ADDED: Rye::Box#quietly
15
+ * CHANGE: Updated Rye::Set#inspect and Rye::Set#to_s
16
+ * CHANGE: Exception hook now receives: ex, cmd, user, host, nickname
17
+ * CHANGE: Increased Kernel.sleep to 0.03 in Rye::Set.run_command_parallel
18
+ * CHANGE: Renamed Rye::Cmd#upload and Rye::Cmd#download to file_upload and file_download
19
+ * CHANGE: Rye::Cmd#file_exists? now executes quietly (doesn't pollute logging)
20
+
21
+
10
22
  #### 0.7.6 (2009-06-19) #############################
11
23
 
12
24
  * FIXED: Raise Rye::NoPty exception when Net::SSH returns message
data/README.rdoc CHANGED
@@ -1,4 +1,4 @@
1
- = Rye - v0.7
1
+ = Rye - v0.8
2
2
 
3
3
  Safely run SSH commands on a bunch of machines at the same time (from Ruby).
4
4
 
@@ -42,7 +42,7 @@ You can specify environment variables
42
42
  rbox.env # => ['HOME=/home/rye', 'RYE=Forty Creek', ...]
43
43
 
44
44
 
45
- == EXAMPLE 3 -- Accessing Multiple Machines
45
+ == EXAMPLE 3a -- Accessing Multiple Machines
46
46
 
47
47
  rset = Rye::Set.new
48
48
  rbox = Rye::Box.new
@@ -54,25 +54,33 @@ Calling methods on Rye::Set objects is very similar to calling them on Rye::Box
54
54
  p rset.uptime # => [[14:19:02 up 32 days, 19:35 ...], [14:19:02 up 30 days, 01:35]]
55
55
  p rset['/etc'].ls # => [['file1', 'file2', ...], ['life1', 'life2', ...]]
56
56
 
57
-
58
- == EXAMPLE 4 -- FILE TRANSFERS
57
+ == EXAMPLE 3b -- Accessing Multiple Machines -- In Parallel
58
+
59
+ By default, Rye:Set connects to each machine sequentially in the order they were added to the set. Commands can also be run in parallel:
60
+
61
+ rset = Rye::Set.new('set-name', :parallel => true)
62
+ OR
63
+ rset.parallel = true
64
+
65
+
66
+ == EXAMPLE 4 -- File Transfers
59
67
 
60
68
  rbox = Rye::Box.new("localhost", :info => true)
61
69
 
62
70
  dir_upload = "#{Rye.sysinfo.tmpdir}/rye-upload/"
63
71
  dir_download = "#{Rye.sysinfo.tmpdir}/rye-download/"
64
72
 
65
- rbox.upload("#{RYE_HOME}/README.rdoc",
73
+ rbox.file_upload("#{RYE_HOME}/README.rdoc",
66
74
  "#{RYE_HOME}/LICENSE.txt", dir_upload)
67
75
 
68
76
  applejack = StringIO.new("Some in-memory content")
69
- rbox.upload(applejack, "#{dir_upload}/applejack.txt")
77
+ rbox.file_upload(applejack, "#{dir_upload}/applejack.txt")
70
78
 
71
79
  p rbox.ls(dir_upload) # => [README.rdoc, LICENSE.txt, applejack.txt]
72
80
  p rbox.cat("#{dir_upload}/applejack.txt") # => "Some in-memory content"
73
81
 
74
82
  filecontent = StringIO.new
75
- rbox.download("#{dir_upload}/applejack.txt", filecontent)
83
+ rbox.file_download("#{dir_upload}/applejack.txt", filecontent)
76
84
 
77
85
  p filecontent.read
78
86
 
data/lib/rye/box.rb CHANGED
@@ -34,20 +34,24 @@ 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+
37
+ # Returns the current value of the stash +@rye_stash+
38
38
  def stash; @rye_stash; end
39
+ def quiet; @rye_quiet; end
39
40
  def nickname; @rye_nickname || host; end
40
-
41
+
41
42
  def host=(val); @rye_host = val; end
42
43
  def opts=(val); @rye_opts = val; end
43
44
 
44
- # Returns the storage area +@rye_stash+
45
+ # Store a value to the stash +@rye_stash+
45
46
  def stash=(val); @rye_stash = val; end
46
47
  def nickname=(val); @rye_nickname = val; end
47
48
 
48
49
  def enable_safe_mode; @rye_safe = true; end
49
50
  def disable_safe_mode; @rye_safe = false; end
50
51
 
52
+ def enable_quiet_mode; @rye_quiet = true; end
53
+ def disable_quiet_mode; @rye_quiet = false; end
54
+
51
55
  # The most recent value from Box.cd or Box.[]
52
56
  def current_working_directory; @rye_current_working_directory; end
53
57
 
@@ -94,6 +98,7 @@ module Rye
94
98
  :debug => nil,
95
99
  :error => STDERR,
96
100
  :getenv => true,
101
+ :quiet => false
97
102
  }.merge(opts)
98
103
 
99
104
  # Close the SSH session before Ruby exits. This will do nothing
@@ -105,6 +110,7 @@ module Rye
105
110
  @rye_safe, @rye_debug = @rye_opts.delete(:safe), @rye_opts.delete(:debug)
106
111
  @rye_info, @rye_error = @rye_opts.delete(:info), @rye_opts.delete(:error)
107
112
  @rye_getenv = {} if @rye_opts.delete(:getenv) # Enable getenv with a hash
113
+ @rye_quiet = @rye_opts.delete(:quiet)
108
114
 
109
115
  # Just in case someone sends a true value rather than IO object
110
116
  @rye_debug = STDERR if @rye_debug == true
@@ -279,11 +285,11 @@ module Rye
279
285
  def to_s; '%s@rye_%s' % [user, @rye_host]; end
280
286
 
281
287
  def inspect
282
- %q{#<%s:%s name=%s cwd=%s umask=%s env=%s safe=%s opts=%s>} %
288
+ %q{#<%s:%s name=%s cwd=%s umask=%s env=%s safe=%s opts=%s keys=%s>} %
283
289
  [self.class.to_s, self.host, self.nickname,
284
290
  @rye_current_working_directory, @rye_current_umask,
285
291
  (@rye_current_environment_variables || '').inspect,
286
- self.safe, self.opts.inspect]
292
+ self.safe, self.opts.inspect, self.keys.inspect]
287
293
  end
288
294
 
289
295
  # Compares itself with the +other+ box. If the hostnames
@@ -372,7 +378,7 @@ module Rye
372
378
  if self.file_exists?(akey_path)
373
379
  # TODO: Make Rye::Cmd.incremental_backup
374
380
  self.cp(akey_path, "#{akey_path}-previous")
375
- authorized_keys = self.download("#{homedir}/#{akey_path}")
381
+ authorized_keys = self.file_download("#{homedir}/#{akey_path}")
376
382
  end
377
383
  authorized_keys ||= StringIO.new
378
384
 
@@ -391,7 +397,7 @@ module Rye
391
397
  authorized_keys.rewind
392
398
 
393
399
  self.mkdir(:p, :m, '700', File.dirname(akey_path))
394
- self.upload(authorized_keys, "#{homedir}/#{akey_path}")
400
+ self.file_upload(authorized_keys, "#{homedir}/#{akey_path}")
395
401
  self.chmod('0600', akey_path)
396
402
  self.chown(:R, this_user.to_s, File.dirname(akey_path))
397
403
  end
@@ -490,18 +496,35 @@ module Rye
490
496
  def unsafely(*args, &block)
491
497
  previous_state = @rye_safe
492
498
  disable_safe_mode
493
- self.instance_exec *args, &block
499
+ ret = self.instance_exec *args, &block
494
500
  @rye_safe = previous_state
501
+ ret
495
502
  end
496
503
 
497
504
  # See unsafely (except in reverse)
498
505
  def safely(*args, &block)
499
506
  previous_state = @rye_safe
500
507
  enable_safe_mode
501
- self.instance_exec *args, &block
508
+ ret = self.instance_exec *args, &block
502
509
  @rye_safe = previous_state
510
+ ret
503
511
  end
504
512
 
513
+ # Like batch, except it enables quiet mode before executing the block.
514
+ # After executing the block, quiet mode is returned back to whichever
515
+ # state it was previously in. In other words, this method won't enable
516
+ # quiet mode if it was already disabled.
517
+ #
518
+ # In quiet mode, the pre and post command hooks are not called. This
519
+ # is used internally when calling commands like +ls+ to check whether
520
+ # a file path exists (to prevent polluting the logs).
521
+ def quietly(*args, &block)
522
+ previous_state = @rye_quiet
523
+ enable_quiet_mode
524
+ ret = self.instance_exec *args, &block
525
+ @rye_quiet = previous_state
526
+ ret
527
+ end
505
528
 
506
529
  # instance_exec for Ruby 1.8 written by Mauricio Fernandez
507
530
  # http://eigenclass.org/hiki/instance_exec
@@ -646,22 +669,24 @@ module Rye
646
669
  raise Rye::NotConnected, @rye_host unless @rye_ssh && !@rye_ssh.closed?
647
670
 
648
671
  cmd_clean = Rye.escape(@rye_safe, cmd, args)
649
- cmd_clean = prepend_env(cmd_clean)
672
+
673
+ # This following is the command we'll actually execute. cmd_clean
674
+ # can be used for logging, otherwise the output is confusing.
675
+ cmd_internal = prepend_env(cmd_clean)
650
676
 
651
677
  # Add the current working directory before the command if supplied.
652
678
  # The command will otherwise run in the user's home directory.
653
679
  if @rye_current_working_directory
654
680
  cwd = Rye.escape(@rye_safe, 'cd', @rye_current_working_directory)
655
- cmd_clean = [cwd, cmd_clean].join(' && ')
681
+ cmd_internal = [cwd, cmd_internal].join(' && ')
656
682
  end
657
683
 
658
684
  # ditto (same explanation as cwd)
659
685
  if @rye_current_umask
660
686
  cwd = Rye.escape(@rye_safe, 'umask', @rye_current_umask)
661
- cmd_clean = [cwd, cmd_clean].join(' && ')
687
+ cmd_internal = [cwd, cmd_internal].join(' && ')
662
688
  end
663
689
 
664
-
665
690
  ## NOTE: Do not raise a CommandNotFound exception in this method.
666
691
  # We want it to be possible to define methods to a single instance
667
692
  # of Rye::Box. i.e. def rbox.rm()...
@@ -673,20 +698,21 @@ module Rye
673
698
 
674
699
  begin
675
700
  info "COMMAND: #{cmd_clean}"
676
- debug "Executing: %s" % cmd_clean
701
+ debug "Executing: #{cmd_internal}"
677
702
 
678
- if @rye_pre_command_hook.is_a?(Proc)
703
+ if !@rye_quiet && @rye_pre_command_hook.is_a?(Proc)
679
704
  @rye_pre_command_hook.call(cmd_clean, user, host, nickname)
680
705
  end
681
706
 
682
- stdout, stderr, ecode, esignal = net_ssh_exec!(cmd_clean)
683
-
684
707
  rap = Rye::Rap.new(self)
708
+ rap.cmd = cmd_clean
709
+
710
+ stdout, stderr, ecode, esignal = net_ssh_exec!(cmd_internal)
711
+
685
712
  rap.add_stdout(stdout || '')
686
713
  rap.add_stderr(stderr || '')
687
714
  rap.add_exit_code(ecode)
688
715
  rap.exit_signal = esignal
689
- rap.cmd = cmd
690
716
 
691
717
  #info "stdout: #{rap.stdout}"
692
718
  #info "stderr: #{rap.stderr}"
@@ -699,10 +725,11 @@ module Rye
699
725
  raise Rye::CommandError.new(rap) if ecode != 0
700
726
 
701
727
  rescue Exception => ex
728
+ return rap if @rye_quiet
702
729
  choice = nil
703
730
  @rye_exception_hook.each_pair do |klass,act|
704
731
  next unless ex.kind_of? klass
705
- choice = @rye_exception_hook[klass].call(ex)
732
+ choice = act.call(ex, cmd_clean, user, host, nickname)
706
733
  break
707
734
  end
708
735
  if choice == :retry
@@ -714,7 +741,9 @@ module Rye
714
741
  end
715
742
  end
716
743
 
717
- @rye_post_command_hook.call(rap) if @rye_post_command_hook.is_a?(Proc)
744
+ if !@rye_quiet && @rye_post_command_hook.is_a?(Proc)
745
+ @rye_post_command_hook.call(rap)
746
+ end
718
747
 
719
748
  rap
720
749
  end
@@ -775,7 +804,7 @@ module Rye
775
804
  raise Rye::NoPty if data =~ /Pseudo-terminal will not/
776
805
 
777
806
  end
778
-
807
+
779
808
  end
780
809
 
781
810
  channel = @rye_ssh.exec(command, &block)
data/lib/rye/cmd.rb CHANGED
@@ -92,7 +92,7 @@ module Rye;
92
92
  # Always return nil.
93
93
  #
94
94
  # NOTE: Changes to current working directory with +cd+ or +[]+ are ignored.
95
- def upload(*files); net_scp_transfer!(:upload, *files); end
95
+ def file_upload(*files); net_scp_transfer!(:upload, *files); end
96
96
 
97
97
  # Transfer files from a machine via Net::SCP.
98
98
  # * +files+ is an Array of files to download. The last element must be the
@@ -105,7 +105,7 @@ module Rye;
105
105
  # Return nil or a StringIO object, if specified as the target.
106
106
  #
107
107
  # NOTE: Changes to current working directory with +cd+ or +[]+ are ignored.
108
- def download(*files); net_scp_transfer!(:download, *files); end
108
+ def file_download(*files); net_scp_transfer!(:download, *files); end
109
109
 
110
110
  # Append +newcontent+ to remote +filepath+. If the file doesn't exist
111
111
  # it will be created. If +backup+ is specified, +filepath+ will be
@@ -113,7 +113,7 @@ module Rye;
113
113
  def file_append(filepath, newcontent, backup=false)
114
114
  if self.file_exists?(filepath)
115
115
  self.cp filepath, "#{filepath}-previous" if backup
116
- file_content = self.download filepath
116
+ file_content = self.file_download filepath
117
117
  end
118
118
 
119
119
  file_content ||= StringIO.new
@@ -124,13 +124,13 @@ module Rye;
124
124
  file_content.puts newcontent
125
125
  end
126
126
 
127
- self.upload file_content, filepath
127
+ self.file_upload file_content, filepath
128
128
  end
129
129
 
130
130
  # Does +path+ from the current working directory?
131
131
  def file_exists?(path)
132
132
  begin
133
- ret = self.ls(path)
133
+ ret = self.quietly { ls(path) }
134
134
  rescue Rye::CommandError => ex
135
135
  ret = ex.rap
136
136
  end
data/lib/rye/set.rb CHANGED
@@ -8,6 +8,10 @@ module Rye
8
8
  attr_reader :boxes
9
9
  attr_reader :opts
10
10
 
11
+ # Run commands in parallel? A Boolean value. Default: false.
12
+ attr_accessor :parallel
13
+
14
+
11
15
  # * +name+ The name of the set of machines
12
16
  # * +opts+ a hash of optional arguments
13
17
  #
@@ -83,11 +87,12 @@ module Rye
83
87
  end
84
88
 
85
89
  def to_s
86
- "%s: %s" % [self.name, ]
90
+ "%s:%s" % [self.class.to_s, @name]
87
91
  end
88
92
 
89
93
  def inspect
90
- %q{#<%s:%s boxes=%s opts=%s>} % [self.class.to_s, self.name, self.boxes.join(','), self.opts.inspect]
94
+ a = [self.class.to_s, @name, @parallel, @opts.inspect, @boxes.inspect]
95
+ %q{#<%s:%s parallel=%s opts=%s boxes=%s>} % a
91
96
  end
92
97
 
93
98
  # See Rye::Box.[]
@@ -142,12 +147,11 @@ module Rye
142
147
  end
143
148
  end
144
149
 
145
- # Should it bubble up the exception for a single box?
146
- # socket errors?
150
+ # Should it bubble up the exception for a single box? socket errors?
147
151
  threads.each do |t|
148
- sleep 0.01 # Give the thread some breathing room
149
- t.join # Wait for the thread to finish
150
- raps << t[:rap] # Grab the result
152
+ Kernel.sleep 0.03 # Give the thread some breathing room
153
+ t.join # Wait for the thread to finish
154
+ raps << t[:rap] # Grab the result
151
155
  end
152
156
 
153
157
  raps
data/lib/rye.rb CHANGED
@@ -1,8 +1,4 @@
1
1
 
2
- # Temporary fix before Highline 1.5.1 is release. This fixes
3
- # a the issue with Ruby 1.9 that causes the prompts to hang.
4
- $:.unshift File.join(File.dirname(__FILE__), '..', 'vendor', 'highline-1.5.1', 'lib')
5
-
6
2
  require 'logger'
7
3
  require 'thread'
8
4
  require 'base64'
@@ -47,7 +43,7 @@ module Rye
47
43
  extend self
48
44
 
49
45
  unless defined?(SYSINFO)
50
- VERSION = 0.7.freeze
46
+ VERSION = "0.8.0".freeze
51
47
  SYSINFO = SysInfo.new.freeze
52
48
  end
53
49
 
@@ -205,7 +201,8 @@ module Rye
205
201
  # NOTE: shell is a bit paranoid so it escapes every argument. This means
206
202
  # you can only use literal values. That means no asterisks too.
207
203
  #
208
- # Returns a Rye::Rap object containing the
204
+ # Returns a Rye::Rap object.
205
+ #
209
206
  def shell(cmd, *args)
210
207
  args = args.flatten.compact
211
208
  cmd = cmd.to_s if cmd.is_a?(Symbol)
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.7.6"
4
+ s.version = "0.8.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.7.6
4
+ version: 0.8.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-06-19 00:00:00 -04:00
12
+ date: 2009-06-21 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency