capistrano 2.11.2 → 2.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/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
|