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.
Files changed (37) hide show
  1. data/bin/cap +11 -0
  2. data/examples/sample.rb +113 -0
  3. data/lib/capistrano.rb +1 -0
  4. data/lib/capistrano/actor.rb +438 -0
  5. data/lib/capistrano/cli.rb +295 -0
  6. data/lib/capistrano/command.rb +90 -0
  7. data/lib/capistrano/configuration.rb +243 -0
  8. data/lib/capistrano/extensions.rb +38 -0
  9. data/lib/capistrano/gateway.rb +118 -0
  10. data/lib/capistrano/generators/rails/deployment/deployment_generator.rb +25 -0
  11. data/lib/capistrano/generators/rails/deployment/templates/capistrano.rake +46 -0
  12. data/lib/capistrano/generators/rails/deployment/templates/deploy.rb +122 -0
  13. data/lib/capistrano/generators/rails/loader.rb +20 -0
  14. data/lib/capistrano/logger.rb +59 -0
  15. data/lib/capistrano/recipes/standard.rb +242 -0
  16. data/lib/capistrano/recipes/templates/maintenance.rhtml +53 -0
  17. data/lib/capistrano/scm/base.rb +62 -0
  18. data/lib/capistrano/scm/baz.rb +118 -0
  19. data/lib/capistrano/scm/bzr.rb +70 -0
  20. data/lib/capistrano/scm/cvs.rb +124 -0
  21. data/lib/capistrano/scm/darcs.rb +27 -0
  22. data/lib/capistrano/scm/perforce.rb +139 -0
  23. data/lib/capistrano/scm/subversion.rb +122 -0
  24. data/lib/capistrano/ssh.rb +39 -0
  25. data/lib/capistrano/transfer.rb +90 -0
  26. data/lib/capistrano/utils.rb +26 -0
  27. data/lib/capistrano/version.rb +30 -0
  28. data/test/actor_test.rb +294 -0
  29. data/test/command_test.rb +43 -0
  30. data/test/configuration_test.rb +233 -0
  31. data/test/fixtures/config.rb +5 -0
  32. data/test/fixtures/custom.rb +3 -0
  33. data/test/scm/cvs_test.rb +186 -0
  34. data/test/scm/subversion_test.rb +137 -0
  35. data/test/ssh_test.rb +104 -0
  36. data/test/utils.rb +50 -0
  37. 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