capistrano 2.14.2 → 2.15.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +7 -0
  2. data/.travis.yml +1 -0
  3. data/CHANGELOG +49 -8
  4. data/Gemfile +1 -1
  5. data/README.md +4 -4
  6. data/capistrano.gemspec +9 -17
  7. data/lib/capistrano/callback.rb +1 -1
  8. data/lib/capistrano/cli.rb +1 -1
  9. data/lib/capistrano/cli/execute.rb +3 -3
  10. data/lib/capistrano/cli/help.rb +3 -3
  11. data/lib/capistrano/cli/help.txt +23 -23
  12. data/lib/capistrano/cli/options.rb +12 -12
  13. data/lib/capistrano/command.rb +20 -7
  14. data/lib/capistrano/configuration/actions/invocation.rb +23 -11
  15. data/lib/capistrano/configuration/connections.rb +22 -15
  16. data/lib/capistrano/configuration/execution.rb +2 -2
  17. data/lib/capistrano/configuration/loading.rb +2 -2
  18. data/lib/capistrano/configuration/log_formatters.rb +5 -1
  19. data/lib/capistrano/configuration/roles.rb +1 -1
  20. data/lib/capistrano/configuration/servers.rb +6 -6
  21. data/lib/capistrano/errors.rb +4 -4
  22. data/lib/capistrano/ext/multistage.rb +2 -2
  23. data/lib/capistrano/logger.rb +14 -1
  24. data/lib/capistrano/recipes/deploy.rb +94 -27
  25. data/lib/capistrano/recipes/deploy/assets.rb +21 -18
  26. data/lib/capistrano/recipes/deploy/dependencies.rb +2 -2
  27. data/lib/capistrano/recipes/deploy/remote_dependency.rb +11 -11
  28. data/lib/capistrano/recipes/deploy/scm.rb +1 -1
  29. data/lib/capistrano/recipes/deploy/scm/accurev.rb +6 -6
  30. data/lib/capistrano/recipes/deploy/scm/cvs.rb +4 -4
  31. data/lib/capistrano/recipes/deploy/scm/darcs.rb +3 -3
  32. data/lib/capistrano/recipes/deploy/scm/git.rb +3 -0
  33. data/lib/capistrano/recipes/deploy/scm/mercurial.rb +3 -3
  34. data/lib/capistrano/recipes/deploy/scm/none.rb +9 -5
  35. data/lib/capistrano/recipes/deploy/scm/perforce.rb +5 -5
  36. data/lib/capistrano/recipes/deploy/scm/subversion.rb +1 -1
  37. data/lib/capistrano/recipes/deploy/strategy.rb +1 -1
  38. data/lib/capistrano/recipes/deploy/strategy/base.rb +5 -1
  39. data/lib/capistrano/recipes/deploy/strategy/copy.rb +14 -2
  40. data/lib/capistrano/recipes/standard.rb +1 -1
  41. data/lib/capistrano/server_definition.rb +1 -1
  42. data/lib/capistrano/shell.rb +4 -1
  43. data/lib/capistrano/ssh.rb +1 -1
  44. data/lib/capistrano/version.rb +2 -2
  45. data/test/cli/options_test.rb +1 -1
  46. data/test/cli/ui_test.rb +1 -1
  47. data/test/command_test.rb +11 -1
  48. data/test/configuration/actions/invocation_test.rb +5 -1
  49. data/test/configuration/callbacks_test.rb +1 -1
  50. data/test/configuration/connections_test.rb +19 -0
  51. data/test/configuration/execution_test.rb +1 -1
  52. data/test/configuration/namespace_dsl_test.rb +6 -6
  53. data/test/configuration/roles_test.rb +2 -2
  54. data/test/configuration/servers_test.rb +12 -12
  55. data/test/configuration/variables_test.rb +3 -3
  56. data/test/deploy/scm/bzr_test.rb +1 -1
  57. data/test/deploy/scm/darcs_test.rb +2 -2
  58. data/test/deploy/scm/git_test.rb +10 -0
  59. data/test/deploy/scm/mercurial_test.rb +3 -3
  60. data/test/deploy/scm/perforce_test.rb +1 -1
  61. data/test/deploy/strategy/copy_test.rb +25 -1
  62. data/test/extensions_test.rb +1 -1
  63. data/test/logger_formatting_test.rb +56 -1
  64. data/test/recipes_test.rb +1 -1
  65. data/test/server_definition_test.rb +2 -2
  66. data/test/shell_test.rb +12 -6
  67. data/test/transfer_test.rb +1 -1
  68. metadata +63 -31
