db-clone 2.0.0 → 2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/db/clone/base.rb +42 -40
- data/lib/db/clone/cmd_builder.rb +48 -46
- data/lib/db/clone/cmd_prompt.rb +35 -33
- data/lib/db/clone/rake_task.rb +12 -10
- data/lib/db/clone/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c090e84df3d16883f1600d89227986469a2daff1
|
4
|
+
data.tar.gz: 23b0f66de665e22a2f3c3cda6b16307bfde989da
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7e9d7498cce799c664c36c79da2705cb706d74828be76d1e6c88be24d2d05ecc2204ba5b7b5c9815d90da9d12cd907fcc6099ff4c601a593d79f5db12896b7d0
|
7
|
+
data.tar.gz: 841edcf55819ac435c93cb45aa8727575efa936a1d61544de7f870c16c8f139dd5fb37b5a20078f4cddb7893bae28132808c382d619afd974d448d46c042854a
|
data/README.md
CHANGED
@@ -16,7 +16,7 @@ db-clone requires `mysqldump` (for MySQL) and/or `pg_dump` (for PostgreSQL).
|
|
16
16
|
|
17
17
|
## Installation
|
18
18
|
|
19
|
-
Add to `gem 'db-clone', '~> 2.0'` to your `Gemfile` and `bundle install`.
|
19
|
+
Add to `gem 'db-clone', '~> 2.0', '>= 2.0.1'` to your `Gemfile` and `bundle install`.
|
20
20
|
|
21
21
|
## Usage
|
22
22
|
|
data/lib/db/clone/base.rb
CHANGED
@@ -1,59 +1,61 @@
|
|
1
|
-
module Db
|
2
|
-
|
3
|
-
|
1
|
+
module Db
|
2
|
+
module Clone
|
3
|
+
class Base
|
4
|
+
include CmdPrompt
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
6
|
+
def self.clone! invoke_cli
|
7
|
+
self.new.clone! invoke_cli
|
8
|
+
end
|
8
9
|
|
9
|
-
|
10
|
-
|
11
|
-
|
10
|
+
def initialize
|
11
|
+
@db_yml = YAML.load_file Db::Clone.database_yml_path
|
12
|
+
raise ArgumentError.new("#{Db::Clone.database_yml_path} does not have at least 2 database blocks.") unless @db_yml.length >= 2
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
14
|
+
@default_src = Db::Clone.default_source_database
|
15
|
+
@default_dest = Db::Clone.default_destination_database
|
16
|
+
end
|
16
17
|
|
17
|
-
|
18
|
-
|
18
|
+
def clone! invoke_cli
|
19
|
+
src_db, dest_db = invoke_cli ? prompt_for_src_and_dest : default_src_and_dest
|
19
20
|
|
20
|
-
|
21
|
+
cmd_builder = CmdBuilder.new src: @db_yml[src_db], dest: @db_yml[dest_db]
|
21
22
|
|
22
|
-
|
23
|
-
|
24
|
-
|
23
|
+
puts "\n Executing: #{cmd_builder.cmd.light_blue}\n\n"
|
24
|
+
exec cmd_builder.cmd
|
25
|
+
end
|
25
26
|
|
26
|
-
|
27
|
+
private
|
27
28
|
|
28
|
-
|
29
|
-
|
30
|
-
|
29
|
+
def prompt_for_src_and_dest
|
30
|
+
databases = @db_yml.keys.sort
|
31
|
+
default_src = databases.include?(@default_src) ? @default_src : databases.first
|
31
32
|
|
32
|
-
|
33
|
-
|
33
|
+
src_db = prompt 'Which is the source database?', default_src, databases.map{|name| [name, name.yellow]}.to_h
|
34
|
+
puts "Source database = #{src_db.green}"
|
34
35
|
|
35
|
-
|
36
|
-
|
36
|
+
databases.delete src_db
|
37
|
+
default_dest = src_db != @default_dest && databases.include?(@default_dest) ? @default_dest : databases.first
|
37
38
|
|
38
|
-
|
39
|
-
|
39
|
+
dest_db = prompt 'Which is the destination database?', default_dest, databases.map{|name| [name, name.yellow]}.to_h
|
40
|
+
puts "Destination database = #{dest_db.green}"
|
40
41
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
42
|
+
if dest_db == @default_src
|
43
|
+
proceed = ask_yes_no "#{'WARNING!'.black.on_yellow} You have selected #{@default_src.green} as your destination database, meaning that db-clone will overwrite it with the contents of your #{src_db.green} database. Do you want to proceed anyway?", false
|
44
|
+
unless proceed
|
45
|
+
puts "\nCloning #{'canceled'.red}."
|
46
|
+
abort
|
47
|
+
end
|
46
48
|
end
|
47
|
-
end
|
48
49
|
|
49
|
-
|
50
|
-
|
50
|
+
[src_db, dest_db]
|
51
|
+
end
|
51
52
|
|
52
|
-
|
53
|
-
|
54
|
-
|
53
|
+
def default_src_and_dest
|
54
|
+
raise ArgumentError.new("Configured default source database, #{@default_src}, does not exist in #{Db::Clone.database_yml_path}") unless @db_yml[@default_src]
|
55
|
+
raise ArgumentError.new("Configured default destination database, #{@default_dest}, does not exist in #{Db::Clone.database_yml_path}") unless @db_yml[@default_dest]
|
55
56
|
|
56
|
-
|
57
|
+
[@default_src, @default_dest]
|
58
|
+
end
|
57
59
|
end
|
58
60
|
end
|
59
61
|
end
|
data/lib/db/clone/cmd_builder.rb
CHANGED
@@ -1,56 +1,58 @@
|
|
1
|
-
module Db
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
module Db
|
2
|
+
module Clone
|
3
|
+
class CmdBuilder
|
4
|
+
VALID_DB_KEYS = ['host', 'port', 'username', 'database', 'password']
|
5
|
+
SUPPORTED_DBS = [:mysql, :postgresql]
|
5
6
|
|
6
|
-
|
7
|
+
attr_reader :cmd
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
9
|
+
def initialize selections
|
10
|
+
raise ArgumentError.new('Both source and destination must be set') unless selections[:src] && selections[:dest]
|
11
|
+
raise ArgumentError.new('Source and destination databases must be of the same type') unless selections[:src]['adapter'] == selections[:dest]['adapter']
|
12
|
+
SUPPORTED_DBS.each{|db| @db_type = db if selections[:src]['adapter'].include?(db.to_s)}
|
13
|
+
raise ArgumentError.new("Unsupported database: #{selections[:src]['adapter']}") unless @db_type
|
14
|
+
src_dest = selections.map{|k,v| [k,v.delete_if{|i,j| !VALID_DB_KEYS.include?(i)}]}.to_h
|
15
|
+
@cmd = send "build_#{@db_type}_cmd", src_dest
|
16
|
+
end
|
16
17
|
|
17
|
-
|
18
|
+
private
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
20
|
+
def build_mysql_cmd src_dest
|
21
|
+
mysqldump_args = [
|
22
|
+
"mysqldump --no-create-db --add-drop-table --lock-tables=false",
|
23
|
+
"--user=#{src_dest[:src]['username']}",
|
24
|
+
"--password=#{src_dest[:src]['password']}",
|
25
|
+
"--host=#{src_dest[:src]['host']}",
|
26
|
+
"--port=#{src_dest[:src]['port']}"
|
27
|
+
]
|
27
28
|
|
28
|
-
|
29
|
+
Db::Clone.ignore_tables.each{|tbl| mysqldump_args << "--ignore-table=#{src_dest[:src]['database']}.#{tbl}"}
|
29
30
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
31
|
+
(mysqldump_args + [
|
32
|
+
"#{src_dest[:src]['database']}",
|
33
|
+
"| mysql",
|
34
|
+
"--user=#{src_dest[:dest]['username']}",
|
35
|
+
"--password=#{src_dest[:dest]['password']}",
|
36
|
+
"--host=#{src_dest[:dest]['host']}",
|
37
|
+
"--port=#{src_dest[:dest]['port']}",
|
38
|
+
"#{src_dest[:dest]['database']}"
|
39
|
+
]).join(' ')
|
40
|
+
end
|
40
41
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
42
|
+
def build_postgresql_cmd src_dest
|
43
|
+
[
|
44
|
+
"pg_dump --no-password --clean",
|
45
|
+
"--host=#{src_dest[:src]['host']}",
|
46
|
+
"--port=#{src_dest[:src]['port']}",
|
47
|
+
"--username=#{src_dest[:src]['username']}",
|
48
|
+
"#{src_dest[:src]['database']}",
|
49
|
+
"| psql",
|
50
|
+
"--host=#{src_dest[:dest]['host']}",
|
51
|
+
"--port=#{src_dest[:dest]['port']}",
|
52
|
+
"--username=#{src_dest[:dest]['username']}",
|
53
|
+
"#{src_dest[:dest]['database']}"
|
54
|
+
].join(' ')
|
55
|
+
end
|
54
56
|
end
|
55
57
|
end
|
56
58
|
end
|
data/lib/db/clone/cmd_prompt.rb
CHANGED
@@ -1,42 +1,44 @@
|
|
1
|
-
module Db
|
2
|
-
module
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
1
|
+
module Db
|
2
|
+
module Clone
|
3
|
+
module CmdPrompt
|
4
|
+
# def ask_for_text instruction, default_text=nil
|
5
|
+
# if default_text
|
6
|
+
# print "\n#{instruction} [default = \"#{default_text}\"]: "
|
7
|
+
# else
|
8
|
+
# print "\n#{instruction}: "
|
9
|
+
# end
|
10
|
+
# text = STDIN.gets.chomp.strip
|
11
|
+
# text = default_text if text.blank? && default_text
|
12
|
+
# text
|
13
|
+
# end
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
15
|
+
def ask_yes_no question, default_to_yes=true
|
16
|
+
print "\n#{question} [#{default_to_yes ? 'Yn' : 'yN'}]: "
|
17
|
+
answer = STDIN.gets.chomp.strip.downcase
|
18
|
+
default_to_yes ? !(answer == 'n') : answer == 'y'
|
19
|
+
end
|
19
20
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
21
|
+
def prompt question, default, options={}
|
22
|
+
default_num = nil
|
23
|
+
numbered_opts = options.map.with_index do |opt, idx|
|
24
|
+
default_num = idx+1 if opt[0] == default
|
25
|
+
[idx+1, {ret_key: opt[0], label: opt[1]}]
|
26
|
+
end.to_h
|
26
27
|
|
27
|
-
|
28
|
-
|
28
|
+
puts "\n"
|
29
|
+
numbered_opts.each{|choice_num, opt| puts " [#{choice_num.to_s.white}] #{opt[:label]}" }
|
29
30
|
|
30
|
-
|
31
|
+
print "\n#{question} [1-#{options.length}, default=#{default_num}]: "
|
31
32
|
|
32
|
-
|
33
|
-
|
33
|
+
selection = STDIN.gets.chomp.strip.to_i
|
34
|
+
selection = default_num if selection.zero?
|
34
35
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
36
|
+
if numbered_opts.has_key? selection
|
37
|
+
numbered_opts[selection][:ret_key]
|
38
|
+
else
|
39
|
+
puts "#{'Invalid selection:'.red} #{selection}"
|
40
|
+
prompt question, default, options
|
41
|
+
end
|
40
42
|
end
|
41
43
|
end
|
42
44
|
end
|
data/lib/db/clone/rake_task.rb
CHANGED
@@ -1,15 +1,17 @@
|
|
1
|
-
module Db
|
2
|
-
|
3
|
-
|
1
|
+
module Db
|
2
|
+
module Clone
|
3
|
+
class RakeTask
|
4
|
+
include Rake::DSL if defined? Rake::DSL
|
4
5
|
|
5
|
-
|
6
|
-
|
6
|
+
def install_tasks
|
7
|
+
return unless defined? namespace
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
namespace :db do
|
10
|
+
desc 'clones a source database to a destination database'
|
11
|
+
task :clone, [:manual] => :environment do |t, args|
|
12
|
+
invoke_cli = !args[:manual].nil?
|
13
|
+
Db::Clone::Base.clone! invoke_cli
|
14
|
+
end
|
13
15
|
end
|
14
16
|
end
|
15
17
|
end
|
data/lib/db/clone/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: db-clone
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sean Huber
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-10-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: colorize
|