capistrano 2.13.5 → 2.14.1

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.
data/CHANGELOG CHANGED
@@ -1,5 +1,10 @@
1
- ## 2.13.5 (tentative) / October 26 2012
1
+ ## 2.14.1 (tentative) / January 10 2013
2
2
 
3
+ ## 2.14.0 / January 9 2013
4
+
5
+ * Removed ui.output_cols limit of 80 chars (@aussielunix)
6
+ * Added :p4charset variable for Perforce command line (@randyinla)
7
+ * Added support for rolling back assets, and removing expired assets (@ndbroadbent)
3
8
  * Merged in `capistrano_colors` gem, and renamed to 'log_formatters', since it does much more than just colors
4
9
  (@ndbroadbent)
5
10
  * Use more intelligence in setting the :scm variable based on known version control directory names (@czarneckid)
@@ -112,7 +112,7 @@ module Capistrano
112
112
 
113
113
  def output_columns #:nodoc:
114
114
  if ( @output_columns.nil? )
115
- if ( self.class.ui.output_cols.nil? || self.class.ui.output_cols > 80 )
115
+ if ( self.class.ui.output_cols.nil? )
116
116
  @output_columns = 80
117
117
  else
118
118
  @output_columns = self.class.ui.output_cols
@@ -43,7 +43,14 @@ module Capistrano
43
43
  # Must mix last, because it hooks into previously defined methods
44
44
  include Callbacks
45
45
 
46
- ((self.instance_methods & Kernel.methods) - Namespaces::Namespace.instance_methods).each do |name|
46
+ (self.instance_methods & Kernel.methods).select do |name|
47
+ # Select the instance methods owned by the Configuration class.
48
+ self.instance_method(name).owner.to_s.start_with?("Capistrano::Configuration")
49
+ end.select do |name|
50
+ # Of those, select methods that are being shadowed by the Kernel module in the Namespace class.
51
+ Namespaces::Namespace.method_defined?(name) && Namespaces::Namespace.instance_method(name).owner == Kernel
52
+ end.each do |name|
53
+ # Undefine the shadowed methods, since we want Namespace objects to defer handling to the Configuration object.
47
54
  Namespaces::Namespace.send(:undef_method, name)
48
55
  end
49
56
  end
@@ -160,7 +160,7 @@ module Capistrano
160
160
  # or #invoke_command.
161
161
  def run_tree(tree, options={}) #:nodoc:
162
162
  if tree.branches.empty? && tree.fallback
163
- logger.debug "executing #{tree.fallback}"
163
+ logger.debug "executing #{tree.fallback}" unless options[:silent]
164
164
  elsif tree.branches.any?
165
165
  logger.debug "executing multiple commands in parallel"
166
166
  tree.each do |branch|
@@ -213,7 +213,7 @@ module Kernel
213
213
 
214
214
  namespace = Capistrano::Configuration::Namespaces::Namespace
215
215
 
216
- if namespace.method_defined?(name) && namespace.method(name).owner == Kernel
216
+ if namespace.method_defined?(name) && namespace.instance_method(name).owner == Kernel
217
217
  namespace.send :undef_method, name
218
218
  end
219
219
 
@@ -1,8 +1,9 @@
1
- require 'benchmark'
2
- require 'yaml'
3
- require 'shellwords'
4
- require 'capistrano/recipes/deploy/scm'
5
- require 'capistrano/recipes/deploy/strategy'
1
+ require "benchmark"
2
+ require "set"
3
+ require "shellwords"
4
+ require "yaml"
5
+ require "capistrano/recipes/deploy/scm"
6
+ require "capistrano/recipes/deploy/strategy"
6
7
 
7
8
  def _cset(name, *args, &block)
8
9
  unless exists?(name)
@@ -287,7 +288,8 @@ namespace :deploy do
287
288
  if fetch(:normalize_asset_timestamps, true)
288
289
  stamp = Time.now.utc.strftime("%Y%m%d%H%M.%S")
289
290
  asset_paths = fetch(:public_children, %w(images stylesheets javascripts)).map { |p| "#{escaped_release}/public/#{p}" }
290
- run("find #{asset_paths.join(" ").shellescape} -exec touch -t -- #{stamp} {} ';'; true", :env => { "TZ" => "UTC" }) if asset_paths.any?
291
+ run("find #{asset_paths.join(" ")} -exec touch -t #{stamp} -- {} ';'; true",
292
+ :env => { "TZ" => "UTC" }) if asset_paths.any?
291
293
  end
292
294
  end
293
295
 
@@ -3,11 +3,15 @@ load 'deploy' unless defined?(_cset)
3
3
  _cset :asset_env, "RAILS_GROUPS=assets"
