capistrano-edge 2.5.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (109) hide show
  1. data/CHANGELOG.rdoc +770 -0
  2. data/Manifest +104 -0
  3. data/README.rdoc +66 -0
  4. data/Rakefile +35 -0
  5. data/bin/cap +4 -0
  6. data/bin/capify +95 -0
  7. data/capistrano.gemspec +51 -0
  8. data/examples/sample.rb +14 -0
  9. data/lib/capistrano.rb +2 -0
  10. data/lib/capistrano/callback.rb +45 -0
  11. data/lib/capistrano/cli.rb +47 -0
  12. data/lib/capistrano/cli/execute.rb +84 -0
  13. data/lib/capistrano/cli/help.rb +125 -0
  14. data/lib/capistrano/cli/help.txt +75 -0
  15. data/lib/capistrano/cli/options.rb +224 -0
  16. data/lib/capistrano/cli/ui.rb +40 -0
  17. data/lib/capistrano/command.rb +283 -0
  18. data/lib/capistrano/configuration.rb +43 -0
  19. data/lib/capistrano/configuration/actions/file_transfer.rb +47 -0
  20. data/lib/capistrano/configuration/actions/inspect.rb +46 -0
  21. data/lib/capistrano/configuration/actions/invocation.rb +293 -0
  22. data/lib/capistrano/configuration/callbacks.rb +148 -0
  23. data/lib/capistrano/configuration/connections.rb +204 -0
  24. data/lib/capistrano/configuration/execution.rb +143 -0
  25. data/lib/capistrano/configuration/loading.rb +197 -0
  26. data/lib/capistrano/configuration/namespaces.rb +197 -0
  27. data/lib/capistrano/configuration/roles.rb +73 -0
  28. data/lib/capistrano/configuration/servers.rb +85 -0
  29. data/lib/capistrano/configuration/variables.rb +127 -0
  30. data/lib/capistrano/errors.rb +15 -0
  31. data/lib/capistrano/extensions.rb +57 -0
  32. data/lib/capistrano/logger.rb +59 -0
  33. data/lib/capistrano/processable.rb +53 -0
  34. data/lib/capistrano/recipes/compat.rb +32 -0
  35. data/lib/capistrano/recipes/deploy.rb +438 -0
  36. data/lib/capistrano/recipes/deploy/dependencies.rb +44 -0
  37. data/lib/capistrano/recipes/deploy/local_dependency.rb +54 -0
  38. data/lib/capistrano/recipes/deploy/remote_dependency.rb +105 -0
  39. data/lib/capistrano/recipes/deploy/scm.rb +19 -0
  40. data/lib/capistrano/recipes/deploy/scm/accurev.rb +169 -0
  41. data/lib/capistrano/recipes/deploy/scm/base.rb +196 -0
  42. data/lib/capistrano/recipes/deploy/scm/bzr.rb +83 -0
  43. data/lib/capistrano/recipes/deploy/scm/cvs.rb +152 -0
  44. data/lib/capistrano/recipes/deploy/scm/darcs.rb +85 -0
  45. data/lib/capistrano/recipes/deploy/scm/git.rb +274 -0
  46. data/lib/capistrano/recipes/deploy/scm/mercurial.rb +137 -0
  47. data/lib/capistrano/recipes/deploy/scm/none.rb +44 -0
  48. data/lib/capistrano/recipes/deploy/scm/perforce.rb +138 -0
  49. data/lib/capistrano/recipes/deploy/scm/subversion.rb +121 -0
  50. data/lib/capistrano/recipes/deploy/strategy.rb +19 -0
  51. data/lib/capistrano/recipes/deploy/strategy/base.rb +79 -0
  52. data/lib/capistrano/recipes/deploy/strategy/checkout.rb +20 -0
  53. data/lib/capistrano/recipes/deploy/strategy/copy.rb +210 -0
  54. data/lib/capistrano/recipes/deploy/strategy/export.rb +20 -0
  55. data/lib/capistrano/recipes/deploy/strategy/remote.rb +52 -0
  56. data/lib/capistrano/recipes/deploy/strategy/remote_cache.rb +56 -0
  57. data/lib/capistrano/recipes/deploy/templates/maintenance.rhtml +53 -0
  58. data/lib/capistrano/recipes/ext/rails-database-migrations.rb +50 -0
  59. data/lib/capistrano/recipes/ext/web-disable-enable.rb +40 -0
  60. data/lib/capistrano/recipes/standard.rb +37 -0
  61. data/lib/capistrano/recipes/templates/maintenance.rhtml +53 -0
  62. data/lib/capistrano/recipes/upgrade.rb +33 -0
  63. data/lib/capistrano/role.rb +102 -0
  64. data/lib/capistrano/server_definition.rb +56 -0
  65. data/lib/capistrano/shell.rb +260 -0
  66. data/lib/capistrano/ssh.rb +99 -0
  67. data/lib/capistrano/task_definition.rb +70 -0
  68. data/lib/capistrano/transfer.rb +216 -0
  69. data/lib/capistrano/version.rb +18 -0
  70. data/setup.rb +1346 -0
  71. data/test/cli/execute_test.rb +132 -0
  72. data/test/cli/help_test.rb +165 -0
  73. data/test/cli/options_test.rb +317 -0
  74. data/test/cli/ui_test.rb +28 -0
  75. data/test/cli_test.rb +17 -0
  76. data/test/command_test.rb +286 -0
  77. data/test/configuration/actions/file_transfer_test.rb +61 -0
  78. data/test/configuration/actions/inspect_test.rb +65 -0
  79. data/test/configuration/actions/invocation_test.rb +224 -0
  80. data/test/configuration/callbacks_test.rb +220 -0
  81. data/test/configuration/connections_test.rb +349 -0
  82. data/test/configuration/execution_test.rb +175 -0
  83. data/test/configuration/loading_test.rb +132 -0
  84. data/test/configuration/namespace_dsl_test.rb +311 -0
  85. data/test/configuration/roles_test.rb +144 -0
  86. data/test/configuration/servers_test.rb +121 -0
  87. data/test/configuration/variables_test.rb +184 -0
  88. data/test/configuration_test.rb +88 -0
  89. data/test/deploy/local_dependency_test.rb +76 -0
  90. data/test/deploy/remote_dependency_test.rb +114 -0
  91. data/test/deploy/scm/accurev_test.rb +23 -0
  92. data/test/deploy/scm/base_test.rb +55 -0
  93. data/test/deploy/scm/git_test.rb +184 -0
  94. data/test/deploy/scm/mercurial_test.rb +129 -0
  95. data/test/deploy/scm/none_test.rb +35 -0
  96. data/test/deploy/strategy/copy_test.rb +258 -0
  97. data/test/extensions_test.rb +69 -0
  98. data/test/fixtures/cli_integration.rb +5 -0
  99. data/test/fixtures/config.rb +5 -0
  100. data/test/fixtures/custom.rb +3 -0
  101. data/test/logger_test.rb +123 -0
  102. data/test/role_test.rb +11 -0
  103. data/test/server_definition_test.rb +121 -0
  104. data/test/shell_test.rb +90 -0
  105. data/test/ssh_test.rb +104 -0
  106. data/test/task_definition_test.rb +101 -0
  107. data/test/transfer_test.rb +160 -0
  108. data/test/utils.rb +38 -0
  109. metadata +321 -0