@@ -2,6 +2,7 @@ load 'deploy' unless defined?(_cset)
2
2
 
3
3
  _cset :asset_env, "RAILS_GROUPS=assets"
4
4
  _cset :assets_prefix, "assets"
5
+ _cset :shared_assets_prefix, "assets"
5
6
  _cset :assets_role, [:web]
6
7
  _cset :expire_assets_after, (3600 * 24 * 7)
7
8
 
@@ -21,14 +22,15 @@ namespace :deploy do
21
22
  mid-deploy mismatches between old application html asking for assets \
22
23
  and getting a 404 file not found error. The assets cache is shared \
23
24
  for efficiency. If you customize the assets path prefix, override the \
24
- :assets_prefix variable to match.
25
+ :assets_prefix variable to match. If you customize shared assets path \
26
+ prefix, override :shared_assets_prefix variable to match.
25
27
  DESC
26
- task :symlink, :roles => assets_role, :except => { :no_release => true } do
28
+ task :symlink, :roles => lambda { assets_role }, :except => { :no_release => true } do
27
29
  run <<-CMD.compact
28
30
  rm -rf #{latest_release}/public/#{assets_prefix} &&
29
31
  mkdir -p #{latest_release}/public &&
30
- mkdir -p #{shared_path}/assets &&
31
- ln -s #{shared_path}/assets #{latest_release}/public/#{assets_prefix}
32
+ mkdir -p #{shared_path}/#{shared_assets_prefix} &&
33
+ ln -s #{shared_path}/#{shared_assets_prefix} #{latest_release}/public/#{assets_prefix}
32
34
  CMD
33
35
  end
34
36
 
@@ -42,11 +44,11 @@ namespace :deploy do
42
44
  set :rails_env, "production"
43
45
  set :asset_env, "RAILS_GROUPS=assets"
44
46
  DESC
45
- task :precompile, :roles => assets_role, :except => { :no_release => true } do
47
+ task :precompile, :roles => lambda { assets_role }, :except => { :no_release => true } do
46
48
  run <<-CMD.compact
47
- cd -- #{latest_release.shellescape} &&
49
+ cd -- #{latest_release} &&
48
50
  #{rake} RAILS_ENV=#{rails_env.to_s.shellescape} #{asset_env} assets:precompile &&
49
- cp -- #{shared_path.shellescape}/assets/manifest.yml #{current_release.shellescape}/assets_manifest.yml
51
+ cp -- #{shared_path.shellescape}/#{shared_assets_prefix}/manifest.yml #{current_release.to_s.shellescape}/assets_manifest.yml
50
52
  CMD
51
53
  end
52
54
 
@@ -54,19 +56,19 @@ namespace :deploy do
54
56
  [internal] Updates the mtimes for assets that are required by the current release.
55
57
  This task runs before assets:precompile.
56
58
  DESC
57
- task :update_asset_mtimes, :roles => assets_role, :except => { :no_release => true } do
59
+ task :update_asset_mtimes, :roles => lambda { assets_role }, :except => { :no_release => true } do
58
60
  # Fetch assets/manifest.yml contents.
59
- manifest_path = "#{shared_path}/assets/manifest.yml"
61
+ manifest_path = "#{shared_path}/#{shared_assets_prefix}/manifest.yml"
60
62
  manifest_yml = capture("[ -e #{manifest_path.shellescape} ] && cat #{manifest_path.shellescape} || echo").strip
61
63
 
62
64
  if manifest_yml != ""
63
65
  manifest = YAML.load(manifest_yml)
64
66
  current_assets = manifest.to_a.flatten.map {|a| [a, "#{a}.gz"] }.flatten
65
67
  logger.info "Updating mtimes for ~#{current_assets.count} assets..."
66
- put current_assets.map{|a| "#{shared_path}/assets/#{a}" }.join("\n"), "#{deploy_to}/TOUCH_ASSETS"
68
+ put current_assets.map{|a| "#{shared_path}/#{shared_assets_prefix}/#{a}" }.join("\n"), "#{deploy_to}/TOUCH_ASSETS", :via => :scp
67
69
  run <<-CMD.compact
68
70
  cat #{deploy_to.shellescape}/TOUCH_ASSETS | while read asset; do
69
- touch -cm -- "$asset";
71
+ touch -c -- "$asset";
70
72
  done &&
