db-clone 2.0.0 → 2.0.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 +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
|