capistrano 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +241 -0
- data/MIT-LICENSE +20 -0
- data/README +35 -0
- data/THANKS +4 -0
- data/lib/capistrano/actor.rb +111 -24
- data/lib/capistrano/cli.rb +18 -9
- data/lib/capistrano/command.rb +8 -0
- data/lib/capistrano/configuration.rb +1 -1
- data/lib/capistrano/gateway.rb +29 -43
- data/lib/capistrano/recipes/standard.rb +38 -10
- data/lib/capistrano/scm/base.rb +1 -2
- data/lib/capistrano/scm/cvs.rb +5 -0
- data/lib/capistrano/scm/mercurial.rb +83 -0
- data/lib/capistrano/scm/subversion.rb +18 -18
- data/lib/capistrano/shell.rb +224 -0
- data/lib/capistrano/ssh.rb +2 -3
- data/lib/capistrano/version.rb +2 -2
- data/test/actor_test.rb +104 -5
- data/test/scm/cvs_test.rb +10 -0
- data/test/scm/subversion_test.rb +6 -6
- metadata +95 -79
data/CHANGELOG
ADDED
@@ -0,0 +1,241 @@
|
|
1
|
+
*SVN*
|
2
|
+
|
3
|
+
* Add experimental 'shell' task [Jamis Buck]
|
4
|
+
|
5
|
+
* Display file for external configurations, rather than inspected proc. [Jamis Buck]
|
6
|
+
|
7
|
+
* Connect to multiple servers in parallel, rather than serially. [Jamis Buck]
|
8
|
+
|
9
|
+
* Add SCM module for Mercurial (closes #4150) [Matthew Elder]
|
10
|
+
|
11
|
+
* Remove unused line in SCM::Base (closes #5619) [chris@seagul.co.uk]
|
12
|
+
|
13
|
+
* More efficient "svn log" usage (closes #5620) [Anatol Pomozov]
|
14
|
+
|
15
|
+
* Better support for key passphrases in the SVN module (closes #5920) [llasram@gmail.com]
|
16
|
+
|
17
|
+
* Fix missing default for :local in cvs.rb (closes #3645) [jeremy@hinegardner.org]
|
18
|
+
|
19
|
+
* Fix awkward spacing in gemspec file (closes #3888) [grant@antiflux.org]
|
20
|
+
|
21
|
+
* Add support for :sudo variable to specify path to sudo (closes #4578) [timothee.peignier@tryphon.org]
|
22
|
+
|
23
|
+
* Make previous_release return nil if there are no previous releases (closes #4959) [bdabney@cavoksolutions.com]
|
24
|
+
|
25
|
+
* Uncache releases list after update_code is called so that newly released dir is included (closes #3766) [Jamis Buck]
|
26
|
+
|
27
|
+
* Allow the subversion scm to accept HTTPS certificates (closes #4792) [Jamis Buck]
|
28
|
+
|
29
|
+
* Make sure rollbacks occur within the scope of the task that triggered them [Jamis Buck]
|
30
|
+
|
31
|
+
* Fixed the default recipe to work with setups that haven't yet gone pids [DHH]
|
32
|
+
|
33
|
+
* Symlink and setup for shared/pids to tmp/pids [DHH]
|
34
|
+
|
35
|
+
* Fix some incorrect usage text (closes #4507) [gerry_shaw@yahoo.com]
|
36
|
+
|
37
|
+
* Added Actor#stream method that makes it easy to create cross-server streams [DHH]. Example:
|
38
|
+
|
39
|
+
desc "Run a tail on multiple log files at the same time"
|
40
|
+
task :tail_fcgi, :roles => :app do
|
41
|
+
stream "tail -f #{shared_path}/log/fastcgi.crash.log"
|
42
|
+
end
|
43
|
+
|
44
|
+
* Make update_code and symlink a macro task under the name "update" for easy of deploy to servers that does not run fcgis [DHH]
|
45
|
+
|
46
|
+
* Changed setup, update_code, rollback_code, and symlink to work on all servers instead of only those in the :app, :web, and :db roles. A server can opt out of being part of the release deployment by setting :no_release => true [DHH]
|
47
|
+
|
48
|
+
* Added support for :except on task declarations as the opposite of :only [DHH]. Example:
|
49
|
+
|
50
|
+
role :app, "192.168.0.2"
|
51
|
+
role :file, "192.168.0.3", :no_release => true
|
52
|
+
|
53
|
+
task :symlink, :except => { :no_release => true } do
|
54
|
+
on_rollback { run "ln -nfs #{previous_release} #{current_path}" }
|
55
|
+
run "ln -nfs #{current_release} #{current_path}"
|
56
|
+
end
|
57
|
+
|
58
|
+
cap symlink # will not run on 192.168.0.3
|
59
|
+
|
60
|
+
* Deprecate the -r/--recipe switch in favor of -f/--file (for more make/rake-like semantics) [Jamis Buck]
|
61
|
+
|
62
|
+
* Fix gemspec to include a dependency on rake 0.7 [Jamis Buck]
|
63
|
+
|
64
|
+
* Added respect for ENV["HOSTS"] that'll be used instead of the roles specified in the task definition [DHH]. Example:
|
65
|
+
|
66
|
+
HOSTS=192.168.0.1 cap setup # one-off setup for that server, doesn't need to be prespecified in the recipes file
|
67
|
+
|
68
|
+
* Added respect for ENV["ROLES"] that'll be used instead of the roles specified in the task definition [DHH]. Example:
|
69
|
+
|
70
|
+
task :setup, :roles => [ :app, :web, :db ]
|
71
|
+
# normally this would run every where
|
72
|
+
end
|
73
|
+
|
74
|
+
ROLES=app cap setup # this will only run for the app role, overwritting the default declaration
|
75
|
+
|
76
|
+
* Added :hosts option to task definition that allows you to specify cross-cutting tasks [DHH]. Example:
|
77
|
+
|
78
|
+
task :setup, :hosts => [ "06.example.com", "01.example.com" ] do
|
79
|
+
# this task will happen on 06 and 01 regardless of which roles they belong to
|
80
|
+
end
|
81
|
+
|
82
|
+
* Fix operator precedence problem in script for touching the revisions.log #3223 [jason.garber@emu.edu]
|
83
|
+
|
84
|
+
|
85
|
+
*1.1.0* (March 6th, 2006)
|
86
|
+
|
87
|
+
* Simplify the generated capistrano.rake file, and make it easier to customize
|
88
|
+
|
89
|
+
* Use rake-like command-line semantics ("cap deploy", in addition to "cap -a deploy")
|
90
|
+
|
91
|
+
* Rename to capistrano
|
92
|
+
|
93
|
+
* Make the generated capistrano.rake file use rake namespaces, and include all default tasks
|
94
|
+
|
95
|
+
* Look for config/deploy.rb, capfile, and Capfile by default
|
96
|
+
|
97
|
+
|
98
|
+
*1.0.1* (February 20th, 2006)
|
99
|
+
|
100
|
+
* Fix broken switchtower_invoke function in switchtower.rake (missing require statement)
|
101
|
+
|
102
|
+
|
103
|
+
*1.0.0* (Feburary 18th, 2006)
|
104
|
+
|
105
|
+
* Make CVS module's :local value default to "."
|
106
|
+
|
107
|
+
* Add "invoke" task for executing one-off commands
|
108
|
+
|
109
|
+
* Make port selection smarter for gateway connections
|
110
|
+
|
111
|
+
* Add extension mechanism for custom ST operations and third-party task libraries
|
112
|
+
|
113
|
+
* Make ST rails rake tasks more configurable
|
114
|
+
|
115
|
+
* Add Actor#current_task and simplify Task#servers
|
116
|
+
|
117
|
+
* Add Actor#connect! method for working around lazy connection establishing
|
118
|
+
|
119
|
+
* Make sure IO::TRUNC is specified for Net::SFTP uploads (#3510)
|
120
|
+
|
121
|
+
* Add branch support to CVS [jeremy@hinegardner.org] (#3596)
|
122
|
+
|
123
|
+
* Add bazaar-ng SCM module [Damien Merenne]
|
124
|
+
|
125
|
+
* Add optional :svn_username and :svn_password variables
|
126
|
+
|
127
|
+
* Allow Proc-valued variables to be set more conveniently (set(:foo) { "bar" })
|
128
|
+
|
129
|
+
* Add perforce SCM module [Richard McMahon]
|
130
|
+
|
131
|
+
* Add bazaar (v1) SCM module [Edd Dumbill] (#3533)
|
132
|
+
|
133
|
+
* Fix stftime format string used in CVS module to be Windows-compatible (fixes #3383)
|
134
|
+
|
135
|
+
* Add an better error when a task is run and no servers match the required conditions
|
136
|
+
|
137
|
+
* Add default spinner and cold_deploy tasks, and spinner_user variable
|
138
|
+
|
139
|
+
* Changed restart_via variable to (boolean) use_sudo
|
140
|
+
|
141
|
+
* Only chmod when the revisions.log file is first created
|
142
|
+
|
143
|
+
* Make UPPERCASE variables work
|
144
|
+
|
145
|
+
* Added rails_env variable (defaults to production) for use by tasks that employ the RAILS_ENV environment variable
|
146
|
+
|
147
|
+
* Added Actor.default_io_proc
|
148
|
+
|
149
|
+
* Set :actor key on SSH channel instances
|
150
|
+
|
151
|
+
|
152
|
+
*0.10.0* (January 2nd, 2006)
|
153
|
+
|
154
|
+
* Handle ssh password prompts like "someone's password:"
|
155
|
+
|
156
|
+
* Make CLI#echo available as a class method.
|
157
|
+
|
158
|
+
* Add CLI#with_echo.
|
159
|
+
|
160
|
+
* Make the default password prompt available as a class method.
|
161
|
+
|
162
|
+
# Add documentation for the CLI class.
|
163
|
+
|
164
|
+
* Add a sanity check to make sure the correct versions of Net::SSH and Net::SFTP are installed.
|
165
|
+
|
166
|
+
* Added a cleanup task to remove unused releases from the deployment directory
|
167
|
+
|
168
|
+
* Allow password to be reentered on sudo if it was entered incorrectly
|
169
|
+
|
170
|
+
* Use && as the command separator for the checkouts, so that errors are caught early.
|
171
|
+
|
172
|
+
* Ping each SSH connection every 1s during command processing so that long-running commands don't cause the connection to timeout.
|
173
|
+
|
174
|
+
* Add a 0.01s sleep during the command loop so that the CPU doesn't go ballistic while ST is doing its thing.
|
175
|
+
|
176
|
+
* Add :restart_via variable for specifying whether restart ought to use :sudo (default, use sudo)
|
177
|
+
|
178
|
+
* Use SFTP for file transfers (if available).
|
179
|
+
|
180
|
+
* Add an "update_current" task that will do an svn up on the current release
|
181
|
+
|
182
|
+
* Use the :checkout variable to determine what operation to use for svn checkouts (instead of co, like "export").
|
183
|
+
|
184
|
+
* The Rails rake tasks now load ST directly, instead of invoking it via system
|
185
|
+
|
186
|
+
* Added ssh_options variable to configure the SSH connection parameters #2734 [jerrett@bravenet.com]
|
187
|
+
|
188
|
+
* Require Net::SSH 1.0.5
|
189
|
+
|
190
|
+
|
191
|
+
*0.9.0* (October 18th, 2005)
|
192
|
+
|
193
|
+
* Use process reaper instead of custom reap script for restarting
|
194
|
+
|
195
|
+
* Use -S switch to set variables before reading recipe files #2242
|
196
|
+
|
197
|
+
* Have setup.rb create a switchtower.cmd file on Win32 platforms #2402
|
198
|
+
|
199
|
+
* Add diff_from_last_deploy to the rails switchtower rakefile template
|
200
|
+
|
201
|
+
* Add diff_from_last_deploy task (currently only works with subversion)
|
202
|
+
|
203
|
+
* Add deploy_with_migrations task.
|
204
|
+
|
205
|
+
* Make the migrate task more customizable.
|
206
|
+
|
207
|
+
* If no password is given with the -p switch, prompt for password immediately.
|
208
|
+
|
209
|
+
* Do not install a switchtower stub in the script directory. Assume the switchtower executable is in the path.
|
210
|
+
|
211
|
+
* Remove trailing newlines from commands to prevent trailing backslash #2141
|
212
|
+
|
213
|
+
* Default parameters work correctly with the generator #2218 [Scott Barron]
|
214
|
+
|
215
|
+
* Attempt to require 'rubygems' explicitly when running the switchtower utility #2134
|
216
|
+
|
217
|
+
* Make default tasks work only on app/db/web roles, so that additional roles may be created for boxes with specific needs without needing to (for instance) deploy the app to those boxes
|
218
|
+
|
219
|
+
* Default the application name to "Application" when using --apply-to
|
220
|
+
|
221
|
+
* Show the help screen instead of an error when no arguments are given
|
222
|
+
|
223
|
+
* Make SwitchTower easier to invoke programmatically via SwitchTower::CLI
|
224
|
+
|
225
|
+
* Specify the revision to release via the :revision variable (defaults to latest revision)
|
226
|
+
|
227
|
+
* Allow variables to be set via the cli using the -s switch
|
228
|
+
|
229
|
+
* Log checkouts to a "revisions.log" file
|
230
|
+
|
231
|
+
* Changed behavior of checkout to use the timestamp as the release name, instead of the revision number
|
232
|
+
|
233
|
+
* Added CVS module (very very experimental!)
|
234
|
+
|
235
|
+
* Works with public keys now, for passwordless deployment
|
236
|
+
|
237
|
+
* Subversion module recognizes the password prompt for HTTP authentication
|
238
|
+
|
239
|
+
* Preserve +x on scripts when using darcs #1929 [Scott Barron]
|
240
|
+
|
241
|
+
* When executing multiline commands, use a backslash to escape the newline
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2005,2006 Jamis Buck
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
= Capistrano
|
2
|
+
|
3
|
+
Capistrano is a utility and framework for executing commands in parallel on multiple remote machines, via SSH. It uses a simple DSL (borrowed in part from Rake, http://rake.rubyforge.org/) that allows you to define _tasks_, which may be applied to machines in certain roles. It also supports tunneling connections via some gateway machine to allow operations to be performed behind VPN's and firewalls.
|
4
|
+
|
5
|
+
Capistrano was originally designed to simplify and automate deployment of web applications to distributed environments, and so it comes with many tasks predefined for that ("update_code" and "deploy", for instance).
|
6
|
+
|
7
|
+
== Dependencies
|
8
|
+
|
9
|
+
Capistrano depends upon the Net::SSH library by Jamis Buck (http://net-ssh.rubyforge.org). Net::SSH itself depends on the Needle library (http://needle.rubyforge.org), also by Jamis Buck.
|
10
|
+
|
11
|
+
== Assumptions
|
12
|
+
|
13
|
+
In keeping with Rails' "convention over configuration", Capistrano makes several assumptions about how you will use it (most, if not all, of which may be explicitly overridden):
|
14
|
+
|
15
|
+
* You are writing web applications and want to use Capistrano to deploy them.
|
16
|
+
* You are using Ruby on Rails (http://www.rubyonrails.com) to build your apps.
|
17
|
+
* You are using Subversion (http://subversion.tigris.org/) to manage your source code.
|
18
|
+
* You are running your apps using FastCGI, together with Rails' spinner/reaper utilities.
|
19
|
+
|
20
|
+
As with the rest of Rails, if you can abide by these assumptions, you can use Capistrano "out of the box". If any of these assumptions do not hold, you'll need to make some adjustments to your deployment recipe files.
|
21
|
+
|
22
|
+
== Usage
|
23
|
+
|
24
|
+
More documentation is always pending, but you'll want to see the user manual for detailed usage instructions. (The manual is online at http://manuals.rubyonrails.org/read/book/17).
|
25
|
+
|
26
|
+
In general, you'll use Capistrano as follows:
|
27
|
+
|
28
|
+
* Create a deployment recipe ("deploy.rb") for your application. You can use the sample recipe in examples/sample.rb as a starting point.
|
29
|
+
* Use the +cap+ script to execute your recipe (see below).
|
30
|
+
|
31
|
+
Use the +cap+ script as follows:
|
32
|
+
|
33
|
+
cap -vvv someaction
|
34
|
+
|
35
|
+
By default, the script will look for a file called one of <tt>config/deploy</tt>, <tt>config/deploy.rb</tt>, <tt>capistrano</tt>, or <tt>capistrano.rb</tt>. You can the <tt>-v</tt> switch multiple times (as shown) to increase the verbosity of the output. The +someaction+ text indicates which action to execute.
|
data/THANKS
ADDED
data/lib/capistrano/actor.rb
CHANGED
@@ -78,31 +78,65 @@ module Capistrano
|
|
78
78
|
|
79
79
|
# Returns the list of servers (_not_ connections to servers) that are
|
80
80
|
# the target of this task.
|
81
|
-
def servers
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
81
|
+
def servers(reevaluate=false)
|
82
|
+
@servers = nil if reevaluate
|
83
|
+
@servers ||=
|
84
|
+
if hosts = find_hosts
|
85
|
+
hosts
|
86
|
+
else
|
87
|
+
roles = find_roles
|
88
|
+
apply_only!(roles)
|
89
|
+
apply_except!(roles)
|
90
|
+
|
91
|
+
roles.map { |role| role.host }.uniq
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
def find_roles
|
97
|
+
role_names = [ *(environment_values(:roles, true) || @options[:roles] || actor.configuration.roles.keys) ]
|
98
|
+
role_names.collect do |name|
|
99
|
+
actor.configuration.roles[name] ||
|
100
|
+
raise(ArgumentError, "task #{self.name.inspect} references non-existant role #{name.inspect}")
|
101
|
+
end.flatten
|
102
|
+
end
|
103
|
+
|
104
|
+
def find_hosts
|
105
|
+
environment_values(:hosts) || @options[:hosts]
|
106
|
+
end
|
107
|
+
|
108
|
+
def environment_values(key, use_symbols = false)
|
109
|
+
if variable = ENV[key.to_s.upcase]
|
110
|
+
values = variable.split(",")
|
111
|
+
use_symbols ? values.collect { |e| e.to_sym } : values
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def apply_only!(roles)
|
116
|
+
only = @options[:only] || {}
|
89
117
|
|
90
118
|
unless only.empty?
|
91
119
|
roles = roles.delete_if do |role|
|
92
120
|
catch(:done) do
|
93
|
-
only.keys.each
|
94
|
-
throw(:done, true) if role.options[key] != only[key]
|
95
|
-
end
|
121
|
+
only.keys.each { |key| throw(:done, true) if role.options[key] != only[key] }
|
96
122
|
false
|
97
123
|
end
|
98
124
|
end
|
99
|
-
end
|
100
|
-
|
101
|
-
@servers = roles.map { |role| role.host }.uniq
|
125
|
+
end
|
102
126
|
end
|
127
|
+
|
128
|
+
def apply_except!(roles)
|
129
|
+
except = @options[:except] || {}
|
103
130
|
|
104
|
-
|
105
|
-
|
131
|
+
unless except.empty?
|
132
|
+
roles = roles.delete_if do |role|
|
133
|
+
catch(:done) do
|
134
|
+
except.keys.each { |key| throw(:done, true) if role.options[key] == except[key] }
|
135
|
+
false
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
106
140
|
end
|
107
141
|
|
108
142
|
def initialize(config) #:nodoc:
|
@@ -177,6 +211,27 @@ module Capistrano
|
|
177
211
|
end
|
178
212
|
end
|
179
213
|
|
214
|
+
# Streams the result of the command from all servers that are the target of the
|
215
|
+
# current task. All these streams will be joined into a single one,
|
216
|
+
# so you can, say, watch 10 log files as though they were one. Do note that this
|
217
|
+
# is quite expensive from a bandwidth perspective, so use it with care.
|
218
|
+
#
|
219
|
+
# Example:
|
220
|
+
#
|
221
|
+
# desc "Run a tail on multiple log files at the same time"
|
222
|
+
# task :tail_fcgi, :roles => :app do
|
223
|
+
# stream "tail -f #{shared_path}/log/fastcgi.crash.log"
|
224
|
+
# end
|
225
|
+
def stream(command)
|
226
|
+
run(command) do |ch, stream, out|
|
227
|
+
puts out if stream == :out
|
228
|
+
if stream == :err
|
229
|
+
puts "[err : #{ch[:host]}] #{out}"
|
230
|
+
break
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
180
235
|
# Deletes the given file from all servers targetted by the current task.
|
181
236
|
# If <tt>:recursive => true</tt> is specified, it may be used to remove
|
182
237
|
# directories.
|
@@ -210,6 +265,12 @@ module Capistrano
|
|
210
265
|
# Like #run, but executes the command via <tt>sudo</tt>. This assumes that
|
211
266
|
# the sudo password (if required) is the same as the password for logging
|
212
267
|
# in to the server.
|
268
|
+
#
|
269
|
+
# Also, this module accepts a <tt>:sudo</tt> configuration variable,
|
270
|
+
# which (if specified) will be used as the full path to the sudo
|
271
|
+
# executable on the remote machine:
|
272
|
+
#
|
273
|
+
# set :sudo, "/opt/local/bin/sudo"
|
213
274
|
def sudo(command, options={}, &block)
|
214
275
|
block ||= default_io_proc
|
215
276
|
|
@@ -218,7 +279,7 @@ module Capistrano
|
|
218
279
|
# prompts from that host.
|
219
280
|
prompt_host = nil
|
220
281
|
|
221
|
-
run "
|
282
|
+
run "#{sudo_command} #{command}", options do |ch, stream, out|
|
222
283
|
if out =~ /^Password:/
|
223
284
|
ch.send_data "#{password}\n"
|
224
285
|
elsif out =~ /try again/
|
@@ -293,16 +354,14 @@ module Capistrano
|
|
293
354
|
# Inspects the remote servers to determine the list of all released versions
|
294
355
|
# of the software. Releases are sorted with the most recent release last.
|
295
356
|
def releases
|
296
|
-
|
357
|
+
@releases ||= begin
|
297
358
|
buffer = ""
|
298
359
|
run "ls -x1 #{releases_path}", :once => true do |ch, str, out|
|
299
360
|
buffer << out if str == :out
|
300
361
|
raise "could not determine releases #{out.inspect}" if str == :err
|
301
362
|
end
|
302
|
-
|
363
|
+
buffer.split.sort
|
303
364
|
end
|
304
|
-
|
305
|
-
@releases
|
306
365
|
end
|
307
366
|
|
308
367
|
# Returns the most recent deployed release
|
@@ -312,7 +371,7 @@ module Capistrano
|
|
312
371
|
|
313
372
|
# Returns the release immediately before the currently deployed one
|
314
373
|
def previous_release
|
315
|
-
release_path(releases[-2])
|
374
|
+
release_path(releases[-2]) if releases[-2]
|
316
375
|
end
|
317
376
|
|
318
377
|
# Invoke a set of tasks in a transaction. If any task fails (raises an
|
@@ -333,10 +392,16 @@ module Capistrano
|
|
333
392
|
logger.important "transaction: rollback", current ? current.name : "transaction start"
|
334
393
|
task_call_history.reverse.each do |task|
|
335
394
|
begin
|
395
|
+
# throw the task back on the stack so that roles are properly
|
396
|
+
# interpreted in the scope of the task in question.
|
397
|
+
push_task_call_frame(task.name)
|
398
|
+
|
336
399
|
logger.debug "rolling back", task.name
|
337
400
|
task.rollback.call if task.rollback
|
338
401
|
rescue Object => e
|
339
402
|
logger.info "exception while rolling back: #{e.class}, #{e.message}", task.name
|
403
|
+
ensure
|
404
|
+
pop_task_call_frame
|
340
405
|
end
|
341
406
|
end
|
342
407
|
raise
|
@@ -376,6 +441,10 @@ module Capistrano
|
|
376
441
|
end
|
377
442
|
|
378
443
|
private
|
444
|
+
|
445
|
+
def sudo_command
|
446
|
+
configuration[:sudo] || "sudo"
|
447
|
+
end
|
379
448
|
|
380
449
|
def define_method(name, &block)
|
381
450
|
metaclass.send(:define_method, name, &block)
|
@@ -393,9 +462,27 @@ module Capistrano
|
|
393
462
|
|
394
463
|
def establish_connections(servers)
|
395
464
|
@factory = establish_gateway if needs_gateway?
|
396
|
-
servers
|
397
|
-
|
465
|
+
servers = Array(servers)
|
466
|
+
|
467
|
+
# because Net::SSH uses lazy loading for things, we need to make sure
|
468
|
+
# that at least one connection has been made successfully, to kind of
|
469
|
+
# "prime the pump", before we go gung-ho and do mass connection in
|
470
|
+
# parallel. Otherwise, the threads start doing things in wierd orders
|
471
|
+
# and causing Net::SSH to die of confusion.
|
472
|
+
|
473
|
+
if !@established_gateway && @sessions.empty?
|
474
|
+
server, servers = servers.first, servers[1..-1]
|
475
|
+
@sessions[server] = @factory.connect_to(server)
|
398
476
|
end
|
477
|
+
|
478
|
+
servers.map { |server| establish_connection_to(server) }.each { |t| t.join }
|
479
|
+
end
|
480
|
+
|
481
|
+
# We establish the connection by creating a thread in a new method--this
|
482
|
+
# prevents problems with the thread's scope seeing the wrong 'server'
|
483
|
+
# variable if the thread just happens to take too long to start up.
|
484
|
+
def establish_connection_to(server)
|
485
|
+
Thread.new { @sessions[server] ||= @factory.connect_to(server) }
|
399
486
|
end
|
400
487
|
|
401
488
|
def establish_gateway
|