k3_capistrano 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in k3_capistrano.gemspec
4
+ gemspec
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,86 @@
1
+ k3_capistrano
2
+ =============
3
+
4
+ The k3_capistrano gem sets some reasonable defaults so that your app's config/deploy* files can be
5
+ very minimal and ideally only need to include any app-specific configuration.
6
+
7
+ It also adds some additional deploy tasks such as deploy:test_request (see below for a list).
8
+
9
+ Getting started
10
+ ===============
11
+
12
+ Add k3_capistrano to your Gemfile and add something like this to your config/deploy.rb:
13
+
14
+ set :application, 'app_name'
15
+ set :repository, "user@server:#{application}.git"
16
+
17
+ require 'k3_capistrano/capistrano'
18
+
19
+ Add your staging/production -server-specific config in config/deploy/staging.rb /
20
+ config/deploy/production.rb, respectively. For example:
21
+
22
+ set :domain, 'my.domain.org'
23
+
24
+ To deploy, you just do the usual:
25
+
26
+ cap deploy # defaults to staging
27
+
28
+ or to deploy to production:
29
+
30
+ cap production deploy
31
+
32
+ If your app needs to, it can override any of the defaults, for example these:
33
+
34
+ set :deploy_to, "/apps/#{application}"
35
+ set :branch, 'master' # The git branch to deploy. Could also be set in config/deploy/#{stage}.rb
36
+
37
+ Integrating with Chef
38
+ =====================
39
+
40
+ If you are using Chef and would like capistrano to simply use the configuration that you've already
41
+ defined for this app using Chef, you can follow this alternate instructions to avoid duplicating
42
+ that configuration data in two places...
43
+
44
+ Set the chef_home environment variable to point to your copy of K3's deployment/kitchen/.
45
+
46
+ Just add a line like this to your .bashrc and source your .bashrc:
47
+
48
+ export chef_home=/path/to/deployment/kitchen/
49
+
50
+ Add k3_capistrano to your Gemfile and add something like this to your config/deploy.rb:
51
+
52
+ set :application, 'app_name'
53
+ require 'k3_capistrano/chef'
54
+ require 'k3_capistrano/capistrano'
55
+
56
+
57
+ Tasks provided by k3_capistrano
58
+ ===============================
59
+
60
+ cap backup:create # Back up the database
61
+ cap backup:download # Download the latest backup
62
+ cap backup:locate_last # Locate the latest backup
63
+ cap backup:restore # Restore a database backup file.
64
+ cap backup:upload_backup # Upload a database backup file to the ...
65
+ cap db:database_yml:setup # Creates the database.yml file under t...
66
+ cap db:pull # Pull data from remote database to you...
67
+ cap db:pull_to_staging # Pull data from production database to...
68
+ cap db:setup # Run the db:setup rake task.
69
+ cap db:taps_server # This uses your database config from y...
70
+ cap deploy:test_request # Does a test request to the web site s...
71
+ cap git:check_if_needs_push # Checks to see if your branch is ahead...
72
+ cap git:push # Pushes your local commits to the git ...
73
+ cap logs:tail # tail all 4 app log files to help you ...
74
+ cap logs:watch # tail -f the production.log file
75
+
76
+ Skipping steps
77
+ ==============
78
+
79
+ This deploy script (and its before/after hooks) will take care of doing everything, including
80
+ running db:migrate and precompiling your assets.
81
+
82
+ Since some of those steps aren't necessary for every signle deploy and can make your deploy take
83
+ longer than it needs to, you can skip some of those steps by setting the skip environment variable
84
+ when you run cap deploy. For example, to skip the migrate and assets steps, just run this:
85
+
86
+ skip=assets,migrate cap production deploy
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "k3_capistrano/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "k3_capistrano"
7
+ s.version = K3Capistrano.version
8
+ s.authors = ["Tyler Rick"]
9
+ s.email = ["tyler@k3integrations.com"]
10
+ s.homepage = ""
11
+ s.summary = %q{Common Capistrano tasks and defaults used by K3 Integrations}
12
+ s.description = s.summary
13
+
14
+ s.rubyforge_project = "k3_capistrano"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_runtime_dependency 'parseconfig'
22
+ s.add_runtime_dependency 'capistrano-ext'
23
+ s.add_runtime_dependency 'capistrano_colors'
24
+ s.add_runtime_dependency 'facets'
25
+ s.add_runtime_dependency 'rvm-capistrano'
26
+ s.add_runtime_dependency 'colored'
27
+
28
+ #s.add_runtime_dependency 'tylerrick-chef'
29
+ #s.add_runtime_dependency 'capistrano-chef'
30
+ end
@@ -0,0 +1,142 @@
1
+ #
2
+ # = Capistrano database.yml task
3
+ #
4
+ # Provides a couple of tasks for creating the database.yml
5
+ # configuration file dynamically when deploy:setup is run.
6
+ #
7
+ # Category:: Capistrano
8
+ # Package:: Database
9
+ # Author:: Simone Carletti <weppos@weppos.net>
10
+ # Copyright:: 2007-2010 The Authors
11
+ # License:: MIT License
12
+ # Link:: http://www.simonecarletti.com/
13
+ # Source:: http://gist.github.com/2769
14
+ #
15
+ #
16
+ # == Requirements
17
+ #
18
+ # This extension requires the original <tt>config/database.yml</tt> to be excluded
19
+ # from source code checkout. You can easily accomplish this by renaming
20
+ # the file (for example to database.example.yml) and appending <tt>database.yml</tt>
21
+ # value to your SCM ignore list.
22
+ #
23
+ # # Example for Subversion
24
+ #
25
+ # $ svn mv config/database.yml config/database.example.yml
26
+ # $ svn propset svn:ignore 'database.yml' config
27
+ #
28
+ # # Example for Git
29
+ #
30
+ # $ git mv config/database.yml config/database.example.yml
31
+ # $ echo 'config/database.yml' >> .gitignore
32
+ #
33
+ #
34
+ # == Usage
35
+ #
36
+ # Include this file in your <tt>deploy.rb</tt> configuration file.
37
+ # Assuming you saved this recipe as capistrano_database_yml.rb:
38
+ #
39
+ # require "capistrano_database_yml"
40
+ #
41
+ # Now, when <tt>deploy:setup</tt> is called, this script will automatically
42
+ # create the <tt>database.yml</tt> file in the shared folder.
43
+ # Each time you run a deploy, this script will also create a symlink
44
+ # from your application <tt>config/database.yml</tt> pointing to the shared configuration file.
45
+ #
46
+ # == Custom template
47
+ #
48
+ # By default, this script creates an exact copy of the default
49
+ # <tt>database.yml</tt> file shipped with a new Rails 2.x application.
50
+ # If you want to overwrite the default template, simply create a custom Erb template
51
+ # called <tt>database.yml.erb</tt> and save it into <tt>config/deploy</tt> folder.
52
+ #
53
+ # Although the name of the file can't be changed, you can customize the directory
54
+ # where it is stored defining a variable called <tt>:template_dir</tt>.
55
+ #
56
+ # # store your custom template at foo/bar/database.yml.erb
57
+ # set :template_dir, "foo/bar"
58
+ #
59
+ # # example of database template
60
+ #
61
+ # base: &base
62
+ # adapter: sqlite3
63
+ # timeout: 5000
64
+ # development:
65
+ # database: #{shared_path}/db/development.sqlite3
66
+ # <<: *base
67
+ # test:
68
+ # database: #{shared_path}/db/test.sqlite3
69
+ # <<: *base
70
+ # production:
71
+ # adapter: mysql
72
+ # database: #{application}_production
73
+ # username: #{user}
74
+ # password: #{Capistrano::CLI.ui.ask("Enter MySQL database password: ")}
75
+ # encoding: utf8
76
+ # timeout: 5000
77
+ #
78
+ # Because this is an Erb template, you can place variables and Ruby scripts
79
+ # within the file.
80
+ # For instance, the template above takes advantage of Capistrano CLI
81
+ # to ask for a MySQL database password instead of hard coding it into the template.
82
+ #
83
+ # === Password prompt
84
+ #
85
+ # For security reasons, in the example below the password is not
86
+ # hard coded (or stored in a variable) but asked on setup.
87
+ # I don't like to store passwords in files under version control
88
+ # because they will live forever in your history.
89
+ # This is why I use the Capistrano::CLI utility.
90
+ #
91
+
92
+ unless Capistrano::Configuration.respond_to?(:instance)
93
+ abort "This extension requires Capistrano 2"
94
+ end
95
+
96
+ require 'pathname'
97
+
98
+ Capistrano::Configuration.instance.load do
99
+
100
+ namespace :db do
101
+ namespace :database_yml do
102
+
103
+ desc <<-DESC
104
+ Creates the database.yml file under the shared dir on the server.
105
+
106
+ During a deploy, the db:database_yml:symlink task will symlink from config/database.yml to
107
+ the shared file.
108
+
109
+ By default, this task uses the default template found in lib/templates/database.yml.erb of
110
+ the k3_capistrano gem unless a template called database.yml.erb is found either in your
111
+ app's config/deploy directory.
112
+ DESC
113
+ task :setup, :except => { :no_release => true } do
114
+ upload_to = "#{shared_path}/config/database.yml"
115
+
116
+ default_template = Pathname.new(__FILE__).dirname + 'templates/database.yml.erb'
117
+
118
+ override_template = Pathname.new(fetch(:template_dir, "config/deploy")) + 'database.yml.erb'
119
+ template = override_template.file? ? override_template.read : default_template.read
120
+
121
+ config = ERB.new(template).result(binding)
122
+ puts "Installing this database.yml to #{upload_to}:\n#{config}"
123
+
124
+ run "mkdir -p #{shared_path}/db"
125
+ run "mkdir -p #{shared_path}/config"
126
+ put config, upload_to
127
+ end
128
+
129
+ desc <<-DESC
130
+ [internal] Updates the symlink for database.yml file to the just deployed release.
131
+ DESC
132
+ task :symlink, :except => { :no_release => true } do
133
+ run "ln -nfs #{shared_path}/config/database.yml #{release_path}/config/database.yml"
134
+ end
135
+
136
+ end
137
+ end
138
+
139
+ before 'db:database_yml:setup', 'db:read_remote_my_cnf' # lib/templates/database.yml.erb gets password from my_cnf
140
+ after "deploy:setup", "db:database_yml:setup" unless fetch(:skip_db_setup, false)
141
+ after "deploy:finalize_update", "db:database_yml:symlink"
142
+ end
@@ -0,0 +1,2 @@
1
+ # This file is here for backwards compatibility. You should just require the following file instead:
2
+ require 'k3_capistrano/capistrano'
@@ -0,0 +1,5 @@
1
+ # This file will be automatically required if the k3_capistrano gem is in your
2
+ # Gemfile, so we don't want to put anything Capistrano-dependent here in case
3
+ # they aren't loading/running cap.
4
+ #
5
+ # To actually load this into your config/deploy.rb, you need to explicitly require 'k3_capistrano/capistrano' instead.
@@ -0,0 +1,316 @@
1
+ Capistrano::Configuration.instance(:must_exist).load do
2
+
3
+ # From Rails 3.1 and later, we should assume they want to use the asset pipeline. Can be disabled by setting to false.
4
+ _cset :asset_pipeline, true
5
+
6
+ if asset_pipeline
7
+ #===================================================================================================
8
+ # Standard recipe
9
+
10
+ load 'deploy/assets'
11
+ # The assets recipes that are included with capistrano work like this:
12
+ # 1. deploy:assets:symlink creates a symlink from #{latest_release}/public/assets to #{shared_path}/assets
13
+ # 2. Runs rake assets:precompile on the server
14
+ #
15
+ # We will make use of #1, but override #2 as needed to also allow assets to precompiled locally on
16
+ # the developer's localhost.
17
+
18
+ #===================================================================================================
19
+ # More libraries and requires
20
+
21
+ require 'pp'
22
+ require 'facets/class/to_proc'
23
+ require 'facets/string/cleanlines'
24
+ require 'colored'
25
+
26
+ # We can just get the digests from the manifest.yml instead of recomputing them!
27
+ # Also, when I had it recomputing the digest of every file, it would give false positives for a
28
+ # bunch of .gz files. Apparently, gzipping the same file twice can produce a file with a different
29
+ # digest each time? Anyway, if the source file that the .gz file was produced to hasn't changed, we
30
+ # don't care if the .gz file itself is not identical.
31
+ #Pathname.class_eval do
32
+ # def digest
33
+ # Digest::MD5.file(@path).hexdigest
34
+ # end
35
+ #end
36
+ class K3Capistrano::AssetManifest
37
+ attr_reader :digests
38
+ def initialize(manifest_file)
39
+ @manifest_file = manifest_file
40
+ @digests = YAML.load_file(manifest_file)
41
+ end
42
+
43
+ # Compare to digest_for actionpack-3.2.11/lib/sprockets/helpers/rails_helper.rb
44
+ # We could just reuse that, if we were okay with it loading the Rails application (in order to get
45
+ # Rails.application.config.assets)
46
+ def digest_for!(logical_path)
47
+ digest_for(logical_path) or (raise "#{logical_path} not found in #{@manifest_file}" if logical_path =~ /\.js$|\.css$/)
48
+ end
49
+
50
+ def digest_for(logical_path)
51
+ #puts %(@digests[#{logical_path}]=#{(@digests[logical_path]).inspect})
52
+ @digests[logical_path]
53
+ end
54
+
55
+ def to_s
56
+ @manifest_file.to_s
57
+ end
58
+ end
59
+
60
+ #===================================================================================================
61
+ # Variables
62
+
63
+ _cset :precompile_assets_locally, false
64
+ # The following options only apply if precompile_assets_locally is true:
65
+ (
66
+ # Set skip to include 'local_precompile' to skip running assets:precompile locally during this deploy.
67
+ # You may want to do this to speed up the deploy if you know that your local assets directory is
68
+ # already current -- for example, if you just deployed to staging (and did the precompile during
69
+ # that deploy) and now you are ready to deploy the exact same code to production.
70
+
71
+ # Can also set to :previous_local
72
+ #_cset :compare_to_manifest_from, :remote
73
+
74
+ # If true, keeps a local public/assets; if false, renames it immediately after running precompile
75
+ # It is recommended to set this to false, because if a public/assets dir exists in development mode,
76
+ # changes to your assets files will *not* take effect until you run precompile, whereas if there is
77
+ # *no* public/assets dir, changes will be compiled automatically as needed and take immediately
78
+ # after changing them.
79
+ set :keep_public_assets_dir, false
80
+
81
+ # TODO: How many backups of public/assets to keep
82
+ set :local_asset_dirs_to_keep, 5
83
+
84
+ # Set to false if you don't want it to show the list of changed assets during a deploy.
85
+ set :list_changed_assets_during_deploy, true
86
+ )
87
+
88
+ #===================================================================================================
89
+ namespace :deploy do
90
+ namespace :assets do
91
+
92
+ # If you already know that no changes have been made to your assets since your last deploy, you
93
+ # can speed up the deploy by several minutes by skipping the precompilation step and just reusing
94
+ # the assets in shared/assets that were used by the previous deploy.
95
+ #
96
+ # Usage: skip=assets cap deploy
97
+ #
98
+ if skip.include?('assets')
99
+ task :precompile, :roles => :app, :except => { :no_release => false } do
100
+ # Do nothing.
101
+ puts "Warning: Skipping the 'deploy:assets:precompile' task. Make sure the assets in shared/assets are current."
102
+ end
103
+
104
+ else
105
+ if precompile_assets_locally
106
+ # This strategy precompiles your assets locally and then copies the files to the remote server.
107
+ # This way you can deploy to multiple servers in a row without having to recompile the assets each time,
108
+ # and you can redeploy to the same server without recompiling as long as no assets have changed.
109
+ # You must set :precompile_assets_locally, true if you want to opt in to using this.
110
+ #
111
+ # Overview:
112
+ # * Downloads current manifest from shared/assets/manifest.yml on server.
113
+ # * For each file in local public/assets dir (or most recent timestamped dir):
114
+ # * If local file not present in currently deployed manifest, upload it
115
+ # * If local file has different digest, upload it
116
+ # Do incremental update instead of rsyncing all
117
+
118
+ # List all asset dirs (dirs matching public/assets.*), sorted by filename, except always returning
119
+ # public/assets last if it exists.
120
+ def local_asset_dirs
121
+ (
122
+ Dir["public/assets.*"].map(&Pathname).sort +
123
+ [Pathname.new('public/assets')]
124
+ ).select(&:directory?).select(&:exist?).to_a
125
+ end
126
+
127
+ task :list_local_asset_dirs do
128
+ puts local_asset_dirs
129
+ end
130
+
131
+ def changed_from(previous_file_list, previous_manifest, verbose = false)
132
+ current_dir = local_asset_dirs.last or raise "no local public/assets* dirs exist"
133
+ current_manifest = K3Capistrano::AssetManifest.new(current_dir + 'manifest.yml')
134
+
135
+ if verbose
136
+ puts "Listing changes between '#{previous_manifest}' (previous) and '#{current_manifest}' (latest local precompile, at '#{current_dir}')..."
137
+ puts "Legend: " + "doesn't exist (in dir of '#{previous_manifest}')".cyan + ' | ' + "exists but has changed since '#{previous_manifest}'".yellow
138
+ end
139
+
140
+ descendants = []; current_dir.find {|_| descendants << _ if _.file? }
141
+ descendants.select do |file_in_current|
142
+ base_name = file_in_current.relative_path_from(current_dir).to_s.gsub(%r<^../>, '')
143
+ logical_path = base_name.gsub(/-\w{32}/, '').gsub(/\.gz$/, '')
144
+ #file_in_previous = previous_dir + base_name if previous_dir
145
+
146
+ # Only if the file *exists* in and is in the manifest can we skip it.
147
+ # This is a safeguard against the case where the manifest.yml file gets uploaded but the
148
+ # files themselves haven't yet.
149
+
150
+ file_in_previous = previous_file_list.include?(base_name) && previous_manifest.digest_for(logical_path)
151
+ changed =
152
+ if file_in_previous #&& file_in_previous.exist?
153
+ if previous_manifest.digest_for!(logical_path) == current_manifest.digest_for!(logical_path)
154
+ color = :green
155
+ false
156
+ else
157
+ color = :yellow
158
+ true
159
+ end
160
+ else
161
+ color = :cyan
162
+ true
163
+ end
164
+ puts file_in_current.to_s.send(color) if verbose && changed
165
+ changed
166
+ end.map do |_|
167
+ _.relative_path_from(current_dir).to_s.gsub(%r<^../>, '')
168
+ end
169
+ end
170
+
171
+ def changed_since_previous_local_precompile(verbose = false)
172
+ # TODO: It is also possible for there to be no previous assets dir, in which case it should
173
+ # list *all* files in latest_dir as being new files.
174
+ previous_dir = local_asset_dirs[-2]
175
+ previous_file_list = []; previous_dir.find {|_| previous_file_list << _ if _.file? }
176
+ latest_dir = local_asset_dirs.last
177
+ puts "Listing changes between '#{previous_dir}' and latest local precompile, '#{latest_dir}'..." if verbose
178
+ previous_manifest = K3Capistrano::AssetManifest.new(previous_dir + 'manifest.yml')
179
+ changed_from(previous_file_list, previous_manifest, verbose)
180
+ end
181
+
182
+ def remote_file_list
183
+ capture("cd #{shared_path}/assets && find . -type f").
184
+ cleanlines.map {|_| _.gsub(%r<^\./>, '') }
185
+ end
186
+
187
+ def changed_since_last_deploy(verbose = false)
188
+ remote_manifest = 'tmp/manifest_from_last_deploy.yml'
189
+ get "#{shared_path}/assets/manifest.yml", remote_manifest, via: :scp
190
+ remote_manifest = K3Capistrano::AssetManifest.new(remote_manifest)
191
+ remote_file_list = remote_file_list()
192
+ Pathname('tmp/asset_file_from_last_deploy.txt').tap do |file|
193
+ puts %(Saving list of files from server at: #{file})
194
+ file.open('w') {|_| _.puts remote_file_list.join("\n" )}
195
+ end
196
+ puts "Listing changes between latest deploy and latest local precompile..." if verbose
197
+ changed_from(remote_file_list, remote_manifest, verbose)
198
+ end
199
+
200
+ def changed_assets(verbose = false)
201
+ #case compare_to_manifest_from
202
+ #when :remote
203
+ changed_since_last_deploy(verbose)
204
+ #when :previous_local
205
+ # changed_since_previous_local_precompile(verbose)
206
+ #else
207
+ # raise "unrecognized value for compare_to_manifest_from: #{compare_to_manifest_from.inspect}"
208
+ #end
209
+ end
210
+
211
+ task :list_changed_since_previous_local_precompile do
212
+ puts changed_since_previous_local_precompile(verbose = true)
213
+ end
214
+
215
+ task :list_changed_assets do
216
+ changed_assets(verbose = true)
217
+ end
218
+
219
+ task :list_changed_since_last_deploy do
220
+ changed_since_last_deploy(verbose = true)
221
+ end
222
+
223
+ task :push_changed_assets do
224
+ current_dir = local_asset_dirs.last or raise "no local public/assets* dirs exist"
225
+ changed_files = changed_assets(verbose = list_changed_assets_during_deploy)
226
+
227
+ #remote_host_and_path = "#{user}@#{domain}:#{release_or_current_path.gsub('~/', './')}/public/assets/"
228
+ remote_host_and_path = "#{user}@#{domain}:#{shared_path}/assets/"
229
+
230
+ changed_files_in_root, changed_files_in_subdir = changed_files.partition {|_|
231
+ Pathname.new(_).dirname.to_s == '.'
232
+ }
233
+ if changed_files_in_root.any?
234
+ # TODO: shell escape arguments
235
+ command = "time scp " +
236
+ "#{changed_files_in_root.map {|_| "#{current_dir}/#{_}" }.join(' ')} " +
237
+ "#{remote_host_and_path}"
238
+ #command = "rsync -a --itemize-changes --recursive --compress --times #{changed_files} #{remote_host_and_path}"
239
+ run_locally command
240
+
241
+ # See also this version from https://groups.google.com/forum/#!topic/capistrano/cuOeI-aNLfo
242
+ # servers = find_servers_for_task(current_task)
243
+ # port_option = port ? " -e 'ssh -p #{port}' " : ''
244
+ # servers.each do |server|
245
+ # run_locally("rsync --recursive --times --rsh=ssh --compress --human-readable #{port_option} --progress public/assets #{user} @#{server}:#{shared_path}")
246
+ # end
247
+ end
248
+
249
+ remote_dir_list = remote_file_list().map {|_| Pathname(_).dirname }.uniq
250
+ changed_files_in_subdir.each do |_|
251
+ # mkdir subdir if it doesn't exist on server. (Check in remote_file_list so we don't
252
+ # have to hit the server to check each file individually.)
253
+ dir = Pathname(_).dirname
254
+ unless remote_dir_list.include? dir
255
+ remote_dir_list << dir
256
+ run "mkdir -p #{shared_path}/assets/#{dir}"
257
+ end
258
+
259
+ #put "#{current_dir}/#{_}", "#{shared_path}/assets/#{_}", via: :scp
260
+ command = "scp #{"#{current_dir}/#{_}"} #{remote_host_and_path}#{_}"
261
+ run_locally command
262
+ end
263
+ end
264
+
265
+ def skip_local_precompile?
266
+ skip.include?('local_precompile')
267
+ end
268
+
269
+ def local_asset_current?
270
+ # TODO: Compare time of last commit to app/assets or vendor/assets with time of last local
271
+ # precompile. Return true if there have been any changes since the last precompile that
272
+ # wouldn't be included in the last precompile.
273
+ #
274
+ #local_asset_dirs.any?
275
+ skip_local_precompile?
276
+ end
277
+
278
+ task :precompile_locally do
279
+ run_locally "time bundle exec rake assets:precompile RAILS_ENV=production RAILS_GROUPS=assets"
280
+ after_local_precompile
281
+ end
282
+
283
+ task :after_local_precompile do
284
+ unless keep_public_assets_dir
285
+ latest_dir = "public/assets.#{Time.now.strftime("%Y-%m-%dT%H.%M.%S")}"
286
+ # Move them out of the way locally, so that in development it won't try to use (possibly stale) assets from public/assets instead of dynamically generating them
287
+ run_locally "mv public/assets #{latest_dir}"
288
+ end
289
+ end
290
+
291
+ task :precompile, :roles => :app, :except => { :no_release => false } do
292
+ if local_asset_current?
293
+ # We'll just reuse the assets that we've already previously precompiled locally.
294
+ #latest_dir = local_asset_dirs.last or raise "local_asset_dirs empty"
295
+ puts "Using existing local asset dir: #{local_asset_dirs.last}"
296
+ else
297
+ precompile_locally
298
+ end
299
+ #Pathname(latest_dir).exist? or raise "local assets dir #{latest_dir.inspect} does not exist"
300
+
301
+ push_changed_assets
302
+
303
+ # This is so that the deploy will be aborted if the previous steps failed to produce
304
+ # asset files in the target directory on the server.
305
+ run "ls #{release_or_current_path}/public/assets/*.js"
306
+ end
307
+
308
+ else
309
+ # Just use the standard recipe supplied with capistrano in 'deploy/assets'
310
+ end
311
+ end
312
+
313
+ end
314
+ end
315
+ end # if asset_pipeline
316
+ end