pg_export 0.6.1 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.rubocop.yml +9 -13
- data/.travis.yml +2 -2
- data/CHANGELOG.md +9 -0
- data/Gemfile +2 -0
- data/README.md +28 -29
- data/Rakefile +2 -0
- data/bin/console +2 -8
- data/bin/pg_export +44 -45
- data/lib/pg_export/build_logger.rb +4 -2
- data/lib/pg_export/configuration.rb +22 -2
- data/lib/pg_export/container.rb +48 -0
- data/lib/pg_export/import.rb +7 -0
- data/lib/pg_export/lib/pg_export/adapters/bash_adapter.rb +37 -0
- data/lib/pg_export/lib/pg_export/adapters/ftp_adapter.rb +67 -0
- data/lib/pg_export/lib/pg_export/entities/dump.rb +45 -0
- data/lib/pg_export/lib/pg_export/factories/cipher_factory.rb +32 -0
- data/lib/pg_export/lib/pg_export/factories/dump_factory.rb +31 -0
- data/lib/pg_export/lib/pg_export/factories/ftp_adapter_factory.rb +22 -0
- data/lib/pg_export/lib/pg_export/listeners/interactive/build_dump.rb +19 -0
- data/lib/pg_export/lib/pg_export/listeners/interactive/close_ftp_connection.rb +19 -0
- data/lib/pg_export/lib/pg_export/listeners/interactive/decrypt_dump.rb +19 -0
- data/lib/pg_export/lib/pg_export/listeners/interactive/download_dump_from_ftp.rb +19 -0
- data/lib/pg_export/lib/pg_export/listeners/interactive/encrypt_dump.rb +19 -0
- data/lib/pg_export/lib/pg_export/listeners/interactive/fetch_dumps_from_ftp.rb +19 -0
- data/lib/pg_export/lib/pg_export/listeners/interactive/open_ftp_connection.rb +19 -0
- data/lib/pg_export/lib/pg_export/listeners/interactive/remove_old_dumps_from_ftp.rb +23 -0
- data/lib/pg_export/lib/pg_export/listeners/interactive/restore.rb +19 -0
- data/lib/pg_export/lib/pg_export/listeners/interactive/upload_dump_to_ftp.rb +19 -0
- data/lib/pg_export/lib/pg_export/listeners/interactive_listener.rb +49 -0
- data/lib/pg_export/lib/pg_export/listeners/plain/build_dump.rb +15 -0
- data/lib/pg_export/lib/pg_export/listeners/plain/close_ftp_connection.rb +15 -0
- data/lib/pg_export/lib/pg_export/listeners/plain/decrypt_dump.rb +15 -0
- data/lib/pg_export/lib/pg_export/listeners/plain/download_dump_from_ftp.rb +15 -0
- data/lib/pg_export/lib/pg_export/listeners/plain/encrypt_dump.rb +15 -0
- data/lib/pg_export/lib/pg_export/listeners/plain/fetch_dumps_from_ftp.rb +15 -0
- data/lib/pg_export/lib/pg_export/listeners/plain/open_ftp_connection.rb +15 -0
- data/lib/pg_export/lib/pg_export/listeners/plain/remove_old_dumps_from_ftp.rb +17 -0
- data/lib/pg_export/lib/pg_export/listeners/plain/restore.rb +15 -0
- data/lib/pg_export/lib/pg_export/listeners/plain/upload_dump_to_ftp.rb +15 -0
- data/lib/pg_export/lib/pg_export/listeners/plain_listener.rb +17 -0
- data/lib/pg_export/lib/pg_export/operations/decrypt_dump.rb +20 -0
- data/lib/pg_export/lib/pg_export/operations/encrypt_dump.rb +18 -0
- data/lib/pg_export/lib/pg_export/operations/open_ftp_connection.rb +19 -0
- data/lib/pg_export/lib/pg_export/operations/remove_old_dumps_from_ftp.rb +22 -0
- data/lib/pg_export/lib/pg_export/repositories/ftp_dump_file_repository.rb +19 -0
- data/lib/pg_export/lib/pg_export/repositories/ftp_dump_repository.rb +36 -0
- data/lib/pg_export/lib/pg_export/transactions/export_dump.rb +56 -0
- data/lib/pg_export/lib/pg_export/transactions/import_dump_interactively.rb +67 -0
- data/lib/pg_export/lib/pg_export/types.rb +14 -0
- data/lib/pg_export/lib/pg_export/ui/interactive/input.rb +36 -0
- data/lib/pg_export/lib/pg_export/ui/plain/input.rb +17 -0
- data/lib/pg_export/lib/pg_export/value_objects/dump_file.rb +70 -0
- data/lib/pg_export/system/boot/config.rb +11 -0
- data/lib/pg_export/system/boot/interactive.rb +32 -0
- data/lib/pg_export/system/boot/logger.rb +15 -0
- data/lib/pg_export/system/boot/plain.rb +33 -0
- data/lib/pg_export/version.rb +3 -1
- data/lib/pg_export.rb +23 -20
- data/pg_export.gemspec +13 -10
- metadata +108 -52
- data/lib/pg_export/aes/base.rb +0 -47
- data/lib/pg_export/aes/decryptor.rb +0 -13
- data/lib/pg_export/aes/encryptor.rb +0 -13
- data/lib/pg_export/aes.rb +0 -3
- data/lib/pg_export/bash/adapter.rb +0 -31
- data/lib/pg_export/bash/factory.rb +0 -23
- data/lib/pg_export/bash/repository.rb +0 -18
- data/lib/pg_export/boot_container.rb +0 -69
- data/lib/pg_export/dump.rb +0 -62
- data/lib/pg_export/errors.rb +0 -5
- data/lib/pg_export/ftp/adapter.rb +0 -41
- data/lib/pg_export/ftp/connection.rb +0 -40
- data/lib/pg_export/ftp/repository.rb +0 -40
- data/lib/pg_export/roles/colourable_string.rb +0 -19
- data/lib/pg_export/roles/human_readable.rb +0 -17
- data/lib/pg_export/roles/interactive.rb +0 -98
- data/lib/pg_export/roles/validatable.rb +0 -24
- data/lib/pg_export/services/create_and_export_dump.rb +0 -20
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# auto_register: false
|
4
|
+
|
5
|
+
require 'dry/transaction'
|
6
|
+
|
7
|
+
require 'pg_export/import'
|
8
|
+
require 'pg_export/container'
|
9
|
+
|
10
|
+
class PgExport
|
11
|
+
module Transactions
|
12
|
+
class ImportDumpInteractively
|
13
|
+
include Dry::Transaction(container: PgExport::Container)
|
14
|
+
include Import[
|
15
|
+
'adapters.bash_adapter',
|
16
|
+
'repositories.ftp_dump_repository',
|
17
|
+
'repositories.ftp_dump_file_repository',
|
18
|
+
'ui_input'
|
19
|
+
]
|
20
|
+
|
21
|
+
step :open_ftp_connection, with: 'operations.open_ftp_connection'
|
22
|
+
step :fetch_dumps_from_ftp
|
23
|
+
step :select_dump
|
24
|
+
step :download_dump_from_ftp
|
25
|
+
step :close_ftp_connection
|
26
|
+
step :decrypt_dump, with: 'operations.decrypt_dump'
|
27
|
+
step :select_database
|
28
|
+
step :restore
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def fetch_dumps_from_ftp(database_name:, ftp_adapter:)
|
33
|
+
dumps = ftp_dump_repository.all(database_name: database_name, ftp_adapter: ftp_adapter)
|
34
|
+
return Failure(message: 'No dumps') if dumps.none?
|
35
|
+
|
36
|
+
Success(ftp_adapter: ftp_adapter, dumps: dumps)
|
37
|
+
end
|
38
|
+
|
39
|
+
def select_dump(dumps:, ftp_adapter:)
|
40
|
+
dump = ui_input.select_dump(dumps)
|
41
|
+
Success(dump: dump, ftp_adapter: ftp_adapter)
|
42
|
+
end
|
43
|
+
|
44
|
+
def download_dump_from_ftp(dump:, ftp_adapter:)
|
45
|
+
dump.file = ftp_dump_file_repository.by_name(name: dump.name, ftp_adapter: ftp_adapter)
|
46
|
+
Success(dump: dump, ftp_adapter: ftp_adapter)
|
47
|
+
end
|
48
|
+
|
49
|
+
def close_ftp_connection(dump:, ftp_adapter:)
|
50
|
+
Thread.new { ftp_adapter.close_ftp }
|
51
|
+
Success(dump: dump)
|
52
|
+
end
|
53
|
+
|
54
|
+
def select_database(dump:)
|
55
|
+
name = ui_input.enter_database_name(dump.database)
|
56
|
+
Success(dump: dump, database: name)
|
57
|
+
end
|
58
|
+
|
59
|
+
def restore(dump:, database:)
|
60
|
+
bash_adapter.pg_restore(dump.file, database)
|
61
|
+
Success({})
|
62
|
+
rescue bash_adapter.class::PgRestoreError => e
|
63
|
+
Failure(message: e.to_s)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'dry-types'
|
4
|
+
require 'pg_export/lib/pg_export/value_objects/dump_file'
|
5
|
+
|
6
|
+
class PgExport
|
7
|
+
module Types
|
8
|
+
include Dry::Types.module
|
9
|
+
|
10
|
+
DumpName = Strict::String.constrained(format: /.+_20[0-9]{6}_[0-9]{6}\Z/)
|
11
|
+
DumpType = Types::Coercible::String.enum('plain', 'encrypted')
|
12
|
+
DumpFile = Types.Instance(PgExport::ValueObjects::DumpFile)
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'tty-prompt'
|
4
|
+
|
5
|
+
class PgExport
|
6
|
+
module Ui
|
7
|
+
module Interactive
|
8
|
+
class Input
|
9
|
+
def select_dump(dumps)
|
10
|
+
idx = prompt.select('Select dump to import:') do |menu|
|
11
|
+
menu.enum '.'
|
12
|
+
dumps.each_with_index do |d, i|
|
13
|
+
menu.choice(d.to_s, i)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
dumps[idx]
|
18
|
+
end
|
19
|
+
|
20
|
+
def enter_database_name(default = nil)
|
21
|
+
puts 'To which database would you like to restore the downloaded dump?'
|
22
|
+
prompt.ask('Enter a local database name:') do |q|
|
23
|
+
q.required(true)
|
24
|
+
q.default(default) if default
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def prompt
|
31
|
+
TTY::Prompt.new
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'tempfile'
|
4
|
+
|
5
|
+
class PgExport
|
6
|
+
module ValueObjects
|
7
|
+
class DumpFile
|
8
|
+
def initialize(file = Tempfile.new)
|
9
|
+
@file = file
|
10
|
+
end
|
11
|
+
|
12
|
+
def path
|
13
|
+
file.path
|
14
|
+
end
|
15
|
+
|
16
|
+
def size
|
17
|
+
file.size
|
18
|
+
end
|
19
|
+
|
20
|
+
def rewind
|
21
|
+
file.rewind
|
22
|
+
end
|
23
|
+
|
24
|
+
def read
|
25
|
+
file.read
|
26
|
+
end
|
27
|
+
|
28
|
+
def copy(cipher:)
|
29
|
+
cipher.reset
|
30
|
+
new_self = self.class.new
|
31
|
+
new_self.write do |f|
|
32
|
+
each_chunk do |chunk|
|
33
|
+
f << cipher.update(chunk)
|
34
|
+
end
|
35
|
+
f << cipher.final
|
36
|
+
end
|
37
|
+
|
38
|
+
new_self
|
39
|
+
end
|
40
|
+
|
41
|
+
def write(&block)
|
42
|
+
File.open(path, 'w', &block)
|
43
|
+
end
|
44
|
+
|
45
|
+
def each_chunk
|
46
|
+
File.open(path, 'r') do |file|
|
47
|
+
yield file.read(CHUNK_SIZE) until file.eof?
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def size_human
|
52
|
+
MAPPING.each_pair { |e, s| return "#{(size.to_f / (s / 1024)).round(2)}#{e}" if size < s }
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
CHUNK_SIZE = (2**16).freeze
|
58
|
+
MAPPING = {
|
59
|
+
'B' => 1024,
|
60
|
+
'kB' => 1024 * 1024,
|
61
|
+
'MB' => 1024 * 1024 * 1024,
|
62
|
+
'GB' => 1024 * 1024 * 1024 * 1024,
|
63
|
+
'TB' => 1024 * 1024 * 1024 * 1024 * 1024
|
64
|
+
}.freeze
|
65
|
+
private_constant :CHUNK_SIZE, :MAPPING
|
66
|
+
|
67
|
+
attr_reader :file
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
PgExport::Container.boot(:interactive) do
|
4
|
+
init do
|
5
|
+
require 'pg_export/lib/pg_export/transactions/import_dump_interactively'
|
6
|
+
end
|
7
|
+
|
8
|
+
start do
|
9
|
+
use :main
|
10
|
+
|
11
|
+
# type = 'plain'
|
12
|
+
type = 'interactive'
|
13
|
+
|
14
|
+
transaction = PgExport::Transactions::ImportDumpInteractively.new(ui_input: target["ui.#{type}.input"])
|
15
|
+
|
16
|
+
unless target[:config].logger_muted?
|
17
|
+
use :logger
|
18
|
+
|
19
|
+
%i[
|
20
|
+
open_ftp_connection
|
21
|
+
fetch_dumps_from_ftp
|
22
|
+
download_dump_from_ftp
|
23
|
+
decrypt_dump
|
24
|
+
restore
|
25
|
+
].each do |step|
|
26
|
+
transaction.subscribe(step => target["listeners.#{type}.#{step}"])
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
register('transactions.import_dump_interactively', memoize: true) { transaction }
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
PgExport::Container.boot :logger do
|
4
|
+
init do
|
5
|
+
require 'pg_export/build_logger'
|
6
|
+
end
|
7
|
+
|
8
|
+
start do
|
9
|
+
use :config
|
10
|
+
|
11
|
+
register(:logger, memoize: true) do
|
12
|
+
PgExport::BuildLogger.call(stream: $stdout, format: target[:config].logger_format)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
PgExport::Container.boot(:plain) do
|
4
|
+
init do
|
5
|
+
require 'pg_export/lib/pg_export/transactions/export_dump'
|
6
|
+
end
|
7
|
+
|
8
|
+
start do
|
9
|
+
use :main
|
10
|
+
|
11
|
+
transaction = PgExport::Transactions::ExportDump.new
|
12
|
+
|
13
|
+
unless target[:config].logger_muted?
|
14
|
+
use :logger
|
15
|
+
|
16
|
+
type = 'plain'
|
17
|
+
# type = 'interactive'
|
18
|
+
|
19
|
+
%i[
|
20
|
+
build_dump
|
21
|
+
encrypt_dump
|
22
|
+
open_ftp_connection
|
23
|
+
upload_dump_to_ftp
|
24
|
+
remove_old_dumps_from_ftp
|
25
|
+
close_ftp_connection
|
26
|
+
].each do |step|
|
27
|
+
transaction.subscribe(step => target["listeners.#{type}.#{step}"])
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
register('transactions.export_dump', memoize: true) { transaction }
|
32
|
+
end
|
33
|
+
end
|
data/lib/pg_export/version.rb
CHANGED
data/lib/pg_export.rb
CHANGED
@@ -1,29 +1,32 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require '
|
4
|
-
require 'pg_export/
|
5
|
-
require 'pg_export/errors'
|
6
|
-
require 'pg_export/roles/validatable'
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'pry'
|
4
|
+
require 'pg_export/container'
|
7
5
|
|
8
6
|
class PgExport
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
7
|
+
class InitializationError < StandardError; end
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def interactive
|
11
|
+
PgExport::Container.start(:interactive)
|
12
|
+
new(transaction: PgExport::Container['transactions.import_dump_interactively'])
|
13
|
+
end
|
14
|
+
|
15
|
+
def plain
|
16
|
+
PgExport::Container.start(:plain)
|
17
|
+
new(transaction: PgExport::Container['transactions.export_dump'])
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(transaction:)
|
22
|
+
@transaction = transaction
|
17
23
|
end
|
18
24
|
|
19
|
-
def call(database_name,
|
20
|
-
|
21
|
-
validate_database_name(database_name),
|
22
|
-
validate_keep_dumps(keep_dumps)
|
23
|
-
)
|
25
|
+
def call(database_name, &block)
|
26
|
+
transaction.call(database_name: database_name, &block)
|
24
27
|
end
|
25
28
|
|
26
29
|
private
|
27
30
|
|
28
|
-
attr_reader :
|
31
|
+
attr_reader :transaction
|
29
32
|
end
|
data/pg_export.gemspec
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
3
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
5
|
require 'pg_export/version'
|
5
6
|
|
@@ -18,16 +19,18 @@ Gem::Specification.new do |spec|
|
|
18
19
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
19
20
|
spec.executables = ['pg_export']
|
20
21
|
spec.require_paths = ['lib']
|
21
|
-
spec.required_ruby_version = '>= 2.
|
22
|
+
spec.required_ruby_version = '>= 2.3.0'
|
22
23
|
|
23
|
-
spec.add_dependency '
|
24
|
-
spec.add_dependency 'dry-
|
25
|
-
spec.add_dependency 'dry-
|
24
|
+
spec.add_dependency 'dry-initializer', '~> 2.5.0'
|
25
|
+
spec.add_dependency 'dry-system', '~> 0.10.0'
|
26
|
+
spec.add_dependency 'dry-transaction', '~> 0.13.0'
|
27
|
+
spec.add_dependency 'tty-prompt'
|
28
|
+
spec.add_dependency 'tty-spinner'
|
26
29
|
|
27
|
-
spec.add_development_dependency 'bundler', '~> 1.
|
28
|
-
spec.add_development_dependency '
|
30
|
+
spec.add_development_dependency 'bundler', '~> 1.16'
|
31
|
+
spec.add_development_dependency 'pg', '~> 0.21'
|
32
|
+
spec.add_development_dependency 'pry'
|
29
33
|
spec.add_development_dependency 'rake', '~> 10.0'
|
30
34
|
spec.add_development_dependency 'rspec', '~> 3.4'
|
31
|
-
spec.add_development_dependency '
|
32
|
-
spec.add_development_dependency 'pry'
|
35
|
+
spec.add_development_dependency 'rubocop', '~> 0.59.2'
|
33
36
|
end
|