71
73
  rm -f -- #{deploy_to.shellescape}/TOUCH_ASSETS
72
74
  CMD
@@ -84,7 +86,7 @@ namespace :deploy do
84
86
  set :rails_env, "production"
85
87
  set :asset_env, "RAILS_GROUPS=assets"
86
88
  DESC
87
- task :clean, :roles => assets_role, :except => { :no_release => true } do
89
+ task :clean, :roles => lambda { assets_role }, :except => { :no_release => true } do
88
90
  run "cd #{latest_release} && #{rake} RAILS_ENV=#{rails_env} #{asset_env} assets:clean"
89
91
  end
90
92
 
@@ -94,7 +96,7 @@ namespace :deploy do
94
96
  to change the assets expiry time. Assets will only be deleted if they are not required by
95
97
  an existing release.
96
98
  DESC
97
- task :clean_expired, :roles => assets_role, :except => { :no_release => true } do
99
+ task :clean_expired, :roles => lambda { assets_role }, :except => { :no_release => true } do
98
100
  # Fetch all assets_manifest.yml contents.
99
101
  manifests_output = capture <<-CMD.compact
100
102
  for manifest in #{releases_path.shellescape}/*/assets_manifest.yml; do
@@ -117,7 +119,7 @@ namespace :deploy do
117
119
  # Write the list of required assets to server.
118
120
  logger.info "Writing required assets to #{deploy_to}/REQUIRED_ASSETS..."
119
121
  escaped_assets = current_assets.sort.join("\n").gsub("\"", "\\\"") << "\n"
120
- put escaped_assets, "#{deploy_to}/REQUIRED_ASSETS"
122
+ put escaped_assets, "#{deploy_to}/REQUIRED_ASSETS", :via => :scp
121
123
 
122
124
  # Finds all files older than X minutes, then removes them if they are not referenced
123
125
  # in REQUIRED_ASSETS.
@@ -125,7 +127,9 @@ namespace :deploy do
125
127
  logger.info "Removing assets that haven't been deployed for #{expire_after_mins} minutes..."
126
128
  # LC_COLLATE=C tells the `sort` and `comm` commands to sort files in byte order.
127
129
  run <<-CMD.compact
