capistrano 2.11.2 → 2.12.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +27 -11
- data/bin/capify +3 -0
- data/lib/capistrano/command.rb +0 -2
- data/lib/capistrano/configuration/actions/file_transfer.rb +4 -5
- data/lib/capistrano/configuration/alias_task.rb +2 -1
- data/lib/capistrano/configuration/callbacks.rb +1 -1
- data/lib/capistrano/configuration/namespaces.rb +13 -0
- data/lib/capistrano/recipes/compat.rb +2 -2
- data/lib/capistrano/recipes/deploy.rb +3 -5
- data/lib/capistrano/recipes/deploy/assets.rb +4 -3
- data/lib/capistrano/recipes/deploy/remote_dependency.rb +6 -0
- data/lib/capistrano/recipes/deploy/scm/mercurial.rb +1 -1
- data/lib/capistrano/recipes/deploy/strategy/base.rb +3 -3
- data/lib/capistrano/recipes/deploy/strategy/copy.rb +150 -73
- data/lib/capistrano/recipes/deploy/strategy/unshared_remote_cache.rb +21 -0
- data/lib/capistrano/transfer.rb +3 -3
- data/lib/capistrano/version.rb +2 -2
- data/test/configuration/actions/invocation_test.rb +2 -2
- data/test/configuration/alias_task_test.rb +8 -0
- data/test/configuration/namespace_dsl_test.rb +21 -0
- data/test/deploy/remote_dependency_test.rb +11 -0
- data/test/deploy/scm/mercurial_test.rb +1 -1
- data/test/deploy/strategy/copy_test.rb +3 -3
- metadata +16 -15
data/CHANGELOG
CHANGED
@@ -1,6 +1,22 @@
|
|
1
|
-
## 2.
|
2
|
-
|
3
|
-
|
1
|
+
## 2.12.0 / April 13 2012
|
2
|
+
|
3
|
+
This release revserts the very verbose logging introduced in the previous version, it also
|
4
|
+
enables a handful of power-user features which are largely un-documented, but shouldn't be
|
5
|
+
important unless you are looking for them. Undocumented code shouldn't scare you, simply
|
6
|
+
read through deploy.rb in the Gem if you want to know how a new feature works!
|
7
|
+
|
8
|
+
* Update mapped commands to remove symlink deprecation warning. Despo Pentara (despo)
|
9
|
+
* Add the "rpm" remote dependency. Nick Hoffman (nickhoffman)
|
10
|
+
* Add commented deploy:cleanup task to default recipe. Jean-Philippe Doyle (j15e)
|
11
|
+
* Teach deploy:web:enable to fail gracefully. Lee Marlow (lmarlow)
|
12
|
+
* Ticket 193 alias task show wrong name when it is not overridden. Rafa García (rgo)
|
13
|
+
* Allow configuration of which roles assets are precompiled on. Frederick Cheung (fcheung)
|
14
|
+
* Fix transfer action to honor dry-run flag. Serg Podtynnyi (shtirlic)
|
15
|
+
* Changed single to double quotes for Windows, fixes a Windows bug in the HG module. Matthew J Morrison (mattjmorrison)
|
16
|
+
* Add UnsharedRemoteCache (copied from eycap gem). Ben Symonds (bensymonds)
|
17
|
+
|
18
|
+
As ever, a sincere thanks to all contributors, and do not hesitate to contact me if this
|
19
|
+
release causes problems for you.
|
4
20
|
|
5
21
|
## 2.11.0 / Febuary 20 2012
|
6
22
|
|
@@ -190,7 +206,7 @@ acceptable)
|
|
190
206
|
* Various fixes to path handling bugs in the copt strategy. (Philippe Rathé)
|
191
207
|
|
192
208
|
## 2.5.21 / April 6 2011
|
193
|
-
|
209
|
+
|
194
210
|
* Fixed to follow best-practice guidelines from Bundler (Ben Langfeld)
|
195
211
|
* No longer force a gemset for Capistrano development. (Ben Langfeld)
|
196
212
|
|
@@ -259,7 +275,7 @@ Fixes a low-value bug, thanks to Chris G for the well submitted patch:
|
|
259
275
|
|
260
276
|
* Fixes Darcs remote repository problem when using the copy strategy [Alex `regularfry` Young]
|
261
277
|
* Documentation improvements for embedding Capistrano [Lee Hambley]
|
262
|
-
* Fixes ticket #95 -formally deprecating the before_something and after_something methods [Lee Hambley]
|
278
|
+
* Fixes ticket #95 -formally deprecating the before_something and after_something methods [Lee Hambley]
|
263
279
|
|
264
280
|
## 2.5.9 / 1 August 2009
|
265
281
|
|
@@ -274,7 +290,7 @@ Fixes a low-value bug, thanks to Chris G for the well submitted patch:
|
|
274
290
|
* #77 - Copy command doesn't work on Solaris due to tar/gtar
|
275
291
|
* #76 - Invalid Subversion URL
|
276
292
|
* Improved web:disable task, now suggests a .htaccess block to use suggested by Rafael García
|
277
|
-
* Includes more logger options (can now select stdout, stderr of a file) [Rafael García]
|
293
|
+
* Includes more logger options (can now select stdout, stderr of a file) [Rafael García]
|
278
294
|
|
279
295
|
## 2.5.8 / July 2009
|
280
296
|
|
@@ -424,7 +440,7 @@ Fixes a low-value bug, thanks to Chris G for the well submitted patch:
|
|
424
440
|
* Added :normalize_asset_timestamps option to deployment, defaulting to true, which allows asset timestamping to be disabled [John Trupiano]
|
425
441
|
|
426
442
|
|
427
|
-
## 2.4.0 Preview Release #1 (2.3.101) / June 5, 2008
|
443
|
+
## 2.4.0 Preview Release #1 (2.3.101) / June 5, 2008
|
428
444
|
|
429
445
|
* Only make deploy:start, deploy:stop, and deploy:restart try sudo as :runner. The other sudo-enabled tasks (deploy:setup, deploy:cleanup, etc.) will now use the :admin_runner user (which by default is unset). [Jamis Buck]
|
430
446
|
|
@@ -452,7 +468,7 @@ Fixes a low-value bug, thanks to Chris G for the well submitted patch:
|
|
452
468
|
|
453
469
|
* Revert "make sudo helper play nicely with complex command chains", since it broke stuff [Jamis Buck]
|
454
470
|
|
455
|
-
* Make set(:default_shell, false) work for not using a shell on a per-command basis [Ryan McGeary]
|
471
|
+
* Make set(:default_shell, false) work for not using a shell on a per-command basis [Ryan McGeary]
|
456
472
|
|
457
473
|
* Improved test coverage [Ryan McGeary]
|
458
474
|
|
@@ -660,7 +676,7 @@ Fixes a low-value bug, thanks to Chris G for the well submitted patch:
|
|
660
676
|
|
661
677
|
|
662
678
|
## 1.99.2 (2.0 Preview 3) / June 15, 2007
|
663
|
-
|
679
|
+
|
664
680
|
* CVS SCM module [Brian Phillips]
|
665
681
|
|
666
682
|
* Fix typo in Perforce SCM module [Chris Bailey]
|
@@ -870,7 +886,7 @@ Fixes a low-value bug, thanks to Chris G for the well submitted patch:
|
|
870
886
|
on_rollback { run "ln -nfs #{previous_release} #{current_path}" }
|
871
887
|
run "ln -nfs #{current_release} #{current_path}"
|
872
888
|
end
|
873
|
-
|
889
|
+
|
874
890
|
cap symlink # will not run on 192.168.0.3
|
875
891
|
|
876
892
|
* Deprecate the -r/--recipe switch in favor of -f/--file (for more make/rake-like semantics) [Jamis Buck]
|
@@ -886,7 +902,7 @@ Fixes a low-value bug, thanks to Chris G for the well submitted patch:
|
|
886
902
|
task :setup, :roles => [ :app, :web, :db ]
|
887
903
|
# normally this would run every where
|
888
904
|
end
|
889
|
-
|
905
|
+
|
890
906
|
ROLES=app cap setup # this will only run for the app role, overwritting the default declaration
|
891
907
|
|
892
908
|
* Added :hosts option to task definition that allows you to specify cross-cutting tasks [DHH]. Example:
|
data/bin/capify
CHANGED
@@ -59,6 +59,9 @@ role :app, "your app-server here" # This may be the sam
|
|
59
59
|
role :db, "your primary db-server here", :primary => true # This is where Rails migrations will run
|
60
60
|
role :db, "your slave db-server here"
|
61
61
|
|
62
|
+
# if you want to clean up old releases on each deploy uncomment this:
|
63
|
+
# after "deploy:restart", "deploy:cleanup"
|
64
|
+
|
62
65
|
# if you\'re still using the script/reaper helper you will need
|
63
66
|
# these http://github.com/rails/irs_process_scripts
|
64
67
|
|
data/lib/capistrano/command.rb
CHANGED
@@ -219,8 +219,6 @@ module Capistrano
|
|
219
219
|
command_line = [environment, shell, cmd].compact.join(" ")
|
220
220
|
ch[:command] = command_line
|
221
221
|
|
222
|
-
logger.trace command_line, ch[:server] if logger
|
223
|
-
|
224
222
|
ch.exec(command_line)
|
225
223
|
ch.send_data(options[:data]) if options[:data]
|
226
224
|
else
|
@@ -12,7 +12,7 @@ module Capistrano
|
|
12
12
|
opts = options.dup
|
13
13
|
upload(StringIO.new(data), path, opts)
|
14
14
|
end
|
15
|
-
|
15
|
+
|
16
16
|
# Get file remote_path from FIRST server targeted by
|
17
17
|
# the current task and transfer it to local machine as path.
|
18
18
|
#
|
@@ -35,13 +35,12 @@ module Capistrano
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def transfer(direction, from, to, options={}, &block)
|
38
|
+
if dry_run
|
39
|
+
return logger.debug "transfering: #{[direction, from, to] * ', '}"
|
40
|
+
end
|
38
41
|
execute_on_servers(options) do |servers|
|
39
42
|
targets = servers.map { |s| sessions[s] }
|
40
|
-
if dry_run
|
41
|
-
logger.debug "transfering: #{[direction, from, to, targets, options.merge(:logger => logger).inspect ] * ', '}"
|
42
|
-
else
|
43
43
|
Transfer.process(direction, from, to, targets, options.merge(:logger => logger), &block)
|
44
|
-
end
|
45
44
|
end
|
46
45
|
end
|
47
46
|
|
@@ -15,7 +15,8 @@ module Capistrano
|
|
15
15
|
raise ArgumentError, "expected a valid task name"
|
16
16
|
end
|
17
17
|
|
18
|
-
|
18
|
+
original_task = find_task(old_name) or raise NoSuchTaskError, "the task `#{old_name}' does not exist"
|
19
|
+
task = original_task.dup # Dup. task to avoid modify original task
|
19
20
|
task.name = new_name
|
20
21
|
|
21
22
|
define_task(task)
|
@@ -90,7 +90,7 @@ module Capistrano
|
|
90
90
|
# Usage:
|
91
91
|
#
|
92
92
|
# on :before, "some:hook", "another:hook", :only => "deploy:update"
|
93
|
-
# on :after, "some:hook", :except => "deploy:
|
93
|
+
# on :after, "some:hook", :except => "deploy:create_symlink"
|
94
94
|
# on :before, "global:hook"
|
95
95
|
# on :after, :only => :deploy do
|
96
96
|
# puts "after deploy here"
|
@@ -176,6 +176,8 @@ module Capistrano
|
|
176
176
|
def initialize(name, parent)
|
177
177
|
@parent = parent
|
178
178
|
@name = name
|
179
|
+
|
180
|
+
explicitly_define_clashing_kernel_methods
|
179
181
|
end
|
180
182
|
|
181
183
|
def role(*args)
|
@@ -197,6 +199,17 @@ module Capistrano
|
|
197
199
|
include Capistrano::Configuration::AliasTask
|
198
200
|
include Capistrano::Configuration::Namespaces
|
199
201
|
undef :desc, :next_description
|
202
|
+
|
203
|
+
protected
|
204
|
+
def explicitly_define_clashing_kernel_methods
|
205
|
+
(parent.public_methods & Kernel.methods).each do |m|
|
206
|
+
next if self.method(m).owner == self.class
|
207
|
+
if parent.method(m).owner == parent.class
|
208
|
+
metaclass = class << self; self; end
|
209
|
+
metaclass.send(:define_method, m) {|*args, &block| parent.send(m, *args, &block)}
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
200
213
|
end
|
201
214
|
end
|
202
215
|
end
|
@@ -7,7 +7,7 @@ load 'deploy'
|
|
7
7
|
map = { "diff_from_last_deploy" => "deploy:pending:diff",
|
8
8
|
"update" => "deploy:update",
|
9
9
|
"update_code" => "deploy:update_code",
|
10
|
-
"symlink" => "deploy:
|
10
|
+
"symlink" => "deploy:create_symlink",
|
11
11
|
"restart" => "deploy:restart",
|
12
12
|
"rollback" => "deploy:rollback",
|
13
13
|
"cleanup" => "deploy:cleanup",
|
@@ -29,4 +29,4 @@ task :spinner do
|
|
29
29
|
warn "[DEPRECATED] `spinner' is deprecated. Use `deploy:start' instead."
|
30
30
|
set :runner, fetch(:spinner_user, "app")
|
31
31
|
deploy.start
|
32
|
-
end
|
32
|
+
end
|
@@ -265,6 +265,7 @@ namespace :deploy do
|
|
265
265
|
DESC
|
266
266
|
task :symlink, :except => { :no_release => true } do
|
267
267
|
Kernel.warn "[Deprecation Warning] This API has changed, please hook `deploy:create_symlink` instead of `deploy:symlink`."
|
268
|
+
create_symlink
|
268
269
|
end
|
269
270
|
|
270
271
|
desc <<-DESC
|
@@ -277,9 +278,6 @@ namespace :deploy do
|
|
277
278
|
except `restart').
|
278
279
|
DESC
|
279
280
|
task :create_symlink, :except => { :no_release => true } do
|
280
|
-
|
281
|
-
symlink # (Deprecated)
|
282
|
-
|
283
281
|
on_rollback do
|
284
282
|
if previous_release
|
285
283
|
run "rm -f #{current_path}; ln -s #{previous_release} #{current_path}; true"
|
@@ -548,7 +546,7 @@ namespace :deploy do
|
|
548
546
|
DESC
|
549
547
|
task :disable, :roles => :web, :except => { :no_release => true } do
|
550
548
|
require 'erb'
|
551
|
-
on_rollback { run "rm #{shared_path}/system/#{maintenance_basename}.html" }
|
549
|
+
on_rollback { run "rm -f #{shared_path}/system/#{maintenance_basename}.html" }
|
552
550
|
|
553
551
|
warn <<-EOHTACCESS
|
554
552
|
|
@@ -590,7 +588,7 @@ namespace :deploy do
|
|
590
588
|
web-accessible again.
|
591
589
|
DESC
|
592
590
|
task :enable, :roles => :web, :except => { :no_release => true } do
|
593
|
-
run "rm #{shared_path}/system/#{maintenance_basename}.html"
|
591
|
+
run "rm -f #{shared_path}/system/#{maintenance_basename}.html"
|
594
592
|
end
|
595
593
|
end
|
596
594
|
end
|
@@ -2,6 +2,7 @@ load 'deploy' unless defined?(_cset)
|
|
2
2
|
|
3
3
|
_cset :asset_env, "RAILS_GROUPS=assets"
|
4
4
|
_cset :assets_prefix, "assets"
|
5
|
+
_cset :assets_role, [:web]
|
5
6
|
|
6
7
|
_cset :normalize_asset_timestamps, false
|
7
8
|
|
@@ -18,7 +19,7 @@ namespace :deploy do
|
|
18
19
|
for efficiency. If you cutomize the assets path prefix, override the \
|
19
20
|
:assets_prefix variable to match.
|
20
21
|
DESC
|
21
|
-
task :symlink, :roles =>
|
22
|
+
task :symlink, :roles => assets_role, :except => { :no_release => true } do
|
22
23
|
run <<-CMD
|
23
24
|
rm -rf #{latest_release}/public/#{assets_prefix} &&
|
24
25
|
mkdir -p #{latest_release}/public &&
|
@@ -37,7 +38,7 @@ namespace :deploy do
|
|
37
38
|
set :rails_env, "production"
|
38
39
|
set :asset_env, "RAILS_GROUPS=assets"
|
39
40
|
DESC
|
40
|
-
task :precompile, :roles =>
|
41
|
+
task :precompile, :roles => assets_role, :except => { :no_release => true } do
|
41
42
|
run "cd #{latest_release} && #{rake} RAILS_ENV=#{rails_env} #{asset_env} assets:precompile"
|
42
43
|
end
|
43
44
|
|
@@ -52,7 +53,7 @@ namespace :deploy do
|
|
52
53
|
set :rails_env, "production"
|
53
54
|
set :asset_env, "RAILS_GROUPS=assets"
|
54
55
|
DESC
|
55
|
-
task :clean, :roles =>
|
56
|
+
task :clean, :roles => assets_role, :except => { :no_release => true } do
|
56
57
|
run "cd #{latest_release} && #{rake} RAILS_ENV=#{rails_env} #{asset_env} assets:clean"
|
57
58
|
end
|
58
59
|
end
|
@@ -49,6 +49,12 @@ module Capistrano
|
|
49
49
|
self
|
50
50
|
end
|
51
51
|
|
52
|
+
def rpm(name, version, options={})
|
53
|
+
@message ||= "package `#{name}' #{version} could not be found"
|
54
|
+
try("rpm -q #{name} | grep '#{version}'", options)
|
55
|
+
self
|
56
|
+
end
|
57
|
+
|
52
58
|
def match(command, expect, options={})
|
53
59
|
expect = Regexp.new(Regexp.escape(expect.to_s)) unless expect.is_a?(Regexp)
|
54
60
|
|
@@ -34,7 +34,7 @@ module Capistrano
|
|
34
34
|
d.remote.writable(configuration[:releases_path]).or("You do not have permissions to write to `#{configuration[:releases_path]}'.")
|
35
35
|
end
|
36
36
|
end
|
37
|
-
|
37
|
+
|
38
38
|
protected
|
39
39
|
|
40
40
|
# This is to allow helper methods like "run" and "put" to be more
|
@@ -52,7 +52,7 @@ module Capistrano
|
|
52
52
|
cmd = args.join(' ')
|
53
53
|
result = nil
|
54
54
|
if RUBY_PLATFORM =~ /win32/
|
55
|
-
|
55
|
+
cmd = cmd.split(/\s+/).collect {|w| w.match(/^[\w+]+:\/\//) ? w : w.gsub('/', '\\') }.join(' ') # Split command by spaces, change / by \\ unless element is a some+thing://
|
56
56
|
cmd.gsub!(/^cd /,'cd /D ') # Replace cd with cd /D
|
57
57
|
cmd.gsub!(/&& cd /,'&& cd /D ') # Replace cd with cd /D
|
58
58
|
logger.trace "executing locally: #{cmd}"
|
@@ -65,7 +65,7 @@ module Capistrano
|
|
65
65
|
result = super
|
66
66
|
end
|
67
67
|
end
|
68
|
-
|
68
|
+
|
69
69
|
logger.trace "command finished in #{(elapsed * 1000).round}ms"
|
70
70
|
result
|
71
71
|
end
|
@@ -54,83 +54,19 @@ module Capistrano
|
|
54
54
|
# servers, and uncompresses it on each of them into the deployment
|
55
55
|
# directory.
|
56
56
|
def deploy!
|
57
|
-
|
58
|
-
if File.exists?(copy_cache)
|
59
|
-
logger.debug "refreshing local cache to revision #{revision} at #{copy_cache}"
|
60
|
-
system(source.sync(revision, copy_cache))
|
61
|
-
else
|
62
|
-
logger.debug "preparing local cache at #{copy_cache}"
|
63
|
-
system(source.checkout(revision, copy_cache))
|
64
|
-
end
|
65
|
-
|
66
|
-
# Check the return code of last system command and rollback if not 0
|
67
|
-
unless $? == 0
|
68
|
-
raise Capistrano::Error, "shell command failed with return code #{$?}"
|
69
|
-
end
|
70
|
-
|
71
|
-
build(copy_cache)
|
72
|
-
|
73
|
-
FileUtils.mkdir_p(destination)
|
74
|
-
|
75
|
-
logger.debug "copying cache to deployment staging area #{destination}"
|
76
|
-
Dir.chdir(copy_cache) do
|
77
|
-
queue = Dir.glob("*", File::FNM_DOTMATCH)
|
78
|
-
while queue.any?
|
79
|
-
item = queue.shift
|
80
|
-
name = File.basename(item)
|
81
|
-
|
82
|
-
next if name == "." || name == ".."
|
83
|
-
next if copy_exclude.any? { |pattern| File.fnmatch(pattern, item) }
|
84
|
-
|
85
|
-
if File.symlink?(item)
|
86
|
-
FileUtils.ln_s(File.readlink(item), File.join(destination, item))
|
87
|
-
elsif File.directory?(item)
|
88
|
-
queue += Dir.glob("#{item}/*", File::FNM_DOTMATCH)
|
89
|
-
FileUtils.mkdir(File.join(destination, item))
|
90
|
-
else
|
91
|
-
FileUtils.ln(item, File.join(destination, item))
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
|
-
else
|
96
|
-
logger.debug "getting (via #{copy_strategy}) revision #{revision} to #{destination}"
|
97
|
-
system(command)
|
98
|
-
|
99
|
-
build(destination)
|
100
|
-
|
101
|
-
if copy_exclude.any?
|
102
|
-
logger.debug "processing exclusions..."
|
103
|
-
|
104
|
-
copy_exclude.each do |pattern|
|
105
|
-
delete_list = Dir.glob(File.join(destination, pattern), File::FNM_DOTMATCH)
|
106
|
-
# avoid the /.. trap that deletes the parent directories
|
107
|
-
delete_list.delete_if { |dir| dir =~ /\/\.\.$/ }
|
108
|
-
FileUtils.rm_rf(delete_list.compact)
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
File.open(File.join(destination, "REVISION"), "w") { |f| f.puts(revision) }
|
114
|
-
|
115
|
-
logger.trace "compressing #{destination} to #{filename}"
|
116
|
-
Dir.chdir(copy_dir) { system(compress(File.basename(destination), File.basename(filename)).join(" ")) }
|
57
|
+
copy_cache ? run_copy_cache_strategy : run_copy_strategy
|
117
58
|
|
59
|
+
create_revision_file
|
60
|
+
compress_repository
|
118
61
|
distribute!
|
119
62
|
ensure
|
120
|
-
|
121
|
-
FileUtils.rm_rf destination rescue nil
|
63
|
+
rollback_changes
|
122
64
|
end
|
123
65
|
|
124
|
-
def build
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
self.system(configuration[:build_script])
|
129
|
-
# Check the return code of last system command and rollback if not 0
|
130
|
-
unless $? == 0
|
131
|
-
raise Capistrano::Error, "shell command failed with return code #{$?}"
|
132
|
-
end
|
133
|
-
end
|
66
|
+
def build directory
|
67
|
+
execute "running build script on #{directory}" do
|
68
|
+
Dir.chdir(directory) { system(build_script) }
|
69
|
+
end if build_script
|
134
70
|
end
|
135
71
|
|
136
72
|
def check!
|
@@ -153,6 +89,143 @@ module Capistrano
|
|
153
89
|
|
154
90
|
private
|
155
91
|
|
92
|
+
def run_copy_cache_strategy
|
93
|
+
copy_repository_to_local_cache
|
94
|
+
build copy_cache
|
95
|
+
copy_cache_to_staging_area
|
96
|
+
end
|
97
|
+
|
98
|
+
def run_copy_strategy
|
99
|
+
copy_repository_to_server
|
100
|
+
build destination
|
101
|
+
remove_excluded_files if copy_exclude.any?
|
102
|
+
end
|
103
|
+
|
104
|
+
def execute description, &block
|
105
|
+
logger.debug description
|
106
|
+
handle_system_errors &block
|
107
|
+
end
|
108
|
+
|
109
|
+
def handle_system_errors &block
|
110
|
+
block.call
|
111
|
+
raise_command_failed if last_command_failed?
|
112
|
+
end
|
113
|
+
|
114
|
+
def refresh_local_cache
|
115
|
+
execute "refreshing local cache to revision #{revision} at #{copy_cache}" do
|
116
|
+
system(source.sync(revision, copy_cache))
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def create_local_cache
|
121
|
+
execute "preparing local cache at #{copy_cache}" do
|
122
|
+
system(source.checkout(revision, copy_cache))
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def raise_command_failed
|
127
|
+
raise Capistrano::Error, "shell command failed with return code #{$?}"
|
128
|
+
end
|
129
|
+
|
130
|
+
def last_command_failed?
|
131
|
+
$? != 0
|
132
|
+
end
|
133
|
+
|
134
|
+
def copy_cache_to_staging_area
|
135
|
+
execute "copying cache to deployment staging area #{destination}" do
|
136
|
+
create_destination
|
137
|
+
Dir.chdir(copy_cache) { copy_files(queue_files) }
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def create_destination
|
142
|
+
FileUtils.mkdir_p(destination)
|
143
|
+
end
|
144
|
+
|
145
|
+
def copy_files files
|
146
|
+
files.each { |name| process_file(name) }
|
147
|
+
end
|
148
|
+
|
149
|
+
def process_file name
|
150
|
+
send "copy_#{filetype(name)}", name
|
151
|
+
end
|
152
|
+
|
153
|
+
def filetype name
|
154
|
+
filetype = File.ftype name
|
155
|
+
filetype = "file" unless ["link", "directory"].include? filetype
|
156
|
+
filetype
|
157
|
+
end
|
158
|
+
|
159
|
+
def copy_link name
|
160
|
+
FileUtils.ln_s(File.readlink(name), File.join(destination, name))
|
161
|
+
end
|
162
|
+
|
163
|
+
def copy_directory name
|
164
|
+
FileUtils.mkdir(File.join(destination, name))
|
165
|
+
copy_files(queue_files(name))
|
166
|
+
end
|
167
|
+
|
168
|
+
def copy_file name
|
169
|
+
FileUtils.ln(name, File.join(destination, name))
|
170
|
+
end
|
171
|
+
|
172
|
+
def queue_files directory=nil
|
173
|
+
Dir.glob(pattern_for(directory), File::FNM_DOTMATCH).reject! { |file| excluded_files_contain? file }
|
174
|
+
end
|
175
|
+
|
176
|
+
def pattern_for directory
|
177
|
+
!directory.nil? ? "#{directory}/*" : "*"
|
178
|
+
end
|
179
|
+
|
180
|
+
def excluded_files_contain? file
|
181
|
+
copy_exclude.any? { |p| File.fnmatch(p, file) } or [ ".", ".."].include? File.basename(file)
|
182
|
+
end
|
183
|
+
|
184
|
+
def copy_repository_to_server
|
185
|
+
execute "getting (via #{copy_strategy}) revision #{revision} to #{destination}" do
|
186
|
+
copy_repository_via_strategy
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def copy_repository_via_strategy
|
191
|
+
system(command)
|
192
|
+
end
|
193
|
+
|
194
|
+
def remove_excluded_files
|
195
|
+
logger.debug "processing exclusions..."
|
196
|
+
|
197
|
+
copy_exclude.each do |pattern|
|
198
|
+
delete_list = Dir.glob(File.join(destination, pattern), File::FNM_DOTMATCH)
|
199
|
+
# avoid the /.. trap that deletes the parent directories
|
200
|
+
delete_list.delete_if { |dir| dir =~ /\/\.\.$/ }
|
201
|
+
FileUtils.rm_rf(delete_list.compact)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def create_revision_file
|
206
|
+
File.open(File.join(destination, "REVISION"), "w") { |f| f.puts(revision) }
|
207
|
+
end
|
208
|
+
|
209
|
+
def compress_repository
|
210
|
+
execute "Compressing #{destination} to #{filename}" do
|
211
|
+
Dir.chdir(copy_dir) { system(compress(File.basename(destination), File.basename(filename)).join(" ")) }
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
def rollback_changes
|
216
|
+
FileUtils.rm filename rescue nil
|
217
|
+
FileUtils.rm_rf destination rescue nil
|
218
|
+
end
|
219
|
+
|
220
|
+
def copy_repository_to_local_cache
|
221
|
+
return refresh_local_cache if File.exists?(copy_cache)
|
222
|
+
create_local_cache
|
223
|
+
end
|
224
|
+
|
225
|
+
def build_script
|
226
|
+
configuration[:build_script]
|
227
|
+
end
|
228
|
+
|
156
229
|
# Specify patterns to exclude from the copy. This is only valid
|
157
230
|
# when using a local cache.
|
158
231
|
def copy_exclude
|
@@ -237,10 +310,14 @@ module Capistrano
|
|
237
310
|
compression.decompress_command + [file]
|
238
311
|
end
|
239
312
|
|
313
|
+
def decompress_remote_file
|
314
|
+
run "cd #{configuration[:releases_path]} && #{decompress(remote_filename).join(" ")} && rm #{remote_filename}"
|
315
|
+
end
|
316
|
+
|
240
317
|
# Distributes the file to the remote servers
|
241
318
|
def distribute!
|
242
319
|
upload(filename, remote_filename)
|
243
|
-
|
320
|
+
decompress_remote_file
|
244
321
|
end
|
245
322
|
end
|
246
323
|
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'capistrano/recipes/deploy/strategy/remote_cache'
|
2
|
+
|
3
|
+
module Capistrano
|
4
|
+
module Deploy
|
5
|
+
module Strategy
|
6
|
+
class UnsharedRemoteCache < RemoteCache
|
7
|
+
def check!
|
8
|
+
super.check do |d|
|
9
|
+
d.remote.writable(repository_cache)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def repository_cache
|
16
|
+
configuration[:repository_cache]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/capistrano/transfer.rb
CHANGED
@@ -117,7 +117,7 @@ module Capistrano
|
|
117
117
|
|
118
118
|
def prepare_scp_transfer(from, to, session)
|
119
119
|
real_callback = callback || Proc.new do |channel, name, sent, total|
|
120
|
-
logger.trace "#{
|
120
|
+
logger.trace "[#{channel[:host]}] #{name}" if logger && sent == 0
|
121
121
|
end
|
122
122
|
|
123
123
|
channel = case direction
|
@@ -167,9 +167,9 @@ module Capistrano
|
|
167
167
|
if callback
|
168
168
|
callback.call(event, op, *args)
|
169
169
|
elsif event == :open
|
170
|
-
logger.trace "#{
|
170
|
+
logger.trace "[#{op[:host]}] #{args[0].remote}"
|
171
171
|
elsif event == :finish
|
172
|
-
logger.trace "#{
|
172
|
+
logger.trace "[#{op[:host]}] done"
|
173
173
|
end
|
174
174
|
end
|
175
175
|
|
data/lib/capistrano/version.rb
CHANGED
@@ -59,7 +59,7 @@ class ConfigurationActionsInvocationTest < Test::Unit::TestCase
|
|
59
59
|
config = make_config
|
60
60
|
config.dry_run = true
|
61
61
|
config.servers = %w[ foo ]
|
62
|
-
config.expects(:
|
62
|
+
config.expects(:execute_on_servers).never
|
63
63
|
::Capistrano::Transfer.expects(:process).never
|
64
64
|
config.put "foo", "bar", :mode => 0644
|
65
65
|
end
|
@@ -203,7 +203,7 @@ class ConfigurationActionsInvocationTest < Test::Unit::TestCase
|
|
203
203
|
a = mock("channel", :called => true)
|
204
204
|
b = mock("stream", :called => true)
|
205
205
|
c = mock("data", :called => true)
|
206
|
-
|
206
|
+
|
207
207
|
callback[a, b, c]
|
208
208
|
end
|
209
209
|
|
@@ -30,6 +30,14 @@ class AliasTaskTest < Test::Unit::TestCase
|
|
30
30
|
assert @config.tasks.key?(:new_foo)
|
31
31
|
end
|
32
32
|
|
33
|
+
def test_original_task_remain_with_same_name
|
34
|
+
@config.task(:foo) { 42 }
|
35
|
+
@config.alias_task 'new_foo', 'foo'
|
36
|
+
|
37
|
+
assert_equal :foo, @config.tasks[:foo].name
|
38
|
+
assert_equal :new_foo, @config.tasks[:new_foo].name
|
39
|
+
end
|
40
|
+
|
33
41
|
def test_aliased_task_do_the_same
|
34
42
|
@config.task(:foo) { 42 }
|
35
43
|
@config.alias_task 'new_foo', 'foo'
|
@@ -308,4 +308,25 @@ class ConfigurationNamespacesDSLTest < Test::Unit::TestCase
|
|
308
308
|
end
|
309
309
|
assert_nil @config.find_task("outer::inner")
|
310
310
|
end
|
311
|
+
|
312
|
+
def test_kernel_method_clashing_should_not_affect_method_delegation_to_parent
|
313
|
+
@config.class.class_eval do
|
314
|
+
def some_weird_method() 'config' end
|
315
|
+
end
|
316
|
+
|
317
|
+
@config.namespace(:clash) {}
|
318
|
+
namespace = @config.namespaces[:clash]
|
319
|
+
assert_equal 'config', namespace.some_weird_method
|
320
|
+
|
321
|
+
Kernel.module_eval do
|
322
|
+
def some_weird_method() 'kernel' end
|
323
|
+
end
|
324
|
+
|
325
|
+
@config.namespace(:clash2) {}
|
326
|
+
namespace = @config.namespaces[:clash2]
|
327
|
+
assert_equal 'config', namespace.some_weird_method
|
328
|
+
|
329
|
+
Kernel.send :remove_method, :some_weird_method
|
330
|
+
@config.class.send :remove_method, :some_weird_method
|
331
|
+
end
|
311
332
|
end
|
@@ -43,6 +43,12 @@ class RemoteDependencyTest < Test::Unit::TestCase
|
|
43
43
|
assert_equal "package `dpkg' 1.15 could not be found (host)", @dependency.message
|
44
44
|
end
|
45
45
|
|
46
|
+
def test_should_use_standard_error_message_for_rpm
|
47
|
+
setup_for_a_configuration_rpm_run("rpm", "4.8", false)
|
48
|
+
@dependency.rpm("rpm", "4.8")
|
49
|
+
assert_equal "package `rpm' 4.8 could not be found (host)", @dependency.message
|
50
|
+
end
|
51
|
+
|
46
52
|
def test_should_fail_if_directory_not_found
|
47
53
|
setup_for_a_configuration_run("test -d /data", false)
|
48
54
|
assert !@dependency.directory("/data").pass?
|
@@ -132,4 +138,9 @@ class RemoteDependencyTest < Test::Unit::TestCase
|
|
132
138
|
find_deb_cmd = "dpkg -s #{name} | grep '^Version: #{version}'"
|
133
139
|
setup_for_a_configuration_run(find_deb_cmd, passing)
|
134
140
|
end
|
141
|
+
|
142
|
+
def setup_for_a_configuration_rpm_run(name, version, passing)
|
143
|
+
find_rpm_cmd = "rpm -q #{name} | grep '#{version}'"
|
144
|
+
setup_for_a_configuration_run(find_rpm_cmd, passing)
|
145
|
+
end
|
135
146
|
end
|
@@ -39,7 +39,7 @@ class DeploySCMMercurialTest < Test::Unit::TestCase
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def test_query_revision
|
42
|
-
assert_equal "hg log -r 8a8e00b8f11b --template
|
42
|
+
assert_equal "hg log -r 8a8e00b8f11b --template \"{node|short}\"", @source.query_revision('8a8e00b8f11b') { |o| o }
|
43
43
|
end
|
44
44
|
|
45
45
|
def test_username_should_be_backwards_compatible
|
@@ -306,15 +306,15 @@ class DeployStrategyCopyTest < Test::Unit::TestCase
|
|
306
306
|
|
307
307
|
def prepare_directory_tree!(cache, exclude=false)
|
308
308
|
Dir.expects(:glob).with("*", File::FNM_DOTMATCH).returns([".", "..", "app", "foo.txt"])
|
309
|
-
File.expects(:
|
309
|
+
File.expects(:ftype).with("app").returns("directory")
|
310
310
|
FileUtils.expects(:mkdir).with("/temp/dir/1234567890/app")
|
311
|
-
File.expects(:
|
311
|
+
File.expects(:ftype).with("foo.txt").returns("file")
|
312
312
|
FileUtils.expects(:ln).with("foo.txt", "/temp/dir/1234567890/foo.txt")
|
313
313
|
|
314
314
|
Dir.expects(:glob).with("app/*", File::FNM_DOTMATCH).returns(["app/.", "app/..", "app/bar.txt"])
|
315
315
|
|
316
316
|
unless exclude
|
317
|
-
|
317
|
+
File.expects(:ftype).with("app/bar.txt").returns("file")
|
318
318
|
FileUtils.expects(:ln).with("app/bar.txt", "/temp/dir/1234567890/app/bar.txt")
|
319
319
|
end
|
320
320
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: capistrano
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.12.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,11 +10,11 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2012-
|
13
|
+
date: 2012-04-13 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: highline
|
17
|
-
requirement: &
|
17
|
+
requirement: &70100200770260 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ! '>='
|
@@ -22,10 +22,10 @@ dependencies:
|
|
22
22
|
version: '0'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
|
-
version_requirements: *
|
25
|
+
version_requirements: *70100200770260
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: net-ssh
|
28
|
-
requirement: &
|
28
|
+
requirement: &70100200769760 !ruby/object:Gem::Requirement
|
29
29
|
none: false
|
30
30
|
requirements:
|
31
31
|
- - ! '>='
|
@@ -33,10 +33,10 @@ dependencies:
|
|
33
33
|
version: 2.0.14
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
|
-
version_requirements: *
|
36
|
+
version_requirements: *70100200769760
|
37
37
|
- !ruby/object:Gem::Dependency
|
38
38
|
name: net-sftp
|
39
|
-
requirement: &
|
39
|
+
requirement: &70100200769280 !ruby/object:Gem::Requirement
|
40
40
|
none: false
|
41
41
|
requirements:
|
42
42
|
- - ! '>='
|
@@ -44,10 +44,10 @@ dependencies:
|
|
44
44
|
version: 2.0.0
|
45
45
|
type: :runtime
|
46
46
|
prerelease: false
|
47
|
-
version_requirements: *
|
47
|
+
version_requirements: *70100200769280
|
48
48
|
- !ruby/object:Gem::Dependency
|
49
49
|
name: net-scp
|
50
|
-
requirement: &
|
50
|
+
requirement: &70100200768800 !ruby/object:Gem::Requirement
|
51
51
|
none: false
|
52
52
|
requirements:
|
53
53
|
- - ! '>='
|
@@ -55,10 +55,10 @@ dependencies:
|
|
55
55
|
version: 1.0.0
|
56
56
|
type: :runtime
|
57
57
|
prerelease: false
|
58
|
-
version_requirements: *
|
58
|
+
version_requirements: *70100200768800
|
59
59
|
- !ruby/object:Gem::Dependency
|
60
60
|
name: net-ssh-gateway
|
61
|
-
requirement: &
|
61
|
+
requirement: &70100200768320 !ruby/object:Gem::Requirement
|
62
62
|
none: false
|
63
63
|
requirements:
|
64
64
|
- - ! '>='
|
@@ -66,10 +66,10 @@ dependencies:
|
|
66
66
|
version: 1.1.0
|
67
67
|
type: :runtime
|
68
68
|
prerelease: false
|
69
|
-
version_requirements: *
|
69
|
+
version_requirements: *70100200768320
|
70
70
|
- !ruby/object:Gem::Dependency
|
71
71
|
name: mocha
|
72
|
-
requirement: &
|
72
|
+
requirement: &70100200767840 !ruby/object:Gem::Requirement
|
73
73
|
none: false
|
74
74
|
requirements:
|
75
75
|
- - ! '>='
|
@@ -77,7 +77,7 @@ dependencies:
|
|
77
77
|
version: '0'
|
78
78
|
type: :development
|
79
79
|
prerelease: false
|
80
|
-
version_requirements: *
|
80
|
+
version_requirements: *70100200767840
|
81
81
|
description: Capistrano is a utility and framework for executing commands in parallel
|
82
82
|
on multiple remote machines, via SSH.
|
83
83
|
email:
|
@@ -152,6 +152,7 @@ files:
|
|
152
152
|
- lib/capistrano/recipes/deploy/strategy/export.rb
|
153
153
|
- lib/capistrano/recipes/deploy/strategy/remote.rb
|
154
154
|
- lib/capistrano/recipes/deploy/strategy/remote_cache.rb
|
155
|
+
- lib/capistrano/recipes/deploy/strategy/unshared_remote_cache.rb
|
155
156
|
- lib/capistrano/recipes/deploy/templates/maintenance.rhtml
|
156
157
|
- lib/capistrano/recipes/standard.rb
|
157
158
|
- lib/capistrano/recipes/templates/maintenance.rhtml
|
@@ -226,7 +227,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
226
227
|
version: '0'
|
227
228
|
requirements: []
|
228
229
|
rubyforge_project:
|
229
|
-
rubygems_version: 1.8.
|
230
|
+
rubygems_version: 1.8.11
|
230
231
|
signing_key:
|
231
232
|
specification_version: 3
|
232
233
|
summary: Capistrano - Welcome to easy deployment with Ruby over SSH
|