rye 0.4.1 → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -5,6 +5,22 @@ TODO
5
5
  * Fingerprints: ssh-keygen -l -f id_rsa_repos.pub
6
6
 
7
7
 
8
+ #### 0.4.3 (2009-04-14) #############################
9
+
10
+ * ADDED: Rye::Box.missing_method to handle non existent commands
11
+ * FIXED: All Rye::Cmd command methods accept *args to make calling consistent.
12
+
13
+
14
+ #### 0.4.2 (2009-04-13) #############################
15
+
16
+ * ADDED: More helpful debug output
17
+ * ADDED: hostname command to Rye::Cmd
18
+ * CHANGE: Using OpenSSL's ssh-agent but also let's Net::SSH handle
19
+ the ssh keys.
20
+ * ADDED: Rye::Box.connect now supports multiple password attempts if STDIN.tty returns true
21
+ * ADDED: Rye::Box.interactive_ssh for opening an SSH session to the given box.
22
+
23
+
8
24
  #### 0.4.1 (2009-04-06) #############################
9
25
 
10
26
  * FIXED: Rye::Box.authorize_keys was not disabling safe mode properly
@@ -18,7 +34,7 @@ TODO
18
34
  * ADDED: == method for Rye::Box
19
35
  * ADDED: exit code and exit signal to Rye::Rap objects
20
36
  * ADDED: commands now raise a Rye::CommandError exception
21
- when the command returns an exit code greater than 0.
37
+ when the command returns an exit code greater than 0.
22
38
  * CHANGED: Box.add_command renamed to Box.run_command
23
39
  * FIXED: Box.run_command was parsing arguments incorrectly
24
40
  * FIXED: Box.net_ssh_exec was working on nil stderr
@@ -32,7 +48,7 @@ when the command returns an exit code greater than 0.
32
48
 
33
49
  * FIXED: Module.instance_methods bug. In Ruby 1.9 it's Symbols (1.8 was Strings).
34
50
  * FIXED: Rye::Set#add_boxes didn't return self.
35
- # UPDATED: Lots of docs tweaks.
51
+ * UPDATED: Lots of docs tweaks.
36
52
 
37
53
 
38
54
  #### 0.3 (2009-04-05) ###############################
@@ -42,9 +58,9 @@ when the command returns an exit code greater than 0.
42
58
  * FIXED: Rye::Box wasn't properly adding keypairs to SSH Agent
43
59
  * CHANGED: Moved all SSH key stuff to Rye (used to be done per Box)
44
60
  * ADDED: Supports all options provided by Net::SSH#start. This
45
- includes support for password logins and proxies.
61
+ includes support for password logins and proxies.
46
62
  * ADDED: Safe mode can now be disabled (to allow file globs
47
- and environment variable access).
63
+ and environment variable access).
48
64
  * ADDED: Basic sanity test
49
65
  * FIXED: Rye::Box.method_missing Symbol/String ambiguity
50
66
  * ADDED: Mucho more rdocs and examples.
@@ -1,6 +1,6 @@
1
1
  = Rye - v0.4
2
2
 
3
- Safely run remote commands via SSH in Ruby.
3
+ Safely run SSH commands on a bunch of machines at the same time (from Ruby).
4
4
 