128
- cd -- #{shared_path.shellescape}/assets/ &&
130
+ cd -- #{deploy_to.shellescape}/ &&
131
+ LC_COLLATE=C sort REQUIRED_ASSETS -o REQUIRED_ASSETS &&
132
+ cd -- #{shared_path.shellescape}/#{shared_assets_prefix}/ &&
129
133
  for f in $(
130
134
  find * -mmin +#{expire_after_mins.to_s.shellescape} -type f | LC_COLLATE=C sort |
131
135
  LC_COLLATE=C comm -23 -- - #{deploy_to.shellescape}/REQUIRED_ASSETS
@@ -142,16 +146,15 @@ namespace :deploy do
142
146
  Rolls back assets to the previous release by symlinking the release's manifest
143
147
  to shared/assets/manifest.yml, and finally recompiling or regenerating nondigest assets.
144
148
  DESC
145
- task :rollback, :roles => assets_role, :except => { :no_release => true } do
149
+ task :rollback, :roles => lambda { assets_role }, :except => { :no_release => true } do
146
150
  previous_manifest = "#{previous_release}/assets_manifest.yml"
147
151
  if capture("[ -e #{previous_manifest.shellescape} ] && echo true || echo false").strip != 'true'
148
152
  puts "#{previous_manifest} is missing! Cannot roll back assets. " <<
149
153
  "Please run deploy:assets:precompile to update your assets when the rollback is finished."
150
- return false
151
154
  else
152
155
  run <<-CMD.compact
153
156
  cd -- #{previous_release.shellescape} &&
154
- cp -f -- #{previous_manifest.shellescape} #{shared_path.shellescape}/assets/manifest.yml &&
157
+ cp -f -- #{previous_manifest.shellescape} #{shared_path.shellescape}/#{shared_assets_prefix}/manifest.yml &&
155
158
  #{rake} RAILS_ENV=#{rails_env.to_s.shellescape} #{asset_env} assets:precompile:nondigest
156
159
  CMD
157
160
  end
@@ -18,7 +18,7 @@ module Capistrano
18
18
  yield self
19
19
  self
20
20
  end
21
-
21
+
22
22
  def remote
23
23
  dep = RemoteDependency.new(configuration)
24
24
  @dependencies << dep
@@ -41,4 +41,4 @@ module Capistrano
41
41
  end
42
42
  end
43
43
  end
44
- end
44
+ end
@@ -58,31 +58,31 @@ module Capistrano
58
58
  def match(command, expect, options={})
59
59
  expect = Regexp.new(Regexp.escape(expect.to_s)) unless expect.is_a?(Regexp)
60
60
 
61
- output_per_server = {}
62
- try("#{command} ", options) do |ch, stream, out|
63
- output_per_server[ch[:server]] ||= ''
64
- output_per_server[ch[:server]] += out
65
- end
61
+ output_per_server = {}
62
+ try("#{command} ", options) do |ch, stream, out|
63
+ output_per_server[ch[:server]] ||= ''
64
+ output_per_server[ch[:server]] += out
65
+ end
66
66
 
67
67
  # It is possible for some of these commands to return a status != 0
68
68
  # (for example, rake --version exits with a 1). For this check we
69
69
  # just care if the output matches, so we reset the success flag.
70
70
  @success = true
71
71
 
72
- errored_hosts = []
73
- output_per_server.each_pair do |server, output|
72
+ errored_hosts = []
73
+ output_per_server.each_pair do |server, output|
74
74
  next if output =~ expect
75
- errored_hosts << server
76
- end
75
+ errored_hosts << server
76
+ end
77
77
 
78
78
  if errored_hosts.any?
79
79
  @hosts = errored_hosts.join(', ')
80
80
  output = output_per_server[errored_hosts.first]
81
81
  @message = "the output #{output.inspect} from #{command.inspect} did not match #{expect.inspect}"
82
82
  @success = false
83
- end
83
+ end
84
84
 
85
- self
85
+ self
86
86
  end
87
87
 
88
88
  def or(message)
@@ -16,4 +16,4 @@ module Capistrano
16
16
  end
17
17
  end
18
18
  end
19
- end
19
+ end
@@ -14,9 +14,9 @@ module Capistrano
14
14
  # * :repository - This should match the depot that code lives in. If your code
15
15
  # exists in a subdirectory, you can append the path depot.
16
16
  # eg. foo-depot/bar_dir
17
- # * :stream - The stream in the depot that code should be pulled from. If
17
+ # * :stream - The stream in the depot that code should be pulled from. If
18
18
  # left blank, the depot stream will be used
19
- # * :revision - Should be in the form 'stream/transaction'.
19
+ # * :revision - Should be in the form 'stream/transaction'.
20
20
  class Accurev < Base
21
21
  include REXML
22
22
  default_command 'accurev'
@@ -54,10 +54,10 @@ module Capistrano
54
54
  end
55
55
  end
56
56
 
57
- # Pops a copy of the code for the specified Accurev revision identifier.
57
+ # Pops a copy of the code for the specified Accurev revision identifier.
58
58
  # The revision identifier is represented as a stream & transaction ID combo.
59
59
  # Accurev can only pop a particular transaction if a stream is created on the server
60
- # with a time basis of that transaction id. Therefore, we will create a stream with
60
+ # with a time basis of that transaction id. Therefore, we will create a stream with
61
61
  # the required criteria and pop that.
62
62
  def export(revision_id, destination)
63
63
  revision = InternalRevision.parse(revision_id)
@@ -89,7 +89,7 @@ module Capistrano
89
89
  ].join(' | ')
90
90
  end
91
91
 
92
- # Returns the command needed to show the diff between what is deployed and what is
92
+ # Returns the command needed to show the diff between what is deployed and what is
93
93
  # pending. Because Accurev can not do this task without creating some streams,
94
94
  # two time basis streams will be created for the purposes of doing the diff.
95
95
  def diff(from, to=head)
@@ -156,7 +156,7 @@ module Capistrano
156
156
  end
157
157
 
158
158
  def to_s
159
- "#{stream}/#{transaction_id}"
159
+ "#{stream}/#{transaction_id}"
160
160
  end
161
161
 
162
162
  def ==(other)
@@ -63,7 +63,7 @@ module Capistrano
63
63
  scm cvs_root, :log, range_arg
64
64
  end
65
65
 
66
- # Unfortunately, cvs doesn't support the concept of a revision number like
66
+ # Unfortunately, cvs doesn't support the concept of a revision number like
67
67
  # subversion and other SCM's do. For now, we'll rely on getting the timestamp
68
68
  # of the latest checkin under the revision that's passed to us.
69
69
  def query_revision(revision)
