capistrano 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|