5
5
  Rye is similar to Rush[http://rush.heroku.com] but everything happens over SSH (no HTTP daemon) and the default settings are less powerful (for safety). For example, file globs are disabled so unless otherwise specified, you can't do this: <tt>rbox.rm('-rf', '/etc/**/*')</tt>.
6
6
 
@@ -205,6 +205,8 @@ Rye permits only a limited number of system commands to be run. This default whi
205
205
  This list will grow. If you find one let me know!
206
206
 
207
207
  * Rye doesn't read the ~/.ssh/config file yet
208
+ * Highline 1.5 not working in Ruby 1.9 (password prompts hang)
209
+ * Rye uses OpenSSL's ssh-agent (if it exists). Rye starts it up as a child process and shuts it down using at_exit. If you have code in an at_exit that rely's on Rye, make sure your code runs before Rye's at_exit block is called. For example, Drydock uses at_exit too which is why in bin/rye you can see that Drydock is called explicitly so that Rye's at_exit is executed after Drydock executes a command.
208
210
 
209
211
  == Thanks
210
212
 
data/Rakefile CHANGED
@@ -74,7 +74,7 @@ Rake::RDocTask.new do |t|
74
74
  t.rdoc_files.include(LICENSE)
75
75
  t.rdoc_files.include(README)
76
76
  t.rdoc_files.include(CHANGES)
77
- #t.rdoc_files.include('bin/*')
77
+ t.rdoc_files.include('bin/*')
78
78
  t.rdoc_files.include('lib/**/*.rb')
79
79
  end
80
80
 
data/bin/rye CHANGED
@@ -21,7 +21,6 @@ include Drydock
21
21
  global :p, :path, String, "A directory containing SSH private keys or the path to a private key"
22
22
 
23
23
  before do |obj|
24
- STDERR.puts
25
24
  # Load private keys if specified
26
25
  if obj.global.path
27
26
  keys = Rye.find_private_keys(obj.global.path)
@@ -30,7 +29,7 @@ before do |obj|
30
29
  end
31
30
 
32
31
  after do
33
- STDERR.puts
32
+
34
33
  end
35
34
 
36
35
  desc "Add your public keys to one or more remote machines"
@@ -39,44 +38,16 @@ argv :hostname
39
38
  command :authorize do |obj|
40
39
  raise "You must specify a host" unless obj.argv.hostname
41
40
 
42
- highline = HighLine.new # Used for password prompt
43
-
44
41
  opts = { :debug => nil, :auth_methods => %w(publickey hostbased) }
45
42
  opts[:user] = obj.option.user if obj.option.user
46
43
 
47
44
  obj.argv.each do |hostname|
48
45
 
49
-
50
- retried = 0
51
- begin
52
- rbox = Rye::Box.new(hostname, opts).connect
53
- puts "Authorizing #{rbox.opts[:user]}@#{hostname}" if retried == 0
54
-
55
- # We know we're already authorized b/c we didn't have to give a password
56
- if retried == 0
57
- puts "%s is already authorized" % rbox.opts[:user]
58
- puts
59
- next
60
- end
61
-
62
- # An authentication failure means either the requested user doesn't
63
- # exist on the remote machine or we need to supply a password.
64
- rescue Net::SSH::AuthenticationFailed => ex
65
- STDERR.puts
66
- retried += 1
67
- if retried <= 3
68
- #opts[:password] = highline.ask("Password: ") { |q| q.echo = '' }
69
- opts[:auth_methods] = %w(password keyboard-interactive)
70
- retry
71
- else
72
- STDERR.puts "Authentication failed."
73
- exit 1
74
- end
75
- end
76
-
46
+ rbox = Rye::Box.new(hostname, opts).connect
47
+ puts "Authorizing #{rbox.opts[:user]}@#{hostname}"
77
48
  puts "Added public keys for: ", rbox.authorize_keys
49
+ puts "Now try: " << "ssh #{rbox.opts[:user]}@#{hostname}"
78
50
 
79
- puts
80
51
  end
81
52
 
82
53
  end
@@ -124,7 +95,7 @@ command_alias :pubkeys, :pubkey
124
95
  default :keys
125
96
  debug :off
126
97
 
127
- # We can Drydock specifically otherwise it will run at_exit. Rye also
98
+ # We call Drydock specifically otherwise it will run at_exit. Rye also
128
99
  # uses at_exit for shutting down the ssh-agent. Ruby executes at_exit
129
100
  # blocks in reverse order so if Drydock is required first, it's block
130
101
  # will run after Rye shuts down the ssh-agent.
data/bin/try CHANGED
@@ -105,7 +105,7 @@ puts %Q(
105
105
  # EXAMPLE 4 -- Accessing Multiple Machines
106
106
  #)
107
107
 
108
- rset = Rye::Set.new
108
+ rset = Rye::Set.new('default', :parallel => true)
109
109
  rbox = Rye::Box.new
110
110
 
111
111
  rset.add_keys('/private/key/path') # For passwordless logins
data/lib/rye.rb CHANGED
@@ -22,6 +22,12 @@ require 'sys'
22
22
  # disabled so unless otherwise specified, you can't do this:
23
23
  # <tt>rbox.rm('/etc/**/*')</tt>.
24
24
  #
25
+ # However, you can do this:
26
+ #
27
+ # rset = Rye::Set.new("dev-machines")
28
+ # rset.add_boxes('host1', 'host2', 'host3', 'host4')
29
+ # rset.ps('aux').grep
30
+ #
25
31
  # * See +bin/try+ for a bunch of working examples.
26
32
  # * See Rye::Box#initialize for info about disabling safe-mode.
27
33
  #
@@ -103,8 +109,7 @@ module Rye
103
109
  def add_keys(*keys)
104
110
  keys = keys.flatten.compact || []
105
111
  return if keys.empty?
106
- Rye.shell("ssh-add", keys) if keys
107
- keys
112
+ Rye.shell("ssh-add", keys)
108
113
  end
109
114
 
110
115
  # Returns an Array of info about the currently available
@@ -214,6 +219,10 @@ module Rye
214
219
  safe ? Escape.shell_command(cmd, *args).to_s : [cmd, args].flatten.compact.join(' ')
215
220
  end
216
221
 
222
+ def sshagent_info
223
+ @@agent_env
224
+ end
225
+
217
226
 
218
227
  private
219
228
 
@@ -17,7 +17,7 @@ module Rye
17
17
  #
18
18
  # rbox = Rye::Box.new('localhost')
19
19
  # rbox.hostname # => localhost
20
- # rbox.uname # => Darwin
20
+ # rbox.uname(:a) # => Darwin vanya 9.6.0 ...
21
21
  #
22
22
  class Box
23
23
  include Rye::Cmd
@@ -78,11 +78,16 @@ module Rye
78
78
  @debug = @opts.delete(:debug)
79
79
  @error = @opts.delete(:error)
80
80
 
81
+ debug @opts.inspect
82
+
81
83
  add_keys(@opts[:keys])
82
84
 
83
85
  # We don't want Net::SSH to handle the keypairs. This may change
84
86
  # but for we're letting ssh-agent do it.
85
- @opts.delete(:keys)
87
+ #@opts.delete(:keys)
88
+
89
+
90
+ debug "ssh-agent info: #{Rye.sshagent_info.inspect}"
86
91
 
87
92
  end
88
93
 
@@ -123,15 +128,47 @@ module Rye
123
128
  # Open an SSH session with +@host+. This called automatically
124
129
  # when you the first comamnd is run if it's not already connected.
125
130
  # Raises a Rye::NoHost exception if +@host+ is not specified.
131
+ # Will attempt a password login up to 3 times if the initial
132
+ # authentication fails.
126
133
  def connect
127
134
  raise Rye::NoHost unless @host
128
135
  disconnect if @ssh
129
136
  debug "Opening connection to #{@host}"
130
- @ssh = Net::SSH.start(@host, @opts[:user], @opts || {})
137
+ highline = HighLine.new # Used for password prompt
138
+ retried = 0
139
+ begin
140
+ @ssh = Net::SSH.start(@host, @opts[:user], @opts || {})
141
+ rescue Net::SSH::AuthenticationFailed => ex
142
+ retried += 1
143
+ if STDIN.tty? && retried <= 3
144
+ @opts[:password] = highline.ask("Password: ") { |q| q.echo = '' }
145
+ @opts[:auth_methods] ||= []
146
+ @opts[:auth_methods] = %w(password)
147
+ retry
148
+ else
149
+ STDERR.puts "Authentication failed."
150
+ exit 0
151
+ end
152
+ end
153
+
131
154
  @ssh.is_a?(Net::SSH::Connection::Session) && !@ssh.closed?
132
155
  self
133
156
  end
134
-
157
+
158
+ # Open an interactive SSH session. This only works if STDIN.tty?
159
+ # returns true. Otherwise it returns the SSH command that would
160
+ # have been run. This requires the SSH command-line executable (ssh).
161
+ # * +run+ when set to false, it will return the SSH command as a String
162
+ # and not open an SSH session.
163
+ #
164
+ def interactive_ssh(run=true)
165
+ debug "interactive_ssh with keys: #{Rye.keys.inspect}"
166
+ run = false unless STDIN.tty?
167
+ cmd = Rye.prepare_command("ssh", "#{@opts[:user]}@#{@host}")
168
+ return cmd unless run
169
+ system(cmd)
170
+ end
171
+
135
172
  # Close the SSH session with +@host+. This is called
136
173
  # automatically at exit if the connection is open.
137
174
  def disconnect
@@ -146,7 +183,13 @@ module Rye
146
183
  # Returns the instance of Box
147
184
  def add_keys(*additional_keys)
148
185
  additional_keys = [additional_keys].flatten.compact || []
149
- Rye.add_keys(additional_keys)
186
+ return if additional_keys.empty?
187
+ ret = Rye.add_keys(additional_keys)
188
+ if ret.is_a?(Rye::Rap)
189
+ debug "ssh-add exit_code: #{ret.exit_code}"
190
+ debug "ssh-add stdout: #{ret.stdout}"
191
+ debug "ssh-add stderr: #{ret.stderr}"
192
+ end
150
193
  self
151
194
  end
152
195
  alias :add_key :add_keys
@@ -202,7 +245,7 @@ module Rye
202
245
  path = key[2]
203
246
  debug "# Public key for #{path}"
204
247
  k = Rye::Key.from_file(path).public_key.to_ssh2
205
- self.mkdir('-p', '$HOME/.ssh') # Silently create dir if it doesn't exist
248
+ self.mkdir(:p, :m, '700', '$HOME/.ssh') # Silently create dir if it doesn't exist
206
249
  self.echo("'#{k}' >> $HOME/.ssh/authorized_keys")
207
250
  self.echo("'#{k}' >> $HOME/.ssh/authorized_keys2")
208
251
  self.chmod('-R', '0600', '$HOME/.ssh/authorized_keys*')
@@ -212,11 +255,17 @@ module Rye
212
255
  added_keys
213
256
  end
214
257
 
258
+ # A handler for undefined commands.
259
+ # Raises Rye::CommandNotFound exception.
260
+ def method_missing(meth, *args, &block)
261
+ raise Rye::CommandNotFound, "#{meth.to_s} (args: #{args.join(' ')})"
262
+ end
263
+
215
264
  private
216
265
 
217
266
 
218
- def debug(msg); @debug.puts msg if @debug; end
219
- def error(msg); @error.puts msg if @error; end
267
+ def debug(msg="unknown debug msg"); @debug.puts msg if @debug; end
268
+ def error(msg="unknown error msg"); @error.puts msg if @error; end
220
269
 
221
270
 
222
271
  # Add the current environment variables to the beginning of +cmd+
@@ -230,6 +279,7 @@ module Rye
230
279
  end
231
280
 
232
281
 
282
+
233
283
  # Execute a command over SSH
234
284
  #
235
285
  # * +args+ is a command name and list of arguments.
@@ -248,6 +298,8 @@ module Rye
248
298
  # but if it fails it will raise a Rye::NotConnected exception.
249
299
  #
250
300
  def run_command(*args)
301
+ debug "run_command with keys: #{Rye.keys.inspect}"
302
+
251
303
  connect if !@ssh || @ssh.closed?
252
304
  args = args.flatten.compact
253
305
  args = args.first.split(/\s+/) if args.size == 1
@@ -301,7 +353,7 @@ module Rye
301
353
  channel[:exit_signal] = data.read_long
302
354
  end
303
355
  # For long-running commands like top, this will print the output.
304
- # It cool, but we'd also need to enable STDIN to interact with
356
+ # It's cool, but we'd also need to enable STDIN to interact with
305
357
  # command.
306
358
  #channel.on_data do |ch, data|
307
359
  # puts "got stdout: #{data}"
@@ -14,8 +14,8 @@ module Rye;
14
14
  # def special(*args); cmd("/your/special/command", args); end
15
15
  # end
16
16
  #
17
- # rbox = Rye::Box.new
18
- # rbox.special # => "your output"
17
+ # rbox = Rye::Box.new('somehost')
18
+ # rbox.special # => "special on somehost"
19
19
  #
20
20
  module Cmd
21
21
  def wc(*args); cmd('wc', args); end
@@ -26,8 +26,8 @@ module Rye;
26
26
  def ps(*args); cmd('ps', args); end
27
27
  def sh(*args); cmd('sh', args); end
28
28
 
29
- def env; cmd "env"; end
30
- def pwd; cmd "pwd"; end
29
+ def env(*args); cmd "env"; end
30
+ def pwd(*args); cmd "pwd"; end
31
31
  def svn(*args); cmd('svn', args); end
32
32
  def cvs(*args); cmd('cvs', args); end
33
33
  def git(*args); cmd('git', args); end
@@ -45,16 +45,17 @@ module Rye;
45
45
  def echo(*args); cmd('echo', args); end
46
46
  def test(*args); cmd('test', args); end
47
47
 
48
- def mount; cmd("mount"); end
48
+ def mount(*args); cmd("mount"); end
49
49
  def sleep(seconds=1); cmd("sleep", seconds); end
50
50
  def mkdir(*args); cmd('mkdir', args); end
51
51
  def touch(*args); cmd('touch', args); end
52
52
  def uname(*args); cmd('uname', args); end
53
53
  def chmod(*args); cmd('chmod', args); end
54
54
 
55
- def uptime; cmd("uptime"); end
55
+ def uptime(*args); cmd("uptime"); end
56
56
  def python(*args); cmd('python', args); end
57
57
  def printenv(*args); cmd('printenv', args); end
58
+ def hostname(*args); cmd('hostname', args); end
58
59
 
59
60
 
60
61
  # def copy_to(*boxes)
@@ -73,10 +73,19 @@ module Rye;
73
73
  super
74
74
  end
75
75
 
76
- def >>(*other)
77
- p other
76
+ # NOTE: This is broken!
77
+ def grep *args
78
+ self.select do |boxrap|
79
+ b = boxrap.grep(*args)
80
+ b.empty? ? false : b
81
+ end
78
82
  end
79
83
 
84
+
85
+ #def >>(*other)
86
+ # p other
87
+ #end
88
+
80
89
  #---
81
90
  # If Box's shell methods return Rap objects, then
82
91
  # we can do stuff like this
@@ -128,6 +128,8 @@ module Rye
128
128
  end
129
129
  end
130
130
 
131
+ # Should it bubble up the exception for a single box?
132
+ # socket errors?
131
133
  threads.each do |t|
132
134
  sleep 0.01 # Give the thread some breathing room
133
135
  t.join # Wait for the thread to finish
data/lib/sys.rb CHANGED
@@ -6,51 +6,52 @@ require 'socket'
6
6
  # Portions of this code were originally from Amazon's EC2 AMI tools,
7
7
  # specifically lib/platform.rb.
8
8
  class SystemInfo #:nodoc:all
9
- VERSION = 2
10
- IMPLEMENTATIONS = [
9
+ unless defined?(IMPLEMENTATIONS)
10
+ VERSION = 4.freeze
11
+ IMPLEMENTATIONS = [
11
12
 
12
- # These are for JRuby, System.getproperty('os.name').
13
- # For a list of all values, see: http://lopica.sourceforge.net/os.html
14
- [/mac\s*os\s*x/i, :unix, :osx ],
15
- [/sunos/i, :unix, :solaris ],
16
- [/windows\s*ce/i, :win32, :windows ],
17
- [/windows/i, :win32, :windows ],
18
- [/osx/i, :unix, :osx ],
13
+ # These are for JRuby, System.getproperty('os.name').
14
+ # For a list of all values, see: http://lopica.sourceforge.net/os.html
15
+ [/mac\s*os\s*x/i, :unix, :osx ],
16
+ [/sunos/i, :unix, :solaris ],
17
+ [/windows\s*ce/i, :win32, :windows ],
18
+ [/windows/i, :win32, :windows ],
19
+ [/osx/i, :unix, :osx ],
19
20
 
20
- # TODO: implement other windows matches: # /djgpp|(cyg|ms|bcc)win|mingw/ (from mongrel)
21
+ # TODO: implement other windows matches: # /djgpp|(cyg|ms|bcc)win|mingw/ (from mongrel)
21
22
 
22
- # These are for RUBY_PLATFORM and JRuby
23
- [/java/i, :java, :java ],
24
- [/darwin/i, :unix, :osx ],
25
- [/linux/i, :unix, :linux ],
26
- [/freebsd/i, :unix, :freebsd ],
27
- [/netbsd/i, :unix, :netbsd ],
28
- [/solaris/i, :unix, :solaris ],
29
- [/irix/i, :unix, :irix ],
30
- [/cygwin/i, :unix, :cygwin ],
31
- [/mswin/i, :win32, :windows ],
32
- [/mingw/i, :win32, :mingw ],
33
- [/bccwin/i, :win32, :bccwin ],
34
- [/wince/i, :win32, :wince ],
35
- [/vms/i, :vms, :vms ],
36
- [/os2/i, :os2, :os2 ],
37
- [nil, :unknown, :unknown ],
23
+ # These are for RUBY_PLATFORM and JRuby
24
+ [/java/i, :java, :java ],
25
+ [/darwin/i, :unix, :osx ],
26
+ [/linux/i, :unix, :linux ],
27
+ [/freebsd/i, :unix, :freebsd ],
28
+ [/netbsd/i, :unix, :netbsd ],
29
+ [/solaris/i, :unix, :solaris ],
30
+ [/irix/i, :unix, :irix ],
31
+ [/cygwin/i, :unix, :cygwin ],
32
+ [/mswin/i, :win32, :windows ],
33
+ [/mingw/i, :win32, :mingw ],
34
+ [/bccwin/i, :win32, :bccwin ],
35
+ [/wince/i, :win32, :wince ],
36
+ [/vms/i, :vms, :vms ],
37
+ [/os2/i, :os2, :os2 ],
38
+ [nil, :unknown, :unknown ],
38
39
 
39
- ]
40
+ ].freeze
40
41
 
41
- ARCHITECTURES = [
42
- [/(i\d86)/i, :i386 ],
43
- [/x86_64/i, :x86_64 ],
44
- [/x86/i, :i386 ], # JRuby
45
- [/ia64/i, :ia64 ],
46
- [/alpha/i, :alpha ],
47
- [/sparc/i, :sparc ],
48
- [/mips/i, :mips ],
49
- [/powerpc/i, :powerpc ],
50
- [/universal/i,:universal ],
51
- [nil, :unknown ],
52
- ]
53
-
42
+ ARCHITECTURES = [
43
+ [/(i\d86)/i, :i386 ],
44
+ [/x86_64/i, :x86_64 ],
45
+ [/x86/i, :i386 ], # JRuby
46
+ [/ia64/i, :ia64 ],
47
+ [/alpha/i, :alpha ],
48
+ [/sparc/i, :sparc ],
49
+ [/mips/i, :mips ],
50
+ [/powerpc/i, :powerpc ],
51
+ [/universal/i,:universal ],
52
+ [nil, :unknown ],
53
+ ].freeze
54
+ end
54
55
 
55
56
 
56
57
  attr_reader :os
@@ -1,8 +1,8 @@
1
1
  @spec = Gem::Specification.new do |s|
2
2
  s.name = "rye"
3
3
  s.rubyforge_project = "rye"
4
- s.version = "0.4.1"
5
- s.summary = "Rye: Run system commands via SSH locally and remotely in a Ruby way."
4
+ s.version = "0.4.3"
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"
8
8
  s.email = "delano@solutious.com"
@@ -5,8 +5,7 @@
5
5
  $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
6
6
 
7
7
  require 'rye'
8
-
9
- boxA = Rye::Box.new('ryehost', :user => "root")
8
+ boxA = Rye::Box.new('localhost', :user => "delano")
10
9
  boxB = Rye::Box.new('127.0.0.1', :user => 'delano', :safe => false, :debug => STDOUT)
11
10
  set = Rye::Set.new
12
11
  set.add_boxes(boxA, boxB)
@@ -2,6 +2,8 @@
2
2
 
3
3
  # THIS IS A SCRAP FILE.
4
4
 
5
+
6
+
5
7
  __END__
6
8
  require 'openssl'
7
9
  key = OpenSSL::PKey::RSA.generate(1024)
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.4.1
4
+ version: 0.4.3
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-04-05 00:00:00 -04:00
12
+ date: 2009-04-14 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -52,7 +52,7 @@ dependencies:
52
52
  - !ruby/object:Gem::Version
53
53
  version: "0"
54
54
  version:
55
- description: "Rye: Run system commands via SSH locally and remotely in a Ruby way."
55
+ description: "Rye: Safely run SSH commands on a bunch of machines at the same time (from Ruby)."
56
56
  email: delano@solutious.com
57
57
  executables:
58
58
  - rye
@@ -91,7 +91,7 @@ post_install_message:
91
91
  rdoc_options:
92
92
  - --line-numbers
93
93
  - --title
94
- - "Rye: Run system commands via SSH locally and remotely in a Ruby way."
94
+ - "Rye: Safely run SSH commands on a bunch of machines at the same time (from Ruby)."
95
95
  - --main
96
96
  - README.rdoc
97
97
  require_paths:
@@ -114,6 +114,6 @@ rubyforge_project: rye
114
114
  rubygems_version: 1.3.1
115
115
  signing_key:
116
116
  specification_version: 2
117
- summary: "Rye: Run system commands via SSH locally and remotely in a Ruby way."
117
+ summary: "Rye: Safely run SSH commands on a bunch of machines at the same time (from Ruby)."
118
118
  test_files: []
119
119