4
4
  _cset :assets_prefix, "assets"
5
5
  _cset :assets_role, [:web]
6
+ _cset :expire_assets_after, (3600 * 24 * 7)
6
7
 
7
8
  _cset :normalize_asset_timestamps, false
8
9
 
9
- before 'deploy:finalize_update', 'deploy:assets:symlink'
10
- after 'deploy:update_code', 'deploy:assets:precompile'
10
+ before 'deploy:finalize_update', 'deploy:assets:symlink'
11
+ after 'deploy:update_code', 'deploy:assets:precompile'
12
+ before 'deploy:assets:precompile', 'deploy:assets:update_asset_mtimes'
13
+ after 'deploy:cleanup', 'deploy:assets:clean_expired'
14
+ after 'deploy:rollback:revision', 'deploy:assets:rollback'
11
15
 
12
16
  namespace :deploy do
13
17
  namespace :assets do
@@ -20,7 +24,7 @@ namespace :deploy do
20
24
  :assets_prefix variable to match.
21
25
  DESC
22
26
  task :symlink, :roles => assets_role, :except => { :no_release => true } do
23
- run <<-CMD
27
+ run <<-CMD.compact
24
28
  rm -rf #{latest_release}/public/#{assets_prefix} &&
25
29
  mkdir -p #{latest_release}/public &&
26
30
  mkdir -p #{shared_path}/assets &&
@@ -39,7 +43,34 @@ namespace :deploy do
39
43
  set :asset_env, "RAILS_GROUPS=assets"
40
44
  DESC
41
45
  task :precompile, :roles => assets_role, :except => { :no_release => true } do
42
- run "cd #{latest_release} && #{rake} RAILS_ENV=#{rails_env} #{asset_env} assets:precompile"
46
+ run <<-CMD.compact
47
+ cd -- #{latest_release.shellescape} &&
48
+ #{rake} RAILS_ENV=#{rails_env.shellescape} #{asset_env} assets:precompile &&
49
+ cp -- #{shared_path.shellescape}/assets/manifest.yml #{current_release.shellescape}/assets_manifest.yml
50
+ CMD
51
+ end
52
+
53
+ desc <<-DESC
54
+ [internal] Updates the mtimes for assets that are required by the current release.
55
+ This task runs before assets:precompile.
56
+ DESC
57
+ task :update_asset_mtimes, :roles => assets_role, :except => { :no_release => true } do
58
+ # Fetch assets/manifest.yml contents.
59
+ manifest_path = "#{shared_path}/assets/manifest.yml"
60
+ manifest_yml = capture("[ -e #{manifest_path.shellescape} ] && cat #{manifest_path.shellescape} || echo").strip
61
+
62
+ if manifest_yml != ""
63
+ manifest = YAML.load(manifest_yml)
64
+ current_assets = manifest.to_a.flatten.map {|a| [a, "#{a}.gz"] }.flatten
65
+ 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"
67
+ run <<-CMD.compact
68
+ cat #{deploy_to.shellescape}/TOUCH_ASSETS | while read asset; do
69
+ touch -cm -- "$asset";
70
+ done &&
71
+ rm -f -- #{deploy_to.shellescape}/TOUCH_ASSETS
72
+ CMD
73
+ end
43
74
  end
44
75
 
45
76
  desc <<-DESC
@@ -56,5 +87,76 @@ namespace :deploy do
56
87
  task :clean, :roles => assets_role, :except => { :no_release => true } do
57
88
  run "cd #{latest_release} && #{rake} RAILS_ENV=#{rails_env} #{asset_env} assets:clean"
58
89
  end
