app-deployer 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +174 -0
- data/Rakefile +2 -0
- data/app-deployer.gemspec +19 -0
- data/lib/app-deployer.rb +11 -0
- data/lib/app-deployer/compass.rb +8 -0
- data/lib/app-deployer/composer.rb +68 -0
- data/lib/app-deployer/framework/cakephp/cakephp.rb +215 -0
- data/lib/app-deployer/framework/cakephp/templates/database.php.erb +14 -0
- data/lib/app-deployer/framework/lithium/lithium.rb +213 -0
- data/lib/app-deployer/framework/lithium/templates/connections.php.erb +64 -0
- data/lib/app-deployer/helpers.rb +142 -0
- data/lib/app-deployer/mysql/mysql.rb +42 -0
- data/lib/app-deployer/mysql/templates/create_database.sql.erb +7 -0
- data/lib/app-deployer/railsless-deploy.rb +399 -0
- data/lib/app-deployer/server/apache/apache.rb +59 -0
- data/lib/app-deployer/server/apache/templates/apache-vhost.erb +17 -0
- data/lib/app-deployer/server/apache/templates/maintenance.rhtml +52 -0
- data/lib/app-deployer/server/php-fpm.rb +10 -0
- data/lib/app-deployer/version.rb +5 -0
- metadata +94 -0
@@ -0,0 +1,14 @@
|
|
1
|
+
<?php
|
2
|
+
class DATABASE_CONFIG {
|
3
|
+
public $default = array(
|
4
|
+
'datasource' => '<%= datasource %>',
|
5
|
+
'persistent' => '<%= persistent %>',
|
6
|
+
'host' => '<%= host %>',
|
7
|
+
'login' => '<%= login %>',
|
8
|
+
'password' => '<%= password %>',
|
9
|
+
'database' => '<%= database %>',
|
10
|
+
'prefix' => '<%= prefix %>',
|
11
|
+
'encoding' => '<%= encoding %>'
|
12
|
+
);
|
13
|
+
}
|
14
|
+
?>
|
@@ -0,0 +1,213 @@
|
|
1
|
+
Capistrano::Configuration.instance(:must_exist).load do
|
2
|
+
|
3
|
+
require 'erb'
|
4
|
+
|
5
|
+
# =========================================================================
|
6
|
+
# Settings
|
7
|
+
# =========================================================================
|
8
|
+
|
9
|
+
_cset :shared_app_dirs, []
|
10
|
+
_cset(:lithium_repo) { "https://github.com/UnionOfRAD/lithium.git" }
|
11
|
+
_cset(:lithium_branch) { "master" }
|
12
|
+
_cset :shared_children, %w(libraries tmp)
|
13
|
+
_cset :tmp_children, %w(cache logs tests)
|
14
|
+
_cset :cache_children, %w(templates)
|
15
|
+
_cset :logs_files, %w(debug error)
|
16
|
+
_cset(:database_folder) { File.join(shared_path, "config/bootstrap") }
|
17
|
+
_cset(:database_path) { File.join("#{database_folder}", "connections.php") }
|
18
|
+
_cset(:tmp_path) { File.join(shared_path, "tmp") }
|
19
|
+
_cset(:cache_path) { File.join(tmp_path, "cache") }
|
20
|
+
_cset(:logs_path) { File.join(tmp_path, "logs") }
|
21
|
+
|
22
|
+
# =========================================================================
|
23
|
+
# Hooks
|
24
|
+
# =========================================================================
|
25
|
+
|
26
|
+
after('deploy:setup', 'lithium:setup')
|
27
|
+
after('deploy:create_symlink', 'lithium:create_symlink')
|
28
|
+
|
29
|
+
["composer:install", "composer:update"].each do |action|
|
30
|
+
before action do
|
31
|
+
if copy_vendors
|
32
|
+
composer.copy_vendors
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
after "deploy:finalize_update" do
|
38
|
+
if use_composer
|
39
|
+
if update_vendors
|
40
|
+
composer.update
|
41
|
+
else
|
42
|
+
composer.install
|
43
|
+
end
|
44
|
+
end
|
45
|
+
if clear_cache
|
46
|
+
lithium.cache.clear
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# =========================================================================
|
51
|
+
# Tasks
|
52
|
+
# =========================================================================
|
53
|
+
|
54
|
+
namespace :lithium do
|
55
|
+
|
56
|
+
desc <<-DESC
|
57
|
+
Prepares server for deployment of a lithium application. \
|
58
|
+
|
59
|
+
By default, it will create a shallow clone of the lithium repository \
|
60
|
+
inside #{shared_path}/libraries/lithium and run deploy:lithium:update.
|
61
|
+
DESC
|
62
|
+
task :setup do
|
63
|
+
transaction do
|
64
|
+
unless use_composer
|
65
|
+
run "cd #{shared_path}/libraries && git clone --depth 1 #{lithium_repo} lithium"
|
66
|
+
checkout
|
67
|
+
end
|
68
|
+
connections.setup
|
69
|
+
shared.setup
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
desc <<-DESC
|
74
|
+
Force lithium installation to checkout a new branch/tag.
|
75
|
+
DESC
|
76
|
+
task :checkout do
|
77
|
+
on_rollback { run "rm -rf #{shared_path}/lithium; true" }
|
78
|
+
stream "cd #{shared_path}/lithium && git checkout -q #{lithium_branch}"
|
79
|
+
end
|
80
|
+
|
81
|
+
desc <<-DESC
|
82
|
+
Update the lithium repository to the latest version.
|
83
|
+
DESC
|
84
|
+
task :update do
|
85
|
+
stream "cd #{shared_path}/libraries/lithium && git pull"
|
86
|
+
end
|
87
|
+
|
88
|
+
desc <<-DESC
|
89
|
+
This is a task that will get called from the deploy:create_symlink task
|
90
|
+
It runs just before the release is symlinked to the current directory
|
91
|
+
|
92
|
+
You should use it to create symlinks to things like your database config \
|
93
|
+
and any shared directories or files that your app uses
|
94
|
+
DESC
|
95
|
+
task :create_symlink do
|
96
|
+
transaction do
|
97
|
+
connections.create_symlink
|
98
|
+
shared.create_symlink
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Framework specific tasks
|
103
|
+
|
104
|
+
# Caching
|
105
|
+
namespace :cache do
|
106
|
+
desc <<-DESC
|
107
|
+
Clears cache and sub-directories.
|
108
|
+
|
109
|
+
Recursively finds all files in :cache_path and runs `rm -f` on each. If a file \
|
110
|
+
is renamed/removed after it was found but before it removes it, no error \
|
111
|
+
will prompt (-ignore_readdir_race). If symlinks are found, they will not be followed
|
112
|
+
|
113
|
+
You will rarely need to call this task directly; instead, use the `deploy' \
|
114
|
+
task (which performs a complete deploy, including `lithium:cache:clear')
|
115
|
+
DESC
|
116
|
+
task :clear, :roles => :web, :except => { :no_release => true } do
|
117
|
+
run "#{try_sudo} find -P #{cache_path} -ignore_readdir_race -type f -name '*' -exec rm -f {} \\;"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# Connections config
|
122
|
+
namespace :connections do
|
123
|
+
desc <<-DESC
|
124
|
+
Generates lithium connections file in #{shared_path}/config/bootstrap/ \
|
125
|
+
and symlinks #{current_path}/config/bootstrap/connections.php to it
|
126
|
+
DESC
|
127
|
+
task :setup, :roles => :web, :except => { :no_release => true } do
|
128
|
+
on_rollback { run "rm -f #{database_path}; true" }
|
129
|
+
puts "Connections setup"
|
130
|
+
|
131
|
+
prompt_with_default(:type, "database|MongoDb|http")
|
132
|
+
case type
|
133
|
+
when 'database'
|
134
|
+
prompt_with_default(:login, user)
|
135
|
+
set :password, Capistrano::CLI.password_prompt("password:")
|
136
|
+
prompt_with_default(:encoding, 'UTF-8')
|
137
|
+
end
|
138
|
+
|
139
|
+
prompt_with_default(:host, "127.0.0.1")
|
140
|
+
prompt_with_default(:database, application)
|
141
|
+
|
142
|
+
template = File.read(File.join(File.dirname(__FILE__), "templates", "connections.php.erb"))
|
143
|
+
result = ERB.new(template).result(binding)
|
144
|
+
|
145
|
+
run "#{try_sudo} mkdir -p #{database_folder}"
|
146
|
+
put(result, "#{database_path}", :mode => 0644, :via => :scp)
|
147
|
+
end
|
148
|
+
|
149
|
+
desc <<-DESC
|
150
|
+
Symlinks the connections file.
|
151
|
+
DESC
|
152
|
+
task :create_symlink, :roles => :web, :except => { :no_release => true } do
|
153
|
+
run "#{try_sudo} ln -s #{database_path} #{current_path}/config/bootstrap/connections.php"
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# Shared directories and files
|
158
|
+
namespace :shared do
|
159
|
+
desc <<-DESC
|
160
|
+
Creates shared folders on the server
|
161
|
+
DESC
|
162
|
+
task :setup do
|
163
|
+
dirs = [deploy_to, releases_path, shared_path]
|
164
|
+
dirs += shared_children.map { |d| File.join(shared_path, d) }
|
165
|
+
tmp_dirs = tmp_children.map { |d| File.join(tmp_path, d) }
|
166
|
+
tmp_dirs += cache_children.map { |d| File.join(cache_path, d) }
|
167
|
+
run "echo #{dirs} && #{try_sudo} mkdir -p #{(dirs + tmp_dirs).join(' ')} && #{try_sudo} chmod -R 777 #{tmp_path}" if (!user.empty?)
|
168
|
+
|
169
|
+
if shared_app_dirs
|
170
|
+
shared_app_dirs.each { | link | run "#{try_sudo} mkdir -p #{shared_path}/#{link}" }
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
desc <<-DESC
|
175
|
+
Symlinks all shared files and folders
|
176
|
+
DESC
|
177
|
+
task :create_symlink do
|
178
|
+
run "ln -s #{shared_path}/tmp #{latest_release}/resources/tmp";
|
179
|
+
if shared_app_dirs
|
180
|
+
shared_app_dirs.each { | link | run "ln -nfs #{shared_path}/#{link} #{current_path}/#{link}" }
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
# Logs
|
186
|
+
namespace :log do
|
187
|
+
desc <<-DESC
|
188
|
+
Clears logs and sub-directories
|
189
|
+
|
190
|
+
Recursively finds all files in :logs_path and runs `rm -f` on each. If a file \
|
191
|
+
is renamed/removed after it was found but before it removes it, no error \
|
192
|
+
will prompt (-ignore_readdir_race). If symlinks are found, they will not be followed
|
193
|
+
DESC
|
194
|
+
task :clear, :roles => :web, :except => { :no_release => true } do
|
195
|
+
run "#{try_sudo} find -P #{logs_path} -ignore_readdir_race -type f -name '*' -exec rm -f {} \\;"
|
196
|
+
end
|
197
|
+
|
198
|
+
desc <<-DESC
|
199
|
+
Streams the result of `tail -f` on all :logs_files \
|
200
|
+
|
201
|
+
By default, the files are `debug` and `error`. You can add your own \
|
202
|
+
in config/deploy.rb
|
203
|
+
|
204
|
+
set :logs_files %w(debug error my_log_file)
|
205
|
+
DESC
|
206
|
+
task :tail, :roles => :web, :except => { :no_release => true } do
|
207
|
+
files = logs_files.map { |d| File.join(logs_path, d) }
|
208
|
+
stream "#{try_sudo} tail -f #{files.join(' ')}"
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
end
|
213
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
<?php
|
2
|
+
/**
|
3
|
+
* Lithium: the most rad php framework
|
4
|
+
*
|
5
|
+
* @copyright Copyright 2012, Union of RAD (http://union-of-rad.org)
|
6
|
+
* @license http://opensource.org/licenses/bsd-license.php The BSD License
|
7
|
+
*/
|
8
|
+
|
9
|
+
/**
|
10
|
+
* ### Configuring backend database connections
|
11
|
+
*
|
12
|
+
* Lithium supports a wide variety relational and non-relational databases, and is designed to allow
|
13
|
+
* and encourage you to take advantage of multiple database technologies, choosing the most optimal
|
14
|
+
* one for each task.
|
15
|
+
*
|
16
|
+
* As with other `Adaptable`-based configurations, each database configuration is defined by a name,
|
17
|
+
* and an array of information detailing what database adapter to use, and how to connect to the
|
18
|
+
* database server. Unlike when configuring other classes, `Connections` uses two keys to determine
|
19
|
+
* which class to select. First is the `'type'` key, which specifies the type of backend to
|
20
|
+
* connect to. For relational databases, the type is set to `'database'`. For HTTP-based backends,
|
21
|
+
* like CouchDB, the type is `'http'`. Some backends have no type grouping, like MongoDB, which is
|
22
|
+
* unique and connects via a custom PECL extension. In this case, the type is set to `'MongoDb'`,
|
23
|
+
* and no `'adapter'` key is specified. In other cases, the `'adapter'` key identifies the unique
|
24
|
+
* adapter of the given type, i.e. `'MySql'` for the `'database'` type, or `'CouchDb'` for the
|
25
|
+
* `'http'` type. Note that while adapters are always specified in CamelCase form, types are
|
26
|
+
* specified either in CamelCase form, or in underscored form, depending on whether an `'adapter'`
|
27
|
+
* key is specified. See the examples below for more details.
|
28
|
+
*
|
29
|
+
* ### Multiple environments
|
30
|
+
*
|
31
|
+
* As with other `Adaptable` classes, `Connections` supports optionally specifying different
|
32
|
+
* configurations per named connection, depending on the current environment. For information on
|
33
|
+
* specifying environment-based configurations, see the `Environment` class.
|
34
|
+
*
|
35
|
+
* @see lithium\core\Adaptable
|
36
|
+
* @see lithium\core\Environment
|
37
|
+
*/
|
38
|
+
use lithium\data\Connections;
|
39
|
+
<% case type
|
40
|
+
when 'database' %>
|
41
|
+
Connections::add('default', array(
|
42
|
+
'type' => 'database',
|
43
|
+
'adapter' => 'MySql',
|
44
|
+
'host' => '<%= host %>',
|
45
|
+
'login' => '<%= login %>',
|
46
|
+
'password' => '<%= password %>',
|
47
|
+
'database' => '<%= database %>',
|
48
|
+
'encoding' => '<%= encoding %>'
|
49
|
+
));
|
50
|
+
<% when 'http' %>
|
51
|
+
Connections::add('default', array(
|
52
|
+
'type' => 'http',
|
53
|
+
'adapter' => 'CouchDb',
|
54
|
+
'host' => '<%= host %>',
|
55
|
+
'database' => '<%= database %>'
|
56
|
+
));
|
57
|
+
<% else %>
|
58
|
+
Connections::add('default', array(
|
59
|
+
'type' => 'MongoDb',
|
60
|
+
'host' => '<%= host %>',
|
61
|
+
'database' => '<%= database %>'
|
62
|
+
));
|
63
|
+
<% end %>
|
64
|
+
?>
|
@@ -0,0 +1,142 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
Capistrano::Configuration.instance(:must_exist).load do
|
3
|
+
# =========================================================================
|
4
|
+
# These are helper methods that will be available to your recipes.
|
5
|
+
# =========================================================================
|
6
|
+
|
7
|
+
def _cset(name, *args, &block)
|
8
|
+
unless exists?(name)
|
9
|
+
set(name, *args, &block)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# Asks the shell for a response or else uses the default if nothing
|
14
|
+
# is entered
|
15
|
+
def prompt_with_default(var, default, &block)
|
16
|
+
set(var) do
|
17
|
+
Capistrano::CLI.ui.ask("#{var} [#{default}] : ", &block)
|
18
|
+
end
|
19
|
+
set var, default if eval("#{var.to_s}.empty?")
|
20
|
+
end
|
21
|
+
|
22
|
+
# Check to see if a file exists
|
23
|
+
def remote_file_exists?(full_path)
|
24
|
+
'true' == capture("if [ -e #{full_path} ]; then echo 'true'; fi").strip
|
25
|
+
end
|
26
|
+
|
27
|
+
# Auxiliary helper method for the `deploy:check' task. Lets you set up your
|
28
|
+
# own dependencies.
|
29
|
+
def depend(location, type, *args)
|
30
|
+
deps = fetch(:dependencies, {})
|
31
|
+
deps[location] ||= {}
|
32
|
+
deps[location][type] ||= []
|
33
|
+
deps[location][type] << args
|
34
|
+
set :dependencies, deps
|
35
|
+
end
|
36
|
+
|
37
|
+
# Temporarily sets an environment variable, yields to a block, and restores
|
38
|
+
# the value when it is done.
|
39
|
+
def with_env(name, value)
|
40
|
+
saved, ENV[name] = ENV[name], value
|
41
|
+
yield
|
42
|
+
ensure
|
43
|
+
ENV[name] = saved
|
44
|
+
end
|
45
|
+
|
46
|
+
# logs the command then executes it locally.
|
47
|
+
# returns the command output as a string
|
48
|
+
def run_locally(cmd)
|
49
|
+
logger.trace "executing locally: #{cmd.inspect}" if logger
|
50
|
+
output_on_stdout = nil
|
51
|
+
elapsed = Benchmark.realtime do
|
52
|
+
output_on_stdout = `#{cmd}`
|
53
|
+
end
|
54
|
+
if $?.to_i > 0 # $? is command exit code (posix style)
|
55
|
+
raise Capistrano::LocalArgumentError, "Command #{cmd} returned status code #{$?}"
|
56
|
+
end
|
57
|
+
logger.trace "command finished in #{(elapsed * 1000).round}ms" if logger
|
58
|
+
output_on_stdout
|
59
|
+
end
|
60
|
+
|
61
|
+
# If a command is given, this will try to execute the given command, as
|
62
|
+
# described below. Otherwise, it will return a string for use in embedding in
|
63
|
+
# another command, for executing that command as described below.
|
64
|
+
#
|
65
|
+
# If :run_method is :sudo (or :use_sudo is true), this executes the given command
|
66
|
+
# via +sudo+. Otherwise is uses +run+. If :as is given as a key, it will be
|
67
|
+
# passed as the user to sudo as, if using sudo. If the :as key is not given,
|
68
|
+
# it will default to whatever the value of the :admin_runner variable is,
|
69
|
+
# which (by default) is unset.
|
70
|
+
#
|
71
|
+
# THUS, if you want to try to run something via sudo, and what to use the
|
72
|
+
# root user, you'd just to try_sudo('something'). If you wanted to try_sudo as
|
73
|
+
# someone else, you'd just do try_sudo('something', :as => "bob"). If you
|
74
|
+
# always wanted sudo to run as a particular user, you could do
|
75
|
+
# set(:admin_runner, "bob").
|
76
|
+
def try_sudo(*args)
|
77
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
78
|
+
command = args.shift
|
79
|
+
raise ArgumentError, "too many arguments" if args.any?
|
80
|
+
|
81
|
+
as = options.fetch(:as, fetch(:admin_runner, nil))
|
82
|
+
via = fetch(:run_method, :sudo)
|
83
|
+
if command
|
84
|
+
invoke_command(command, :via => via, :as => as)
|
85
|
+
elsif via == :sudo
|
86
|
+
sudo(:as => as)
|
87
|
+
else
|
88
|
+
""
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# Same as sudo, but tries sudo with :as set to the value of the :runner
|
93
|
+
# variable (which defaults to "app").
|
94
|
+
def try_runner(*args)
|
95
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
96
|
+
args << options.merge(:as => fetch(:runner, "app"))
|
97
|
+
try_sudo(*args)
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
def pretty_print(msg)
|
102
|
+
if logger.level == Capistrano::Logger::IMPORTANT
|
103
|
+
pretty_errors
|
104
|
+
|
105
|
+
msg = msg.slice(0, 57)
|
106
|
+
msg << '.' * (60 - msg.size)
|
107
|
+
print msg
|
108
|
+
else
|
109
|
+
puts msg.green
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def puts_ok
|
114
|
+
if logger.level == Capistrano::Logger::IMPORTANT && !$error
|
115
|
+
puts '✔'.green
|
116
|
+
end
|
117
|
+
|
118
|
+
$error = false
|
119
|
+
end
|
120
|
+
|
121
|
+
def pretty_errors
|
122
|
+
if !$pretty_errors_defined
|
123
|
+
$pretty_errors_defined = true
|
124
|
+
|
125
|
+
class << $stderr
|
126
|
+
@@firstLine = true
|
127
|
+
alias _write write
|
128
|
+
|
129
|
+
def write(s)
|
130
|
+
if @@firstLine
|
131
|
+
s = '✘' << "\n" << s
|
132
|
+
@@firstLine = false
|
133
|
+
end
|
134
|
+
|
135
|
+
_write(s.red)
|
136
|
+
$error = true
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
Capistrano::Configuration.instance(:must_exist).load do
|
2
|
+
namespace :mysql do
|
3
|
+
desc <<-DESC
|
4
|
+
Creates MySQL database, database user and grants permissions on DB servers
|
5
|
+
DESC
|
6
|
+
task :create, :roles => :db, :except => { :no_releases => true } do
|
7
|
+
require 'erb'
|
8
|
+
prompt_with_default(:mysql_admin_user, 'root')
|
9
|
+
_cset :mysql_admin_password, Capistrano::CLI.password_prompt("password:")
|
10
|
+
prompt_with_default(:mysql_grant_priv_type, 'ALL')
|
11
|
+
prompt_with_default(:mysql_grant_locations, 'localhost')
|
12
|
+
prompt_with_default(:db_login, user)
|
13
|
+
_cset :db_password, Capistrano::CLI.password_prompt("password:")
|
14
|
+
prompt_with_default(:db_name, application)
|
15
|
+
prompt_with_default(:db_encoding, 'utf8')
|
16
|
+
|
17
|
+
set :tmp_filename, File.join(shared_path, "config/create_db_#{db_name}.sql")
|
18
|
+
|
19
|
+
template = File.read(File.join(File.dirname(__FILE__), "../templates", "create_database.sql.erb"))
|
20
|
+
result = ERB.new(template).result(binding)
|
21
|
+
|
22
|
+
put(result, "#{tmp_filename}", :mode => 0644, :via => :scp)
|
23
|
+
|
24
|
+
run "mysql -u #{mysql_admin_user} -p#{mysql_admin_password} < #{tmp_filename}"
|
25
|
+
run "#{try_sudo} rm #{tmp_filename}"
|
26
|
+
end
|
27
|
+
|
28
|
+
desc <<-DESC
|
29
|
+
Exports MySQL database and copies it to the shared directory
|
30
|
+
DESC
|
31
|
+
task :export, :roles => :db, :except => { :no_releases => true } do
|
32
|
+
prompt_with_default(:mysql_admin_user, 'root')
|
33
|
+
_cset :mysql_admin_password, Capistrano::CLI.password_prompt("password:")
|
34
|
+
database = Capistrano::CLI.ui.ask("Which database should we export: ")
|
35
|
+
timestamp = Time.now.utc.strftime("%Y%m%d%H%M%S")
|
36
|
+
run "mysqldump -u #{mysql_admin_user} -p #{mysql_admin_password} > #{database}-#{timestamp}.sql"
|
37
|
+
download "#{database}-#{timestamp}.sql", "~/#{database}-#{timestamp}.sql"
|
38
|
+
logger.info "Database dump has been downloaded to ~/#{database}-#{timestamp}.sql"
|
39
|
+
run "rm #{database}-#{timestamp}.sql"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|