capistrano-demonz 0.0.5
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/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +1 -0
- data/capistrano-demonz.gemspec +22 -0
- data/lib/capistrano-demonz.rb +7 -0
- data/lib/demonz/base.rb +541 -0
- data/lib/demonz/common.rb +128 -0
- data/lib/demonz/drupal.rb +312 -0
- data/lib/demonz/version.rb +5 -0
- metadata +106 -0
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Chinthaka Godawita
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Capistrano::Demonz
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'capistrano-demonz'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install capistrano-demonz
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'demonz/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "capistrano-demonz"
|
8
|
+
gem.version = Capistrano::Demonz::VERSION
|
9
|
+
gem.authors = ["Chinthaka Godawita"]
|
10
|
+
gem.email = ["chinthaka.godawita@demonzmedia.com"]
|
11
|
+
gem.description = "Demonz Media recipes for Capistrano"
|
12
|
+
gem.summary = "Useful task libraries for Demonz Media recipes for Capistrano"
|
13
|
+
gem.homepage = "https://github.com/demonz/capistrano-demonz"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_dependency "railsless-deploy", ">= 1.0.2"
|
21
|
+
gem.add_dependency "capistrano", ">= 2.13.5"
|
22
|
+
end
|
data/lib/demonz/base.rb
ADDED
@@ -0,0 +1,541 @@
|
|
1
|
+
# Capistrano2 differentiator
|
2
|
+
load 'deploy' if respond_to?(:namespace)
|
3
|
+
Dir['vendor/plugins/*/recipes/*.rb'].each { |plugin| load(plugin) }
|
4
|
+
|
5
|
+
# Required gems/libraries
|
6
|
+
require 'rubygems'
|
7
|
+
require 'demonz/common'
|
8
|
+
require 'capistrano/ext/multistage'
|
9
|
+
|
10
|
+
# Bootstrap Capistrano instance
|
11
|
+
configuration = Capistrano::Configuration.respond_to?(:instance) ?
|
12
|
+
Capistrano::Configuration.instance(:must_exist) :
|
13
|
+
Capistrano.configuration(:must_exist)
|
14
|
+
|
15
|
+
configuration.load do
|
16
|
+
|
17
|
+
# Set default stages
|
18
|
+
set :stages, %w(staging production)
|
19
|
+
set :default_stage, "staging"
|
20
|
+
|
21
|
+
# Set shared path to be inside app directory
|
22
|
+
set :shared_path, File.join(deploy_to, 'shared')
|
23
|
+
|
24
|
+
# --------------------------------------------
|
25
|
+
# Task chains
|
26
|
+
# --------------------------------------------
|
27
|
+
after "multistage:ensure", "demonz:set_release_history"
|
28
|
+
before "deploy", "demonz:set_release_info"
|
29
|
+
before "deploy:finalize_update", "demonz:add_release_tracking"
|
30
|
+
after "deploy:setup", "deploy:setup_shared"
|
31
|
+
after "deploy:setup_shared", "deploy:setup_backup"
|
32
|
+
after "deploy:finalize_update", "demonz:htaccess"
|
33
|
+
after "deploy", "deploy:cleanup"
|
34
|
+
after "deploy:cleanup", "demonz:cleanup_release_tracking"
|
35
|
+
before "deploy:rollback", "demonz:set_rollback_release"
|
36
|
+
after "deploy:rollback", "demonz:update_release_tracking_for_rollback"
|
37
|
+
|
38
|
+
# --------------------------------------------
|
39
|
+
# Default variables
|
40
|
+
# --------------------------------------------
|
41
|
+
# SSH
|
42
|
+
set :user, proc{text_prompt("SSH username: ")}
|
43
|
+
set :group, :user
|
44
|
+
set :password, proc{Capistrano::CLI.password_prompt("SSH password for '#{user}':")}
|
45
|
+
|
46
|
+
# Database
|
47
|
+
# set :dbuser, proc{text_prompt("Database username: ")}
|
48
|
+
# set :dbpass, proc{Capistrano::CLI.password_prompt("Database password for '#{dbuser}':")}
|
49
|
+
# set :dbname, proc{text_prompt("Database name: ")}
|
50
|
+
_cset :mysqldump, "mysqldump"
|
51
|
+
_cset :dump_options, "--single-transaction --create-options --quick"
|
52
|
+
|
53
|
+
# Source Control
|
54
|
+
set :group_writable, true
|
55
|
+
set :use_sudo, false
|
56
|
+
set :scm, :git
|
57
|
+
set :scm_verbose, true
|
58
|
+
set :scm_username, proc{text_prompt("Git username: ")}
|
59
|
+
set :scm_password, proc{Capistrano::CLI.password_prompt("Git password for '#{scm_username}': ")}
|
60
|
+
set :deploy_via, :remote_cache
|
61
|
+
set :copy_strategy, :checkout
|
62
|
+
set :copy_compression, :bz2
|
63
|
+
set :copy_exclude, [".svn", ".DS_Store", "*.sample", "LICENSE*", "Capfile",
|
64
|
+
"RELEASE*", "*.rb", "*.sql", "nbproject", "_template", "*.sublime*"]
|
65
|
+
|
66
|
+
# Backups Path
|
67
|
+
_cset(:backups_path) { File.join(deploy_to, "backups") }
|
68
|
+
_cset(:tmp_backups_path) { File.join("#{backups_path}", "tmp") }
|
69
|
+
_cset(:backups) { capture("ls -x #{backups_path}", :except => { :no_release => true }).split.sort }
|
70
|
+
|
71
|
+
# Define which files or directories you want to exclude from being backed up
|
72
|
+
_cset(:backup_exclude) { [] }
|
73
|
+
set :exclude_string, ''
|
74
|
+
|
75
|
+
# show password requests on windows
|
76
|
+
# (http://weblog.jamisbuck.org/2007/10/14/capistrano-2-1)
|
77
|
+
default_run_options[:pty] = true
|
78
|
+
|
79
|
+
# Release tracking
|
80
|
+
set :release_file, File.join(shared_path, "RELEASES")
|
81
|
+
|
82
|
+
# SASS compilation support (via compass)
|
83
|
+
set :uses_sass, false
|
84
|
+
|
85
|
+
# Add a dependency on compass and :themes if required
|
86
|
+
if uses_sass
|
87
|
+
depend :remote, :gem, "compass", ">=0.12"
|
88
|
+
_cset(:themes) { abort "Please specify themes on this site, set :themes, ['theme1', 'theme2']" }
|
89
|
+
end
|
90
|
+
|
91
|
+
# We need PHP and gzip
|
92
|
+
depend :remote, :command, "php"
|
93
|
+
depend :remote, :command, "gzip"
|
94
|
+
|
95
|
+
# --------------------------------------------
|
96
|
+
# Overloaded tasks
|
97
|
+
# --------------------------------------------
|
98
|
+
namespace :deploy do
|
99
|
+
desc <<-DESC
|
100
|
+
Prepares one or more servers for deployment. Before you can use any \
|
101
|
+
of the Capistrano deployment tasks with your project, you will need to \
|
102
|
+
make sure all of your servers have been prepared with `cap deploy:setup'. When \
|
103
|
+
you add a new server to your cluster, you can easily run the setup task \
|
104
|
+
on just that server by specifying the HOSTS environment variable:
|
105
|
+
|
106
|
+
$ cap HOSTS=new.server.com deploy:setup
|
107
|
+
|
108
|
+
It is safe to run this task on servers that have already been set up; it \
|
109
|
+
will not destroy any deployed revisions or data.
|
110
|
+
DESC
|
111
|
+
task :setup, :except => { :no_release => true } do
|
112
|
+
dirs = [deploy_to, releases_path, shared_path]
|
113
|
+
dirs += shared_children.map { |d| File.join(shared_path, d.split('/').last) }
|
114
|
+
run "#{try_sudo} mkdir -p #{dirs.join(' ')}"
|
115
|
+
run "#{try_sudo} chmod 775 #{dirs.join(' ')}" if fetch(:group_writable, true)
|
116
|
+
run "#{try_sudo} touch #{release_file}"
|
117
|
+
run "#{try_sudo} chmod g+w #{release_file}" if fetch(:group_writable, true)
|
118
|
+
run "#{try_sudo} chown -R #{user}:#{group} #{deploy_to}"
|
119
|
+
end
|
120
|
+
|
121
|
+
desc "Setup backup directory for database and web files"
|
122
|
+
task :setup_backup, :except => { :no_release => true } do
|
123
|
+
run "#{try_sudo} mkdir -p #{backups_path} #{tmp_backups_path} && #{try_sudo} chmod 775 #{backups_path} && #{try_sudo} chmod 775 #{tmp_backups_path}"
|
124
|
+
end
|
125
|
+
|
126
|
+
desc <<-DESC
|
127
|
+
Clean up old releases. By default, the last 5 releases are kept on each \
|
128
|
+
server (though you can change this with the keep_releases variable). All \
|
129
|
+
other deployed revisions are removed from the servers. By default, this \
|
130
|
+
will use sudo to clean up the old releases, but if sudo is not available \
|
131
|
+
for your environment, set the :use_sudo variable to false instead. \
|
132
|
+
|
133
|
+
Overridden to set/reset file and directory permissions
|
134
|
+
DESC
|
135
|
+
task :cleanup, :except => { :no_release => true } do
|
136
|
+
count = fetch(:keep_releases, 5).to_i
|
137
|
+
local_releases = get_release_history(release_file).split.reverse
|
138
|
+
if count >= local_releases.length
|
139
|
+
logger.important "no old releases to clean up"
|
140
|
+
else
|
141
|
+
logger.info "keeping #{count} of #{local_releases.length} deployed releases"
|
142
|
+
set :cleanup_releases, (local_releases - local_releases.last(count))
|
143
|
+
directories = cleanup_releases.map { |release|
|
144
|
+
File.join(releases_path, release) }.join(" ")
|
145
|
+
|
146
|
+
directories.split(" ").each do |dir|
|
147
|
+
set_perms_dirs(dir)
|
148
|
+
set_perms_files(dir)
|
149
|
+
end
|
150
|
+
|
151
|
+
try_sudo "rm -rf #{directories}"
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
desc "Show deployment release history"
|
156
|
+
task :history do
|
157
|
+
logger.important "Previous deployments (in ascending order)"
|
158
|
+
history = get_release_history(release_file)
|
159
|
+
|
160
|
+
if history.empty?
|
161
|
+
logger.info "No previous deployments found"
|
162
|
+
else
|
163
|
+
logger.info history
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
# --------------------------------------------
|
169
|
+
# Demonz tasks
|
170
|
+
# --------------------------------------------
|
171
|
+
namespace :demonz do
|
172
|
+
desc "[internal] Set release history"
|
173
|
+
task :set_release_history, :roles => :web, :except => { :no_release => true } do
|
174
|
+
set :releases, get_release_history(release_file).split
|
175
|
+
end
|
176
|
+
|
177
|
+
desc "Set standard permissions for Demonz servers"
|
178
|
+
task :fixperms, :roles => :web, :except => { :no_release => true } do
|
179
|
+
# chmod the files and directories.
|
180
|
+
set_perms_dirs("#{latest_release}")
|
181
|
+
set_perms_files("#{latest_release}")
|
182
|
+
end
|
183
|
+
|
184
|
+
desc "Test: Task used to verify Capistrano is working. Prints operating system name."
|
185
|
+
task :uname do
|
186
|
+
run "uname -a"
|
187
|
+
end
|
188
|
+
|
189
|
+
desc "Test: Task used to verify Capistrano is working. Prints environment of Capistrano user."
|
190
|
+
task :getpath do
|
191
|
+
run "echo $PATH"
|
192
|
+
end
|
193
|
+
|
194
|
+
desc 'Copy distribution htaccess file'
|
195
|
+
task :htaccess, :roles => :web do
|
196
|
+
case true
|
197
|
+
when remote_file_exists?("#{latest_release}/htaccess.#{stage}.dist")
|
198
|
+
run "#{try_sudo} mv #{latest_release}/htaccess.#{stage}.dist #{latest_release}/.htaccess"
|
199
|
+
when remote_file_exists?("#{latest_release}/htaccess.#{stage}")
|
200
|
+
run "#{try_sudo} mv #{latest_release}/htaccess.#{stage} #{latest_release}/.htaccess"
|
201
|
+
when remote_file_exists?("#{latest_release}/htaccess.dist")
|
202
|
+
run "#{try_sudo} mv #{latest_release}/htaccess.dist #{latest_release}/.htaccess"
|
203
|
+
else
|
204
|
+
logger.important "Failed to move the .htaccess file in #{latest_release} because an unknown pattern was used"
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
# Modified from https://gist.github.com/2016396
|
209
|
+
desc "Push local changes to Git repository"
|
210
|
+
task :push do
|
211
|
+
# Check we are on the right branch, so we can't forget to merge before deploying
|
212
|
+
branch = %x(git branch --no-color 2>/dev/null | sed -e '/^[^*]/d' -e 's/* \\(.*\\)/\\1/').chomp
|
213
|
+
if branch != "#{branch}" && !ENV["IGNORE_BRANCH"]
|
214
|
+
raise Capistrano::Error, "Not on #{branch} branch (set IGNORE_BRANCH=1 to ignore)"
|
215
|
+
end
|
216
|
+
|
217
|
+
# Push the changes
|
218
|
+
if ! system "git push --tags #{fetch(:repository)} #{branch}"
|
219
|
+
raise Capistrano::Error, "Failed to push changes to #{fetch(:repository)}"
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
desc "[internal] Set release info (such as release name and git tag)"
|
224
|
+
task :set_release_info, :roles => :web, :except => { :no_release => true } do
|
225
|
+
# Get all Git tags from local repository
|
226
|
+
all_tags = %x[git for-each-ref --sort='*authordate' --format='%(refname:short)' refs/tags].split
|
227
|
+
|
228
|
+
# Error out if not tags
|
229
|
+
# if all_tags.empty?
|
230
|
+
# raise Capistrano::Error, "No Git tags found, please define some before attempting deployment"
|
231
|
+
# end
|
232
|
+
|
233
|
+
# We're not using pure timestamps to track deployment anymore
|
234
|
+
set :deploy_timestamped, false
|
235
|
+
|
236
|
+
if variables.include?(:tag) && !all_tags.empty? && all_tags.include?(tag)
|
237
|
+
logger.info "deploying using Git tag '#{tag}'"
|
238
|
+
|
239
|
+
# Set revision to the commit that :tag points to
|
240
|
+
set :revision, run_locally("git rev-list #{tag} | head -n 1")
|
241
|
+
|
242
|
+
# Slashes are bad in directory names
|
243
|
+
clean_tag = tag.gsub("/", "-")
|
244
|
+
else
|
245
|
+
logger.important "no valid Git tag specified, continuing with HEAD instead"
|
246
|
+
|
247
|
+
# Get tag from user
|
248
|
+
tag = text_prompt("Please specify a tag name for this release (this will be created): ")
|
249
|
+
logger.info "setting release tag to #{tag}"
|
250
|
+
|
251
|
+
# Slashes are bad in directory names
|
252
|
+
clean_tag = tag.gsub("/", "-")
|
253
|
+
|
254
|
+
# Try to add tag to git
|
255
|
+
if ! system "git tag #{release_name}"
|
256
|
+
raise Capistrano::Error, "Failed to Git tag: #{release_name}"
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
# If the release directory already exists, append timestamp
|
261
|
+
if remote_file_exists?(File.join(releases_path, clean_tag, 'REVISION'))
|
262
|
+
clean_tag += '-' + Time.now.utc.strftime("%Y%m%d%H%M%S")
|
263
|
+
logger.important "previous deployment with this tag found, setting current release name to #{clean_tag}"
|
264
|
+
end
|
265
|
+
|
266
|
+
set :release_name, clean_tag
|
267
|
+
set :latest_release, release_path
|
268
|
+
end
|
269
|
+
|
270
|
+
desc "[internal] Keep track of the current release"
|
271
|
+
task :add_release_tracking, :roles => :web, :except => { :no_release => true } do
|
272
|
+
on_rollback { remove_release_from_history(release_name, release_file) }
|
273
|
+
run "#{try_sudo} echo #{release_name} >> #{release_file}"
|
274
|
+
end
|
275
|
+
|
276
|
+
desc "[internal] Cleanup release tracking"
|
277
|
+
task :cleanup_release_tracking, :roles => :web, :except => { :no_release => true } do
|
278
|
+
if variables.include?(:cleanup_releases)
|
279
|
+
cleanup_releases = fetch(:cleanup_releases, nil)
|
280
|
+
|
281
|
+
if !cleanup_releases.nil?
|
282
|
+
files_backups = cleanup_releases.map { |release|
|
283
|
+
remove_release_from_history(release, release_file) }
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
desc "[internal] Set last release name for rollback"
|
289
|
+
task :set_rollback_release, :except => { :no_release => true } do
|
290
|
+
set :release_name, releases.last
|
291
|
+
end
|
292
|
+
|
293
|
+
desc "[internal] Remove rollback release from release tracking"
|
294
|
+
task :update_release_tracking_for_rollback, :except => { :no_release => true } do
|
295
|
+
remove_release_from_history(release_name, release_file)
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
# --------------------------------------------
|
300
|
+
# PHP tasks
|
301
|
+
# --------------------------------------------
|
302
|
+
namespace :php do
|
303
|
+
namespace :apc do
|
304
|
+
desc "Disable the APC administrative panel"
|
305
|
+
task :disable, :roles => :web, :except => { :no_release => true } do
|
306
|
+
run "#{try_sudo} rm #{current_path}/apc.php"
|
307
|
+
end
|
308
|
+
|
309
|
+
desc "Enable the APC administrative panel"
|
310
|
+
task :enable, :roles => :web, :except => { :no_release => true } do
|
311
|
+
run "#{try_sudo} ln -s /usr/local/lib/php/apc.php #{current_path}/apc.php"
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
# --------------------------------------------
|
317
|
+
# Remote/Local database migration tasks
|
318
|
+
# --------------------------------------------
|
319
|
+
namespace :db do
|
320
|
+
desc "Migrate remote application database to local server"
|
321
|
+
task :to_local, :roles => :db, :except => { :no_release => true } do
|
322
|
+
remote_export
|
323
|
+
remote_download
|
324
|
+
local_import
|
325
|
+
end
|
326
|
+
|
327
|
+
desc "Migrate local application database to remote server"
|
328
|
+
task :to_remote, :roles => :db, :except => { :no_release => true } do
|
329
|
+
local_export
|
330
|
+
local_upload
|
331
|
+
remote_import
|
332
|
+
end
|
333
|
+
|
334
|
+
desc "Handles importing a MySQL database dump file. Uncompresses the file, does regex replacements, and imports."
|
335
|
+
task :local_import, :roles => :db do
|
336
|
+
# check for compressed file and decompress
|
337
|
+
if local_file_exists?("#{db_remote_name}.sql.gz")
|
338
|
+
system "gunzip -f #{db_remote_name}.sql.gz"
|
339
|
+
end
|
340
|
+
|
341
|
+
if local_file_exists?("#{db_remote_name}.sql")
|
342
|
+
# import into database
|
343
|
+
system "mysql -h#{db_local_host} -u#{db_local_user} -p#{db_local_pass} #{db_local_name} < #{db_remote_name}.sql"
|
344
|
+
# remove used file
|
345
|
+
run "#{try_sudo} rm -f #{deploy_to}/#{db_remote_name}.sql.gz"
|
346
|
+
system "#{try_sudo} rm -f #{db_remote_name}.sql"
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
task :local_export do
|
351
|
+
mysqldump = fetch(:mysqldump, "mysqldump")
|
352
|
+
dump_options = fetch(:dump_options, "--single-transaction --create-options --quick")
|
353
|
+
|
354
|
+
system "#{try_sudo} #{mysqldump} #{dump_options} --opt -h#{db_local_host} -u#{db_local_user} -p#{db_local_pass} #{db_local_name} | gzip -c --best > #{db_local_name}.sql.gz"
|
355
|
+
end
|
356
|
+
|
357
|
+
desc "Upload locally created MySQL dumpfile to remote server via SCP"
|
358
|
+
task :local_upload, :roles => :db do
|
359
|
+
upload "#{db_local_name}.sql.gz", "#{deploy_to}/#{db_local_name}.sql.gz", :via => :scp
|
360
|
+
end
|
361
|
+
|
362
|
+
desc "Handles importing a MySQL database dump file. Uncompresses the file, does regex replacements, and imports."
|
363
|
+
task :remote_import, :roles => :db do
|
364
|
+
# check for compressed file and decompress
|
365
|
+
if remote_file_exists?("#{deploy_to}/#{db_local_name}.sql.gz")
|
366
|
+
run "gunzip -f #{deploy_to}/#{db_local_name}.sql.gz"
|
367
|
+
end
|
368
|
+
|
369
|
+
if remote_file_exists?("#{deploy_to}/#{db_local_name}.sql")
|
370
|
+
# import into database
|
371
|
+
run "mysql -h#{db_remote_host} -u#{db_remote_user} -p#{db_remote_pass} #{db_remote_name} < #{deploy_to}/#{db_local_name}.sql"
|
372
|
+
# remove used file
|
373
|
+
run "#{try_sudo} rm -f #{deploy_to}/#{db_local_name}.sql"
|
374
|
+
system "#{try_sudo} rm -rf #{db_local_name}.sql.gz"
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
desc "Create a compressed MySQL dumpfile of the remote database"
|
379
|
+
task :remote_export, :roles => :db do
|
380
|
+
mysqldump = fetch(:mysqldump, "mysqldump")
|
381
|
+
dump_options = fetch(:dump_options, "--single-transaction --create-options --quick")
|
382
|
+
|
383
|
+
run "#{try_sudo} #{mysqldump} #{dump_options} --opt -h#{db_remote_host} -u#{db_remote_user} -p#{db_remote_pass} #{db_remote_name} | gzip -c --best > #{deploy_to}/#{db_remote_name}.sql.gz"
|
384
|
+
end
|
385
|
+
|
386
|
+
desc "Download remotely created MySQL dumpfile to local machine via SCP"
|
387
|
+
task :remote_download, :roles => :db do
|
388
|
+
download "#{deploy_to}/#{db_remote_name}.sql.gz", "#{db_remote_name}.sql.gz", :via => :scp
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
392
|
+
# --------------------------------------------
|
393
|
+
# Backup tasks
|
394
|
+
# --------------------------------------------
|
395
|
+
namespace :backup do
|
396
|
+
desc "Perform a backup of web and database files"
|
397
|
+
task :default do
|
398
|
+
deploy.setup_backup
|
399
|
+
db
|
400
|
+
web
|
401
|
+
cleanup
|
402
|
+
end
|
403
|
+
|
404
|
+
desc <<-DESC
|
405
|
+
Requires the rsync package to be installed.
|
406
|
+
|
407
|
+
Performs a file-level backup of the application and any assets \
|
408
|
+
from the shared directory that have been symlinked into the \
|
409
|
+
applications root or sub-directories.
|
410
|
+
|
411
|
+
You can specify which files or directories to exclude from being \
|
412
|
+
backed up (i.e., log files, sessions, cache) by setting the \
|
413
|
+
:backup_exclude variable
|
414
|
+
set(:backup_exclude) { [ "var/", "tmp/", logs/debug.log ] }
|
415
|
+
DESC
|
416
|
+
task :web, :roles => :web do
|
417
|
+
if previous_release
|
418
|
+
logger.info "Backing up web files (user uploaded content and previous release)"
|
419
|
+
|
420
|
+
if !backup_exclude.nil? && !backup_exclude.empty?
|
421
|
+
logger.debug "processing backup exclusions..."
|
422
|
+
backup_exclude.each do |pattern|
|
423
|
+
exclude_string << "--exclude '#{pattern}' "
|
424
|
+
end
|
425
|
+
logger.debug "Exclude string = #{exclude_string}"
|
426
|
+
end
|
427
|
+
|
428
|
+
# Copy the previous release to the /tmp directory
|
429
|
+
logger.debug "Copying previous release to the #{tmp_backups_path}/#{release_name} directory"
|
430
|
+
run "rsync -avzrtpL #{exclude_string} #{current_path}/ #{tmp_backups_path}/#{release_name}/"
|
431
|
+
|
432
|
+
# --------------------------
|
433
|
+
# SET/RESET PERMISSIONS
|
434
|
+
# --------------------------
|
435
|
+
set_perms_dirs("#{tmp_backups_path}/#{release_name}", 755)
|
436
|
+
set_perms_files("#{tmp_backups_path}/#{release_name}", 644)
|
437
|
+
|
438
|
+
# create the tarball of the previous release
|
439
|
+
set :archive_name, "release_B4_#{release_name}.tar.gz"
|
440
|
+
logger.debug "Creating a Tarball of the previous release in #{backups_path}/#{archive_name}"
|
441
|
+
run "cd #{tmp_backups_path} && tar -cvpf - ./#{release_name}/ | gzip -c --best > #{backups_path}/#{archive_name}"
|
442
|
+
|
443
|
+
# remove the the temporary copy
|
444
|
+
logger.debug "Removing the tempory copy"
|
445
|
+
run "rm -rf #{tmp_backups_path}/#{release_name}"
|
446
|
+
else
|
447
|
+
logger.important "no previous release to backup; backup of files skipped"
|
448
|
+
end
|
449
|
+
end
|
450
|
+
|
451
|
+
desc "Perform a backup of database files"
|
452
|
+
task :db, :roles => :db do
|
453
|
+
if previous_release
|
454
|
+
mysqldump = fetch(:mysqldump, "mysqldump")
|
455
|
+
dump_options = fetch(:dump_options, "--single-transaction --create-options --quick")
|
456
|
+
|
457
|
+
logger.info "Backing up the database now and putting dump file in the previous release directory"
|
458
|
+
# define the filename (include the current_path so the dump file will be within the directory)
|
459
|
+
filename = "#{current_path}/#{dbname}_dump-#{Time.now.to_s.gsub(/ /, "_")}.sql.gz"
|
460
|
+
# dump the database for the proper environment
|
461
|
+
run "#{mysqldump} #{dump_options} -u #{dbuser} -p #{dbname} | gzip -c --best > #{filename}" do |ch, stream, out|
|
462
|
+
ch.send_data "#{dbpass}\n" if out =~ /^Enter password:/
|
463
|
+
end
|
464
|
+
else
|
465
|
+
logger.important "no previous release to backup to; backup of database skipped"
|
466
|
+
end
|
467
|
+
end
|
468
|
+
|
469
|
+
desc <<-DESC
|
470
|
+
Clean up old backups. By default, the last 10 backups are kept on each \
|
471
|
+
server (though you can change this with the keep_backups variable). All \
|
472
|
+
other backups are removed from the servers. By default, this \
|
473
|
+
will use sudo to clean up the old backups, but if sudo is not available \
|
474
|
+
for your environment, set the :use_sudo variable to false instead.
|
475
|
+
DESC
|
476
|
+
task :cleanup, :except => { :no_release => true } do
|
477
|
+
count = fetch(:keep_backups, 10).to_i
|
478
|
+
if count >= backups.length
|
479
|
+
logger.important "no old backups to clean up"
|
480
|
+
else
|
481
|
+
logger.info "keeping #{count} of #{backups.length} backups"
|
482
|
+
|
483
|
+
archives = (backups - backups.last(count)).map { |backup|
|
484
|
+
File.join(backups_path, backup) }.join(" ")
|
485
|
+
|
486
|
+
# fix permissions on the the files and directories before removing them
|
487
|
+
archives.split(" ").each do |backup|
|
488
|
+
set_perms_dirs("#{backup}", 755)
|
489
|
+
set_perms_files("#{backup}", 644)
|
490
|
+
end
|
491
|
+
|
492
|
+
try_sudo "rm -rf #{archives}"
|
493
|
+
end
|
494
|
+
end
|
495
|
+
end
|
496
|
+
|
497
|
+
# --------------------------------------------
|
498
|
+
# Remote File/Directory test tasks
|
499
|
+
# --------------------------------------------
|
500
|
+
namespace :remote do
|
501
|
+
namespace :file do
|
502
|
+
desc "Test: Task to test existence of missing file"
|
503
|
+
task :missing do
|
504
|
+
if remote_file_exists?('/dev/mull')
|
505
|
+
logger.info "FAIL - Why does the '/dev/mull' path exist???"
|
506
|
+
else
|
507
|
+
logger.info "GOOD - Verified the '/dev/mull' path does not exist!"
|
508
|
+
end
|
509
|
+
end
|
510
|
+
|
511
|
+
desc "Test: Task used to test existence of a present file"
|
512
|
+
task :exists do
|
513
|
+
if remote_file_exists?('/dev/null')
|
514
|
+
logger.info "GOOD - Verified the '/dev/null' path exists!"
|
515
|
+
else
|
516
|
+
logger.info "FAIL - WHAT happened to the '/dev/null' path???"
|
517
|
+
end
|
518
|
+
end
|
519
|
+
end
|
520
|
+
|
521
|
+
namespace :dir do
|
522
|
+
desc "Test: Task to test existence of missing dir"
|
523
|
+
task :missing do
|
524
|
+
if remote_dir_exists?('/etc/fake_dir')
|
525
|
+
logger.info "FAIL - Why does the '/etc/fake_dir' dir exist???"
|
526
|
+
else
|
527
|
+
logger.info "GOOD - Verified the '/etc/fake_dir' dir does not exist!"
|
528
|
+
end
|
529
|
+
end
|
530
|
+
|
531
|
+
desc "Test: Task used to test existence of an existing directory"
|
532
|
+
task :exists do
|
533
|
+
if remote_dir_exists?('/etc')
|
534
|
+
logger.info "GOOD - Verified the '/etc' dir exists!"
|
535
|
+
else
|
536
|
+
logger.info "FAIL - WHAT happened to the '/etc' dir???"
|
537
|
+
end
|
538
|
+
end
|
539
|
+
end
|
540
|
+
end
|
541
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
# Prompts user entry
|
2
|
+
# Params:
|
3
|
+
# +prompt+
|
4
|
+
def text_prompt(prompt="Value: ")
|
5
|
+
Capistrano::CLI.ui.ask(prompt) { |q| q.echo = true }
|
6
|
+
end
|
7
|
+
|
8
|
+
# Check if a local file exists
|
9
|
+
def local_file_exists?(full_path)
|
10
|
+
File.exists?(full_path)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Check if a local directory exists
|
14
|
+
def local_dir_exists?(full_path)
|
15
|
+
File.directory?(full_path)
|
16
|
+
end
|
17
|
+
|
18
|
+
# From http://stackoverflow.com/a/1662001/356237
|
19
|
+
# Needs full remote path
|
20
|
+
def remote_file_exists?(full_path)
|
21
|
+
'true' == capture("if [ -e #{full_path} ]; then echo 'true'; fi").strip
|
22
|
+
end
|
23
|
+
|
24
|
+
# Sames as above but with directories
|
25
|
+
def remote_dir_exists?(dir_path)
|
26
|
+
'true' == capture("if [[ -d #{dir_path} ]]; then echo 'true'; fi").strip
|
27
|
+
end
|
28
|
+
|
29
|
+
# Recursively set file permissions in a directory
|
30
|
+
def set_perms_files(dir_path, perm = 644)
|
31
|
+
try_sudo "find #{dir_path} -type f -exec chmod #{perm} {} \\;"
|
32
|
+
end
|
33
|
+
def create_database
|
34
|
+
create_sql = <<-SQL
|
35
|
+
CREATE DATABASE #{db_name};
|
36
|
+
SQL
|
37
|
+
|
38
|
+
run "mysql --user=#{db_admin_user} --password=#{db_admin_password} --execute=\"#{create_sql}\""
|
39
|
+
end
|
40
|
+
# Recursively set directory permissions in a directory
|
41
|
+
def set_perms_dirs(dir_path, perm = 755)
|
42
|
+
try_sudo "find #{dir_path} -type d -exec chmod #{perm} {} \\;"
|
43
|
+
end
|
44
|
+
|
45
|
+
# Get release history from server as string
|
46
|
+
def get_release_history(release_file)
|
47
|
+
release_history = capture("cat #{release_file}").strip
|
48
|
+
release_history
|
49
|
+
end
|
50
|
+
|
51
|
+
# Remove a particular release from history
|
52
|
+
def remove_release_from_history(release, release_file)
|
53
|
+
release_history = capture("cat #{release_file}").split
|
54
|
+
|
55
|
+
# Remove release if it exists
|
56
|
+
release_history.delete_at release_history.index(release) unless release_history.index(release).nil?
|
57
|
+
|
58
|
+
# Save
|
59
|
+
release_history.join("\n")
|
60
|
+
try_sudo "echo #{release_history} > #{release_file}"
|
61
|
+
end
|
62
|
+
|
63
|
+
# Get the database name given an application and release name
|
64
|
+
def get_db_name(application, release)
|
65
|
+
db_name = "#{application}__#{release_name}"
|
66
|
+
# Remove characters that may cause MySQL issues
|
67
|
+
db_name.downcase.gsub(/([\.\-\/])/, '_')
|
68
|
+
end
|
69
|
+
|
70
|
+
# Get the regex pattern to extract details from the mysql connection string
|
71
|
+
def db_string_regex(type)
|
72
|
+
"--#{type}='?([a-zA-Z0-9!@\#$%^&*-=+]+)'?\s"
|
73
|
+
end
|
74
|
+
|
75
|
+
# Check if a MySQL database exists
|
76
|
+
# Modified from http://www.grahambrooks.com/blog/create-mysql-database-with-capistrano/
|
77
|
+
def database_exists?(connection_string, db_name)
|
78
|
+
exists = false
|
79
|
+
|
80
|
+
run "#{connection_string} --execute=\"show databases;\"" do |channel, stream, data|
|
81
|
+
exists = exists || data.include?(db_name)
|
82
|
+
end
|
83
|
+
|
84
|
+
exists
|
85
|
+
end
|
86
|
+
|
87
|
+
# Create a MySQL database
|
88
|
+
# From http://www.grahambrooks.com/blog/create-mysql-database-with-capistrano/
|
89
|
+
def create_database(connection_string, db_name)
|
90
|
+
create_sql = <<-SQL
|
91
|
+
CREATE DATABASE #{db_name};
|
92
|
+
SQL
|
93
|
+
|
94
|
+
run "#{connection_string} --execute=\"#{create_sql}\""
|
95
|
+
end
|
96
|
+
|
97
|
+
# Delete a MySQL database
|
98
|
+
def delete_database(connection_string, db_name)
|
99
|
+
drop_sql = <<-SQL
|
100
|
+
DROP DATABASE #{db_name};
|
101
|
+
SQL
|
102
|
+
|
103
|
+
run "#{connection_string} --execute=\"#{drop_sql}\""
|
104
|
+
end
|
105
|
+
|
106
|
+
# Set permissions for a MySQL database
|
107
|
+
# From http://www.grahambrooks.com/blog/create-mysql-database-with-capistrano/
|
108
|
+
def setup_database_permissions(connection_string, db_name)
|
109
|
+
# We tack on a space at the end to help regex matches
|
110
|
+
connection_string += " "
|
111
|
+
|
112
|
+
db_admin_user = connection_string.match db_string_regex('user')
|
113
|
+
db_admin_user = db_admin_user[1]
|
114
|
+
|
115
|
+
db_admin_password = connection_string.match db_string_regex('password')
|
116
|
+
db_admin_password = db_admin_password[1]
|
117
|
+
|
118
|
+
grant_sql = <<-SQL
|
119
|
+
GRANT ALL PRIVILEGES ON #{db_name}.* TO #{db_admin_user}@localhost IDENTIFIED BY '#{db_admin_password}';
|
120
|
+
SQL
|
121
|
+
|
122
|
+
run "#{connection_string} --execute=\"#{grant_sql}\""
|
123
|
+
end
|
124
|
+
|
125
|
+
# Updates the Drupal settings file with the new database name
|
126
|
+
def update_db_in_settings_file(settings_file, db_name)
|
127
|
+
run "sed -ri \"/^[ \\t]*(#|\\*|\\/)/! s/'database' => ''/'database' => '#{db_name}'/1\" #{settings_file}"
|
128
|
+
end
|
@@ -0,0 +1,312 @@
|
|
1
|
+
# Require our base library.
|
2
|
+
require 'demonz/base'
|
3
|
+
require 'railsless-deploy'
|
4
|
+
|
5
|
+
configuration = Capistrano::Configuration.respond_to?(:instance) ?
|
6
|
+
Capistrano::Configuration.instance(:must_exist) :
|
7
|
+
Capistrano.configuration(:must_exist)
|
8
|
+
|
9
|
+
configuration.load do
|
10
|
+
|
11
|
+
# --------------------------------------------
|
12
|
+
# Setting defaults
|
13
|
+
# --------------------------------------------
|
14
|
+
set :drush_bin, "drush"
|
15
|
+
_cset :dump_options, "" # blank options b/c of MYISAM engine (unless anyone knows options that should be included)
|
16
|
+
|
17
|
+
# Boost module support (Drupal)
|
18
|
+
set :uses_boost, true
|
19
|
+
|
20
|
+
# --------------------------------------------
|
21
|
+
# Calling our Methods
|
22
|
+
# --------------------------------------------
|
23
|
+
after "deploy:setup", "deploy:setup_local"
|
24
|
+
after "deploy:finalize_update", "demonz:fixperms"
|
25
|
+
before "deploy:create_symlink", "drupal:symlink"
|
26
|
+
before "deploy:create_symlink", "drupal:protect"
|
27
|
+
before "deploy:create_symlink", "drupal:backup_files_dir"
|
28
|
+
before "deploy:create_symlink", "drupal:migrate"
|
29
|
+
before "deploy:create_symlink", "drupal:clearcache"
|
30
|
+
|
31
|
+
after "deploy:cleanup", "drupal:cleanup_files_backups"
|
32
|
+
|
33
|
+
# rollback the database and files directory during a rollback too
|
34
|
+
before "deploy:rollback:revision", "drupal:rollback_db"
|
35
|
+
after "drupal:rollback_db", "drupal:rollback_files_dir"
|
36
|
+
|
37
|
+
# --------------------------------------------
|
38
|
+
# Overloaded Methods
|
39
|
+
# --------------------------------------------
|
40
|
+
namespace :deploy do
|
41
|
+
desc "Setup local files necessary for deployment"
|
42
|
+
task :setup_local do
|
43
|
+
logger.important "make sure you copy over your files directory and settings files now"
|
44
|
+
# attempt to create files needed for proper deployment
|
45
|
+
if local_file_exists?('.htaccess')
|
46
|
+
system("cp .htaccess htaccess.dist")
|
47
|
+
system("git add htaccess.dist")
|
48
|
+
puts "Please commit htaccess.dist to your source control repository."
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
desc "Setup shared application directories and permissions after initial setup"
|
53
|
+
task :setup_shared do
|
54
|
+
uses_boost = fetch(:uses_boost, false)
|
55
|
+
|
56
|
+
# remove Capistrano specific directories
|
57
|
+
run "#{try_sudo} rm -Rf #{shared_path}/log"
|
58
|
+
run "#{try_sudo} rm -Rf #{shared_path}/pids"
|
59
|
+
run "#{try_sudo} rm -Rf #{shared_path}/system"
|
60
|
+
|
61
|
+
# create shared directories
|
62
|
+
run "#{try_sudo} mkdir -p #{shared_path}/default/files"
|
63
|
+
if uses_boost
|
64
|
+
run "#{try_sudo} mkdir -p #{shared_path}/boost/cache/normal"
|
65
|
+
end
|
66
|
+
|
67
|
+
# set correct permissions
|
68
|
+
run "#{try_sudo} chmod -R 777 #{shared_path}/*"
|
69
|
+
end
|
70
|
+
|
71
|
+
desc "[internal] Touches up the released code. This is called by update_code after the basic deploy finishes."
|
72
|
+
task :finalize_update, :roles => :web, :except => { :no_release => true } do
|
73
|
+
run "#{try_sudo} rm -Rf #{latest_release}/sites/default/files"
|
74
|
+
end
|
75
|
+
|
76
|
+
namespace :web do
|
77
|
+
desc "Disable the application and show a message screen"
|
78
|
+
task :disable, :roles => :web do
|
79
|
+
run "#{drush_bin} -r #{latest_release} vset --yes site_offline 1"
|
80
|
+
end
|
81
|
+
|
82
|
+
desc "Enable the application and remove the message screen"
|
83
|
+
task :enable, :roles => :web do
|
84
|
+
run "#{drush_bin} -r #{latest_release} vdel --yes site_offline"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# --------------------------------------------
|
90
|
+
# Remote/Local database migration tasks
|
91
|
+
# --------------------------------------------
|
92
|
+
namespace :db do
|
93
|
+
task :local_export do
|
94
|
+
mysqldump = fetch(:mysqldump, "mysqldump")
|
95
|
+
dump_options = fetch(:dump_options, "")
|
96
|
+
|
97
|
+
system "#{mysqldump} #{dump_options} --opt -h#{db_local_host} -u#{db_local_user} -p#{db_local_pass} #{db_local_name} | gzip -c --best > #{db_local_name}.sql.gz"
|
98
|
+
end
|
99
|
+
|
100
|
+
desc "Create a compressed MySQL dumpfile of the remote database"
|
101
|
+
task :remote_export, :roles => :db do
|
102
|
+
mysqldump = fetch(:mysqldump, "mysqldump")
|
103
|
+
dump_options = fetch(:dump_options, "")
|
104
|
+
|
105
|
+
run "#{mysqldump} #{dump_options} --opt -h#{db_remote_host} -u#{db_remote_user} -p#{db_remote_pass} #{db_remote_name} | gzip -c --best > #{deploy_to}/#{db_remote_name}.sql.gz"
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
namespace :backup do
|
111
|
+
desc "Perform a backup of database files"
|
112
|
+
task :db, :roles => :db do
|
113
|
+
if releases.last.nil?
|
114
|
+
logger.important "no previous release to backup; backup of database skipped"
|
115
|
+
else
|
116
|
+
logger.info "Backing up the database now and putting dump file in the previous release directory"
|
117
|
+
# define the filename (include the current_path so the dump file will be within the directory)
|
118
|
+
filename = "#{current_path}/default_dump-#{Time.now.to_s.gsub(/ /, "_")}.sql.gz"
|
119
|
+
# dump the database for the proper environment
|
120
|
+
run "#{drush_bin} -r #{current_path} sql-dump | gzip -c --best > #{filename}"
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# --------------------------------------------
|
126
|
+
# Drupal-specific methods
|
127
|
+
# --------------------------------------------
|
128
|
+
namespace :drupal do
|
129
|
+
desc "Create database"
|
130
|
+
task :create_db, :roles => :web, :except => { :no_release => true } do
|
131
|
+
drupal_app_site_dir = File.join(latest_release, 'sites', 'default')
|
132
|
+
settings_file = File.join(drupal_app_site_dir, 'settings.php')
|
133
|
+
|
134
|
+
# Check if the base settings.php file exists first (we need this for db details)
|
135
|
+
if !remote_file_exists?(settings_file)
|
136
|
+
raise Capistrano::Error, "A settings.php file was not found, please create one before continuing. See previous errors for more info."
|
137
|
+
end
|
138
|
+
|
139
|
+
# Get database name
|
140
|
+
set :clean_db_name, get_db_name(application, release_name)
|
141
|
+
|
142
|
+
# Get MySQL connection string from drush (don't need a full bootstrap)
|
143
|
+
mysql_connection = capture("#{drush_bin} -r #{latest_release} sql-connect").chomp
|
144
|
+
|
145
|
+
# Only create if database doesn't exist
|
146
|
+
if !database_exists?(mysql_connection, clean_db_name)
|
147
|
+
# Remove DB on rollback
|
148
|
+
on_rollback { delete_database(mysql_connection, clean_db_name) }
|
149
|
+
|
150
|
+
create_database(mysql_connection, clean_db_name)
|
151
|
+
setup_database_permissions(mysql_connection, clean_db_name)
|
152
|
+
end
|
153
|
+
|
154
|
+
# Add the database name to the settings file.
|
155
|
+
update_db_in_settings_file(settings_file, clean_db_name)
|
156
|
+
end
|
157
|
+
|
158
|
+
desc "Copy old database to new one"
|
159
|
+
task :copy_old_to_new_db, :roles => :web, :except => { :no_release => true } do
|
160
|
+
if releases.last.nil?
|
161
|
+
# Ask user to upload a gzipped SQL file
|
162
|
+
logger.important "no previous release found, please specify a (gzipped) sql file I can use instead"
|
163
|
+
db_file_path = text_prompt("Full path to SQL file: ")
|
164
|
+
|
165
|
+
# Error out if file doesn't exist
|
166
|
+
raise Capistrano::Error, "File '#{db_file_path}' not found" unless local_file_exists?(db_file_path)
|
167
|
+
|
168
|
+
db_file_parts = File.split(db_file_path)
|
169
|
+
db_file = db_file_parts[1]
|
170
|
+
|
171
|
+
# Upload file to temp directory
|
172
|
+
remote_db_file = File.join(tmp_backups_path, db_file)
|
173
|
+
top.upload(db_file_path, remote_db_file)
|
174
|
+
|
175
|
+
# Just incase the command after fails, remove the upload file
|
176
|
+
on_rollback { run "#{try_sudo} rm #{remote_db_file}" }
|
177
|
+
|
178
|
+
run "gzip -fd #{remote_db_file} -c | #{drush_bin} -r #{latest_release} sqlc"
|
179
|
+
|
180
|
+
# We don't need the upload file anymore
|
181
|
+
run "#{try_sudo} rm #{remote_db_file}"
|
182
|
+
else
|
183
|
+
# Use current release as base
|
184
|
+
run "#{drush_bin} -r #{current_release} sql-dump | #{drush_bin} -r #{latest_release} sqlc"
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
desc "Run any update scripts for this release"
|
189
|
+
task :run_update_scripts, :roles => :web, :except => { :no_release => true } do
|
190
|
+
update_script_file = File.join(latest_release, 'sites', 'all', 'scripts', release_name, 'update.sh')
|
191
|
+
|
192
|
+
if remote_file_exists?(update_script_file)
|
193
|
+
run update_script_file
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
desc "Symlink shared directories"
|
198
|
+
task :symlink, :roles => :web, :except => { :no_release => true } do
|
199
|
+
uses_boost = fetch(:uses_boost, false)
|
200
|
+
# copies the appropriate environment's settings.php file
|
201
|
+
copy_config_file
|
202
|
+
|
203
|
+
run "#{try_sudo} ln -nfs #{shared_path}/default/files #{latest_release}/sites/default/files"
|
204
|
+
# run "#{drush_bin} -r #{latest_release} vset --yes file_directory_path sites/default/files"
|
205
|
+
|
206
|
+
# Symlink boost cache directory
|
207
|
+
if uses_boost
|
208
|
+
run "#{try_sudo} ln -nfs #{shared_path}/boost/cache #{latest_release}/cache"
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
desc <<-DESC
|
213
|
+
Copies the appropriate environment's settings file within the proper sites directory
|
214
|
+
|
215
|
+
Assumes the environment's settings file will be in the following format:
|
216
|
+
settings.<environment>.php
|
217
|
+
DESC
|
218
|
+
task :copy_config_file, :roles => :web, :except => { :no_release => true} do
|
219
|
+
drupal_app_site_dir = " #{latest_release}/sites/default"
|
220
|
+
|
221
|
+
case true
|
222
|
+
when remote_file_exists?("#{shared_path}/settings.#{stage}.php")
|
223
|
+
run "#{try_sudo} cp -fL #{shared_path}/settings.#{stage}.php #{drupal_app_site_dir}/settings.php"
|
224
|
+
when remote_file_exists?("#{drupal_app_site_dir}/settings.#{stage}.php")
|
225
|
+
run "#{try_sudo} cp -fL #{drupal_app_site_dir}/settings.#{stage}.php #{drupal_app_site_dir}/settings.php"
|
226
|
+
else
|
227
|
+
logger.important "Failed to symlink the settings.php file in #{drupal_app_site_dir} because an unknown pattern was used"
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
desc "Migrate old database to new release"
|
232
|
+
task :migrate, :roles => :web, :except => { :no_release => true } do
|
233
|
+
create_db
|
234
|
+
copy_old_to_new_db
|
235
|
+
run_update_scripts
|
236
|
+
# Run drush updb just incase
|
237
|
+
run "#{drush_bin} -r #{latest_release} updb"
|
238
|
+
end
|
239
|
+
|
240
|
+
desc "Backup the shared 'files' directory"
|
241
|
+
task :backup_files_dir, :roles => :web, :except => { :no_release => true } do
|
242
|
+
set :archive_name, "files_before_#{release_name}.tar.gz"
|
243
|
+
set :files_dir_location, File.join(shared_path, 'default')
|
244
|
+
logger.debug "Creating a Tarball of the files directory in #{backups_path}/#{archive_name}"
|
245
|
+
run "cd #{files_dir_location} && tar -cvpf - files | gzip -c --best > #{backups_path}/#{archive_name}"
|
246
|
+
end
|
247
|
+
|
248
|
+
desc "Clear all Drupal cache"
|
249
|
+
task :clearcache, :roles => :web, :except => { :no_release => true } do
|
250
|
+
run "#{drush_bin} -r #{latest_release} cache-clear all"
|
251
|
+
# Remove the 'styles' imagecache directory
|
252
|
+
image_styles_path = File.join(shared_path, 'default', 'files', 'styles')
|
253
|
+
run "#{try_sudo} rm -rf #{image_styles_path}" if remote_dir_exists?(image_styles_path)
|
254
|
+
# Also clear boost cache if set
|
255
|
+
boost_path = File.join(shared_path, 'boost', 'cache', 'normal', '*')
|
256
|
+
run "#{try_sudo} rm -rf #{boost_path}" if fetch(:uses_boost, false)
|
257
|
+
end
|
258
|
+
|
259
|
+
desc "Protect system files"
|
260
|
+
task :protect, :roles => :web, :except => { :no_release => true } do
|
261
|
+
run "#{try_sudo} chmod 644 #{latest_release}/sites/default/settings.php*"
|
262
|
+
end
|
263
|
+
|
264
|
+
desc "[internal] Delete latest version of DB"
|
265
|
+
task :rollback_db, :except => { :no_release => true } do
|
266
|
+
if previous_release
|
267
|
+
clean_db_name = get_db_name(application, releases.last)
|
268
|
+
mysql_connection = capture("#{drush_bin} -r #{latest_release} sql-connect").chomp
|
269
|
+
delete_database(mysql_connection, clean_db_name)
|
270
|
+
else
|
271
|
+
abort "could not rollback the code because there is no prior release"
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
desc "[internal] Rollback shared files directory"
|
276
|
+
task :rollback_files_dir, :except => { :no_release => true } do
|
277
|
+
if previous_release
|
278
|
+
old_release = releases.last
|
279
|
+
files_backup_file = File.join(backups_path, "files_before_#{old_release}.tar.gz")
|
280
|
+
|
281
|
+
if remote_file_exists?(files_backup_file)
|
282
|
+
files_dir_location = File.join(shared_path, 'default')
|
283
|
+
files_dir = File.join(files_dir_location, 'files')
|
284
|
+
files_dir_backup_archive = "files_after_#{old_release}_OLD"
|
285
|
+
|
286
|
+
on_rollback {
|
287
|
+
run "#{try_sudo} rm #{files_dir}" if remote_file_exists?(files_dir_backup_archive) && remote_dir_exists?(files_dir)
|
288
|
+
run "#{try_sudo} tar -xvzf #{files_dir_backup_archive} -C #{files_dir_location}" if remote_file_exists?(files_dir_backup_archive)
|
289
|
+
}
|
290
|
+
|
291
|
+
run "cd #{files_dir_location} && tar -cvpf - files | gzip -c --best > #{backups_path}/#{files_dir_backup_archive}"
|
292
|
+
run "#{try_sudo} tar -xvzf #{files_backup_file} -C #{files_dir_location}"
|
293
|
+
end
|
294
|
+
else
|
295
|
+
abort "could not rollback the code because there is no prior release"
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
desc "[internal] Remove old file directory backups"
|
300
|
+
task :cleanup_files_backups, :roles => :web, :except => { :no_release => true } do
|
301
|
+
if variables.include?(:cleanup_releases)
|
302
|
+
cleanup_releases = fetch(:cleanup_releases, nil)
|
303
|
+
|
304
|
+
if !cleanup_releases.nil?
|
305
|
+
files_backups = cleanup_releases.map { |release|
|
306
|
+
File.join(backups_path, "file_before_#{release}.tar.gz") }.join(" ")
|
307
|
+
try_sudo "rm -rf #{files_backups}"
|
308
|
+
end
|
309
|
+
end
|
310
|
+
end
|
311
|
+
end
|
312
|
+
end
|
metadata
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: capistrano-demonz
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 21
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 5
|
10
|
+
version: 0.0.5
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Chinthaka Godawita
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2012-12-21 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: railsless-deploy
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 19
|
29
|
+
segments:
|
30
|
+
- 1
|
31
|
+
- 0
|
32
|
+
- 2
|
33
|
+
version: 1.0.2
|
34
|
+
type: :runtime
|
35
|
+
version_requirements: *id001
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: capistrano
|
38
|
+
prerelease: false
|
39
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ">="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
hash: 49
|
45
|
+
segments:
|
46
|
+
- 2
|
47
|
+
- 13
|
48
|
+
- 5
|
49
|
+
version: 2.13.5
|
50
|
+
type: :runtime
|
51
|
+
version_requirements: *id002
|
52
|
+
description: Demonz Media recipes for Capistrano
|
53
|
+
email:
|
54
|
+
- chinthaka.godawita@demonzmedia.com
|
55
|
+
executables: []
|
56
|
+
|
57
|
+
extensions: []
|
58
|
+
|
59
|
+
extra_rdoc_files: []
|
60
|
+
|
61
|
+
files:
|
62
|
+
- Gemfile
|
63
|
+
- LICENSE.txt
|
64
|
+
- README.md
|
65
|
+
- Rakefile
|
66
|
+
- capistrano-demonz.gemspec
|
67
|
+
- lib/capistrano-demonz.rb
|
68
|
+
- lib/demonz/base.rb
|
69
|
+
- lib/demonz/common.rb
|
70
|
+
- lib/demonz/drupal.rb
|
71
|
+
- lib/demonz/version.rb
|
72
|
+
homepage: https://github.com/demonz/capistrano-demonz
|
73
|
+
licenses: []
|
74
|
+
|
75
|
+
post_install_message:
|
76
|
+
rdoc_options: []
|
77
|
+
|
78
|
+
require_paths:
|
79
|
+
- lib
|
80
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
hash: 3
|
86
|
+
segments:
|
87
|
+
- 0
|
88
|
+
version: "0"
|
89
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
hash: 3
|
95
|
+
segments:
|
96
|
+
- 0
|
97
|
+
version: "0"
|
98
|
+
requirements: []
|
99
|
+
|
100
|
+
rubyforge_project:
|
101
|
+
rubygems_version: 1.8.24
|
102
|
+
signing_key:
|
103
|
+
specification_version: 3
|
104
|
+
summary: Useful task libraries for Demonz Media recipes for Capistrano
|
105
|
+
test_files: []
|
106
|
+
|