@@ -99,7 +99,7 @@ module Capistrano
99
99
  root << "-d #{repository} " if repository
100
100
  root
101
101
  end
102
-
102
+
103
103
  # Constructs the destination dir command-line option
104
104
  def cvs_destination(destination)
105
105
  dest = ""
@@ -109,7 +109,7 @@ module Capistrano
109
109
  end
110
110
  dest
111
111
  end
112
-
112
+
113
113
  # attempts to guess what type of revision we're working with
114
114
  def revision_type(rev)
115
115
  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
@@ -117,7 +117,7 @@ module Capistrano
117
117
  return :revision if rev =~ /^\d/ # i.e. 1.2.1
118
118
  return :tag # i.e. RELEASE_1_2
119
119
  end
120
-
120
+
121
121
  # constructs the appropriate command-line switch for specifying a
122
122
  # "revision" in CVS. This could be a tag, branch, revision (i.e. 1.3)
123
123
  # or a date (to be used with -d)
@@ -25,13 +25,13 @@ module Capistrano
25
25
  "--to-match='hash #{revision}'"
26
26
  end
27
27
  end
28
-
28
+
29
29
  # Returns the command that will check out the given revision to the
30
30
  # given destination. The 'revision' parameter must be the 'hash' value
31
31
  # for the revision in question, as given by 'darcs changes --xml-output'.
32
32
  def checkout(revision, destination)