90
+
91
+ desc <<-DESC
92
+ Clean up any assets that haven't been deployed for more than :expire_assets_after seconds.
93
+ Default time to keep old assets is one week. Set the :expire_assets_after variable
94
+ to change the assets expiry time. Assets will only be deleted if they are not required by
95
+ an existing release.
96
+ DESC
97
+ task :clean_expired, :roles => assets_role, :except => { :no_release => true } do
98
+ # Fetch all assets_manifest.yml contents.
99
+ manifests_output = capture <<-CMD.compact
100
+ for manifest in #{releases_path.shellescape}/*/assets_manifest.yml; do
101
+ cat -- "$manifest" 2> /dev/null && printf ':::' || true;
102
+ done
103
+ CMD
104
+ manifests = manifests_output.split(':::')
105
+
106
+ if manifests.empty?
107
+ logger.info "No manifests in #{releases_path}/*/assets_manifest.yml"
108
+ else
109
+ logger.info "Fetched #{manifests.count} manifests from #{releases_path}/*/assets_manifest.yml"
110
+ current_assets = Set.new
111
+ manifests.each do |yaml|
112
+ manifest = YAML.load(yaml)
113
+ current_assets += manifest.to_a.flatten.flat_map do |file|
114
+ [file, "#{file}.gz"]
115
+ end
116
+ end
117
+ current_assets += %w(manifest.yml sources_manifest.yml)
118
+
119
+ # Write the list of required assets to server.
120
+ logger.info "Writing required assets to #{deploy_to}/REQUIRED_ASSETS..."
121
+ escaped_assets = current_assets.sort.join("\n").gsub("\"", "\\\"") << "\n"
122
+ put escaped_assets, "#{deploy_to}/REQUIRED_ASSETS"
123
+
124
+ # Finds all files older than X minutes, then removes them if they are not referenced
125
+ # in REQUIRED_ASSETS.
126
+ expire_after_mins = (expire_assets_after.to_f / 60.0).to_i
127
+ logger.info "Removing assets that haven't been deployed for #{expire_after_mins} minutes..."
128
+ # LC_COLLATE=C tells the `sort` and `comm` commands to sort files in byte order.
129
+ run <<-CMD.compact
130
+ cd -- #{shared_path.shellescape}/assets/ &&
131
+ for f in $(
132
+ find * -mmin +#{expire_after_mins.to_s.shellescape} -type f | LC_COLLATE=C sort |
133
+ LC_COLLATE=C comm -23 -- - #{deploy_to.shellescape}/REQUIRED_ASSETS
134
+ ); do
135
+ echo "Removing unneeded asset: $f";
136
+ rm -f -- "$f";
137
+ done;
138
+ rm -f -- #{deploy_to.shellescape}/REQUIRED_ASSETS
139
+ CMD
140
+ end
141
+ end
142
+
143
+ desc <<-DESC
144
+ Rolls back assets to the previous release by symlinking the release's manifest
145
+ to shared/assets/manifest.yml, and finally recompiling or regenerating nondigest assets.
146
+ DESC
147
+ task :rollback, :roles => assets_role, :except => { :no_release => true } do
148
+ previous_manifest = "#{previous_release}/assets_manifest.yml"
149
+ if capture("[ -e #{previous_manifest.shellescape} ] && echo true || echo false").strip != 'true'
150
+ puts "#{previous_manifest} is missing! Cannot roll back assets. " <<
151
+ "Please run deploy:assets:precompile to update your assets when the rollback is finished."
152
+ return false
153
+ else
154
+ run <<-CMD.compact
155
+ cd -- #{previous_release.shellescape} &&
156
+ cp -f -- #{previous_manifest.shellescape} #{shared_path.shellescape}/assets/manifest.yml &&
157
+ #{rake} RAILS_ENV=#{rails_env.shellescape} #{asset_env} assets:precompile:nondigest
158
+ CMD
159
+ end
160
+ end
59
161
  end
60
162
  end
@@ -83,10 +83,11 @@ module Capistrano
83
83
 
84
84
  # Builds the set of authentication switches that perforce understands.
85
85
  def authentication
86
- [ p4port && "-p #{p4port}",
87
- p4user && "-u #{p4user}",
88
- p4passwd && "-P #{p4passwd}",
89
- p4client && "-c #{p4client}" ].compact.join(" ")
86
+ [ p4port && "-p #{p4port}",
87
+ p4user && "-u #{p4user}",
88
+ p4passwd && "-P #{p4passwd}",
89
+ p4client && "-c #{p4client}",
90
+ p4charset && "-C #{p4charset}" ].compact.join(" ")
90
91
  end
91
92
 
92
93
  # Returns the command that will sync the given revision to the given
@@ -112,6 +113,10 @@ module Capistrano
112
113
  def p4passwd
113
114
  variable(:p4passwd) || variable(:scm_password)
114
115
  end
116
+
117
+ def p4charset
118
+ variable(:p4charset)
119
+ end
115
120
 
116
121
  def p4sync_flags
117
122
  variable(:p4sync_flags) || "-f"
@@ -1,8 +1,8 @@
1
1
  module Capistrano
2
2
  class Version
3
3
  MAJOR = 2
4
- MINOR = 13
5
- PATCH = 5
4
+ MINOR = 14
5
+ PATCH = 1
6
6
 
7
7
  def self.to_s
8
8
  "#{MAJOR}.#{MINOR}.#{PATCH}"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capistrano
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.13.5
4
+ version: 2.14.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2012-10-26 00:00:00.000000000 Z
13
+ date: 2013-01-10 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: highline