@@ -0,0 +1,83 @@
1
+ require 'capistrano/recipes/deploy/scm/base'
2
+
3
+ module Capistrano
4
+ module Deploy
5
+ module SCM
6
+
7
+ # Implements the Capistrano SCM interface for the Bazaar-NG revision
8
+ # control system (http://bazaar-vcs.org/).
9
+ class Bzr < Base
10
+ # Sets the default command name for this SCM. Users may override this
11
+ # by setting the :scm_command variable.
12
+ default_command "bzr"
13
+
14
+ # Bazaar-NG doesn't support any pseudo-id's, so we'll use the convention
15
+ # in this adapter that the :head symbol means the most recently
16
+ # committed revision.
17
+ def head
18
+ :head
19
+ end
20
+
21
+ # Returns the command that will check out the given revision to the
22
+ # given destination.
23
+ def checkout(revision, destination)
24
+ scm :checkout, "--lightweight", revswitch(revision), repository, destination
25
+ end
26
+
27
+ # The bzr 'update' command does not support updating to a specific
28
+ # revision, so this just does update, followed by revert (unless
29
+ # updating to head).
30
+ def sync(revision, destination)
31
+ commands = [scm(:update, destination)]
32
+ commands << [scm(:revert, revswitch(revision), destination)] if revision != head
33
+ commands.join(" && ")
34
+ end
35
+
36
+ # The bzr 'export' does an export similar to other SCM systems
37
+ def export(revision, destination)
38
+ scm :export, revswitch(revision), destination, repository
39
+ end
40
+
41
+ # The bzr "diff" command doesn't accept a repository argument, so it
42
+ # must be run from within a working tree.
43
+ def diff(from, to=nil)
44
+ switch = "-r#{from}"
45
+ switch << "..#{to}" if to
46
+
47
+ scm :diff, switch
48
+ end
49
+
50
+ # Returns a log of changes between the two revisions (inclusive).
51
+ def log(from, to=nil)
52
+ scm :log, "--short", "-r#{from}..#{to}", repository
53
+ end
54
+
55
+ # Attempts to translate the given revision identifier to a "real"
56
+ # revision. If the identifier is :head, the "bzr revno" command will
57
+ # be yielded, and the block must execute the command and return the
58
+ # output. The revision will be extracted from the output and returned.
59
+ # If the 'revision' argument, on the other hand, is not :head, it is
60
+ # simply returned.
61
+ def query_revision(revision)
62
+ revision
63
+ end
64
+
65
+ # Increments the given revision number and returns it.
66
+ def next_revision(revision)
67
+ revision.to_i + 1
68
+ end
69
+
70
+ private
71
+
72
+ def revswitch(revision)
73
+ if revision == :head || revision.nil?
74
+ nil
75
+ else
76
+ "-r #{revision}"
77
+ end
78
+ end
79
+ end
80
+
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,152 @@
1
+ require 'capistrano/recipes/deploy/scm/base'
2
+
3
+ module Capistrano
4
+ module Deploy
5
+ module SCM
6
+
7
+ # Implements the Capistrano SCM interface for the CVS revision
8
+ # control system.
9
+ class Cvs < Base
10
+ # Sets the default command name for this SCM. Users may override this
11
+ # by setting the :scm_command variable.
12
+ default_command "cvs"
13
+
14
+ # CVS understands 'HEAD' to refer to the latest revision in the
15
+ # repository.
16
+ def head
17
+ "HEAD"
18
+ end
19
+
20
+ # Returns the command that will check out the given revision to the
21
+ # given destination.
22
+ def checkout(revision, destination)
23
+ [ prep_destination(destination),
24
+ scm(verbose, cvs_root, :checkout, cvs_revision(revision), cvs_destination(destination), variable(:scm_module))
25
+ ].join(' && ')
26
+ end
27
+
28
+ # Returns the command that will do an "cvs update" to the given
29
+ # revision, for the working copy at the given destination.
30
+ def sync(revision, destination)
31
+ [ prep_destination(destination),
32
+ scm(verbose, cvs_root, :update, cvs_revision(revision), cvs_destination(destination))
33
+ ].join(' && ')
34
+ end
35
+
36
+ # Returns the command that will do an "cvs export" of the given revision
37
+ # to the given destination.
38
+ def export(revision, destination)
39
+ [ prep_destination(destination),
40
+ scm(verbose, cvs_root, :export, cvs_revision(revision), cvs_destination(destination), variable(:scm_module))
41
+ ].join(' && ')
42
+ end
43
+
44
+ # Returns the command that will do an "cvs diff" for the two revisions.
45
+ def diff(from, to=nil)
46
+ rev_type = revision_type(from)
47
+ if rev_type == :date
48
+ range_args = "-D '#{from}' -D '#{to || 'now'}'"
49
+ else
50
+ range_args = "-r '#{from}' -r '#{to || head}'"
51
+ end
52
+ scm cvs_root, :diff, range_args
53
+ end
54
+
55
+ # Returns an "cvs log" command for the two revisions.
56
+ def log(from, to=nil)
57
+ rev_type = revision_type(from)
58
+ if rev_type == :date
59
+ range_arg = "-d '#{from}<#{to || 'now'}'"
60
+ else
61
+ range_arg = "-r '#{from}:#{to || head}'"
62
+ end
63
+ scm cvs_root, :log, range_arg
64
+ end
65
+
66
+ # Unfortunately, cvs doesn't support the concept of a revision number like
67
+ # subversion and other SCM's do. For now, we'll rely on getting the timestamp
68
+ # of the latest checkin under the revision that's passed to us.
69
+ def query_revision(revision)
70
+ return revision if revision_type(revision) == :date
71
+ revision = yield(scm(cvs_root, :log, "-r#{revision}")).
72
+ grep(/^date:/).
73
+ map { |line| line[/^date: (.*?);/, 1] }.
74
+ sort.last + " UTC"
75
+ return revision
76
+ end
77
+
78
+ # Determines what the response should be for a particular bit of text
79
+ # from the SCM. Password prompts, connection requests, passphrases,
80
+ # etc. are handled here.
81
+ def handle_data(state, stream, text)
82
+ logger.info "[#{stream}] #{text}"
83
+ case text
84
+ when /\bpassword.*:/i
85
+ # prompting for a password
86
+ "#{variable(:scm_password) || variable(:password)}\n"
87
+ when %r{\(yes/no\)}
88
+ # let's be agreeable...
89
+ "yes\n"
90
+ end
91
+ end
92
+
93
+ private
94
+
95
+ # Constructs the CVSROOT command-line option
96
+ def cvs_root
97
+ root = ""
98
+ root << "-d #{repository} " if repository
99
+ root
100
+ end
101
+
102
+ # Constructs the destination dir command-line option
103
+ def cvs_destination(destination)
104
+ dest = ""
105
+ if destination
106
+ dest_parts = destination.split(/\//);
107
+ dest << "-d #{dest_parts.pop}"
108
+ end
109
+ dest
110
+ end
111
+
112
+ # attempts to guess what type of revision we're working with
113
+ def revision_type(rev)
114
+ return :date if rev =~ /^\d{4}\/\d{2}\/\d{2} \d{2}:\d{2}:\d{2} UTC$/ # i.e 2007-05-15 08:13:25 UTC
115
+ return :date if rev =~ /^\d{4}\/\d{2}\/\d{2} \d{2}:\d{2}:\d{2}$/ # i.e 2007-05-15 08:13:25
116
+ return :revision if rev =~ /^\d/ # i.e. 1.2.1
117
+ return :tag # i.e. RELEASE_1_2
118
+ end
119
+
120
+ # constructs the appropriate command-line switch for specifying a
121
+ # "revision" in CVS. This could be a tag, branch, revision (i.e. 1.3)
122
+ # or a date (to be used with -d)
123
+ def cvs_revision(rev)
124
+ revision = ""
125
+ revision << case revision_type(rev)
126
+ when :date
127
+ "-D \"#{rev}\"" if revision_type(rev) == :date
128
+ when :revision
129
+ "-r #{rev}"
130
+ else
131
+ "-r #{head}"
132
+ end
133
+ return revision
134
+ end
135
+
136
+ # If verbose output is requested, return nil, otherwise return the
137
+ # command-line switch for "quiet" ("-Q").
138
+ def verbose
139
+ variable(:scm_verbose) ? nil : "-Q"
140
+ end
141
+
142
+ def prep_destination(destination)
143
+ dest_parts = destination.split(/\//);
144
+ checkout_dir = dest_parts.pop
145
+ dest = dest_parts.join('/')
146
+ "mkdir -p #{ dest } && cd #{ dest }"
147
+ end
148
+ end
149
+
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,85 @@
1
+ require 'capistrano/recipes/deploy/scm/base'
2
+
3
+ module Capistrano
4
+ module Deploy
5
+ module SCM
6
+
7
+ # Implements the Capistrano SCM interface for the darcs revision
8
+ # control system (http://www.abridgegame.org/darcs/).
9
+ class Darcs < Base
10
+ # Sets the default command name for this SCM. Users may override this
11
+ # by setting the :scm_command variable.
12
+ default_command "darcs"
13
+
14
+ # Because darcs does not have any support for pseudo-ids, we'll just
15
+ # return something here that we can use in the helpers below for
16
+ # determining whether we need to look up the latest revision.
17
+ def head
18
+ :head
19
+ end
20
+
21
+ # Returns the command that will check out the given revision to the
22
+ # given destination. The 'revision' parameter must be the 'hash' value
23
+ # for the revision in question, as given by 'darcs changes --xml-output'.
24
+ def checkout(revision, destination)
25
+ scm :get, verbose, "--repo-name=#{destination}", "--to-match='hash #{revision}'", repository
26
+ end
27
+
28
+ # Tries to update the destination repository in-place, to bring it up
29
+ # to the given revision. Note that because darcs' "pull" operation
30
+ # does not support a "to-match" argument (or similar), this basically
31
+ # nukes the destination directory and re-gets it.
32
+ def sync(revision, destination)
33
+ ["rm -rf #{destination}", checkout(revision, destination)].join(" && ")
34
+ end
35
+
36
+ # Darcs does not have a real 'export' option; there is 'darcs dist',
37
+ # but that presupposes a utility that can untar and ungzip the dist
38
+ # file. We'll cheat and just do a get, followed by a deletion of the
39
+ # _darcs metadata directory.
40
+ def export(revision, destination)
41
+ [checkout(revision, destination), "rm -rf #{destination}/_darcs"].join(" && ")
42
+ end
43
+
44
+ # Returns the command that will do a "darcs diff" for the two revisions.
45
+ # Each revision must be the 'hash' identifier of a darcs revision.
46
+ def diff(from, to=nil)
47
+ scm :diff, "--from-match 'hash #{from}'", to && "--to-match 'hash #{to}'"
48
+ end
49
+
50
+ # Returns the log of changes between the two revisions. Each revision
51
+ # must be the 'hash' identifier of a darcs revision.
52
+ def log(from, to=nil)
53
+ scm :changes, "--from-match 'hash #{from}'", to && "--to-match 'hash #{to}'", "--repo=#{repository}"
54
+ end
55
+
56
+ # Attempts to translate the given revision identifier to a "real"
57
+ # revision. If the identifier is a symbol, it is assumed to be a
58
+ # pseudo-id. Otherwise, it will be immediately returned. If it is a
59
+ # pseudo-id, a set of commands to execute will be yielded, and the
60
+ # result of executing those commands must be returned by the block.
61
+ # This method will then extract the actual revision hash from the
62
+ # returned data.
63
+ def query_revision(revision)
64
+ case revision
65
+ when :head
66
+ xml = yield(scm(:changes, "--last 1", "--xml-output", "--repo=#{repository}"))
67
+ return xml[/hash='(.*?)'/, 1]
68
+ else return revision
69
+ end
70
+ end
71
+
72
+ private
73
+
74
+ def verbose
75
+ case variable(:scm_verbose)
76
+ when nil then "-q"
77
+ when false then nil
78
+ else "-v"
79
+ end
80
+ end
81
+ end
82
+
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,274 @@
1
+ require 'capistrano/recipes/deploy/scm/base'
2
+
3
+ module Capistrano
4
+ module Deploy
5
+ module SCM
6
+
7
+ # An SCM module for using Git as your source control tool with Capistrano
8
+ # 2.0. If you are using Capistrano 1.x, use this plugin instead:
9
+ #
10
+ # http://scie.nti.st/2007/3/16/capistrano-with-git-shared-repository
11
+ #
12
+ # Assumes you are using a shared Git repository.
13
+ #
14
+ # Parts of this plugin borrowed from Scott Chacon's version, which I
15
+ # found on the Capistrano mailing list but failed to be able to get
16
+ # working.
17
+ #
18
+ # FEATURES:
19
+ #
20
+ # * Very simple, only requiring 2 lines in your deploy.rb.
21
+ # * Can deploy different branches, tags, or any SHA1 easily.
22
+ # * Supports prompting for password / passphrase upon checkout.
23
+ # (I am amazed at how some plugins don't do this)
24
+ # * Supports :scm_command, :scm_password, :scm_passphrase Capistrano
25
+ # directives.
26
+ #
27
+ # CONFIGURATION
28
+ # -------------
29
+ #
30
+ # Use this plugin by adding the following line in your config/deploy.rb:
31
+ #
32
+ # set :scm, :git
33
+ #
34
+ # Set <tt>:repository</tt> to the path of your Git repo:
35
+ #
36
+ # set :repository, "someuser@somehost:/home/myproject"
37
+ #
38
+ # The above two options are required to be set, the ones below are
39
+ # optional.
40
+ #
41
+ # You may set <tt>:branch</tt>, which is the reference to the branch, tag,
42
+ # or any SHA1 you are deploying, for example:
43
+ #
44
+ # set :branch, "master"
45
+ #
46
+ # Otherwise, HEAD is assumed. I strongly suggest you set this. HEAD is
47
+ # not always the best assumption.
48
+ #
49
+ # You may also set <tt>:remote</tt>, which will be used as a name for remote
50
+ # tracking of repositories. This option is intended for use with the
51
+ # <tt>:remote_cache</tt> strategy in a distributed git environment.
52
+ #
53
+ # For example in the projects <tt>config/deploy.rb</tt>:
54
+ #
55
+ # set :repository, "#{scm_user}@somehost:~/projects/project.git"
56
+ # set :remote, "#{scm_user}"
57
+ #
58
+ # Then each person with deploy priveledges can add the following to their
59
+ # local <tt>~/.caprc</tt> file:
60
+ #
61
+ # set :scm_user, 'someuser'
62
+ #
63
+ # Now any time a person deploys the project, their repository will be
64
+ # setup as a remote git repository within the cached repository.
65
+ #
66
+ # The <tt>:scm_command</tt> configuration variable, if specified, will
67
+ # be used as the full path to the git executable on the *remote* machine:
68
+ #
69
+ # set :scm_command, "/opt/local/bin/git"
70
+ #
71
+ # For compatibility with deploy scripts that may have used the 1.x
72
+ # version of this plugin before upgrading, <tt>:git</tt> is still
73
+ # recognized as an alias for :scm_command.
74
+ #
75
+ # Set <tt>:scm_password</tt> to the password needed to clone your repo
76
+ # if you don't have password-less (public key) entry:
77
+ #
78
+ # set :scm_password, "my_secret'
79
+ #
80
+ # Otherwise, you will be prompted for a password.
81
+ #
82
+ # <tt>:scm_passphrase</tt> is also supported.
83
+ #
84
+ # The remote cache strategy is also supported.
85
+ #
86
+ # set :repository_cache, "git_master"
87
+ # set :deploy_via, :remote_cache
88
+ #
89
+ # For faster clone, you can also use shallow cloning. This will set the
90
+ # '--depth' flag using the depth specified. This *cannot* be used
91
+ # together with the :remote_cache strategy
92
+ #
93
+ # set :git_shallow_clone, 1
94
+ #
95
+ # For those that don't like to leave your entire repository on
96
+ # your production server you can:
97
+ #
98
+ # set :deploy_via, :export
99
+ #
100
+ # To deploy from a local repository:
101
+ #
102
+ # set :repository, "file://."
103
+ # set :deploy_via, :copy
104
+ #
105
+ # AUTHORS
106
+ # -------
107
+ #
108
+ # Garry Dolley http://scie.nti.st
109
+ # Contributions by Geoffrey Grosenbach http://topfunky.com
110
+ # Scott Chacon http://jointheconversation.org
111
+ # Alex Arnell http://twologic.com
112
+ # and Phillip Goldenburg
113
+
114
+ class Git < Base
115
+ # Sets the default command name for this SCM on your *local* machine.
116
+ # Users may override this by setting the :scm_command variable.
117
+ default_command "git"
118
+
119
+ # When referencing "head", use the branch we want to deploy or, by
120
+ # default, Git's reference of HEAD (the latest changeset in the default
121
+ # branch, usually called "master").
122
+ def head
123
+ configuration[:branch] || 'HEAD'
124
+ end
125
+
126
+ def origin
127
+ configuration[:remote] || 'origin'
128
+ end
129
+
130
+ # Performs a clone on the remote machine, then checkout on the branch
131
+ # you want to deploy.
132
+ def checkout(revision, destination)
133
+ git = command
134
+ remote = origin
135
+
136
+ args = []
137
+ args << "-o #{remote}" unless remote == 'origin'
138
+ if depth = configuration[:git_shallow_clone]
139
+ args << "--depth #{depth}"
140
+ end
141
+
142
+ execute = []
143
+ if args.empty?
144
+ execute << "#{git} clone #{verbose} #{configuration[:repository]} #{destination}"
145
+ else
146
+ execute << "#{git} clone #{verbose} #{args.join(' ')} #{configuration[:repository]} #{destination}"
147
+ end
148
+
149
+ # checkout into a local branch rather than a detached HEAD
150
+ execute << "cd #{destination} && #{git} checkout #{verbose} -b deploy #{revision}"
151
+
152
+ if configuration[:git_enable_submodules]
153
+ execute << "#{git} submodule #{verbose} init"
154
+ execute << "#{git} submodule #{verbose} sync"
155
+ execute << "#{git} submodule #{verbose} update"
156
+ end
157
+
158
+ execute.join(" && ")
159
+ end
160
+
161
+ # An expensive export. Performs a checkout as above, then
162
+ # removes the repo.
163
+ def export(revision, destination)
164
+ checkout(revision, destination) << " && rm -Rf #{destination}/.git"
165
+ end
166
+
167
+ # Merges the changes to 'head' since the last fetch, for remote_cache
168
+ # deployment strategy
169
+ def sync(revision, destination)
170
+ git = command
171
+ remote = origin
172
+
173
+ execute = []
174
+ execute << "cd #{destination}"
175
+
176
+ # Use git-config to setup a remote tracking branches. Could use
177
+ # git-remote but it complains when a remote of the same name already
178
+ # exists, git-config will just silenty overwrite the setting every
179
+ # time. This could cause wierd-ness in the remote cache if the url
180
+ # changes between calls, but as long as the repositories are all
181
+ # based from each other it should still work fine.
182
+ if remote != 'origin'
183
+ execute << "#{git} config remote.#{remote}.url #{configuration[:repository]}"
184
+ execute << "#{git} config remote.#{remote}.fetch +refs/heads/*:refs/remotes/#{remote}/*"
185
+ end
186
+
187
+ # since we're in a local branch already, just reset to specified revision rather than merge
188
+ execute << "#{git} fetch #{verbose} #{remote} && #{git} reset #{verbose} --hard #{revision}"
189
+
190
+ if configuration[:git_enable_submodules]
191
+ execute << "#{git} submodule #{verbose} init"
192
+ execute << "for mod in `#{git} submodule status | awk '{ print $2 }'`; do #{git} config -f .git/config submodule.${mod}.url `#{git} config -f .gitmodules --get submodule.${mod}.url` && echo Synced $mod; done"
193
+ execute << "#{git} submodule #{verbose} sync"
194
+ execute << "#{git} submodule #{verbose} update"
195
+ end
196
+
197
+ execute.join(" && ")
198
+ end
199
+
200
+ # Returns a string of diffs between two revisions
201
+ def diff(from, to=nil)
202
+ from << "..#{to}" if to
203
+ scm :diff, from
204
+ end
205
+
206
+ # Returns a log of changes between the two revisions (inclusive).
207
+ def log(from, to=nil)
208
+ scm :log, "#{from}..#{to}"
209
+ end
210
+
211
+ # Getting the actual commit id, in case we were passed a tag
212
+ # or partial sha or something - it will return the sha if you pass a sha, too
213
+ def query_revision(revision)
214
+ raise ArgumentError, "Deploying remote branches is no longer supported. Specify the remote branch as a local branch for the git repository you're deploying from (ie: '#{revision.gsub('origin/', '')}' rather than '#{revision}')." if revision =~ /^origin\//
215
+ return revision if revision =~ /^[0-9a-f]{40}$/
216
+ command = scm('ls-remote', repository, revision)
217
+ result = yield(command)
218
+ revdata = result.split(/[\t\n]/)
219
+ newrev = nil
220
+ revdata.each_slice(2) do |refs|
221
+ rev, ref = *refs
222
+ if ref.sub(/refs\/.*?\//, '').strip == revision
223
+ newrev = rev
224
+ break
225
+ end
226
+ end
227
+ raise "Unable to resolve revision for '#{revision}' on repository '#{repository}'." unless newrev =~ /^[0-9a-f]{40}$/
228
+ return newrev
229
+ end
230
+
231
+ def command
232
+ # For backwards compatibility with 1.x version of this module
233
+ configuration[:git] || super
234
+ end
235
+
236
+ # Determines what the response should be for a particular bit of text
237
+ # from the SCM. Password prompts, connection requests, passphrases,
238
+ # etc. are handled here.
239
+ def handle_data(state, stream, text)
240
+ host = state[:channel][:host]
241
+ logger.info "[#{host} :: #{stream}] #{text}"
242
+ case text
243
+ when /\bpassword.*:/i
244
+ # git is prompting for a password
245
+ unless pass = configuration[:scm_password]
246
+ pass = Capistrano::CLI.password_prompt
247
+ end
248
+ "#{pass}\n"
249
+ when %r{\(yes/no\)}
250
+ # git is asking whether or not to connect
251
+ "yes\n"
252
+ when /passphrase/i
253
+ # git is asking for the passphrase for the user's key
254
+ unless pass = configuration[:scm_passphrase]
255
+ pass = Capistrano::CLI.password_prompt
256
+ end
257
+ "#{pass}\n"
258
+ when /accept \(t\)emporarily/
259
+ # git is asking whether to accept the certificate
260
+ "t\n"
261
+ end
262
+ end
263
+
264
+ private
265
+
266
+ # If verbose output is requested, return nil, otherwise return the
267
+ # command-line switch for "quiet" ("-q").
268
+ def verbose
269
+ variable(:scm_verbose) ? nil : "-q"
270
+ end
271
+ end
272
+ end
273
+ end
274
+ end