capistrano 1.3.1 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,29 @@
1
+ *1.4.0* (February 3, 2007)
2
+
3
+ * Use the auth info for subversion more consistently [Jamis Buck]
4
+
5
+ * Add a "capture" helper, for capturing the stdout of a remote command and returning it as a string [Jamis Buck]
6
+
7
+ * Add a "get" helper, to pull a file from a remote server to the localhost [bmihelac]
8
+
9
+ * Fix gateway to actually increment local_port if a port is in use, so that multiple capistrano instances can run at the same time [Mark Imbriaco]
10
+
11
+ * Refactor the permissions tweaking in update_code to a separate task so that people on shared hosts can override it as necessary [jaw6]
12
+
13
+ * Set umask during the setup task, so that intermediate directories are created with the proper permissions [NeilW]
14
+
15
+ * Removed -c/--caprc switch, since the new load order renders it meaningless (just use -f now) [Mike Bailey]
16
+
17
+ * Make sure the standard recipe loads first, so that .caprc and friends can override what it defines. [Mike Bailey]
18
+
19
+ * Add support for a system-wide capistrano config file [Mike Bailey]
20
+
21
+ * Make cold_deploy call update instead of deploy (to avoid invoking the restart task).
22
+
23
+ * Make the touch command run by update_code set the TZ to UTC, for consistent setting of asset timestamps. [NeilW]
24
+
25
+ * Fix off-by-one bug in show_tasks width-computation [NeilW]
26
+
1
27
  *1.3.1* (January 5, 2007)
2
28
 
3
29
  * Fix connection problems when using gateways [Ezra Zygmuntowicz]
@@ -261,6 +261,47 @@ module Capistrano
261
261
  end
262
262
  end
263
263
  end
264
+
265
+ # Get file remote_path from FIRST server targetted by
266
+ # the current task and transfer it to local machine as path. It will use
267
+ # SFTP if Net::SFTP is installed; otherwise it will fall back to using
268
+ # 'cat', which may cause corruption in binary files.
269
+ #
270
+ # get "#{deploy_to}/current/log/production.log", "log/production.log.web"
271
+ def get(remote_path, path, options = {})
272
+ if Capistrano::SFTP && options.fetch(:sftp, true)
273
+ execute_on_servers(options.merge(:once => true)) do |servers|
274
+ logger.debug "downloading #{servers.first}:#{remote_path} to #{path}"
275
+ sessions[servers.first].sftp.connect do |tsftp|
276
+ tsftp.get_file remote_path, path
277
+ end
278
+ logger.trace "download finished"
279
+ end
280
+ else
281
+ logger.important "Net::SFTP is not available; using remote 'cat' to get file, which may cause file corruption"
282
+ File.open(path, "w") do |destination|
283
+ run "cat #{remote_path}", :once => true do |ch, stream, data|
284
+ case stream
285
+ when :out then destination << data
286
+ when :err then raise "error while downloading #{remote_path}: #{data.inspect}"
287
+ end
288
+ end
289
+ end
290
+ end
291
+ end
292
+
293
+ # Executes the given command on the first server targetted by the current
294
+ # task, collects it's stdout into a string, and returns the string.
295
+ def capture(command, options={})
296
+ output = ""
297
+ run(command, options.merge(:once => true)) do |ch, stream, data|
298
+ case stream
299
+ when :out then output << data
300
+ when :err then raise "error processing #{command.inspect}: #{data.inspect}"
301
+ end
302
+ end
303
+ output
304
+ end
264
305
 
265
306
  # Like #run, but executes the command via <tt>sudo</tt>. This assumes that
266
307
  # the sudo password (if required) is the same as the password for logging
@@ -96,7 +96,7 @@ module Capistrano
96
96
  def initialize(args = ARGV)
97
97
  @args = args
98
98
  @options = { :recipes => [], :actions => [], :vars => {},
99
- :pre_vars => {}, :dotfile => default_dotfile }
99
+ :pre_vars => {}, :sysconf => default_sysconf, :dotfile => default_dotfile }
100
100
 
101
101
  OptionParser.new do |opts|
102
102
  opts.banner = "Usage: #{$0} [options] [args]"
@@ -109,15 +109,7 @@ module Capistrano
109
109
  "An action to execute. Multiple actions may",
110
110
  "be specified, and are loaded in the given order."
111
111
  ) { |value| @options[:actions] << value }
