capistrano 1.1.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/bin/cap +11 -0
- data/examples/sample.rb +113 -0
- data/lib/capistrano.rb +1 -0
- data/lib/capistrano/actor.rb +438 -0
- data/lib/capistrano/cli.rb +295 -0
- data/lib/capistrano/command.rb +90 -0
- data/lib/capistrano/configuration.rb +243 -0
- data/lib/capistrano/extensions.rb +38 -0
- data/lib/capistrano/gateway.rb +118 -0
- data/lib/capistrano/generators/rails/deployment/deployment_generator.rb +25 -0
- data/lib/capistrano/generators/rails/deployment/templates/capistrano.rake +46 -0
- data/lib/capistrano/generators/rails/deployment/templates/deploy.rb +122 -0
- data/lib/capistrano/generators/rails/loader.rb +20 -0
- data/lib/capistrano/logger.rb +59 -0
- data/lib/capistrano/recipes/standard.rb +242 -0
- data/lib/capistrano/recipes/templates/maintenance.rhtml +53 -0
- data/lib/capistrano/scm/base.rb +62 -0
- data/lib/capistrano/scm/baz.rb +118 -0
- data/lib/capistrano/scm/bzr.rb +70 -0
- data/lib/capistrano/scm/cvs.rb +124 -0
- data/lib/capistrano/scm/darcs.rb +27 -0
- data/lib/capistrano/scm/perforce.rb +139 -0
- data/lib/capistrano/scm/subversion.rb +122 -0
- data/lib/capistrano/ssh.rb +39 -0
- data/lib/capistrano/transfer.rb +90 -0
- data/lib/capistrano/utils.rb +26 -0
- data/lib/capistrano/version.rb +30 -0
- data/test/actor_test.rb +294 -0
- data/test/command_test.rb +43 -0
- data/test/configuration_test.rb +233 -0
- data/test/fixtures/config.rb +5 -0
- data/test/fixtures/custom.rb +3 -0
- data/test/scm/cvs_test.rb +186 -0
- data/test/scm/subversion_test.rb +137 -0
- data/test/ssh_test.rb +104 -0
- data/test/utils.rb +50 -0
- metadata +107 -0
@@ -0,0 +1,53 @@
|
|
1
|
+
|
2
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
3
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
4
|
+
|
5
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
6
|
+
|
7
|
+
<head>
|
8
|
+
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
|
9
|
+
<title>System down for maintenance</title>
|
10
|
+
|
11
|
+
<style type="text/css">
|
12
|
+
div.outer {
|
13
|
+
position: absolute;
|
14
|
+
left: 50%;
|
15
|
+
top: 50%;
|
16
|
+
width: 500px;
|
17
|
+
height: 300px;
|
18
|
+
margin-left: -260px;
|
19
|
+
margin-top: -150px;
|
20
|
+
}
|
21
|
+
|
22
|
+
.DialogBody {
|
23
|
+
margin: 0;
|
24
|
+
padding: 10px;
|
25
|
+
text-align: left;
|
26
|
+
border: 1px solid #ccc;
|
27
|
+
border-right: 1px solid #999;
|
28
|
+
border-bottom: 1px solid #999;
|
29
|
+
background-color: #fff;
|
30
|
+
}
|
31
|
+
|
32
|
+
body { background-color: #fff; }
|
33
|
+
</style>
|
34
|
+
</head>
|
35
|
+
|
36
|
+
<body>
|
37
|
+
|
38
|
+
<div class="outer">
|
39
|
+
<div class="DialogBody" style="text-align: center;">
|
40
|
+
<div style="text-align: center; width: 200px; margin: 0 auto;">
|
41
|
+
<p style="color: red; font-size: 16px; line-height: 20px;">
|
42
|
+
The system is down for <%= reason ? reason : "maintenance" %>
|
43
|
+
as of <%= Time.now.strftime("%H:%M %Z") %>.
|
44
|
+
</p>
|
45
|
+
<p style="color: #666;">
|
46
|
+
It'll be back <%= deadline ? "by #{deadline}" : "shortly" %>.
|
47
|
+
</p>
|
48
|
+
</div>
|
49
|
+
</div>
|
50
|
+
</div>
|
51
|
+
|
52
|
+
</body>
|
53
|
+
</html>
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Capistrano
|
2
|
+
module SCM
|
3
|
+
|
4
|
+
# The ancestor class of the various SCM module implementations.
|
5
|
+
class Base
|
6
|
+
attr_reader :configuration
|
7
|
+
|
8
|
+
def initialize(configuration) #:nodoc:
|
9
|
+
@configuration = configuration
|
10
|
+
end
|
11
|
+
|
12
|
+
def latest_revision
|
13
|
+
nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def current_revision(actor)
|
17
|
+
raise "#{self.class} doesn't support querying the deployed revision"
|
18
|
+
end
|
19
|
+
|
20
|
+
def diff(actor, from=nil, to=nil)
|
21
|
+
raise "#{self.class} doesn't support diff(from, to)"
|
22
|
+
end
|
23
|
+
|
24
|
+
def update(actor)
|
25
|
+
raise "#{self.class} doesn't support update(actor)"
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def run_checkout(actor, guts, &block)
|
31
|
+
log = "#{configuration.deploy_to}/revisions.log"
|
32
|
+
directory = File.basename(configuration.release_path)
|
33
|
+
|
34
|
+
command = <<-STR
|
35
|
+
if [[ ! -d #{configuration.release_path} ]]; then
|
36
|
+
#{guts}
|
37
|
+
#{logging_commands(directory)}
|
38
|
+
fi
|
39
|
+
STR
|
40
|
+
|
41
|
+
actor.run(command, &block)
|
42
|
+
end
|
43
|
+
|
44
|
+
def run_update(actor, guts, &block)
|
45
|
+
command = <<-STR
|
46
|
+
#{guts}
|
47
|
+
#{logging_commands}
|
48
|
+
STR
|
49
|
+
|
50
|
+
actor.run(command, &block)
|
51
|
+
end
|
52
|
+
|
53
|
+
def logging_commands(directory = nil)
|
54
|
+
log = "#{configuration.deploy_to}/revisions.log"
|
55
|
+
|
56
|
+
"(test -e #{log} || touch #{log} && chmod 666 #{log}) && " +
|
57
|
+
"echo `date +\"%Y-%m-%d %H:%M:%S\"` $USER #{configuration.revision} #{directory} >> #{log};"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'capistrano/scm/base'
|
2
|
+
|
3
|
+
module Capistrano
|
4
|
+
module SCM
|
5
|
+
|
6
|
+
# An SCM module for using Bazaar as your source control tool. This
|
7
|
+
# module is used by default, but you can explicitly specify it by
|
8
|
+
# placing the following line in your configuration:
|
9
|
+
#
|
10
|
+
# set :scm, :baz
|
11
|
+
#
|
12
|
+
# Also, this module accepts a <tt>:baz</tt> configuration variable,
|
13
|
+
# which (if specified) will be used as the full path to the svn
|
14
|
+
# executable on the remote machine:
|
15
|
+
#
|
16
|
+
# set :baz, "/opt/local/bin/baz"
|
17
|
+
#
|
18
|
+
# Set the version you wish to deploy as the repository variable,
|
19
|
+
# for example:
|
20
|
+
#
|
21
|
+
# set :repository, "you@example.com--dev/yourstuff--trunk--1.0"
|
22
|
+
#
|
23
|
+
# Ensure that you have already registered the archive on the target
|
24
|
+
# machines.
|
25
|
+
#
|
26
|
+
# As bazaar keeps a great deal of extra information on a checkout,
|
27
|
+
# you will probably want to use export instead:
|
28
|
+
#
|
29
|
+
# set :checkout, "export"
|
30
|
+
#
|
31
|
+
# TODO: provide setup recipe to register archive
|
32
|
+
class Baz < Base
|
33
|
+
# Return an integer identifying the last known revision in the baz
|
34
|
+
# repository. (This integer is currently the revision number.)
|
35
|
+
def latest_revision
|
36
|
+
`#{baz} revisions #{configuration.repository}`.split.last =~ /\-(\d+)$/
|
37
|
+
$1
|
38
|
+
end
|
39
|
+
|
40
|
+
# Return the number of the revision currently deployed.
|
41
|
+
def current_revision(actor)
|
42
|
+
latest = actor.releases.last
|
43
|
+
grep = %(grep " #{latest}$" #{configuration.deploy_to}/revisions.log)
|
44
|
+
result = ""
|
45
|
+
actor.run(grep, :once => true) do |ch, str, out|
|
46
|
+
result << out if str == :out
|
47
|
+
raise "could not determine current revision" if str == :err
|
48
|
+
end
|
49
|
+
|
50
|
+
date, time, user, rev, dir = result.split
|
51
|
+
raise "current revision not found in revisions.log" unless dir == latest
|
52
|
+
rev.to_i
|
53
|
+
end
|
54
|
+
|
55
|
+
# Return a string containing the diff between the two revisions. +from+
|
56
|
+
# and +to+ may be in any format that bzr recognizes as a valid revision
|
57
|
+
# identifier. If +from+ is +nil+, it defaults to the last deployed
|
58
|
+
# revision. If +to+ is +nil+, it defaults to the last developed revision.
|
59
|
+
def diff(actor, from=nil, to=nil)
|
60
|
+
from ||= current_revision(actor)
|
61
|
+
to ||= latest_revision
|
62
|
+
from = baz_revision_name(from)
|
63
|
+
to = baz_revision_name(to)
|
64
|
+
`#{baz} delta --diffs -A #{baz_archive} #{baz_version}--#{from} #{baz_version}--#{to}`
|
65
|
+
end
|
66
|
+
|
67
|
+
# Check out (on all servers associated with the current task) the latest
|
68
|
+
# revision. Uses the given actor instance to execute the command.
|
69
|
+
def checkout(actor)
|
70
|
+
op = configuration[:checkout] || "get"
|
71
|
+
from = baz_revision_name(configuration.revision)
|
72
|
+
command = "#{baz} #{op} #{configuration.repository}--#{from} #{actor.release_path} &&"
|
73
|
+
run_checkout(actor, command, &baz_stream_handler(actor))
|
74
|
+
end
|
75
|
+
|
76
|
+
def update(actor)
|
77
|
+
command = "cd #{actor.current_path} && #{baz} update &&"
|
78
|
+
run_update(actor, command, &baz_stream_handler(actor))
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
def baz
|
83
|
+
configuration[:baz] || "baz"
|
84
|
+
end
|
85
|
+
|
86
|
+
def baz_revision_name(number)
|
87
|
+
if number.to_i == 0 then
|
88
|
+
"base-0"
|
89
|
+
else
|
90
|
+
"patch-#{number}"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def baz_archive
|
95
|
+
configuration[:repository][/(.*)\//, 1]
|
96
|
+
end
|
97
|
+
|
98
|
+
def baz_version
|
99
|
+
configuration[:repository][/\/(.*)$/, 1]
|
100
|
+
end
|
101
|
+
|
102
|
+
def baz_stream_handler(actor)
|
103
|
+
Proc.new do |ch, stream, out|
|
104
|
+
prefix = "#{stream} :: #{ch[:host]}"
|
105
|
+
actor.logger.info out, prefix
|
106
|
+
if out =~ /\bpassword.*:/i
|
107
|
+
actor.logger.info "baz is asking for a password", prefix
|
108
|
+
ch.send_data "#{actor.password}\n"
|
109
|
+
elsif out =~ %r{passphrase}
|
110
|
+
message = "baz needs your key's passphrase, sending empty string"
|
111
|
+
actor.logger.info message, prefix
|
112
|
+
ch.send_data "\n"
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'capistrano/scm/base'
|
2
|
+
|
3
|
+
module Capistrano
|
4
|
+
module SCM
|
5
|
+
|
6
|
+
# An SCM module for using Bazaar-NG (bzr) as your source control tool.
|
7
|
+
# You can use it by placing the following line in your configuration:
|
8
|
+
#
|
9
|
+
# set :scm, :bzr
|
10
|
+
#
|
11
|
+
# Also, this module accepts a <tt>:bzr</tt> configuration variable,
|
12
|
+
# which (if specified) will be used as the full path to the bzr
|
13
|
+
# executable on the remote machine:
|
14
|
+
#
|
15
|
+
# set :bzr, "/opt/local/bin/bzr"
|
16
|
+
class Bzr < Base
|
17
|
+
# Return an integer identifying the last known revision in the bzr
|
18
|
+
# repository. (This integer is currently the revision number.)
|
19
|
+
def latest_revision
|
20
|
+
`#{bzr} revno #{configuration.repository}`.to_i
|
21
|
+
end
|
22
|
+
|
23
|
+
# Return the number of the revision currently deployed.
|
24
|
+
def current_revision(actor)
|
25
|
+
command = "#{bzr} revno #{actor.release_path} &&"
|
26
|
+
run_update(actor, command, &bzr_stream_handler(actor))
|
27
|
+
end
|
28
|
+
|
29
|
+
# Return a string containing the diff between the two revisions. +from+
|
30
|
+
# and +to+ may be in any format that bzr recognizes as a valid revision
|
31
|
+
# identifier. If +from+ is +nil+, it defaults to the last deployed
|
32
|
+
# revision. If +to+ is +nil+, it defaults to the last developed revision.
|
33
|
+
# Pay attention to the fact that as of now bzr does NOT support
|
34
|
+
# diff on remote locations.
|
35
|
+
def diff(actor, from=nil, to=nil)
|
36
|
+
from ||= current_revision(actor)
|
37
|
+
to ||= ""
|
38
|
+
`#{bzr} diff -r #{from}..#{to} #{configuration.repository}`
|
39
|
+
end
|
40
|
+
|
41
|
+
# Check out (on all servers associated with the current task) the latest
|
42
|
+
# revision. Uses the given actor instance to execute the command. If
|
43
|
+
# bzr asks for a password this will automatically provide it (assuming
|
44
|
+
# the requested password is the same as the password for logging into the
|
45
|
+
# remote server.)
|
46
|
+
def checkout(actor)
|
47
|
+
op = configuration[:checkout] || "branch"
|
48
|
+
command = "#{bzr} #{op} -r#{configuration.revision} #{configuration.repository} #{actor.release_path} &&"
|
49
|
+
run_checkout(actor, command, &bzr_stream_handler(actor))
|
50
|
+
end
|
51
|
+
|
52
|
+
def update(actor)
|
53
|
+
command = "cd #{actor.current_path} && #{bzr} pull -q &&"
|
54
|
+
run_update(actor, command, &bzr_stream_handler(actor))
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
def bzr
|
59
|
+
configuration[:bzr] || "bzr"
|
60
|
+
end
|
61
|
+
|
62
|
+
def bzr_stream_handler(actor)
|
63
|
+
Proc.new do |ch, stream, out|
|
64
|
+
prefix = "#{stream} :: #{ch[:host]}"
|
65
|
+
actor.logger.info out, prefix
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'time'
|
2
|
+
require 'capistrano/scm/base'
|
3
|
+
|
4
|
+
module Capistrano
|
5
|
+
module SCM
|
6
|
+
|
7
|
+
# An SCM module for using CVS as your source control tool. You can
|
8
|
+
# specify it by placing the following line in your configuration:
|
9
|
+
#
|
10
|
+
# set :scm, :cvs
|
11
|
+
#
|
12
|
+
# Also, this module accepts a <tt>:cvs</tt> configuration variable,
|
13
|
+
# which (if specified) will be used as the full path to the cvs
|
14
|
+
# executable on the remote machine:
|
15
|
+
#
|
16
|
+
# set :cvs, "/opt/local/bin/cvs"
|
17
|
+
#
|
18
|
+
# You can specify the location of your local copy (used to query
|
19
|
+
# the revisions, etc.) via the <tt>:local</tt> variable, which defaults to
|
20
|
+
# ".".
|
21
|
+
#
|
22
|
+
# You may also specify a <tt>:branch</tt> configuration variable,
|
23
|
+
# which (if specified) will be used in the '-r' option to the cvs
|
24
|
+
# check out command. If it is not set, the module will determine if a
|
25
|
+
# branch is being used in the CVS sandbox relative to
|
26
|
+
# <tt>:local</tt> and act accordingly.
|
27
|
+
#
|
28
|
+
# set :branch, "prod-20060124"
|
29
|
+
#
|
30
|
+
# Also, you can specify the CVS_RSH variable to use on the remote machine(s)
|
31
|
+
# via the <tt>:cvs_rsh</tt> variable. This defaults to the value of the
|
32
|
+
# CVS_RSH environment variable locally, or if it is not set, to "ssh".
|
33
|
+
class Cvs < Base
|
34
|
+
def initialize(configuration)
|
35
|
+
super(configuration)
|
36
|
+
if not configuration.respond_to?(:branch) then
|
37
|
+
configuration.set(:branch) { self.current_branch }
|
38
|
+
else
|
39
|
+
@current_branch = configuration[:branch]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Return a string representing the date of the last revision (CVS is
|
44
|
+
# seriously retarded, in that it does not give you a way to query when
|
45
|
+
# the last revision was made to the repository, so this is a fairly
|
46
|
+
# expensive operation...)
|
47
|
+
def latest_revision
|
48
|
+
return @latest_revision if @latest_revision
|
49
|
+
configuration.logger.debug "querying latest revision..."
|
50
|
+
@latest_revision = cvs_log(cvs_local, configuration.branch).
|
51
|
+
split(/\r?\n/).
|
52
|
+
grep(/^date: (.*?);/) { Time.parse($1).strftime("%Y-%m-%d %H:%M:%S") }.
|
53
|
+
sort.
|
54
|
+
last
|
55
|
+
end
|
56
|
+
|
57
|
+
# Return a string representing the branch that the sandbox
|
58
|
+
# relative to <tt>:local</tt> contains.
|
59
|
+
def current_branch
|
60
|
+
return @current_branch if @current_branch
|
61
|
+
configuration.logger.debug "determining current_branch..."
|
62
|
+
@current_branch = cvs_branch(cvs_local)
|
63
|
+
end
|
64
|
+
|
65
|
+
# Check out (on all servers associated with the current task) the latest
|
66
|
+
# revision, using a branch if necessary. Uses the given actor instance
|
67
|
+
# to execute the command.
|
68
|
+
def checkout(actor)
|
69
|
+
cvs = configuration[:cvs] || "cvs"
|
70
|
+
cvs_rsh = configuration[:cvs_rsh] || ENV['CVS_RSH'] || "ssh"
|
71
|
+
|
72
|
+
if "HEAD" == configuration.branch then
|
73
|
+
branch_option = ""
|
74
|
+
else
|
75
|
+
branch_option = "-r #{configuration.branch}"
|
76
|
+
end
|
77
|
+
|
78
|
+
command = <<-CMD
|
79
|
+
cd #{configuration.releases_path};
|
80
|
+
CVS_RSH="#{cvs_rsh}" #{cvs} -d #{configuration.repository} -Q co -D "#{configuration.revision}" #{branch_option} -d #{File.basename(actor.release_path)} #{actor.application};
|
81
|
+
CMD
|
82
|
+
|
83
|
+
run_checkout(actor, command) do |ch, stream, out|
|
84
|
+
prefix = "#{stream} :: #{ch[:host]}"
|
85
|
+
actor.logger.info out, prefix
|
86
|
+
if out =~ %r{password:}
|
87
|
+
actor.logger.info "CVS is asking for a password", prefix
|
88
|
+
ch.send_data "#{actor.password}\n"
|
89
|
+
elsif out =~ %r{^Enter passphrase}
|
90
|
+
message = "CVS needs your key's passphrase and cannot proceed"
|
91
|
+
actor.logger.info message, prefix
|
92
|
+
raise message
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
# Look for a 'CVS/Tag' file in the path. If this file exists
|
100
|
+
# and contains a Line starting with 'T' then this CVS sandbox is
|
101
|
+
# 'tagged' with a branch. In the default case return 'HEAD'
|
102
|
+
def cvs_branch(path)
|
103
|
+
branch = "HEAD"
|
104
|
+
branch_file = File.join(path || ".", "CVS", "Tag")
|
105
|
+
if File.exists?(branch_file) then
|
106
|
+
File.open(branch_file) do |f|
|
107
|
+
possible_branch = f.find { |l| l =~ %r{^T} }
|
108
|
+
branch = possible_branch.strip[1..-1] if possible_branch
|
109
|
+
end
|
110
|
+
end
|
111
|
+
branch
|
112
|
+
end
|
113
|
+
|
114
|
+
def cvs_log(path,branch)
|
115
|
+
`cd #{path || "."} && cvs -q log -N -r#{branch}`
|
116
|
+
end
|
117
|
+
|
118
|
+
def cvs_local
|
119
|
+
configuration.local || "."
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'capistrano/scm/base'
|
2
|
+
|
3
|
+
module Capistrano
|
4
|
+
module SCM
|
5
|
+
|
6
|
+
# An SCM module for using darcs as your source control tool. Use it by
|
7
|
+
# specifying the following line in your configuration:
|
8
|
+
#
|
9
|
+
# set :scm, :darcs
|
10
|
+
#
|
11
|
+
# Also, this module accepts a <tt>:darcs</tt> configuration variable,
|
12
|
+
# which (if specified) will be used as the full path to the darcs
|
13
|
+
# executable on the remote machine:
|
14
|
+
#
|
15
|
+
# set :darcs, "/opt/local/bin/darcs"
|
16
|
+
class Darcs < Base
|
17
|
+
# Check out (on all servers associated with the current task) the latest
|
18
|
+
# revision. Uses the given actor instance to execute the command.
|
19
|
+
def checkout(actor)
|
20
|
+
darcs = configuration[:darcs] ? configuration[:darcs] : "darcs"
|
21
|
+
revision = configuration[:revision] ? %(--to-match "#{configuration.revision}") : ""
|
22
|
+
run_checkout(actor, "#{darcs} get -q --set-scripts-executable #{revision} #{configuration.repository} #{actor.release_path};")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|