rye 0.8.0 → 0.8.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.txt +8 -0
- data/Rudyfile +135 -0
- data/bin/try +202 -0
- data/lib/rye.rb +1 -1
- data/lib/rye/box.rb +46 -37
- data/lib/rye/cmd.rb +5 -0
- data/rye.gemspec +3 -1
- metadata +3 -1
data/CHANGES.txt
CHANGED
@@ -6,6 +6,14 @@ TODO
|
|
6
6
|
* Fingerprints: ssh-keygen -l -f id_rsa_repos.pub
|
7
7
|
* Add S3 support for Rye::Box.upload / download
|
8
8
|
|
9
|
+
#### 0.8.1 (2009-06-22) #############################
|
10
|
+
|
11
|
+
* FIXED: file_upload now handles globs like a champ
|
12
|
+
* FIXED: Handling of relative paths in Rye::Box#cd and Rye::Box#[]
|
13
|
+
* ADDED: file_upload now assumes uploading to home directory when only 1 arg
|
14
|
+
* ADDED: Rudyfile for remote 'clean-machine' tests
|
15
|
+
* CHANGE: guess_user_home, ostype, and getenv now run quietly
|
16
|
+
|
9
17
|
|
10
18
|
#### 0.8.0 (2009-06-21) #############################
|
11
19
|
|
data/Rudyfile
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
# = Rudy configuration
|
2
|
+
#
|
3
|
+
|
4
|
+
# ----------------------------------------------------------- DEFAULTS --------
|
5
|
+
# These values are used as defaults for their respective global settings. All
|
6
|
+
# non-boolean values are expected to be Symbols.
|
7
|
+
#
|
8
|
+
defaults do
|
9
|
+
zone :'eu-west-1b'
|
10
|
+
environment :rye
|
11
|
+
color true # Terminal colors? true/false
|
12
|
+
yes false # Auto-confirm? true/false
|
13
|
+
end
|
14
|
+
|
15
|
+
# --------------------------------------------------------- MACHINES --------
|
16
|
+
# The machines block describes the 'physical' characteristics of your machines.
|
17
|
+
machines do
|
18
|
+
|
19
|
+
zone :'us-east-1b' do
|
20
|
+
ami 'ami-e348af8a' # Alestic Debian 5.0, 32-bit (US)
|
21
|
+
bucket 'rudy-ami-us'
|
22
|
+
end
|
23
|
+
zone :'eu-west-1b' do
|
24
|
+
ami 'ami-1dbd9569' # rudy-ami-eu/debian-5.0-32-ruby-r1
|
25
|
+
bucket 'rudy-ami-eu'
|
26
|
+
end
|
27
|
+
|
28
|
+
hostname :rudy # One of: :default, :rudy, 'your-name'
|
29
|
+
|
30
|
+
env :rye do
|
31
|
+
user :root # User to connect as
|
32
|
+
size 'm1.small' # EC2 machine type for all machines
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
# ----------------------------------------------------------- COMMANDS --------
|
39
|
+
# The commands block defines shell commands that can be used in routines. The
|
40
|
+
# ones defined here are added to the default list defined by Rye::Cmd (Rudy
|
41
|
+
# executes all SSH commands via Rye).
|
42
|
+
#
|
43
|
+
# Usage:
|
44
|
+
#
|
45
|
+
# allow COMMAND-NAME
|
46
|
+
# allow COMMAND-NAME, '/path/2/COMMAND'
|
47
|
+
# allow COMMAND-NAME, '/path/2/COMMAND', 'default argument', 'another arg'
|
48
|
+
#
|
49
|
+
commands do
|
50
|
+
allow :apt_get, "apt-get", :y, :q
|
51
|
+
allow :gem18_install, "/usr/bin/gem1.8", "install", :n, '/usr/bin', :y, :V, "--no-rdoc", "--no-ri"
|
52
|
+
allow :gem18_sources, "/usr/bin/gem1.8", "sources"
|
53
|
+
allow :gem19_install, "/usr/local/bin/gem", "install", :n, '/usr/bin', :y, :V, "--no-rdoc", "--no-ri"
|
54
|
+
allow :gem19_sources, "/usr/local/bin/gem", "sources"
|
55
|
+
allow :update_rubygems
|
56
|
+
allow :ruby18, "/usr/bin/ruby1.8"
|
57
|
+
allow :ruby19, "/usr/local/bin/ruby"
|
58
|
+
allow :ssh_keygen, 'ssh-keygen'
|
59
|
+
allow :rm
|
60
|
+
end
|
61
|
+
|
62
|
+
# ----------------------------------------------------------- ROUTINES --------
|
63
|
+
# The routines block describes the repeatable processes for each machine group.
|
64
|
+
# To run a routine, specify its name on the command-line: rudy startup
|
65
|
+
routines do
|
66
|
+
|
67
|
+
env :rye do
|
68
|
+
startup do
|
69
|
+
after :installdeps, :authorize
|
70
|
+
after :runtest
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
runtest do
|
75
|
+
remote :root do
|
76
|
+
ruby18 :r, 'rubygems', 'rye/bin/try'
|
77
|
+
ruby19 'rye/bin/try'
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
authorize do
|
82
|
+
remote :root do
|
83
|
+
rm :f, '/root/.ssh/id_rsa'
|
84
|
+
ssh_keygen :q, :f, '/root/.ssh/id_rsa', :N, ''
|
85
|
+
rye 'authorize_local'
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
installdeps do
|
90
|
+
local do
|
91
|
+
rake 'package'
|
92
|
+
end
|
93
|
+
remote :root do
|
94
|
+
gem18_install "rye", "delano-rye"
|
95
|
+
gem19_install "rye", 'delano-rye'
|
96
|
+
disable_safe_mode
|
97
|
+
rm :r, :f, 'rye*'
|
98
|
+
file_upload 'pkg/rye-*gz'
|
99
|
+
tar :z, :x, :f, 'rye-*gz'
|
100
|
+
rm 'rye-*gz'
|
101
|
+
mv 'rye-*', 'rye'
|
102
|
+
cd 'rye'
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# NOTE: sysupdate only needs to be run for the bare instances.
|
107
|
+
sysupdate do
|
108
|
+
remote :root do
|
109
|
+
apt_get "update"
|
110
|
+
apt_get "install", "build-essential", "git-core"
|
111
|
+
apt_get "install", "libssl-dev", "libreadline5-dev", "zlib1g-dev"
|
112
|
+
apt_get "install", "ruby1.8-dev", "rubygems"
|
113
|
+
gem18_install 'rubygems-update' # for 1.8
|
114
|
+
update_rubygems # for 1.8
|
115
|
+
gem18_sources :a, "http://gems.github.com"
|
116
|
+
end
|
117
|
+
after :install_ruby19
|
118
|
+
end
|
119
|
+
|
120
|
+
install_ruby19 do
|
121
|
+
remote :root do
|
122
|
+
wget :q, 'ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.1-p129.tar.gz'
|
123
|
+
tar :z, :x, :f, 'ruby-1.9.1-p129.tar.gz'
|
124
|
+
cd 'ruby-1.9.1-p129'
|
125
|
+
configure
|
126
|
+
make
|
127
|
+
make 'install'
|
128
|
+
apt_get "install", "rubygems1.9"
|
129
|
+
gem19_sources :a, "http://gems.github.com"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
|
data/bin/try
ADDED
@@ -0,0 +1,202 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
# Rye -- A working example
|
4
|
+
#
|
5
|
+
# If your reading this via the rdocs you won't be able to see the code
|
6
|
+
# See: http://github.com/delano/rye/blob/master/bin/try
|
7
|
+
#
|
8
|
+
# Usage: bin/try
|
9
|
+
#
|
10
|
+
|
11
|
+
RYE_HOME = File.join(File.dirname(__FILE__), '..')
|
12
|
+
$:.unshift File.join(RYE_HOME, 'lib')
|
13
|
+
%w{net-ssh sysinfo storable drydock}.each { |dir| $:.unshift File.join(File.dirname(__FILE__), '..', '..', dir, 'lib') }
|
14
|
+
|
15
|
+
require 'stringio'
|
16
|
+
require 'yaml'
|
17
|
+
require 'rye'
|
18
|
+
|
19
|
+
|
20
|
+
puts %Q(
|
21
|
+
# ------------------------------------------------------------------
|
22
|
+
# EXAMPLE 1 -- Basic Usage
|
23
|
+
#)
|
24
|
+
|
25
|
+
rbox = Rye::Box.new('localhost')
|
26
|
+
|
27
|
+
# Commands are run as methods on the Rye::Box object
|
28
|
+
puts rbox.uptime # => 11:02 up 16:01, 3 users
|
29
|
+
|
30
|
+
# The response value for all commands is a Rye::Rap object. The rap is a
|
31
|
+
# subclass of Array so you can treat it as an Array, but it can also act
|
32
|
+
# like a String if there's only one element.
|
33
|
+
p rbox.ls(:a, '/') # => ['.', '..', 'bin', 'etc', ...]
|
34
|
+
|
35
|
+
# You can change directories
|
36
|
+
puts rbox.pwd # => /home/rye
|
37
|
+
puts rbox['/usr/bin'].pwd # => /usr/bin
|
38
|
+
puts rbox.pwd # => /usr/bin
|
39
|
+
|
40
|
+
# You can specify environment variables
|
41
|
+
rbox.setenv(:RYE, "Forty Creek")
|
42
|
+
rbox.env # => ['HOME=/home/rye', 'RYE=Forty Creek', ...]
|
43
|
+
|
44
|
+
# The commands method returns an Array of available commands:
|
45
|
+
puts rbox.commands.join(', ') # => pwd, touch, echo, wc, ...
|
46
|
+
|
47
|
+
# When you're done you can disconnect explicitly.
|
48
|
+
# (Although Rye does this automatically at exit.)
|
49
|
+
rbox.disconnect
|
50
|
+
|
51
|
+
|
52
|
+
puts %Q(
|
53
|
+
# ------------------------------------------------------------------
|
54
|
+
# EXAMPLE 2 -- Disabling Safe-Mode
|
55
|
+
#)
|
56
|
+
|
57
|
+
rbox_safe = Rye::Box.new('localhost')
|
58
|
+
rbox_wild = Rye::Box.new('localhost', :safe => false)
|
59
|
+
|
60
|
+
# Safe-mode is enabled by default. In safe-mode, all command
|
61
|
+
# arguments are thoroughly escaped. This prevents access to
|
62
|
+
# environment variables and file globs (among other things).
|
63
|
+
p rbox_safe.echo('$HOME') # => "$HOME"
|
64
|
+
p rbox_safe['/etc'].ls('host*') rescue Rye::CommandError # Doesn't exist
|
65
|
+
p rbox_safe.ls('-l | wc -l') rescue Rye::CommandError # => '|' is not a valid ls arg
|
66
|
+
|
67
|
+
# Here's the same commands with safe-mode disabled:
|
68
|
+
p rbox_wild.echo('$HOME') # => "/home/rye"
|
69
|
+
p rbox_wild['/etc'].ls('host*') # => ["hostconfig", "hosts"]
|
70
|
+
p rbox_wild.ls('-l | wc -l') # => 110
|
71
|
+
p rbox_wild.echo('$HOME > /tmp/rye-home') # =>
|
72
|
+
p rbox_wild.cat('/tmp/rye-home') # => "/home/rye"
|
73
|
+
|
74
|
+
|
75
|
+
|
76
|
+
puts %Q(
|
77
|
+
# ------------------------------------------------------------------
|
78
|
+
# EXAMPLE 3 -- Custom Commands
|
79
|
+
#)
|
80
|
+
|
81
|
+
rbox = Rye::Box.new('localhost')
|
82
|
+
rbox.add_keys('/private/key/path') # Specify additional private keys
|
83
|
+
|
84
|
+
# There's currently no rye900 command
|
85
|
+
p rbox.commands.member?('rye9000') # => false
|
86
|
+
|
87
|
+
# But we can add our own commands to the Rye::Cmd class. They
|
88
|
+
# automatically become available to all Rye::Box objects.
|
89
|
+
module Rye::Cmd
|
90
|
+
def rye9000(*args)
|
91
|
+
run_command("ls", args)
|
92
|
+
end
|
93
|
+
def somescript(*args)
|
94
|
+
run_command("/path/to/my/script", args)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# We can now run rye9000 (with arguments)
|
99
|
+
p rbox.rye9000('-a') # => [".", "..", ".bashrc", ...]
|
100
|
+
p rbox.commands.member?('rye9000') # => true
|
101
|
+
|
102
|
+
|
103
|
+
puts %Q(
|
104
|
+
# ------------------------------------------------------------------
|
105
|
+
# EXAMPLE 4 -- Accessing Multiple Machines
|
106
|
+
#)
|
107
|
+
|
108
|
+
rset = Rye::Set.new('default', :parallel => true)
|
109
|
+
rbox = Rye::Box.new
|
110
|
+
p rbox
|
111
|
+
|
112
|
+
rset.add_keys('/private/key/path') # For passwordless logins
|
113
|
+
rset.add_boxes(rbox, '127.0.0.1') # Add boxes as hostnames or objects
|
114
|
+
|
115
|
+
# Calling methods on Rye::Set objects is very similar to calling them on
|
116
|
+
# Rye::Box objects. In fact, it's identical:
|
117
|
+
p rset.uptime # => [[14:19:02 up 32 days, 19:35 ...], [14:19:02 up 30 days, 01:35]]
|
118
|
+
p rset['/usr'].ls # => [['bin', 'etc', ...], ['bin', 'etc', ...]]
|
119
|
+
|
120
|
+
# Like Rye::Box, the response value is a Rye::Rap object containing the
|
121
|
+
# responses from each box. Each response is itself a Rye::Rap object.
|
122
|
+
unames = rset.uname
|
123
|
+
p unames # => [["Darwin"], ["Darwin"]]
|
124
|
+
puts unames.class # => Rye::Rap
|
125
|
+
|
126
|
+
# The Rye::Rap object also keeps a reference to the object that called the
|
127
|
+
# command. In this case, it will keep a reference to Rye::Set:
|
128
|
+
puts unames.set.class # => Rye::Set
|
129
|
+
puts unames.set == rset # => true
|
130
|
+
puts unames.size # => 2
|
131
|
+
puts unames.first # => Darwin
|
132
|
+
puts unames.first.class # => Rye::Rap
|
133
|
+
puts unames.first.box.class # => Rye::Box
|
134
|
+
puts unames.first.box == rbox # => true
|
135
|
+
|
136
|
+
# Envrionment variables can be set the same way as with Rye::Box
|
137
|
+
rset.setenv(:RYE, "Forty Creek")
|
138
|
+
p rset.env.first.select { |env| env =~ /RYE/ } # => ["RYE=Forty Creek"]
|
139
|
+
|
140
|
+
|
141
|
+
puts %Q(
|
142
|
+
# ------------------------------------------------------------------
|
143
|
+
# EXAMPLE 5 -- ERROR HANDLING
|
144
|
+
#)
|
145
|
+
|
146
|
+
rbox = Rye::Box.new('localhost', :safe => false) # Note: safe mode is off
|
147
|
+
|
148
|
+
# Rye follows the standard convention of taking exception to a non-zero
|
149
|
+
# exit code by raising a Rye::CommandError. In this case, rye9000.test
|
150
|
+
# is not found by the ls command.
|
151
|
+
begin
|
152
|
+
rbox.ls('rye.test')
|
153
|
+
rescue Rye::CommandError => ex
|
154
|
+
puts ex.exit_code # => 1
|
155
|
+
puts ex.stderr # => ls: rye.test: No such file or directory
|
156
|
+
end
|
157
|
+
|
158
|
+
# The Rye:Rap response objects also give you the STDOUT and STDERR
|
159
|
+
# content separately. Here we redirect STDOUT to STDERR, so this
|
160
|
+
# will return nothing:
|
161
|
+
puts rbox.uname('-a 1>&2').stdout # =>
|
162
|
+
|
163
|
+
# It all went to STDERR:
|
164
|
+
puts rbox.uname('-a 1>&2').stderr # => Darwin ryehost 9.6.0 ...
|
165
|
+
|
166
|
+
# There were no actual errors so the exit code should be 0.
|
167
|
+
puts rbox.uname('-a 1>&2').exit_code # => 0
|
168
|
+
|
169
|
+
|
170
|
+
puts %Q(
|
171
|
+
# ------------------------------------------------------------------
|
172
|
+
# EXAMPLE 6 -- FILE TRANSFERS
|
173
|
+
#)
|
174
|
+
|
175
|
+
dir_upload = "#{Rye.sysinfo.tmpdir}/rye-upload/"
|
176
|
+
dir_download = "#{Rye.sysinfo.tmpdir}/rye-download/"
|
177
|
+
|
178
|
+
rbox = Rye::Box.new("localhost", :info => false)
|
179
|
+
|
180
|
+
# Rye ships without an rm method (for safety!). Here
|
181
|
+
# we add the rm method only to this instance of rbox.
|
182
|
+
def rbox.rm(*args); cmd('rm', args); end
|
183
|
+
|
184
|
+
rbox.rm(:r, :f, dir_upload) # Silently delete test dirs
|
185
|
+
rbox.rm(:r, :f, dir_download)
|
186
|
+
|
187
|
+
rbox.file_upload("#{RYE_HOME}/README.rdoc",
|
188
|
+
"#{RYE_HOME}/LICENSE.txt", dir_upload)
|
189
|
+
|
190
|
+
applejack = StringIO.new("Some in-memory content")
|
191
|
+
rbox.file_upload(applejack, "#{dir_upload}/applejack.txt")
|
192
|
+
|
193
|
+
p rbox.ls(dir_upload) # => [README.rdoc, LICENSE.txt, applejack.txt]
|
194
|
+
p rbox.cat("#{dir_upload}/applejack.txt") # => "Some in-memory content"
|
195
|
+
|
196
|
+
filecontent = StringIO.new
|
197
|
+
rbox.file_download("#{dir_upload}/applejack.txt", filecontent)
|
198
|
+
filecontent.rewind
|
199
|
+
p filecontent.read
|
200
|
+
|
201
|
+
|
202
|
+
|
data/lib/rye.rb
CHANGED
data/lib/rye/box.rb
CHANGED
@@ -155,28 +155,26 @@ module Rye
|
|
155
155
|
# rbox['/usr/bin'].pwd # => /usr/bin ($ cd /usr/bin && pwd)
|
156
156
|
# rbox.pwd # => /usr/bin ($ cd /usr/bin && pwd)
|
157
157
|
#
|
158
|
-
def [](
|
159
|
-
if
|
160
|
-
@rye_current_working_directory =
|
158
|
+
def [](fpath=nil)
|
159
|
+
if fpath.nil? || fpath.index('/') == 0
|
160
|
+
@rye_current_working_directory = fpath
|
161
161
|
else
|
162
162
|
# Append to non-absolute paths
|
163
|
-
|
164
|
-
|
163
|
+
if @rye_current_working_directory
|
164
|
+
newpath = File.join(@rye_current_working_directory, fpath)
|
165
|
+
@rye_current_working_directory = newpath
|
166
|
+
else
|
167
|
+
@rye_current_working_directory = fpath
|
168
|
+
end
|
165
169
|
end
|
170
|
+
info "CWD: #{@rye_current_working_directory}"
|
166
171
|
self
|
167
172
|
end
|
168
173
|
# Like [] except it returns an empty Rye::Rap object to mimick
|
169
174
|
# a regular command method. Call with nil key (or no arg) to
|
170
175
|
# reset.
|
171
|
-
def cd(
|
172
|
-
|
173
|
-
@rye_current_working_directory = key
|
174
|
-
else
|
175
|
-
# Append to non-absolute paths
|
176
|
-
newpath = File.join(@rye_current_working_directory, key)
|
177
|
-
@rye_current_working_directory = File.expand_path(newpath)
|
178
|
-
end
|
179
|
-
ret = Rye::Rap.new(self)
|
176
|
+
def cd(fpath=nil)
|
177
|
+
Rye::Rap.new(self[fpath])
|
180
178
|
end
|
181
179
|
|
182
180
|
# Change the current umask (sort of -- works the same way as cd)
|
@@ -237,7 +235,7 @@ module Rye
|
|
237
235
|
# it, execute it directly, parse the output.
|
238
236
|
def ostype
|
239
237
|
return @rye_ostype if @rye_ostype # simple cache
|
240
|
-
os = self.uname.first rescue nil
|
238
|
+
os = self.quietly { uname.first } rescue nil
|
241
239
|
os ||= 'unknown'
|
242
240
|
os &&= os.downcase
|
243
241
|
@rye_ostype = os
|
@@ -256,11 +254,11 @@ module Rye
|
|
256
254
|
#
|
257
255
|
def getenv
|
258
256
|
if @rye_getenv && @rye_getenv.empty? && self.can?(:env)
|
259
|
-
|
260
|
-
|
257
|
+
vars = self.quietly { env } rescue []
|
258
|
+
vars.each do |nvpair|
|
261
259
|
# Parse "GLORIA_HOME=/gloria/lives/here" into a name/value
|
262
260
|
# pair. The regexp ensures we split only at the 1st = sign
|
263
|
-
n, v =
|
261
|
+
n, v = nvpair.scan(/\A([\w_-]+?)=(.+)\z/).flatten
|
264
262
|
@rye_getenv[n] = v
|
265
263
|
end
|
266
264
|
end
|
@@ -307,6 +305,7 @@ module Rye
|
|
307
305
|
# Uses the output of "useradd -D" to determine the default home
|
308
306
|
# directory. This returns a GUESS rather than the a user's real
|
309
307
|
# home directory. Currently used only by authorize_keys_remote.
|
308
|
+
# Only useful before you've logged in. Otherwise check $HOME
|
310
309
|
def guess_user_home(other_user=nil)
|
311
310
|
this_user = other_user || opts[:user]
|
312
311
|
@rye_guessed_homes ||= {}
|
@@ -321,7 +320,7 @@ module Rye
|
|
321
320
|
# /etc/default/useradd, HOME=/home OR useradd -D
|
322
321
|
# /etc/adduser.config, DHOME=/home OR ??
|
323
322
|
user_defaults = {}
|
324
|
-
raw = self.useradd(:D) rescue ["HOME=/home"]
|
323
|
+
raw = self.quietly { useradd(:D) } rescue ["HOME=/home"]
|
325
324
|
ostmp = self.ostype
|
326
325
|
raw.each do |nv|
|
327
326
|
|
@@ -697,8 +696,7 @@ module Rye
|
|
697
696
|
## raise Rye::CommandNotFound unless self.can?(cmd)
|
698
697
|
|
699
698
|
begin
|
700
|
-
info "COMMAND: #{
|
701
|
-
debug "Executing: #{cmd_internal}"
|
699
|
+
info "COMMAND: #{cmd_internal}"
|
702
700
|
|
703
701
|
if !@rye_quiet && @rye_pre_command_hook.is_a?(Proc)
|
704
702
|
@rye_pre_command_hook.call(cmd_clean, user, host, nickname)
|
@@ -870,15 +868,26 @@ module Rye
|
|
870
868
|
|
871
869
|
# We allow a single file to be downloaded into a StringIO object
|
872
870
|
# but only when no target has been specified.
|
873
|
-
if direction == :download
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
871
|
+
if direction == :download
|
872
|
+
if files.size == 1
|
873
|
+
debug "Created StringIO for download"
|
874
|
+
target = StringIO.new
|
875
|
+
else
|
876
|
+
target = files.pop # The last path is the download target.
|
877
|
+
end
|
878
|
+
|
879
|
+
elsif direction == :upload
|
880
|
+
raise "Cannot upload to a StringIO object" if target.is_a?(StringIO)
|
881
|
+
if files.size == 1
|
882
|
+
target = self.getenv['HOME'] || guess_user_home
|
883
|
+
debug "Assuming upload to #{target}"
|
884
|
+
else
|
885
|
+
target = files.pop
|
886
|
+
end
|
887
|
+
|
888
|
+
# Expand fileglobs (e.g. path/*.rb becomes [path/1.rb, path/2.rb]).
|
889
|
+
# This should happen after checking files.size to determine the target
|
890
|
+
files = files.collect { |file| Dir.glob file }.flatten unless @rye_safe
|
882
891
|
end
|
883
892
|
|
884
893
|
# Fail early. We check whether the StringIO object is available to read
|
@@ -891,21 +900,21 @@ module Rye
|
|
891
900
|
end
|
892
901
|
end
|
893
902
|
|
894
|
-
|
903
|
+
info "#{direction.to_s.upcase} TO: #{target}"
|
895
904
|
debug "FILES: " << files.join(', ')
|
896
905
|
|
897
906
|
# Make sure the remote directory exists. We can do this only when
|
898
|
-
# there's more than one file because "
|
899
|
-
if files.size > 1 && !
|
900
|
-
debug "CREATING TARGET DIRECTORY: #{
|
901
|
-
self.mkdir(:p,
|
907
|
+
# there's more than one file because "target" could be a file name
|
908
|
+
if files.size > 1 && !target.is_a?(StringIO)
|
909
|
+
debug "CREATING TARGET DIRECTORY: #{target}"
|
910
|
+
self.mkdir(:p, target) unless self.file_exists?(target)
|
902
911
|
end
|
903
912
|
|
904
913
|
Net::SCP.start(@rye_host, @rye_opts[:user], @rye_opts || {}) do |scp|
|
905
914
|
transfers = []
|
906
915
|
files.each do |file|
|
907
916
|
debug file.to_s
|
908
|
-
transfers << scp.send(direction, file,
|
917
|
+
transfers << scp.send(direction, file, target) do |ch, n, s, t|
|
909
918
|
pinfo "#{n}: #{s}/#{t}b\r" # update line: "file: sent/total"
|
910
919
|
@rye_info.flush if @rye_info # make sure every line is printed
|
911
920
|
end
|
@@ -914,7 +923,7 @@ module Rye
|
|
914
923
|
info $/
|
915
924
|
end
|
916
925
|
|
917
|
-
|
926
|
+
target.is_a?(StringIO) ? target : nil
|
918
927
|
end
|
919
928
|
|
920
929
|
|
data/lib/rye/cmd.rb
CHANGED
@@ -36,6 +36,7 @@ module Rye;
|
|
36
36
|
def du(*args); cmd('du', args); end
|
37
37
|
|
38
38
|
def env; cmd "env"; end
|
39
|
+
def rye(*args); cmd "rye", args; end
|
39
40
|
def pwd(*args); cmd "pwd", args; end
|
40
41
|
def svn(*args); cmd('svn', args); end
|
41
42
|
def cvs(*args); cmd('cvs', args); end
|
@@ -50,6 +51,7 @@ module Rye;
|
|
50
51
|
def grep(*args); cmd('grep', args); end
|
51
52
|
def date(*args); cmd('date', args); end
|
52
53
|
def ruby(*args); cmd('ruby', args); end
|
54
|
+
def rudy(*args); cmd('rudy', args); end
|
53
55
|
def perl(*args); cmd('perl', args); end
|
54
56
|
def bash(*args); cmd('bash', args); end
|
55
57
|
def echo(*args); cmd('echo', args); end
|
@@ -77,8 +79,11 @@ module Rye;
|
|
77
79
|
def bunzip2(*args); cmd('bunzip2', args); end
|
78
80
|
def getconf(*args); cmd('getconf', args); end
|
79
81
|
def history(*args); cmd('history', args); end
|
82
|
+
def rudy_s3(*args); cmd('rudy-s3', args); end
|
80
83
|
def printenv(*args); cmd('printenv', args); end
|
81
84
|
def hostname(*args); cmd('hostname', args); end
|
85
|
+
def rudy_ec2(*args); cmd('rudy-ec2', args); end
|
86
|
+
def rudy_edb(*args); cmd('rudy-sdb', args); end
|
82
87
|
def configure(*args); cmd('./configure', args); end
|
83
88
|
|
84
89
|
# Transfer files to a machine via Net::SCP.
|
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.8.
|
4
|
+
s.version = "0.8.1"
|
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"
|
@@ -35,7 +35,9 @@
|
|
35
35
|
LICENSE.txt
|
36
36
|
README.rdoc
|
37
37
|
Rakefile
|
38
|
+
Rudyfile
|
38
39
|
bin/rye
|
40
|
+
bin/try
|
39
41
|
lib/esc.rb
|
40
42
|
lib/rye.rb
|
41
43
|
lib/rye/box.rb
|
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.8.
|
4
|
+
version: 0.8.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Delano Mandelbaum
|
@@ -86,7 +86,9 @@ files:
|
|
86
86
|
- LICENSE.txt
|
87
87
|
- README.rdoc
|
88
88
|
- Rakefile
|
89
|
+
- Rudyfile
|
89
90
|
- bin/rye
|
91
|
+
- bin/try
|
90
92
|
- lib/esc.rb
|
91
93
|
- lib/rye.rb
|
92
94
|
- lib/rye/box.rb
|