capistrano-db-tasks.senya 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Gemfile +3 -0
- data/LICENSE +16 -0
- data/README.markdown +103 -0
- data/Rakefile +25 -0
- data/capistrano-db-tasks.gemspec +22 -0
- data/lib/capistrano-db-tasks.rb +2 -0
- data/lib/capistrano-db-tasks/asset.rb +27 -0
- data/lib/capistrano-db-tasks/compressors/base.rb +5 -0
- data/lib/capistrano-db-tasks/compressors/bzip2.rb +40 -0
- data/lib/capistrano-db-tasks/compressors/gzip.rb +40 -0
- data/lib/capistrano-db-tasks/database.rb +245 -0
- data/lib/capistrano-db-tasks/dbtasks.rb +138 -0
- data/lib/capistrano-db-tasks/util.rb +6 -0
- data/lib/capistrano-db-tasks/version.rb +3 -0
- data/test/capistrano_db_tasks_test.rb +8 -0
- data/test/test_helper.rb +3 -0
- metadata +75 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0f34055a123659fdc31c7b0c7454f2f6b1d055db
|
4
|
+
data.tar.gz: f999701b00c2ceb38258df098c23c34762a34f1c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 49fa1a30921b945a3cf6ea1152a16ce6c9b3b715ac488a14c67dcfac036869fc16f4d4c54c54b4bc849d2d68f70e9747ae65f812ea819c0873c5b9bab6a0a6a3
|
7
|
+
data.tar.gz: 661f622abede36dc0e2ea10bcaeb489e319dd046d8e7ccc1fbe42155b2d4411b0e7eb64dc530367a2065aa6b8b3fb477ada8b86f9c646a2d0b7883fb89a48868
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
Copyright (c) 2009 Sébastien Gruhier - Xilinus/Maptimize
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
11
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
12
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
13
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
14
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
15
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
16
|
+
SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
CapistranoDbTasks
|
2
|
+
=================
|
3
|
+
|
4
|
+
Add database AND assets tasks to capistrano to a Rails project.
|
5
|
+
It only works with capistrano 3. Older versions until 0.3 works with capistrano 2.
|
6
|
+
|
7
|
+
Currently
|
8
|
+
|
9
|
+
* It only supports mysql and postgresql (both side remote and local)
|
10
|
+
* Synchronize assets remote to local and local to remote
|
11
|
+
|
12
|
+
Commands mysql, mysqldump (or pg\_dump, psql), bzip2 and unbzip2 (or gzip) must be in your PATH
|
13
|
+
|
14
|
+
Feel free to fork and to add more database support or new tasks.
|
15
|
+
|
16
|
+
Install
|
17
|
+
=======
|
18
|
+
|
19
|
+
Add it as a gem:
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
gem "capistrano-db-tasks", require: false
|
23
|
+
```
|
24
|
+
|
25
|
+
Add to config/deploy.rb:
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
require 'capistrano-db-tasks'
|
29
|
+
|
30
|
+
# if you haven't already specified
|
31
|
+
set :rails_env, "production"
|
32
|
+
|
33
|
+
# if you want to remove the local dump file after loading
|
34
|
+
set :db_local_clean, true
|
35
|
+
|
36
|
+
# if you want to remove the dump file from the server after downloading
|
37
|
+
set :db_remote_clean, true
|
38
|
+
|
39
|
+
# if you want to exclude table from dump
|
40
|
+
set :db_ignore_tables, []
|
41
|
+
|
42
|
+
# if you want to exclude table data (but not table schema) from dump
|
43
|
+
set :db_ignore_data_tables, []
|
44
|
+
|
45
|
+
# If you want to import assets, you can change default asset dir (default = system)
|
46
|
+
# This directory must be in your shared directory on the server
|
47
|
+
set :assets_dir, %w(public/assets public/att)
|
48
|
+
set :local_assets_dir, %w(public/assets public/att)
|
49
|
+
|
50
|
+
# if you want to work on a specific local environment (default = ENV['RAILS_ENV'] || 'development')
|
51
|
+
set :locals_rails_env, "production"
|
52
|
+
|
53
|
+
# if you are highly paranoid and want to prevent any push operation to the server
|
54
|
+
set :disallow_pushing, true
|
55
|
+
|
56
|
+
# if you prefer bzip2/unbzip2 instead of gzip
|
57
|
+
set :compressor, :bzip2
|
58
|
+
|
59
|
+
```
|
60
|
+
|
61
|
+
Add to .gitignore
|
62
|
+
```yml
|
63
|
+
/db/*.sql
|
64
|
+
```
|
65
|
+
|
66
|
+
|
67
|
+
[How to install bzip2 on Windows](http://stackoverflow.com/a/25625988/3324219)
|
68
|
+
|
69
|
+
Available tasks
|
70
|
+
===============
|
71
|
+
|
72
|
+
app:local:sync || app:pull # Synchronize your local assets AND database using remote assets and database
|
73
|
+
app:remote:sync || app:push # Synchronize your remote assets AND database using local assets and database
|
74
|
+
|
75
|
+
assets:local:sync || assets:pull # Synchronize your local assets using remote assets
|
76
|
+
assets:remote:sync || assets:push # Synchronize your remote assets using local assets
|
77
|
+
|
78
|
+
db:local:sync || db:pull # Synchronize your local database using remote database data
|
79
|
+
db:remote:sync || db:push # Synchronize your remote database using local database data
|
80
|
+
db:remote:backup # Dumps database to db folder after that we can take it from there
|
81
|
+
|
82
|
+
Example
|
83
|
+
=======
|
84
|
+
|
85
|
+
cap db:pull
|
86
|
+
cap production db:pull # if you are using capistrano-ext to have multistages
|
87
|
+
|
88
|
+
|
89
|
+
Contributors
|
90
|
+
============
|
91
|
+
|
92
|
+
* tilsammans (http://github.com/tilsammansee)
|
93
|
+
* bigfive (http://github.com/bigfive)
|
94
|
+
* jakemauer (http://github.com/jakemauer)
|
95
|
+
* tjoneseng (http://github.com/tjoneseng)
|
96
|
+
|
97
|
+
TODO
|
98
|
+
====
|
99
|
+
|
100
|
+
* May be change project's name as it's not only database tasks now :)
|
101
|
+
* Add tests
|
102
|
+
|
103
|
+
Copyright (c) 2009 [Sébastien Gruhier - XILINUS], released under the MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rdoc/task'
|
4
|
+
require 'bundler'
|
5
|
+
require 'bundler/gem_tasks'
|
6
|
+
|
7
|
+
desc 'Default: run unit tests.'
|
8
|
+
task :default => :test
|
9
|
+
|
10
|
+
desc 'Test the capistrano_db_tasks plugin.'
|
11
|
+
Rake::TestTask.new(:test) do |t|
|
12
|
+
t.libs << 'lib'
|
13
|
+
t.libs << 'test'
|
14
|
+
t.pattern = 'test/**/*_test.rb'
|
15
|
+
t.verbose = true
|
16
|
+
end
|
17
|
+
|
18
|
+
desc 'Generate documentation for the capistrano_db_tasks plugin.'
|
19
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
20
|
+
rdoc.rdoc_dir = 'rdoc'
|
21
|
+
rdoc.title = 'CapistranoDbTasks'
|
22
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
23
|
+
rdoc.rdoc_files.include('README')
|
24
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
25
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "capistrano-db-tasks/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "capistrano-db-tasks.senya"
|
7
|
+
s.version = CapistranoDbTasks::VERSION
|
8
|
+
s.authors = ["Sebastien Gruhier"]
|
9
|
+
s.email = ["sebastien.gruhier@xilinus.com"]
|
10
|
+
s.homepage = "https://github.com/cmrd-senya/capistrano-db-tasks/tree/dump_task.2"
|
11
|
+
s.summary = "A collection of capistrano tasks for syncing assets and databases (a modification from Senya)"
|
12
|
+
s.description = "A collection of capistrano tasks for syncing assets and databases"
|
13
|
+
|
14
|
+
s.rubyforge_project = "capistrano-db-tasks"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_runtime_dependency "capistrano", ">= 3.0.0"
|
22
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Asset
|
2
|
+
extend self
|
3
|
+
|
4
|
+
def remote_to_local(cap)
|
5
|
+
servers = Capistrano::Configuration.env.send(:servers)
|
6
|
+
server = servers.detect { |s| s.roles.include?(:app) }
|
7
|
+
port = server.netssh_options[:port] || 22
|
8
|
+
user = server.netssh_options[:user] || server.properties.fetch(:user)
|
9
|
+
[cap.fetch(:assets_dir)].flatten.each do |dir|
|
10
|
+
system("rsync -a --del -L -K -vv --progress --rsh='ssh -p #{port}' #{user}@#{server}:#{cap.current_path}/#{dir} #{cap.fetch(:local_assets_dir)}")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def local_to_remote(cap)
|
15
|
+
servers = Capistrano::Configuration.env.send(:servers)
|
16
|
+
server = servers.detect { |s| s.roles.include?(:app) }
|
17
|
+
port = server.netssh_options[:port] || 22
|
18
|
+
user = server.netssh_options[:user] || server.properties.fetch(:user)
|
19
|
+
[cap.fetch(:assets_dir)].flatten.each do |dir|
|
20
|
+
system("rsync -a --del -L -K -vv --progress --rsh='ssh -p #{port}' ./#{dir} #{user}@#{server}:#{cap.current_path}/#{cap.fetch(:local_assets_dir)}")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_string(cap)
|
25
|
+
[cap.fetch(:assets_dir)].flatten.join(" ")
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Compressors
|
2
|
+
class Bzip2 < Base
|
3
|
+
|
4
|
+
class << self
|
5
|
+
|
6
|
+
def file_extension
|
7
|
+
"bz2"
|
8
|
+
end
|
9
|
+
|
10
|
+
def compress(from, to = nil)
|
11
|
+
to = case to
|
12
|
+
when "-"
|
13
|
+
"-c --stdout"
|
14
|
+
when nil
|
15
|
+
""
|
16
|
+
else
|
17
|
+
"-c --stdout > #{to}"
|
18
|
+
end
|
19
|
+
|
20
|
+
"bzip2 #{from} #{to}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def decompress(from, to = nil)
|
24
|
+
from = "-f #{from}" unless from == "-"
|
25
|
+
|
26
|
+
to = case to
|
27
|
+
when "-"
|
28
|
+
"-c --stdout"
|
29
|
+
when nil
|
30
|
+
""
|
31
|
+
else
|
32
|
+
"-c --stdout > #{to}"
|
33
|
+
end
|
34
|
+
|
35
|
+
"bunzip2 -k -f #{from} #{to}"
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Compressors
|
2
|
+
class Gzip < Base
|
3
|
+
|
4
|
+
class << self
|
5
|
+
|
6
|
+
def file_extension
|
7
|
+
"gz"
|
8
|
+
end
|
9
|
+
|
10
|
+
def compress(from, to = nil)
|
11
|
+
from = from == :stdin ? "-" : from
|
12
|
+
to = case to
|
13
|
+
when '-'
|
14
|
+
"-c --stdout"
|
15
|
+
when nil
|
16
|
+
""
|
17
|
+
else
|
18
|
+
"-c --stdout > #{to}"
|
19
|
+
end
|
20
|
+
|
21
|
+
"gzip #{from} #{to}"
|
22
|
+
end
|
23
|
+
|
24
|
+
def decompress(from, to = nil)
|
25
|
+
from = from == :stdin ? "-" : from
|
26
|
+
to = case to
|
27
|
+
when :stdout
|
28
|
+
"-c --stdout"
|
29
|
+
when nil
|
30
|
+
""
|
31
|
+
else
|
32
|
+
"-c --stdout > #{to}"
|
33
|
+
end
|
34
|
+
|
35
|
+
"gzip -d #{from} #{to}"
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,245 @@
|
|
1
|
+
module Database
|
2
|
+
class Base
|
3
|
+
DBCONFIG_BEGIN_FLAG = "__CAPISTRANODB_CONFIG_BEGIN_FLAG__".freeze
|
4
|
+
DBCONFIG_END_FLAG = "__CAPISTRANODB_CONFIG_END_FLAG__".freeze
|
5
|
+
|
6
|
+
attr_accessor :config, :output_file
|
7
|
+
|
8
|
+
def initialize(cap_instance)
|
9
|
+
@cap = cap_instance
|
10
|
+
end
|
11
|
+
|
12
|
+
def mysql?
|
13
|
+
@config['adapter'] =~ /^mysql/
|
14
|
+
end
|
15
|
+
|
16
|
+
def postgresql?
|
17
|
+
%w(postgresql pg postgis).include? @config['adapter']
|
18
|
+
end
|
19
|
+
|
20
|
+
def credentials
|
21
|
+
credential_params = ""
|
22
|
+
username = @config['username'] || @config['user']
|
23
|
+
|
24
|
+
if mysql?
|
25
|
+
credential_params << " -u #{username} " if username
|
26
|
+
credential_params << " -p'#{@config['password']}' " if @config['password']
|
27
|
+
credential_params << " -h #{@config['host']} " if @config['host']
|
28
|
+
credential_params << " -S #{@config['socket']} " if @config['socket']
|
29
|
+
credential_params << " -P #{@config['port']} " if @config['port']
|
30
|
+
elsif postgresql?
|
31
|
+
credential_params << " -U #{username} " if username
|
32
|
+
credential_params << " -h #{@config['host']} " if @config['host']
|
33
|
+
credential_params << " -p #{@config['port']} " if @config['port']
|
34
|
+
end
|
35
|
+
|
36
|
+
credential_params
|
37
|
+
end
|
38
|
+
|
39
|
+
def database
|
40
|
+
@config['database']
|
41
|
+
end
|
42
|
+
|
43
|
+
def current_time
|
44
|
+
Time.now.strftime("%Y-%m-%d-%H%M%S")
|
45
|
+
end
|
46
|
+
|
47
|
+
def output_file
|
48
|
+
@output_file ||= "db/#{database}_#{current_time}.sql.#{compressor.file_extension}"
|
49
|
+
end
|
50
|
+
|
51
|
+
def compressor
|
52
|
+
@compressor ||= begin
|
53
|
+
compressor_klass = @cap.fetch(:compressor).to_s.split('_').collect(&:capitalize).join
|
54
|
+
klass = Object.module_eval("::Compressors::#{compressor_klass}", __FILE__, __LINE__)
|
55
|
+
klass
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def pgpass
|
62
|
+
@config['password'] ? "PGPASSWORD='#{@config['password']}'" : ""
|
63
|
+
end
|
64
|
+
|
65
|
+
def dump_cmd
|
66
|
+
if mysql?
|
67
|
+
"mysqldump #{credentials} #{database} #{dump_cmd_opts}"
|
68
|
+
elsif postgresql?
|
69
|
+
"#{pgpass} pg_dump #{credentials} #{database} #{dump_cmd_opts}"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def import_cmd(file)
|
74
|
+
if mysql?
|
75
|
+
"mysql #{credentials} -D #{database} < #{file}"
|
76
|
+
elsif postgresql?
|
77
|
+
terminate_connection_sql = "SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity WHERE pg_stat_activity.datname = '#{database}' AND pid <> pg_backend_pid();"
|
78
|
+
"#{pgpass} psql -c \"#{terminate_connection_sql};\" #{credentials} #{database}; #{pgpass} dropdb #{credentials} #{database}; #{pgpass} createdb #{credentials} #{database}; #{pgpass} psql #{credentials} -d #{database} < #{file}"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def dump_cmd_opts
|
83
|
+
if mysql?
|
84
|
+
"--lock-tables=false #{dump_cmd_ignore_tables_opts} #{dump_cmd_ignore_data_tables_opts}"
|
85
|
+
elsif postgresql?
|
86
|
+
"--no-acl --no-owner #{dump_cmd_ignore_tables_opts} #{dump_cmd_ignore_data_tables_opts}"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def dump_cmd_ignore_tables_opts
|
91
|
+
ignore_tables = @cap.fetch(:db_ignore_tables, [])
|
92
|
+
if mysql?
|
93
|
+
ignore_tables.map{ |t| "--ignore-table=#{database}.#{t}" }.join(" ")
|
94
|
+
elsif postgresql?
|
95
|
+
ignore_tables.map{ |t| "--exclude-table=#{t}" }.join(" ")
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def dump_cmd_ignore_data_tables_opts
|
100
|
+
ignore_tables = @cap.fetch(:db_ignore_data_tables, [])
|
101
|
+
if postgresql?
|
102
|
+
ignore_tables.map{ |t| "--exclude-table-data=#{t}" }.join(" ")
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
class Remote < Base
|
109
|
+
def initialize(cap_instance)
|
110
|
+
super(cap_instance)
|
111
|
+
@cap.info "Loading remote database config"
|
112
|
+
@cap.within @cap.current_path do
|
113
|
+
@cap.with rails_env: @cap.fetch(:rails_env) do
|
114
|
+
dirty_config_content = @cap.capture(:rails, "runner \"puts '#{DBCONFIG_BEGIN_FLAG}' + ActiveRecord::Base.connection.instance_variable_get(:@config).to_yaml + '#{DBCONFIG_END_FLAG}'\"", '2>/dev/null')
|
115
|
+
# Remove all warnings, errors and artefacts produced by bunlder, rails and other useful tools
|
116
|
+
config_content = dirty_config_content.match(/#{DBCONFIG_BEGIN_FLAG}(.*?)#{DBCONFIG_END_FLAG}/m)[1]
|
117
|
+
@config = YAML.load(config_content).inject({}) { |h, (k, v)| h[k.to_s] = v; h }
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def dump
|
123
|
+
@cap.execute "cd #{@cap.current_path} && #{dump_cmd} | #{compressor.compress('-', output_file)}"
|
124
|
+
@cap.execute("ln -fs #{@cap.current_path}/#{output_file} #{@cap.current_path}/db/latest.sql.#{compressor.file_extension}")
|
125
|
+
self
|
126
|
+
end
|
127
|
+
|
128
|
+
def download(local_file = "#{output_file}")
|
129
|
+
@cap.download! dump_file_path, local_file
|
130
|
+
end
|
131
|
+
|
132
|
+
def clean_dump_if_needed
|
133
|
+
if @cap.fetch(:db_remote_clean)
|
134
|
+
@cap.execute "rm -f #{dump_file_path}"
|
135
|
+
else
|
136
|
+
@cap.info "leaving #{dump_file_path} on the server (add \"set :db_remote_clean, true\" to deploy.rb to remove)"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# cleanup = true removes the mysqldump file after loading, false leaves it in db/
|
141
|
+
def load(file, cleanup)
|
142
|
+
unzip_file = File.join(File.dirname(file), File.basename(file, ".#{compressor.file_extension}"))
|
143
|
+
# @cap.run "cd #{@cap.current_path} && bunzip2 -f #{file} && RAILS_ENV=#{@cap.rails_env} bundle exec rake db:drop db:create && #{import_cmd(unzip_file)}"
|
144
|
+
@cap.execute "cd #{@cap.current_path} && #{compressor.decompress(file)} && RAILS_ENV=#{@cap.fetch(:rails_env)} && #{import_cmd(unzip_file)}"
|
145
|
+
@cap.execute("cd #{@cap.current_path} && rm #{unzip_file}") if cleanup
|
146
|
+
end
|
147
|
+
|
148
|
+
private
|
149
|
+
|
150
|
+
def dump_file_path
|
151
|
+
"#{@cap.current_path}/#{output_file}"
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
class Local < Base
|
156
|
+
def initialize(cap_instance)
|
157
|
+
super(cap_instance)
|
158
|
+
@cap.info "Loading local database config"
|
159
|
+
dirty_config_content = @cap.run_locally do
|
160
|
+
capture(:rails, "runner \"puts '#{DBCONFIG_BEGIN_FLAG}' + ActiveRecord::Base.connection.instance_variable_get(:@config).to_yaml + '#{DBCONFIG_END_FLAG}'\"")
|
161
|
+
end
|
162
|
+
# Remove all warnings, errors and artefacts produced by bunlder, rails and other useful tools
|
163
|
+
config_content = dirty_config_content.match(/#{DBCONFIG_BEGIN_FLAG}(.*?)#{DBCONFIG_END_FLAG}/m)[1]
|
164
|
+
@config = YAML.load(config_content).inject({}) { |h, (k, v)| h[k.to_s] = v; h }
|
165
|
+
end
|
166
|
+
|
167
|
+
# cleanup = true removes the mysqldump file after loading, false leaves it in db/
|
168
|
+
def load(file, cleanup)
|
169
|
+
unzip_file = File.join(File.dirname(file), File.basename(file, ".#{compressor.file_extension}"))
|
170
|
+
# execute("bunzip2 -f #{file} && bundle exec rake db:drop db:create && #{import_cmd(unzip_file)} && bundle exec rake db:migrate")
|
171
|
+
@cap.info "executing local: #{compressor.decompress(file)}" && #{import_cmd(unzip_file)}"
|
172
|
+
execute("#{compressor.decompress(file)} && #{import_cmd(unzip_file)}")
|
173
|
+
if cleanup
|
174
|
+
@cap.info "removing #{unzip_file}"
|
175
|
+
File.unlink(unzip_file)
|
176
|
+
else
|
177
|
+
@cap.info "leaving #{unzip_file} (specify :db_local_clean in deploy.rb to remove)"
|
178
|
+
end
|
179
|
+
@cap.info "Completed database import"
|
180
|
+
end
|
181
|
+
|
182
|
+
def dump
|
183
|
+
execute "#{dump_cmd} | #{compressor.compress('-', output_file)}"
|
184
|
+
self
|
185
|
+
end
|
186
|
+
|
187
|
+
def upload
|
188
|
+
remote_file = "#{@cap.current_path}/#{output_file}"
|
189
|
+
@cap.upload! output_file, remote_file
|
190
|
+
end
|
191
|
+
|
192
|
+
private
|
193
|
+
|
194
|
+
def execute(cmd)
|
195
|
+
result = system cmd
|
196
|
+
@cap.error "Failed to execute the local command: #{cmd}" unless result
|
197
|
+
result
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
|
202
|
+
class << self
|
203
|
+
def check(local_db, remote_db)
|
204
|
+
unless (local_db.mysql? && remote_db.mysql?) || (local_db.postgresql? && remote_db.postgresql?)
|
205
|
+
raise 'Only mysql or postgresql on remote and local server is supported'
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
def remote_to_local(instance)
|
210
|
+
local_db = Database::Local.new(instance)
|
211
|
+
remote_db = Database::Remote.new(instance)
|
212
|
+
|
213
|
+
check(local_db, remote_db)
|
214
|
+
|
215
|
+
begin
|
216
|
+
remote_db.dump.download
|
217
|
+
ensure
|
218
|
+
remote_db.clean_dump_if_needed
|
219
|
+
end
|
220
|
+
local_db.load(remote_db.output_file, instance.fetch(:db_local_clean))
|
221
|
+
end
|
222
|
+
|
223
|
+
def local_to_remote(instance)
|
224
|
+
local_db = Database::Local.new(instance)
|
225
|
+
remote_db = Database::Remote.new(instance)
|
226
|
+
|
227
|
+
check(local_db, remote_db)
|
228
|
+
|
229
|
+
local_db.dump.upload
|
230
|
+
remote_db.load(local_db.output_file, instance.fetch(:db_local_clean))
|
231
|
+
File.unlink(local_db.output_file) if instance.fetch(:db_local_clean)
|
232
|
+
end
|
233
|
+
|
234
|
+
def backup(instance)
|
235
|
+
remote_db = Database::Remote.new(instance)
|
236
|
+
remote_db.dump
|
237
|
+
remote_db.download
|
238
|
+
end
|
239
|
+
|
240
|
+
def restore_latest(instance)
|
241
|
+
remote_db = Database::Remote.new(instance)
|
242
|
+
remote_db.load("#{instance.current_path}/db/latest.sql.#{remote_db.compressor.file_extension}", true)
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
require File.expand_path("#{File.dirname(__FILE__)}/util")
|
2
|
+
require File.expand_path("#{File.dirname(__FILE__)}/database")
|
3
|
+
require File.expand_path("#{File.dirname(__FILE__)}/asset")
|
4
|
+
require File.expand_path("#{File.dirname(__FILE__)}/compressors/base")
|
5
|
+
require File.expand_path("#{File.dirname(__FILE__)}/compressors/bzip2")
|
6
|
+
require File.expand_path("#{File.dirname(__FILE__)}/compressors/gzip")
|
7
|
+
|
8
|
+
set :local_rails_env, ENV['RAILS_ENV'] || 'development' unless fetch(:local_rails_env)
|
9
|
+
set :rails_env, fetch(:stage) || 'production' unless fetch(:rails_env)
|
10
|
+
set :db_local_clean, false unless fetch(:db_local_clean)
|
11
|
+
set :assets_dir, 'system' unless fetch(:assets_dir)
|
12
|
+
set :local_assets_dir, 'public' unless fetch(:local_assets_dir)
|
13
|
+
set :skip_data_sync_confirm, (ENV['SKIP_DATA_SYNC_CONFIRM'].to_s.downcase == 'true')
|
14
|
+
set :disallow_pushing, false unless fetch(:disallow_pushing)
|
15
|
+
set :compressor, :gzip unless fetch(:compressor)
|
16
|
+
|
17
|
+
namespace :capistrano_db_tasks do
|
18
|
+
task :check_can_push do
|
19
|
+
raise "pushing is disabled, set disallow_pushing to false to carry out this operation" if fetch(:disallow_pushing)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
namespace :db do
|
24
|
+
namespace :remote do
|
25
|
+
desc 'Synchronize your remote database using local database data'
|
26
|
+
task :sync => 'capistrano_db_tasks:check_can_push' do
|
27
|
+
on roles(:db) do
|
28
|
+
if fetch(:skip_data_sync_confirm) || Util.prompt('Are you sure you want to REPLACE THE REMOTE DATABASE with local database')
|
29
|
+
Database.local_to_remote(self)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
desc 'Dumps database to db folder after that we can take it from there'
|
35
|
+
task :backup do
|
36
|
+
on roles(:db) do
|
37
|
+
Database.backup(self)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
desc 'Restores the latest database dump from the remote folder (pairs with db:remote:backup)'
|
42
|
+
task :restore_latest do
|
43
|
+
on roles(:db) do
|
44
|
+
Database.restore_latest(self)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
namespace :local do
|
50
|
+
desc 'Synchronize your local database using remote database data'
|
51
|
+
task :sync do
|
52
|
+
on roles(:db) do
|
53
|
+
puts "Local database: #{Database::Local.new(self).database}"
|
54
|
+
if fetch(:skip_data_sync_confirm) || Util.prompt('Are you sure you want to erase your local database with server database')
|
55
|
+
Database.remote_to_local(self)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
desc 'Synchronize your local database using remote database data'
|
62
|
+
task :pull => "db:local:sync"
|
63
|
+
|
64
|
+
desc 'Synchronize your remote database using local database data'
|
65
|
+
task :push => "db:remote:sync"
|
66
|
+
end
|
67
|
+
|
68
|
+
namespace :assets do
|
69
|
+
namespace :remote do
|
70
|
+
desc 'Synchronize your remote assets using local assets'
|
71
|
+
task :sync => 'capistrano_db_tasks:check_can_push' do
|
72
|
+
on roles(:app) do
|
73
|
+
puts "Assets directories: #{fetch(:assets_dir)}"
|
74
|
+
if fetch(:skip_data_sync_confirm) || Util.prompt("Are you sure you want to erase your server assets with local assets")
|
75
|
+
Asset.local_to_remote(self)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
namespace :local do
|
82
|
+
desc 'Synchronize your local assets using remote assets'
|
83
|
+
task :sync do
|
84
|
+
on roles(:app) do
|
85
|
+
puts "Assets directories: #{fetch(:local_assets_dir)}"
|
86
|
+
if fetch(:skip_data_sync_confirm) || Util.prompt("Are you sure you want to erase your local assets with server assets")
|
87
|
+
Asset.remote_to_local(self)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
desc 'Synchronize your local assets using remote assets'
|
94
|
+
task :pull => "assets:local:sync"
|
95
|
+
|
96
|
+
desc 'Synchronize your remote assets using local assets'
|
97
|
+
task :push => "assets:remote:sync"
|
98
|
+
end
|
99
|
+
|
100
|
+
namespace :app do
|
101
|
+
namespace :remote do
|
102
|
+
desc 'Synchronize your remote assets AND database using local assets and database'
|
103
|
+
task :sync => 'capistrano_db_tasks:check_can_push' do
|
104
|
+
if fetch(:skip_data_sync_confirm) || Util.prompt("Are you sure you want to REPLACE THE REMOTE DATABASE AND your remote assets with local database and assets(#{fetch(:assets_dir)})")
|
105
|
+
on roles(:db) do
|
106
|
+
Database.local_to_remote(self)
|
107
|
+
end
|
108
|
+
|
109
|
+
on roles(:app) do
|
110
|
+
Asset.local_to_remote(self)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
namespace :local do
|
117
|
+
desc 'Synchronize your local assets AND database using remote assets and database'
|
118
|
+
task :sync do
|
119
|
+
puts "Local database : #{Database::Local.new(self).database}"
|
120
|
+
puts "Assets directories : #{fetch(:local_assets_dir)}"
|
121
|
+
if fetch(:skip_data_sync_confirm) || Util.prompt("Are you sure you want to erase your local database AND your local assets with server database and assets(#{fetch(:assets_dir)})")
|
122
|
+
on roles(:db) do
|
123
|
+
Database.remote_to_local(self)
|
124
|
+
end
|
125
|
+
|
126
|
+
on roles(:app) do
|
127
|
+
Asset.remote_to_local(self)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
desc 'Synchronize your local assets AND database using remote assets and database'
|
134
|
+
task :pull => "app:local:sync"
|
135
|
+
|
136
|
+
desc 'Synchronize your remote assets AND database using local assets and database'
|
137
|
+
task :push => "app:remote:sync"
|
138
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: capistrano-db-tasks.senya
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sebastien Gruhier
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-11-06 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: capistrano
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 3.0.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 3.0.0
|
27
|
+
description: A collection of capistrano tasks for syncing assets and databases
|
28
|
+
email:
|
29
|
+
- sebastien.gruhier@xilinus.com
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- Gemfile
|
35
|
+
- LICENSE
|
36
|
+
- README.markdown
|
37
|
+
- Rakefile
|
38
|
+
- capistrano-db-tasks.gemspec
|
39
|
+
- lib/capistrano-db-tasks.rb
|
40
|
+
- lib/capistrano-db-tasks/asset.rb
|
41
|
+
- lib/capistrano-db-tasks/compressors/base.rb
|
42
|
+
- lib/capistrano-db-tasks/compressors/bzip2.rb
|
43
|
+
- lib/capistrano-db-tasks/compressors/gzip.rb
|
44
|
+
- lib/capistrano-db-tasks/database.rb
|
45
|
+
- lib/capistrano-db-tasks/dbtasks.rb
|
46
|
+
- lib/capistrano-db-tasks/util.rb
|
47
|
+
- lib/capistrano-db-tasks/version.rb
|
48
|
+
- test/capistrano_db_tasks_test.rb
|
49
|
+
- test/test_helper.rb
|
50
|
+
homepage: https://github.com/cmrd-senya/capistrano-db-tasks/tree/dump_task.2
|
51
|
+
licenses: []
|
52
|
+
metadata: {}
|
53
|
+
post_install_message:
|
54
|
+
rdoc_options: []
|
55
|
+
require_paths:
|
56
|
+
- lib
|
57
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
requirements: []
|
68
|
+
rubyforge_project: capistrano-db-tasks
|
69
|
+
rubygems_version: 2.5.1
|
70
|
+
signing_key:
|
71
|
+
specification_version: 4
|
72
|
+
summary: A collection of capistrano tasks for syncing assets and databases (a modification
|
73
|
+
from Senya)
|
74
|
+
test_files: []
|
75
|
+
has_rdoc:
|