caploy 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +19 -0
- data/Gemfile +4 -0
- data/README.md +12 -0
- data/Rakefile +2 -0
- data/caploy.gemspec +29 -0
- data/lib/caploy/recipes/airbrake.rb +4 -0
- data/lib/caploy/recipes/assets.rb +26 -0
- data/lib/caploy/recipes/bundler.rb +23 -0
- data/lib/caploy/recipes/database.rb +58 -0
- data/lib/caploy/recipes/defaults.rb +90 -0
- data/lib/caploy/recipes/info.rb +38 -0
- data/lib/caploy/recipes/monitoring.rb +12 -0
- data/lib/caploy/recipes/nginx.rb +108 -0
- data/lib/caploy/recipes/paperclip.rb +11 -0
- data/lib/caploy/recipes/passenger.rb +32 -0
- data/lib/caploy/recipes/puma.rb +25 -0
- data/lib/caploy/recipes/rbenv.rb +7 -0
- data/lib/caploy/recipes/redis.rb +41 -0
- data/lib/caploy/recipes/rvm.rb +8 -0
- data/lib/caploy/recipes/seeding.rb +9 -0
- data/lib/caploy/recipes/setup.rb +75 -0
- data/lib/caploy/recipes/symlink.rb +24 -0
- data/lib/caploy/recipes/unicorn.rb +43 -0
- data/lib/caploy/recipes/unicorn_bluepill.rb +90 -0
- data/lib/caploy/recipes/whenever.rb +8 -0
- data/lib/caploy/render.rb +8 -0
- data/lib/caploy/templates/bluepill/init.erb +9 -0
- data/lib/caploy/templates/bluepill/unicorn_config.rb.erb +43 -0
- data/lib/caploy/templates/nginx/vhost.erb +130 -0
- data/lib/caploy/templates/unicorn/unicorn.rb.erb +34 -0
- data/lib/caploy/version.rb +3 -0
- data/lib/caploy.rb +1 -0
- data/lib/examples/deploy.rb +73 -0
- data/lib/mysql.rb +109 -0
- data/lib/util.rb +10 -0
- metadata +225 -0
@@ -0,0 +1,24 @@
|
|
1
|
+
Capistrano::Configuration.instance.load do
|
2
|
+
|
3
|
+
namespace :deploy do
|
4
|
+
desc <<-DESC
|
5
|
+
Symlink shared directories and files.
|
6
|
+
DESC
|
7
|
+
task :symlink_dependencies, :roles => :web, :except => {:no_release => true} do
|
8
|
+
shared_directories_to_link = fetch(:shared_directories_to_link, [])
|
9
|
+
directories_to_create = fetch(:directories_to_create, [])
|
10
|
+
files_to_delete = fetch(:files_to_delete, [])
|
11
|
+
files_to_link = fetch(:files_to_link, {})
|
12
|
+
chmods_to_set = fetch(:chmods_to_set, [])
|
13
|
+
|
14
|
+
directories_to_create.each { |directory| run "mkdir -p #{directory}" }
|
15
|
+
shared_directories_to_link.each { |source, target| run "ln -s #{source} #{target}" }
|
16
|
+
files_to_delete.each { |file| run "rm #{file}" }
|
17
|
+
files_to_link.each { |source, target| run "ln -s #{source} #{target}"}
|
18
|
+
chmods_to_set.each { |target, chmod| run "chmod #{chmod} #{target}" }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
after 'deploy:finalize_update', 'deploy:symlink_dependencies'
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
Capistrano::Configuration.instance.load do
|
2
|
+
|
3
|
+
_cset :unicorn_bin, "bundle exec unicorn"
|
4
|
+
_cset :unicorn_pid, "#{deploy_to}/current/tmp/pids/unicorn.pid"
|
5
|
+
_cset :unicorn_std_log, "log/unicorn.stderr.log"
|
6
|
+
_cset :unicorn_err_log, "log/unicorn.stderr.log"
|
7
|
+
_cset :unicorn_worker_processes, 2
|
8
|
+
_cset :unicorn_listen_backlog, 2048
|
9
|
+
|
10
|
+
require "capistrano-unicorn"
|
11
|
+
|
12
|
+
namespace :unicorn do
|
13
|
+
desc "Setup unicorn"
|
14
|
+
task :setup, :roles => :app, :except => { :no_release => true } do
|
15
|
+
run "mkdir -p \"#{shared_path}/config/unicorn\""
|
16
|
+
config_path = "#{shared_path}/config/unicorn/#{rails_env}.rb"
|
17
|
+
template_path = File.expand_path('../../templates/unicorn/unicorn.rb.erb', __FILE__)
|
18
|
+
vars = {
|
19
|
+
'application'=> application,
|
20
|
+
'current_path' => current_path,
|
21
|
+
'unicorn_pid' => unicorn_pid,
|
22
|
+
'unicorn_std_log' => unicorn_std_log,
|
23
|
+
'unicorn_err_log' => unicorn_err_log,
|
24
|
+
'stage' => stage,
|
25
|
+
'unicorn_listen_backlog' => unicorn_listen_backlog,
|
26
|
+
'unicorn_worker_processes' => unicorn_worker_processes
|
27
|
+
}
|
28
|
+
put(render_erb_template(template_path, vars), config_path)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
after :"deploy:setup", :"unicorn:setup";
|
33
|
+
|
34
|
+
namespace :deploy do
|
35
|
+
task :start, :roles => :app do
|
36
|
+
unicorn.start
|
37
|
+
end
|
38
|
+
|
39
|
+
task :stop, :roles => :app do
|
40
|
+
unicorn.stop
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# sudoers:
|
4
|
+
# %deploy ALL=(ALL) NOPASSWD: /usr/local/bin/bluepill, /sbin/start my_app_bluepill , /sbin/stop my_app_bluepill
|
5
|
+
# sudo chown root:root deploy_conf
|
6
|
+
# sudo chmod 0440 deploy_conf
|
7
|
+
# => /etc/sudoers.d
|
8
|
+
#
|
9
|
+
Capistrano::Configuration.instance.load do
|
10
|
+
|
11
|
+
namespace :deploy do
|
12
|
+
|
13
|
+
task :start, :roles => :app, :except => { :no_release => true } do
|
14
|
+
sudo 'start bluepill_conf'
|
15
|
+
end
|
16
|
+
|
17
|
+
task :stop, :roles => :app, :except => { :no_release => true } do
|
18
|
+
sudo "bluepill stop"
|
19
|
+
sudo "stop bluepill_conf"
|
20
|
+
end
|
21
|
+
|
22
|
+
task :restart, :roles => :app, :except => { :no_release => true } do
|
23
|
+
sudo "bluepill restart unicorn"
|
24
|
+
end
|
25
|
+
|
26
|
+
#desc "Restart Resque Workers"
|
27
|
+
#task :restart_workers do
|
28
|
+
# sudo "bluepill stop resque"
|
29
|
+
# sudo "bluepill start resque"
|
30
|
+
#end
|
31
|
+
#
|
32
|
+
#desc "Start Resque Workers"
|
33
|
+
#task :start_workers do
|
34
|
+
# sudo "bluepill start resque"
|
35
|
+
#end
|
36
|
+
#
|
37
|
+
#desc "Stop Resque Workers"
|
38
|
+
#task :stop_workers do
|
39
|
+
# sudo "bluepill stop resque"
|
40
|
+
#end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
namespace :bluepill do
|
45
|
+
desc "Prints bluepills monitored processes statuses"
|
46
|
+
task :status, :roles => [:app] do
|
47
|
+
sudo "bluepill status"
|
48
|
+
end
|
49
|
+
|
50
|
+
desc "Setup blupill config"
|
51
|
+
task :setup, :roles => [:app] do
|
52
|
+
setup_init
|
53
|
+
setup_config
|
54
|
+
end
|
55
|
+
|
56
|
+
task :setup_init do
|
57
|
+
template_path = File.expand_path('../../templates/bluepill/init.erb', __FILE__)
|
58
|
+
vars = {
|
59
|
+
'application' => application,
|
60
|
+
'config_path' => fetch(:bluepill_config_path, "#{shared_path}/config/bluepill_config.pill")
|
61
|
+
}
|
62
|
+
|
63
|
+
config_path = "#{shared_path}/config/bluepill_init.conf"
|
64
|
+
|
65
|
+
put(render_erb_template(template_path, vars), config_path)
|
66
|
+
sudo "rm -f /etc/init/bluepill_#{application}_#{stage}.conf"
|
67
|
+
sudo "ln -s #{config_path} /etc/init/bluepill_#{application}_#{stage}.conf"
|
68
|
+
end
|
69
|
+
|
70
|
+
task :setup_config do
|
71
|
+
template_path = File.expand_path('../../templates/bluepill/default_config.rb.erb', __FILE__)
|
72
|
+
log_file = "#{latest_release}/log/bluepill.log"
|
73
|
+
unicorn_config_path = "#{shared_path}/config/unicorn/#{stage}.rb"
|
74
|
+
vars = {
|
75
|
+
'application' => application,
|
76
|
+
'stage' => stage,
|
77
|
+
'log_file' => log_file,
|
78
|
+
'unicorn_config_path' => unicorn_config_path
|
79
|
+
}
|
80
|
+
|
81
|
+
config_path = fetch(:bluepill_config_path, "#{shared_path}/config/bluepill_config.pill")
|
82
|
+
put(render_erb_template(template_path, vars), config_path)
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
#after "deploy:restart", "deploy:restart_workers"
|
88
|
+
after "deploy:setup", "bluepill:setup"
|
89
|
+
|
90
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
ENV["RAILS_ENV"] = "<%= stage %>"
|
2
|
+
|
3
|
+
Bluepill.application("<%= application %>-<%= stage %>", :log_file => '<%= log_file %>') do |app|
|
4
|
+
|
5
|
+
app.process("unicorn") do |process|
|
6
|
+
process.pid_file = '<%= unicorn_config_path %>'
|
7
|
+
process.working_dir = '/var/my_app/current'
|
8
|
+
|
9
|
+
process.start_command = "/usr/local/bin/bundle exec unicorn -c /var/my_app/current/config/unicorn.rb -E staging -D"
|
10
|
+
process.stop_command = "kill -QUIT {{PID}}"
|
11
|
+
process.restart_command = "kill -USR2 {{PID}}"
|
12
|
+
|
13
|
+
process.uid = process.gid = 'deploy'
|
14
|
+
|
15
|
+
process.start_grace_time = 30.seconds
|
16
|
+
process.stop_grace_time = 30.seconds
|
17
|
+
process.restart_grace_time = 30.seconds
|
18
|
+
|
19
|
+
|
20
|
+
process.monitor_children do |child_process|
|
21
|
+
child_process.stop_command = "kill -QUIT {{PID}}"
|
22
|
+
|
23
|
+
child_process.checks :mem_usage, :every => 30.seconds, :below => 200.megabytes, :times => [3, 4], :fires => :stop
|
24
|
+
child_process.checks :cpu_usage, :every => 30.seconds, :below => 40, :times => [3, 4], :fires => :stop
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
2.times do |i|
|
29
|
+
app.process("resque-#{i}") do |process|
|
30
|
+
process.working_dir = '/var/my_app/current'
|
31
|
+
process.group = "resque"
|
32
|
+
process.start_command = "/usr/local/bin/bundle exec rake resque:work"
|
33
|
+
process.pid_file = "/var/my_app/shared/pids/my_app-resque-#{i}.pid"
|
34
|
+
process.stop_command = "kill -QUIT {{PID}}"
|
35
|
+
process.daemonize = true
|
36
|
+
|
37
|
+
process.start_grace_time = 30.seconds
|
38
|
+
process.stop_grace_time = 30.seconds
|
39
|
+
process.uid = process.gid = 'deploy'
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
|
2
|
+
<% if with_upstream_server %>
|
3
|
+
|
4
|
+
upstream <%= application %>_<%= stage %>_<%= protocol %>_server {
|
5
|
+
# fail_timeout=0 means we always retry an upstream even if it failed
|
6
|
+
# to return a good HTTP response (in case the Unicorn master nukes a
|
7
|
+
# single worker for timing out).
|
8
|
+
|
9
|
+
# This is the socket we configured in unicorn.rb
|
10
|
+
server unix:/tmp/socket.<%= application %>_<%= stage %>.sock fail_timeout=0;
|
11
|
+
|
12
|
+
# for TCP setups, point these to your backend servers
|
13
|
+
# server 127.0.0.1:8080 fail_timeout=0;
|
14
|
+
# server 192.168.0.8:8080 fail_timeout=0;
|
15
|
+
# server 192.168.0.9:8080 fail_timeout=0;
|
16
|
+
}
|
17
|
+
<% end %>
|
18
|
+
|
19
|
+
<%= optional_nginx_http_content if protocol == 'http' %>
|
20
|
+
<%= optional_nginx_https_content if protocol == 'https' %>
|
21
|
+
|
22
|
+
server {
|
23
|
+
|
24
|
+
server_name <%= domain %>;
|
25
|
+
|
26
|
+
<% if protocol == 'https' %>
|
27
|
+
|
28
|
+
listen 443 ssl;
|
29
|
+
|
30
|
+
ssl_certificate <%= nginx_cert_dir %>/<%= application %>_cert.<%= cert_type %>;
|
31
|
+
ssl_certificate_key <%= nginx_cert_dir %>/<%= application %>_cert.<%= key_type %>;
|
32
|
+
|
33
|
+
#ssl_ciphers SSLv3+HIGH:RC4+MEDIUM:!aNULL:!eNULL:!3DES:!MD5:@STRENGTH;
|
34
|
+
#ssl_prefer_server_ciphers on;
|
35
|
+
#ssl_protocols SSLv3;
|
36
|
+
#ssl_session_cache shared:SSL:10m;
|
37
|
+
|
38
|
+
keepalive_timeout 70;
|
39
|
+
|
40
|
+
<% else %>
|
41
|
+
|
42
|
+
listen 80;
|
43
|
+
|
44
|
+
# ~2 seconds is often enough for most folks to parse HTML/CSS and
|
45
|
+
# retrieve needed images/icons/frames, connections are cheap in
|
46
|
+
# nginx so increasing this is generally safe...
|
47
|
+
#keepalive_timeout 5;
|
48
|
+
|
49
|
+
<% end %>
|
50
|
+
|
51
|
+
client_max_body_size 4G;
|
52
|
+
|
53
|
+
<% if serve_static_files %>
|
54
|
+
|
55
|
+
# path for static files
|
56
|
+
root <%= project_root %>/public;
|
57
|
+
|
58
|
+
<% if with_file_expire_max %>
|
59
|
+
location ~* \.(ico|css|js|gif|jpe?g|png)(\?[0-9]+)?$ {
|
60
|
+
expires max;
|
61
|
+
break;
|
62
|
+
}
|
63
|
+
<% end %>
|
64
|
+
|
65
|
+
<% end %>
|
66
|
+
|
67
|
+
<%= optional_http_content if protocol == 'http' %>
|
68
|
+
<%= optional_https_content if protocol == 'https' %>
|
69
|
+
|
70
|
+
# Prefer to serve static files directly from nginx to avoid unnecessary
|
71
|
+
# data copies from the application server.
|
72
|
+
#
|
73
|
+
# try_files directive appeared in in nginx 0.7.27 and has stabilized
|
74
|
+
# over time. Older versions of nginx (e.g. 0.6.x) requires
|
75
|
+
# "if (!-f $request_filename)" which was less efficient:
|
76
|
+
# http://bogomips.org/unicorn.git/tree/examples/nginx.conf?id=v3.3.1#n127
|
77
|
+
try_files $uri/index.html $uri.html $uri @app;
|
78
|
+
|
79
|
+
location / {
|
80
|
+
# an HTTP header important enough to have its own Wikipedia entry:
|
81
|
+
# http://en.wikipedia.org/wiki/X-Forwarded-For
|
82
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
83
|
+
|
84
|
+
# enable this if and only if you use HTTPS, this helps Rack
|
85
|
+
# set the proper protocol for doing redirects:
|
86
|
+
# proxy_set_header X-Forwarded-Proto https;
|
87
|
+
|
88
|
+
# pass the Host: header from the client right along so redirects
|
89
|
+
# can be set properly within the Rack application
|
90
|
+
proxy_set_header Host $http_host;
|
91
|
+
|
92
|
+
# we don't want nginx trying to do something clever with
|
93
|
+
# redirects, we set the Host: header above already.
|
94
|
+
proxy_redirect off;
|
95
|
+
|
96
|
+
# set "proxy_buffering off" *only* for Rainbows! when doing
|
97
|
+
# Comet/long-poll/streaming. It's also safe to set if you're using
|
98
|
+
# only serving fast clients with Unicorn + nginx, but not slow
|
99
|
+
# clients. You normally want nginx to buffer responses to slow
|
100
|
+
# clients, even with Rails 3.1 streaming because otherwise a slow
|
101
|
+
# client can become a bottleneck of Unicorn.
|
102
|
+
#
|
103
|
+
# The Rack application may also set "X-Accel-Buffering (yes|no)"
|
104
|
+
# in the response headers do disable/enable buffering on a
|
105
|
+
# per-response basis.
|
106
|
+
# proxy_buffering off;
|
107
|
+
|
108
|
+
<% if protocol == 'https' %>
|
109
|
+
# This makes sure that Rack::SslEnforcer knows it's being accessed over SSL.
|
110
|
+
proxy_set_header X-Forwarded-Proto https;
|
111
|
+
<% end %>
|
112
|
+
|
113
|
+
if (!-f $request_filename) {
|
114
|
+
proxy_pass http://<%= application %>_<%= stage %>_<%= protocol %>_server;
|
115
|
+
break;
|
116
|
+
}
|
117
|
+
|
118
|
+
<% if auth_basic_title %>
|
119
|
+
auth_basic "<%= auth_basic_title %>";
|
120
|
+
auth_basic_user_file <%= auth_basic_password_file %>;
|
121
|
+
<% end %>
|
122
|
+
}
|
123
|
+
|
124
|
+
# Rails error pages
|
125
|
+
error_page 500 502 503 504 /500.html;
|
126
|
+
location = /500.html {
|
127
|
+
root <%= project_root %>/public;
|
128
|
+
}
|
129
|
+
}
|
130
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
working_directory "<%= current_path %>"
|
2
|
+
pid "<%= unicorn_pid %>"
|
3
|
+
stderr_path "<%= unicorn_std_log %>"
|
4
|
+
stdout_path "<%= unicorn_err_log %>"
|
5
|
+
|
6
|
+
listen "/tmp/socket.<%= application %>_<%= stage %>.sock", :backlog => <%= unicorn_listen_backlog %>
|
7
|
+
worker_processes <%= unicorn_worker_processes %>
|
8
|
+
timeout 30
|
9
|
+
|
10
|
+
preload_app true
|
11
|
+
|
12
|
+
before_fork do |server, worker|
|
13
|
+
# Disconnect since the database connection will not carry over
|
14
|
+
if defined? ActiveRecord::Base
|
15
|
+
ActiveRecord::Base.connection.disconnect!
|
16
|
+
end
|
17
|
+
|
18
|
+
# Quit the old unicorn process
|
19
|
+
old_pid = "#{server.config[:pid]}.oldbin"
|
20
|
+
if File.exists?(old_pid) && server.pid != old_pid
|
21
|
+
begin
|
22
|
+
Process.kill("QUIT", File.read(old_pid).to_i)
|
23
|
+
rescue Errno::ENOENT, Errno::ESRCH
|
24
|
+
# someone else did our job for us
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
after_fork do |server, worker|
|
30
|
+
# Start up the database connection again in the worker
|
31
|
+
if defined?(ActiveRecord::Base)
|
32
|
+
ActiveRecord::Base.establish_connection
|
33
|
+
end
|
34
|
+
end
|
data/lib/caploy.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "caploy/version"
|
@@ -0,0 +1,73 @@
|
|
1
|
+
|
2
|
+
set :application, ''
|
3
|
+
set :domain, ''
|
4
|
+
set :deploy_domain, ''
|
5
|
+
set :vhost_domain, ''
|
6
|
+
|
7
|
+
# set application folder
|
8
|
+
set :deploy_to, "/var/projects/#{application}/xxx"
|
9
|
+
|
10
|
+
set :rails_root, File.expand_path('../../', __FILE__)
|
11
|
+
set :rails_env, :production # use 'stage' to differ between stage environments
|
12
|
+
|
13
|
+
set :user, 'deploy'
|
14
|
+
|
15
|
+
server domain, :web, :app, :db, :primary => true
|
16
|
+
|
17
|
+
# Multistage settings
|
18
|
+
#set :stage_dir, File.dirname(__FILE__) + '/deploy/stages'
|
19
|
+
#set :default_stage, "vagrant"
|
20
|
+
#require 'capistrano/ext/multistage'
|
21
|
+
|
22
|
+
# database
|
23
|
+
set :db_name, ''
|
24
|
+
set :db_user_name, ''
|
25
|
+
set :db_user_password, ''
|
26
|
+
|
27
|
+
set :branch, ENV['BRANCH'] || 'develop'
|
28
|
+
set :repository, 'xxx.git'
|
29
|
+
|
30
|
+
set(:shared_directories_to_create) {
|
31
|
+
%W(#{shared_path}/bundle #{shared_path}/cache)
|
32
|
+
}
|
33
|
+
|
34
|
+
set(:shared_directories_to_link) {
|
35
|
+
{
|
36
|
+
"#{shared_path}/bundle/" => "#{release_path}/vendor/bundle"
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
40
|
+
set(:directories_to_create) {
|
41
|
+
%W()
|
42
|
+
}
|
43
|
+
|
44
|
+
set(:files_to_link) {
|
45
|
+
{
|
46
|
+
"#{shared_path}/config/config.#{stage}.yml" => "#{release_path}/config/config.local.yml",
|
47
|
+
"#{shared_path}/config/unicorn.#{stage}.rb" => "#{release_path}/config/unicorn.production.rb"
|
48
|
+
}
|
49
|
+
}
|
50
|
+
|
51
|
+
set(:files_to_delete) {
|
52
|
+
%W()
|
53
|
+
}
|
54
|
+
|
55
|
+
set(:chmods_to_set) {
|
56
|
+
{
|
57
|
+
# "#{shared_path}/data/pdf" => 755
|
58
|
+
}
|
59
|
+
}
|
60
|
+
|
61
|
+
require 'caploy/recipes/defaults'
|
62
|
+
|
63
|
+
require 'caploy/recipes/rbenv'
|
64
|
+
require 'caploy/recipes/assets'
|
65
|
+
require 'caploy/recipes/nginx'
|
66
|
+
require 'caploy/recipes/bundler'
|
67
|
+
require 'caploy/recipes/symlink'
|
68
|
+
require 'caploy/recipes/unicorn'
|
69
|
+
require 'caploy/recipes/setup'
|
70
|
+
require 'caploy/recipes/monitoring'
|
71
|
+
require 'caploy/recipes/seeding'
|
72
|
+
#require 'caploy/recipes/paperclip'
|
73
|
+
#require 'caploy/recipes/airbrake'
|
data/lib/mysql.rb
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
module Database
|
2
|
+
class Base
|
3
|
+
attr_accessor :config, :output_file
|
4
|
+
def initialize(cap_instance)
|
5
|
+
@cap = cap_instance
|
6
|
+
end
|
7
|
+
|
8
|
+
def mysql?
|
9
|
+
@config['adapter'] == 'mysql' || @config['adapter'] == 'mysql2'
|
10
|
+
end
|
11
|
+
|
12
|
+
def credentials
|
13
|
+
" -u #{@config['username']} " + (@config['password'] ? " -p\"#{@config['password']}\" " : '') + (@config['host'] ? " -h #{@config['host']}" : '')
|
14
|
+
end
|
15
|
+
|
16
|
+
def database
|
17
|
+
@config['database']
|
18
|
+
end
|
19
|
+
|
20
|
+
def output_file
|
21
|
+
@output_file ||= "db/dump_#{database}.sql.bz2"
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
def dump_cmd
|
26
|
+
"mysqldump #{credentials} #{database}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def import_cmd(file)
|
30
|
+
"mysql #{credentials} -D #{database} < #{file}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class Remote < Base
|
35
|
+
def initialize(cap_instance)
|
36
|
+
super(cap_instance)
|
37
|
+
@cap.run("cat #{@cap.current_path}/config/database.yml") { |c, s, d| @config = YAML.load(d)[(@cap.rails_env || 'production').to_s] }
|
38
|
+
end
|
39
|
+
|
40
|
+
def dump
|
41
|
+
@cap.run "cd #{@cap.current_path}; #{dump_cmd} | bzip2 - - > #{output_file}"
|
42
|
+
self
|
43
|
+
end
|
44
|
+
|
45
|
+
def download(local_file = "#{output_file}")
|
46
|
+
remote_file = "#{@cap.current_path}/#{output_file}"
|
47
|
+
@cap.get remote_file, local_file
|
48
|
+
end
|
49
|
+
|
50
|
+
# cleanup = true removes the mysqldump file after loading, false leaves it in db/
|
51
|
+
def load(file, cleanup)
|
52
|
+
unzip_file = File.join(File.dirname(file), File.basename(file, '.bz2'))
|
53
|
+
@cap.run "cd #{@cap.current_path}; bunzip2 -f #{file} && RAILS_ENV=#{@cap.rails_env} rake db:drop db:create && #{import_cmd(unzip_file)}"
|
54
|
+
File.unlink(unzip_file) if cleanup
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class Local < Base
|
59
|
+
def initialize(cap_instance)
|
60
|
+
super(cap_instance)
|
61
|
+
@config = YAML.load_file(File.join('config', 'database.yml'))[@cap.local_rails_env]
|
62
|
+
end
|
63
|
+
|
64
|
+
# cleanup = true removes the mysqldump file after loading, false leaves it in db/
|
65
|
+
def load(file, cleanup)
|
66
|
+
unzip_file = File.join(File.dirname(file), File.basename(file, '.bz2'))
|
67
|
+
system("bunzip2 -f #{file} && rake db:drop db:create && #{import_cmd(unzip_file)} && rake db:migrate")
|
68
|
+
File.unlink(unzip_file) if cleanup
|
69
|
+
end
|
70
|
+
|
71
|
+
def dump
|
72
|
+
system "#{dump_cmd} | bzip2 - - > #{output_file}"
|
73
|
+
self
|
74
|
+
end
|
75
|
+
|
76
|
+
def upload
|
77
|
+
remote_file = "#{@cap.current_path}/#{output_file}"
|
78
|
+
@cap.upload output_file, remote_file
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
class << self
|
83
|
+
def check(local_db, remote_db)
|
84
|
+
unless local_db.mysql? && remote_db.mysql?
|
85
|
+
raise 'Only mysql on remote and local server is supported'
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def remote_to_local(instance)
|
90
|
+
local_db = Database::Local.new(instance)
|
91
|
+
remote_db = Database::Remote.new(instance)
|
92
|
+
|
93
|
+
check(local_db, remote_db)
|
94
|
+
|
95
|
+
remote_db.dump.download
|
96
|
+
local_db.load(remote_db.output_file, instance.fetch(:db_local_clean))
|
97
|
+
end
|
98
|
+
|
99
|
+
def local_to_remote(instance)
|
100
|
+
local_db = Database::Local.new(instance)
|
101
|
+
remote_db = Database::Remote.new(instance)
|
102
|
+
|
103
|
+
check(local_db, remote_db)
|
104
|
+
|
105
|
+
local_db.dump.upload
|
106
|
+
remote_db.load(local_db.output_file, instance.fetch(:db_local_clean))
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
data/lib/util.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
module Util
|
2
|
+
def self.prompt(msg, prompt = "(y)es, (n)o ")
|
3
|
+
answer = Capistrano::CLI.ui.ask("#{msg} #{prompt} ? ") do |q|
|
4
|
+
q.overwrite = false
|
5
|
+
q.validate = /^y$|^yes$|^n$|^no$/i
|
6
|
+
q.responses[:not_valid] = prompt
|
7
|
+
end
|
8
|
+
(answer =~ /^y$|^yes$/i) == 0
|
9
|
+
end
|
10
|
+
end
|