33
- scm :get, *[verbose,
34
- "--repo-name=#{destination}",
33
+ scm :get, *[verbose,
34
+ "--repo-name=#{destination}",
35
35
  to_match(revision),
36
36
  repository].compact
37
37
  end
@@ -134,6 +134,9 @@ module Capistrano
134
134
  remote = origin
135
135
 
136
136
  args = []
137
+
138
+ # Add an option for the branch name so :git_shallow_clone works with branches
139
+ args << "-b #{variable(:branch)}" unless variable(:branch).nil?
137
140
  args << "-o #{remote}" unless remote == 'origin'
138
141
  if depth = variable(:git_shallow_clone)
139
142
  args << "--depth #{depth}"
@@ -89,11 +89,11 @@ module Capistrano
89
89
  "yes\n"
90
90
  end
91
91
  end
92
-
92
+
93
93
  private
94
94
 
95
95
  # Fine grained mercurial commands
96
- def clone(destination)
96
+ def clone(destination)
97
97
  scm :clone,
98
98
  verbose,
99
99
  "--noupdate", # do not update to tip when cloning is done
@@ -124,7 +124,7 @@ module Capistrano
124
124
  else "--verbose"
125
125
  end
126
126
  end
127
-
127
+
128
128
  # honor Cap 2.1+'s :scm_prefer_prompt if present
129
129
  def scm_password_or_prompt
130
130
  @scm_password_or_prompt ||= variable(:scm_password) ||
@@ -18,6 +18,11 @@ module Capistrano
18
18
  # set :repository, "."
19
19
  # set :scm, :none
20
20
  # set :deploy_via, :copy
21
+ #
22
+ # Dereference symbolic links. Copy files instead. Handy when you
23
+ # reference files and directory outside of your deployment root.
24
+ # set :copy_dereference_symlink, true
25
+
21
26
  class None < Base
22
27
  # No versioning, thus, no head. Returns the empty string.
23
28
  def head
@@ -27,9 +32,8 @@ module Capistrano
27
32
  # Simply does a copy from the :repository directory to the
28
33
  # :destination directory.
29
34
  def checkout(revision, destination)
30
- !Capistrano::Deploy::LocalDependency.on_windows? ? "cp -R #{repository} #{destination}" : "xcopy #{repository} \"#{destination}\" /S/I/Y/Q/E"
35
+ !Capistrano::Deploy::LocalDependency.on_windows? ? "cp -R#{configuration[:copy_dereference_symlink]?'L':''} #{repository} #{destination}" : "xcopy #{repository} \"#{destination}\" /S/I/Y/Q/E"
31
36
  end
32
-
33
37
  alias_method :export, :checkout
34
38
 
35
39
  # No versioning, so this just returns the argument, with no
@@ -37,13 +41,13 @@ module Capistrano
37
41
  def query_revision(revision)
38
42
  revision
39
43
  end
40
-
44
+
41
45
  # log: There's no log, so it just echos from and to.
42
-
46
+
43
47
  def log(from="", to="")
44
48
  "No SCM: #{from} - #{to}"
45
49
  end
46
-
50
+
47
51
  end
48
52
 
49
53
  end
@@ -69,13 +69,13 @@ module Capistrano
69
69
  def handle_data(state, stream, text)
70
70
  case text
71
71
  when /\(P4PASSWD\) invalid or unset\./i
72
- raise Capistrano::Error, "scm_password (or p4passwd) is incorrect or unset"
72
+ raise Capistrano::Error, "scm_password (or p4passwd) is incorrect or unset"
73
73
  when /Can.t create a new user.*/i
74
- raise Capistrano::Error, "scm_username (or p4user) is incorrect or unset"
74
+ raise Capistrano::Error, "scm_username (or p4user) is incorrect or unset"
75
75
  when /Perforce client error\:/i
76
- raise Capistrano::Error, "p4port is incorrect or unset"
76
+ raise Capistrano::Error, "p4port is incorrect or unset"
77
77
  when /Client \'[\w\-\_\.]+\' unknown.*/i
78
- raise Capistrano::Error, "p4client is incorrect or unset"
78
+ raise Capistrano::Error, "p4client is incorrect or unset"
79
79
  end
80
80
  end
81
81
 
@@ -113,7 +113,7 @@ module Capistrano
113
113
  def p4passwd
114
114
  variable(:p4passwd) || variable(:scm_password)
115
115
  end
116
-
116
+
117
117
  def p4charset
118
118
  variable(:p4charset)
119
119
  end
@@ -69,7 +69,7 @@ module Capistrano
69
69
  # etc. are handled here.
70
70
  def handle_data(state, stream, text)
71
71
  host = state[:channel][:host]
72
- logger.info "[#{host} :: #{stream}] #{text}"
72
+ logger.info "[#{host} :: #{stream}] #{text}"
73
73
  case text
74
74
  when /\bpassword.*:/i
75
75
  # subversion is prompting for a password
@@ -16,4 +16,4 @@ module Capistrano
16
16
  end
17
17
  end
18
18
  end
19
- end
19
+ end
@@ -29,7 +29,11 @@ module Capistrano
29
29
  # is setup such that a deploy could succeed.
30
30
  def check!
31
31
  Dependencies.new(configuration) do |d|
32
- d.remote.directory(configuration[:releases_path]).or("`#{configuration[:releases_path]}' does not exist. Please run `cap deploy:setup'.")
32
+ if exists?(:stage)
33
+ d.remote.directory(configuration[:releases_path]).or("`#{configuration[:releases_path]}' does not exist. Please run `cap #{configuration[:stage]} deploy:setup'.")
34
+ else
35
+ d.remote.directory(configuration[:releases_path]).or("`#{configuration[:releases_path]}' does not exist. Please run `cap deploy:setup'.")
36
+ end
33
37
  d.remote.writable(configuration[:deploy_to]).or("You do not have permissions to write to `#{configuration[:deploy_to]}'.")
34
38
  d.remote.writable(configuration[:releases_path]).or("You do not have permissions to write to `#{configuration[:releases_path]}'.")
35
39
  end
@@ -39,6 +39,11 @@ module Capistrano
39
39
  # :zip, and which specifies how the source should be compressed for
40
40
  # transmission to each host.
41
41
  #
42
+ # By default, files will be transferred across to the remote machines via 'sftp'. If you prefer
43
+ # to use 'scp' you can set the :copy_via variable to :scp.
44
+ #
45
+ # set :copy_via, :scp
46
+ #
42
47
  # There is a possibility to pass a build command that will get
43
48
  # executed if your code needs to be compiled or something needs to be
44
49
  # done before the code is ready to run.
@@ -174,7 +179,11 @@ module Capistrano
174
179
  end
175
180
 
176
181
  def pattern_for directory
177
- !directory.nil? ? "#{directory}/*" : "*"
182
+ !directory.nil? ? "#{escape_globs(directory)}/*" : "*"
183
+ end
184
+
185
+ def escape_globs path
186
+ path.gsub(/[*?{}\[\]]/, '\\\\\\&')
178
187
  end
179
188
 
180
189
  def excluded_files_contain? file
@@ -316,7 +325,10 @@ module Capistrano
316
325
 
317
326
  # Distributes the file to the remote servers
318
327
  def distribute!
319
- upload(filename, remote_filename)
328
+ args = [filename, remote_filename]
329
+ args << { :via => configuration[:copy_via] } if configuration[:copy_via]
330
+
331
+ upload(*args)
320
332
  decompress_remote_file
321
333
  end
322
334
  end