capistrano-edge 2.5.6

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 (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