112
-
113
- opts.on("-c", "--caprc FILE",
114
- "Specify an alternate personal config file to load.",
115
- "(Default: #{@options[:dotfile]})"
116
- ) do |value|
117
- abort "The config file `#{value}' does not exist" unless File.exist?(value)
118
- @options[:dotfile] = value
119
- end
120
-
112
+
121
113
  opts.on("-f", "--file FILE",
122
114
  "A recipe file to load. Multiple recipes may",
123
115
  "be specified, and are loaded in the given order."
@@ -214,7 +206,7 @@ as the argument to --apply-to, like this:
214
206
  cap --apply-to ~/projects/myapp
215
207
 
216
208
  You'll wind up with a sample deployment recipe in config/deploy.rb and some new
217
- rake tasks in config/tasks.
209
+ rake tasks in lib/tasks.
218
210
 
219
211
  (Currently, --apply-to only works with Rails applications.)
220
212
  DETAIL
@@ -259,10 +251,15 @@ DETAIL
259
251
  config.set :pretend, options[:pretend]
260
252
 
261
253
  options[:pre_vars].each { |name, value| config.set(name, value) }
262
- config.load(@options[:dotfile]) if @options[:dotfile] && File.exist?(@options[:dotfile])
263
254
 
264
255
  # load the standard recipe definition
265
256
  config.load "standard"
257
+
258
+ # load systemwide config/recipe definition
259
+ config.load(@options[:sysconf]) if @options[:sysconf] && File.exist?(@options[:sysconf])
260
+
261
+ # load user config/recipe definition
262
+ config.load(@options[:dotfile]) if @options[:dotfile] && File.exist?(@options[:dotfile])
266
263
 
267
264
  options[:recipes].each { |recipe| config.load(recipe) }
268
265
  options[:vars].each { |name, value| config.set(name, value) }
@@ -305,10 +302,19 @@ DETAIL
305
302
  end
306
303
  end
307
304
 
305
+ def default_sysconf
306
+ File.join(sysconf_directory, "capistrano.conf")
307
+ end
308
+
308
309
  def default_dotfile
309
310
  File.join(home_directory, ".caprc")
310
311
  end
311
312
 
313
+ def sysconf_directory
314
+ # I'm guessing at where Windows users would keep their conf file.
315
+ ENV["SystemRoot"] || '/etc'
316
+ end
317
+
312
318
  def home_directory
313
319
  ENV["HOME"] ||
314
320
  (ENV["HOMEPATH"] && "#{ENV["HOMEDRIVE"]}#{ENV["HOMEPATH"]}") ||
@@ -80,7 +80,7 @@ module Capistrano
80
80
  connection = SSH.connect('127.0.0.1', @config, local_port)
81
81
  @config.logger.trace "connection to #{server} via gateway established"
82
82
  rescue Errno::EADDRINUSE
83
- port = next_port
83
+ local_port = next_port
84
84
  retry
85
85
  rescue Exception => e
86
86
  puts e.class.name
@@ -26,7 +26,7 @@ task :show_tasks do
26
26
  puts "Available tasks"
27
27
  puts "---------------"
28
28
  each_task do |info|
29
- wrap_length = 80 - info[:longest]
29
+ wrap_length = 80 - info[:longest] - 1
30
30
  lines = info[:desc].gsub(/(.{1,#{wrap_length}})(?:\s|\Z)+/, "\\1\n").split(/\n/)
31
31
  puts "%-#{info[:longest]}s %s" % [info[:task], lines.shift]
32
32
  puts "%#{info[:longest]}s %s" % ["", lines.shift] until lines.empty?
@@ -37,9 +37,10 @@ end
37
37
  desc "Set up the expected application directory structure on all boxes"
38
38
  task :setup, :except => { :no_release => true } do
39
39
  run <<-CMD
40
- mkdir -p -m 775 #{deploy_to} #{releases_path} #{shared_path} #{shared_path}/system &&
41
- mkdir -p -m 777 #{shared_path}/log &&
42
- mkdir -p -m 777 #{shared_path}/pids
40
+ umask 02 &&
41
+ mkdir -p #{deploy_to} #{releases_path} #{shared_path} #{shared_path}/system &&
42
+ mkdir -p #{shared_path}/log &&
43
+ mkdir -p #{shared_path}/pids
43
44
  CMD
44
45
  end
45
46
 
@@ -61,6 +62,14 @@ task :enable_web, :roles => :web do
61
62
  delete "#{shared_path}/system/maintenance.html"
62
63
  end
63
64
 
65
+ desc <<-DESC
66
+ Sets group permissions on checkout. Useful for team environments, bad on
67
+ shared hosts. Override this task if you're on a shared host.
68
+ DESC
69
+ task :set_permissions, :except => { :no_release => true } do
70
+ run "chmod -R g+w #{release_path}"
71
+ end
72
+
64
73
  desc <<-DESC
65
74
  Update all servers with the latest release of the source code. All this does
66
75
  is do a checkout (as defined by the selected scm module).
@@ -70,7 +79,7 @@ task :update_code, :except => { :no_release => true } do
70
79
 
71
80
  source.checkout(self)
72
81
 
73
- run "chmod -R g+w #{release_path}"
82
+ set_permissions
74
83
 
75
84
  run <<-CMD
76
85
  rm -rf #{release_path}/log #{release_path}/public/system &&
@@ -88,7 +97,7 @@ task :update_code, :except => { :no_release => true } do
88
97
  # lets the asset timestamping feature of rails work correctly
89
98
  stamp = Time.now.utc.strftime("%Y%m%d%H%M.%S")
90
99
  asset_paths = %w(images stylesheets javascripts).map { |p| "#{release_path}/public/#{p}" }
91
- run "find #{asset_paths.join(" ")} -exec touch -t #{stamp} {} \\;; true"
100
+ run "TZ=UTC find #{asset_paths.join(" ")} -exec touch -t #{stamp} {} \\;; true"
92
101
 
93
102
  # uncache the list of releases, so that the next time it is called it will
94
103
  # include the newly released path.
@@ -245,11 +254,11 @@ task :spinner, :roles => :app do
245
254
  end
246
255
 
247
256
  desc <<-DESC
248
- Used only for deploying when the spinner isn't running. It invokes deploy,
257
+ Used only for deploying when the spinner isn't running. It invokes 'update',
249
258
  and when it finishes it then invokes the spinner task (to start the spinner).
250
259
  DESC
251
260
  task :cold_deploy do
252
- deploy
261
+ update
253
262
  spinner
254
263
  end
255
264
 
@@ -50,7 +50,7 @@ module Capistrano
50
50
  from ||= current_revision(actor)
51
51
  to ||= "HEAD"
52
52
 
53
- `svn diff #{configuration.repository}@#{from} #{configuration.repository}@#{to}`
53
+ `svn diff #{authorization} #{configuration.repository}@#{from} #{configuration.repository}@#{to}`
54
54
  end
55
55
 
56
56
  # Check out (on all servers associated with the current task) the latest
@@ -60,8 +60,7 @@ module Capistrano
60
60
  # remote server.)
61
61
  def checkout(actor)
62
62
  op = configuration[:checkout] || "co"
63
- username = configuration[:svn_username] ? "--username #{configuration[:svn_username]}" : ""
64
- command = "#{svn} #{op} #{username} -q -r#{configuration.revision} #{configuration.repository} #{actor.release_path} &&"
63
+ command = "#{svn} #{op} #{authorization} -q -r#{configuration.revision} #{configuration.repository} #{actor.release_path} &&"
65
64
  run_checkout(actor, command, &svn_stream_handler(actor))
66
65
  end
67
66
 
@@ -78,8 +77,14 @@ module Capistrano
78
77
  configuration[:svn] || "svn"
79
78
  end
80
79
 
80
+ def authorization
81
+ username = configuration[:svn_username] ? "--username #{configuration[:svn_username]}" : ""
82
+ password = configuration[:svn_password] ? "--password #{configuration[:svn_password]}" : ""
83
+ "#{username} #{password}"
84
+ end
85
+
81
86
  def svn_log(path)
82
- `svn log -q --limit 1 #{path}`
87
+ `svn log #{authorization} -q --limit 1 #{path}`
83
88
  end
84
89
 
85
90
  def svn_password
@@ -19,8 +19,8 @@ module Capistrano
19
19
  end
20
20
 
21
21
  MAJOR = 1
22
- MINOR = 3
23
- TINY = 1
22
+ MINOR = 4
23
+ TINY = 0
24
24
 
25
25
  STRING = [MAJOR, MINOR, TINY].join(".")
26
26
 
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
3
3
  specification_version: 1
4
4
  name: capistrano
5
5
  version: !ruby/object:Gem::Version
6
- version: 1.3.1
7
- date: 2007-01-05 00:00:00 -07:00
6
+ version: 1.4.0
7
+ date: 2007-02-03 00:00:00 -07:00
8
8
  summary: Capistrano is a framework and utility for executing commands in parallel on multiple remote machines, via SSH. The primary goal is to simplify and automate the deployment of web applications.
9
9
  require_paths:
10
10
  - lib