pg_export 1.0.0.rc5 → 1.0.0.rc6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +19 -4
  3. data/CHANGELOG.md +7 -5
  4. data/README.md +46 -24
  5. data/bin/pg_export +27 -29
  6. data/lib/pg_export/configuration.rb +70 -18
  7. data/lib/pg_export/factory.rb +148 -0
  8. data/lib/pg_export/lib/pg_export/adapters/{bash_adapter.rb → shell_adapter.rb} +1 -1
  9. data/lib/pg_export/lib/pg_export/entities/dump.rb +22 -10
  10. data/lib/pg_export/lib/pg_export/factories/cipher_factory.rb +8 -4
  11. data/lib/pg_export/lib/pg_export/factories/dump_factory.rb +0 -1
  12. data/lib/pg_export/lib/pg_export/factories/ftp_gateway_factory.rb +7 -4
  13. data/lib/pg_export/lib/pg_export/factories/ssh_gateway_factory.rb +7 -4
  14. data/lib/pg_export/lib/pg_export/gateways/ftp.rb +1 -3
  15. data/lib/pg_export/lib/pg_export/gateways/ssh.rb +2 -6
  16. data/lib/pg_export/lib/pg_export/listeners/interactive/build_dump.rb +1 -1
  17. data/lib/pg_export/lib/pg_export/listeners/interactive/close_connection.rb +1 -1
  18. data/lib/pg_export/lib/pg_export/listeners/interactive/remove_old_dumps.rb +1 -1
  19. data/lib/pg_export/lib/pg_export/listeners/interactive/restore.rb +1 -1
  20. data/lib/pg_export/lib/pg_export/listeners/interactive/upload_dump.rb +1 -1
  21. data/lib/pg_export/lib/pg_export/listeners/interactive_listener.rb +4 -3
  22. data/lib/pg_export/lib/pg_export/listeners/plain/prepare_params.rb +1 -1
  23. data/lib/pg_export/lib/pg_export/listeners/plain_listener.rb +11 -5
  24. data/lib/pg_export/lib/pg_export/operations/decrypt_dump.rb +16 -6
  25. data/lib/pg_export/lib/pg_export/operations/encrypt_dump.rb +14 -5
  26. data/lib/pg_export/lib/pg_export/operations/open_connection.rb +14 -5
  27. data/lib/pg_export/lib/pg_export/operations/remove_old_dumps.rb +14 -6
  28. data/lib/pg_export/lib/pg_export/repositories/gateway_dump_file_repository.rb +0 -1
  29. data/lib/pg_export/lib/pg_export/repositories/gateway_dump_repository.rb +2 -7
  30. data/lib/pg_export/lib/pg_export/transactions/evaluator.rb +59 -0
  31. data/lib/pg_export/lib/pg_export/transactions/export_dump.rb +27 -21
  32. data/lib/pg_export/lib/pg_export/transactions/import_dump_interactively.rb +31 -29
  33. data/lib/pg_export/lib/pg_export/value_objects/dump_file.rb +2 -2
  34. data/lib/pg_export/lib/pg_export/value_objects/result.rb +49 -0
  35. data/lib/pg_export/version.rb +1 -1
  36. data/lib/pg_export.rb +13 -8
  37. data/pg_export.gemspec +1 -6
  38. metadata +13 -89
  39. data/lib/pg_export/container.rb +0 -23
  40. data/lib/pg_export/import.rb +0 -7
  41. data/lib/pg_export/lib/pg_export/types.rb +0 -14
  42. data/lib/pg_export/system/boot/config.rb +0 -27
  43. data/lib/pg_export/system/boot/ftp.rb +0 -11
  44. data/lib/pg_export/system/boot/interactive.rb +0 -16
  45. data/lib/pg_export/system/boot/operations.rb +0 -17
  46. data/lib/pg_export/system/boot/plain.rb +0 -16
  47. data/lib/pg_export/system/boot/ssh.rb +0 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b927b4b2f8c0ca36682a15ae9f90aa975980d9d3874989f7ab19fe256fcecb7d
4
- data.tar.gz: b653c480d52143bf58864f7904a404a21802aa389e9b24ee9f271dbafa064969
3
+ metadata.gz: ca033b9c62cc381584bd9696e9607b63d89f52310a5847b714908c7140e755dc
4
+ data.tar.gz: 755e0fa8760fa1ba6b2d3d8af65532da26b9a8978b5005853d9aaede8131d748
5
5
  SHA512:
6
- metadata.gz: c1ae01b513f51ef4675b1dbae7337ac6ffe11d3ca481bf272ea6338e1f1b1bcd5fb75b240aefdcc12117e721a6097e945b1832af56344ac232ebfad55a5e98db
7
- data.tar.gz: 31dc4ab7b943ce973f14b6a42867d388fa18a8c8f56d52bd9c0e5e30b241258555e804a4d59b53ed9d409fae8d7a8aa8ad8a130356383b66cbbbc4b1a1b75aba
6
+ metadata.gz: 01a50e23dff7a059c606aaff6ea744f3ee3da607ffcf5062514c447a0f9413386a7df378ae7467ff9e35745b65d5a78fa96c6e9abf93b6cff2d8dc4fa9be5e55
7
+ data.tar.gz: a32e7517a57dcc5eee39c40334ea5552709930d2e5bd402eaf55e67c96625b528aa40f99ef2ee5cdbacae8ad052250d2122f87eb83705ab85fa41599a755fff0
data/.rubocop.yml CHANGED
@@ -6,17 +6,32 @@ Metrics/BlockLength:
6
6
  - 'bin/pg_export'
7
7
  ExcludedMethods: ['describe', 'context']
8
8
 
9
- Metrics/LineLength:
10
- Max: 200
9
+ Layout/LineLength:
10
+ Max: 140
11
11
 
12
12
  Style/ParallelAssignment:
13
13
  Enabled: false
14
14
 
15
- Naming/UncommunicativeMethodParamName:
15
+ Naming/MethodParameterName:
16
16
  Enabled: false
17
17
 
18
- Documentation:
18
+ Style/Documentation:
19
19
  Enabled: false
20
20
 
21
21
  Lint/UnusedMethodArgument:
22
22
  Enabled: false
23
+
24
+ Metrics/MethodLength:
25
+ Max: 50
26
+
27
+ Metrics/CyclomaticComplexity:
28
+ Max: 30
29
+
30
+ Style/TrailingCommaInHashLiteral:
31
+ Enabled: false
32
+
33
+ Metrics/AbcSize:
34
+ Max: 30
35
+
36
+ Metrics/PerceivedComplexity:
37
+ Max: 30
data/CHANGELOG.md CHANGED
@@ -1,4 +1,4 @@
1
- ### 1.0.0 - 2021.03.20
1
+ ### 1.0.0 - 2022.05.17
2
2
  - Make it compatible with Ruby 3.0
3
3
  - Change configuration envs:
4
4
  - BACKUP_FTP_HOST -> PG_EXPORT_GATEWAY_HOST
@@ -7,15 +7,17 @@
7
7
  - DUMP_ENCRYPTION_KEY -> PG_EXPORT_ENCRYPTION_KEY
8
8
  - Drop Ruby 2.3 support
9
9
  - Add SSH option
10
- - Add +encryption_algorith+ moption to interface
10
+ - Add `encryption_algorithm` option to interface
11
+ - Remove dry libraries dependencies
12
+ - in case of failure bin/pg_export now returns with 1 exit value
11
13
 
12
14
  ### 0.7.7 - 2020.09.07
13
15
 
14
- - Upgrade dry-initializer
16
+ - Upgrade dry-initializer
15
17
 
16
18
  ### 0.7.6 - 2020.09.05
17
19
 
18
- - Upgrade dry-types, dry-struct dry-system
20
+ - Upgrade dry-types, dry-struct dry-system
19
21
 
20
22
  ### 0.7.0 - 2018.10.18
21
23
 
@@ -41,7 +43,7 @@
41
43
 
42
44
  ### 0.5.0 - 2017.03.11
43
45
 
44
- - Add restriction on DUMP_ENCRYPTION_KEY, to be exactly 16 characters length
46
+ - Add restriction on DUMP_ENCRYPTION_KEY, to be exactly 16 characters length
45
47
  - Make interactive mode more verbose by adding more messages
46
48
  - Fix concurrently opening ftp connection
47
49
  - Add closing ftp connection while importing dump in interactive mode
data/README.md CHANGED
@@ -11,7 +11,7 @@ Can be used for backups or synchronizing databases between production and develo
11
11
  Example:
12
12
 
13
13
  pg_export --database database_name --keep 5
14
-
14
+
15
15
  Above command will perform database dump, encrypt it, upload it to FTP and remove old dumps from FTP, keeping newest 5.
16
16
 
17
17
  FTP connection params and encryption key are configured by env variables.
@@ -50,20 +50,38 @@ Or install it yourself as:
50
50
 
51
51
  $ pg_export -h
52
52
 
53
- Usage: pg_export [options]
54
- -g, --gateway GATEWAY [Optional] ssh or ftp (default: ftp)
55
- -d, --database DATABASE [Required] Name of the database to export
56
- -k, --keep [KEEP] [Optional] Number of dump files to keep on FTP (default: 10)
57
- -t, --timestamped [Optional] Enables log messages with timestamps
58
- -m, --muted [Optional] Mutes log messages (overrides -t option)
59
- -i, --interactive [Optional] Interactive command line mode - for restoring dumps into databases
60
- -v, --version Show version
61
- -h, --help Show this message
62
-
63
- Setting can be verified by running following commands:
64
- -c, --configuration Prints the configuration
65
- -w, --welcome Tries connecting to the gateway (FTP or SSH) to verify the connection
66
-
53
+ SYNOPSIS
54
+ pg_export DATABASE [OPTION..]
55
+ pg_export --interactive DATABASE [OPTION..]
56
+
57
+ ARGUMENTS
58
+ DATABASE - database name to export (when default mode)
59
+ - phrase to filter database dumps by (when interactive mode)
60
+
61
+ OPTIONS
62
+ -g, --gateway GATEWAY Allowed values: ftp, ssh. Default: ftp. Credentials need to be set via ENVs
63
+ -s, --ssh Same as "--gateway ssh"
64
+ -f, --ftp Same as "--gateway ftp"
65
+ -d, --database DATABASE Alternative way of specifying name of the database to export or phrase to filter by
66
+ -e, --encryption_key KEY Dumps will be SSL encrypted using this key. Should have exactly 16 characters. Overwrites PG_EXPORT_ENCRYPTION_KEY env
67
+ -a, --algorithm ALGORITHM Encryption cipher algorithm (default: AES-128-CBC). Overwrites PG_EXPORT_ENCRYPTION_ALGORITHM env. For available option see `$ openssl list -cipher-algorithms`
68
+ -k, --keep KEEP Number of dump files to keep on FTP (default: 10). Overwrites KEEP_DUMPS env
69
+ -t, --timestamped Enables log messages with timestamps
70
+ -m, --muted Mutes log messages (overrides -t option)
71
+ -i, --interactive Interactive mode, for importing dumps
72
+ -v, --version Show version
73
+ -h, --help Show this message
74
+
75
+ ENV
76
+ PG_EXPORT_GATEWAY_HOST required
77
+ PG_EXPORT_GATEWAY_USER required
78
+ PG_EXPORT_GATEWAY_PASSWORD optional when eg. authorized key is added
79
+ PG_EXPORT_ENCRYPTION_KEY required or set by --encryption_key)
80
+ PG_EXPORT_ENCRYPTION_ALGORITHM required or set by --algorithm)
81
+
82
+ TEST RUN
83
+ -c, --configuration Print the configuration
84
+ -w, --welcome Try connecting to the gateway (FTP or SSH) to verify the connection
67
85
 
68
86
  ## How to start
69
87
 
@@ -73,28 +91,32 @@ __Step 1.__ Prepare ENV variables.
73
91
  PG_EXPORT_GATEWAY_HOST=yourftp.example.com
74
92
  PG_EXPORT_GATEWAY_USER=user
75
93
  PG_EXPORT_GATEWAY_PASSWORD=password
76
-
94
+
77
95
  /* Encryption key should have exactly 16 characters. */
78
96
  /* Dumps will be SSL(AES-128-CBC) encrypted using this key. */
79
97
  PG_EXPORT_ENCRYPTION_KEY=1234567890abcdef
80
-
98
+
81
99
  /* Dumps to be kept on FTP */
82
100
  /* Optional, defaults to 10 */
83
101
  KEEP_DUMPS=5
84
-
85
- Note, that variables cannot include `#` sign, [more info](http://serverfault.com/questions/539730/environment-variable-in-etc-environment-with-pound-hash-sign-in-the-value).
102
+
103
+ Note, that variables cannot include `#` sign, [more info](http://serverfault.com/questions/539730/environment-variable-in-etc-environment-with-pound-hash-sign-in-the-value).
86
104
 
87
105
  __Step 2.__ Print the configuration to verify if env variables has been loaded properly.
88
106
 
89
107
  $ pg_export --configuration
90
- => {:encryption_key=>"k4***", :gateway_host=>"yourftp.example.com", :gateway_user=>"your_gateway_user",
91
- :gateway_password=>"pass***", :logger_format=>"plain", :keep_dumps=>2}
92
-
108
+ => encryption_key k4***
109
+ gateway_host yourftp.example.com
110
+ gateway_user your_gateway_user
111
+ gateway_password pass***
112
+ logger_format plain
113
+ keep_dumps 2
114
+
93
115
  __Step 3.__ Try connecting to FTP to verify the connection.
94
116
 
95
117
  $ pg_export --gateway ftp --welcome
96
118
  => 230 User your_ftp_user logged in
97
-
119
+
98
120
  __Step 4.__ Perform database export.
99
121
 
100
122
  $ pg_export -d your_database [-k 5]
@@ -103,7 +125,7 @@ __Step 4.__ Perform database export.
103
125
  Connect to yourftp.example.com
104
126
  Upload your_database_20181016_121314 (1.34MB) to yourftp.example.com
105
127
  Close FTP
106
-
128
+
107
129
  ## How to restore a dump?
108
130
 
109
131
  Run interactive mode and follow the instructions:
data/bin/pg_export CHANGED
@@ -1,28 +1,27 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'optparse'
4
+ lib = File.expand_path('../lib', __dir__)
5
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
6
 
7
+ require 'optparse'
6
8
  require 'pg_export'
7
- require 'pg_export/version'
8
-
9
- ENV['KEEP_DUMPS'] = ENV['KEEP_DUMPS'] || '10'
10
- ENV['GATEWAY'] = 'ftp'
11
- ENV['PG_EXPORT_MODE'] = 'plain'
12
- ENV['PG_EXPORT_ENCRYPTION_ALGORITHM'] = 'AES-128-CBC'
13
9
 
14
10
  database = nil
11
+ x = nil
15
12
 
16
13
  option_parser = OptionParser.new do |opts|
17
14
  opts.banner = <<~TXT
18
15
  NAME
19
16
  pg_export - CLI for exporting/importing PostgreSQL dumps via FTP/SSH
20
17
 
21
- SYNOPSIS (default mode)
22
- pg_export DATABASE [options]
18
+ SYNOPSIS
19
+ pg_export DATABASE [OPTION..]
20
+ pg_export --interactive DATABASE [OPTION..]
23
21
 
24
- SYNOPSIS (interactive mode)
25
- pg_export --interactive [DATABASE] [options]
22
+ EXIT VALUES
23
+ 0 - Success
24
+ 1 - Error
26
25
 
27
26
  ARGUMENTS
28
27
  DATABASE - database name to export (when default mode)
@@ -97,18 +96,11 @@ option_parser = OptionParser.new do |opts|
97
96
  opts.separator "\nTEST RUN"
98
97
 
99
98
  opts.on('-c', '--configuration', 'Print the configuration') do
100
- require 'pg_export/container'
101
- PgExport::Container.start(:config)
102
- puts PgExport::Container['config'].to_h
103
- exit
99
+ x = -> { puts PgExport.new.config }
104
100
  end
105
101
 
106
102
  opts.on('-w', '--welcome', 'Try connecting to the gateway (FTP or SSH) to verify the connection') do
107
- require 'pg_export/container'
108
- PgExport::Container.start(ENV['GATEWAY'].to_sym)
109
- gateway = PgExport::Container['factories.gateway_factory'].gateway
110
- puts gateway.welcome
111
- exit
103
+ x = -> { puts PgExport.new.gateway_welcome }
112
104
  end
113
105
 
114
106
  if ARGV.empty?
@@ -119,30 +111,36 @@ end
119
111
 
120
112
  begin
121
113
  option_parser.parse!
114
+ if x
115
+ x.call
116
+ exit
117
+ end
122
118
  database = ARGV.first unless ARGV.empty?
123
119
  rescue OptionParser::ParseError => e
124
120
  warn e.message.capitalize
125
121
  warn 'Details:'
126
122
  warn option_parser.to_s.split("\n").grep(/ #{e.args.first}/).join("\n")
127
123
  warn 'Type "pg_export" for available options'
128
- exit
124
+ exit 1
129
125
  end
130
126
 
131
- require 'pg_export/container'
132
-
133
127
  begin
134
- pg_export = PgExport.boot
128
+ pg_export = PgExport.new
135
129
  rescue PgExport::InitializationError => e
136
130
  warn 'Unable to initialize PgExport due to invalid configuration. Check you ENVs.'
137
131
  warn "Detailed message: #{e.message}"
138
- exit
132
+ exit 1
139
133
  end
140
134
 
141
135
  begin
142
- pg_export.call(database) do |result|
143
- result.success { puts 'Success' }
144
- result.failure { |outcome| warn outcome[:message] }
145
- end
136
+ pg_export
137
+ .call(database)
138
+ .on_success { exit 0 }
139
+ .on_failure do |outcome|
140
+ warn outcome[:message]
141
+ exit 1
142
+ end
143
+
146
144
  rescue Interrupt
147
145
  puts
148
146
  end
@@ -1,19 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'pg_export/lib/pg_export/types'
4
- require 'dry-struct'
5
-
6
3
  class PgExport
7
- class Configuration < Dry::Struct
8
- attribute :encryption_key, PgExport::Types::Strict::String.constrained(size: 16)
9
- attribute :encryption_algorithm, PgExport::Types::Strict::String
10
- attribute :gateway_host, PgExport::Types::Strict::String
11
- attribute :gateway_user, PgExport::Types::Strict::String
12
- attribute :gateway_password, PgExport::Types::Strict::String.optional
13
- attribute :logger_format, PgExport::Types::Coercible::Symbol.enum(:plain, :timestamped, :muted)
14
- attribute :keep_dumps, PgExport::Types::Coercible::Integer.constrained(gteq: 0)
15
- attribute :gateway, PgExport::Types::Coercible::Symbol.enum(:ftp, :ssh)
16
- attribute :mode, PgExport::Types::Coercible::Symbol.enum(:plain, :interactive)
4
+ class Configuration
5
+ ATTRS = %i[
6
+ encryption_key
7
+ encryption_algorithm
8
+ gateway_host
9
+ gateway_user
10
+ gateway_password
11
+ logger_format
12
+ keep_dumps
13
+ gateway mode
14
+ ].freeze
15
+
16
+ attr_reader *ATTRS
17
17
 
18
18
  def self.build(env)
19
19
  new(
@@ -21,14 +21,66 @@ class PgExport
21
21
  encryption_algorithm: env['PG_EXPORT_ENCRYPTION_ALGORITHM'],
22
22
  gateway_host: env['PG_EXPORT_GATEWAY_HOST'],
23
23
  gateway_user: env['PG_EXPORT_GATEWAY_USER'],
24
- gateway_password: env['PG_EXPORT_GATEWAY_PASSWORD'] == '' ? nil : env['PG_EXPORT_GATEWAY_PASSWORD'],
25
- logger_format: env['LOGGER_FORMAT'] || 'plain',
26
- keep_dumps: env['KEEP_DUMPS'] || 10,
24
+ gateway_password: env['PG_EXPORT_GATEWAY_PASSWORD'],
25
+ logger_format: env['LOGGER_FORMAT'],
26
+ keep_dumps: env['KEEP_DUMPS'],
27
27
  gateway: env['GATEWAY'],
28
28
  mode: env['PG_EXPORT_MODE']
29
29
  )
30
- rescue Dry::Struct::Error => e
31
- raise PgExport::InitializationError, e.message.gsub('[PgExport::Configuration.new] ', '')
30
+ end
31
+
32
+ def initialize(
33
+ encryption_key: nil,
34
+ encryption_algorithm: nil,
35
+ gateway_host: nil,
36
+ gateway_user: nil,
37
+ gateway_password: nil,
38
+ logger_format: nil,
39
+ keep_dumps: nil,
40
+ gateway: nil,
41
+ mode: nil
42
+ )
43
+
44
+ @encryption_key = String(encryption_key)
45
+ raise ArgumentError, 'Encryption key must be 16 chars long' if @encryption_key.length != 16
46
+
47
+ @encryption_algorithm = String(encryption_algorithm)
48
+ @encryption_algorithm = 'AES-128-CBC' if @encryption_algorithm.empty?
49
+
50
+ @gateway_host = String(gateway_host)
51
+ raise ArgumentError, 'Gatway host must not be empty' if @gateway_host.empty?
52
+
53
+ @gateway_user = String(gateway_user)
54
+ raise ArgumentError, 'Gatway user must not be empty' if @gateway_user.empty?
55
+
56
+ @gateway_password = nil if gateway_password.nil? || gateway_password.to_s.empty?
57
+
58
+ @logger_format = logger_format.to_s.to_sym
59
+ @logger_format = :plain if @logger_format.empty?
60
+ raise ArgumentError, 'Logger format must be one of: plain, timestamped, muted' unless %i[plain timestamped muted].include?(@logger_format)
61
+
62
+ @keep_dumps = Integer(keep_dumps || 10)
63
+ raise ArgumentError, 'Keep dumps must greater or equal to 1' unless @keep_dumps >= 1
64
+
65
+ @gateway = gateway.to_s.to_sym
66
+ @gateway = :ftp if @gateway.empty?
67
+ raise ArgumentError, 'Gateway must be one of: ftp, ssh' unless %i[ftp ssh].include?(@gateway)
68
+
69
+ @mode = mode.to_s.to_sym
70
+ @mode = :plain if @mode.empty?
71
+ raise ArgumentError, 'Mode must be one of: plain, interactive' unless %i[plain interactive].include?(@mode)
72
+ end
73
+
74
+ def to_s
75
+ ATTRS.map do |name|
76
+ value = public_send(name)
77
+
78
+ if %i[encryption_key gateway_password].include?(name)
79
+ " #{name} #{value.nil? ? '' : value[0..2] + '***'}"
80
+ else
81
+ " #{name} #{value}"
82
+ end
83
+ end.join("\n")
32
84
  end
33
85
  end
34
86
  end
@@ -0,0 +1,148 @@
1
+ # frozen_string_literal: true
2
+
3
+ class PgExport
4
+ class Factory
5
+ attr_reader :config
6
+
7
+ def initialize(config:)
8
+ @config = config
9
+ end
10
+
11
+ def gateway_factory
12
+ if config.gateway == :ftp
13
+ require 'pg_export/lib/pg_export/factories/ftp_gateway_factory'
14
+
15
+ Factories::FtpGatewayFactory.new(config: config)
16
+ elsif config.gateway == :ssh
17
+ require 'pg_export/lib/pg_export/factories/ssh_gateway_factory'
18
+
19
+ Factories::SshGatewayFactory.new(config: config)
20
+ else
21
+ raise ArgumentError, "Unknown gateway #{config.gateway}"
22
+ end
23
+ end
24
+
25
+ def transaction
26
+ require 'pg_export/lib/pg_export/operations/encrypt_dump'
27
+ require 'pg_export/lib/pg_export/operations/decrypt_dump'
28
+ require 'pg_export/lib/pg_export/operations/open_connection'
29
+ require 'pg_export/lib/pg_export/factories/cipher_factory'
30
+ require 'pg_export/lib/pg_export/factories/dump_factory'
31
+ require 'pg_export/lib/pg_export/adapters/shell_adapter'
32
+ require 'pg_export/lib/pg_export/repositories/gateway_dump_repository'
33
+ require 'pg_export/lib/pg_export/repositories/gateway_dump_file_repository'
34
+
35
+ cipher_factory = Factories::CipherFactory.new(
36
+ encryption_algorithm: config.encryption_algorithm,
37
+ encryption_key: config.encryption_key
38
+ )
39
+
40
+ gateway_dump_repository = Repositories::GatewayDumpRepository.new
41
+ gateway_dump_file_repository = Repositories::GatewayDumpFileRepository.new
42
+ open_connection = Operations::OpenConnection.new(gateway_factory: gateway_factory)
43
+ bash_adapter = Adapters::ShellAdapter.new
44
+
45
+ encrypt_dump = Operations::EncryptDump.new(cipher_factory: cipher_factory)
46
+
47
+ if config.mode == :plain
48
+ require 'pg_export/lib/pg_export/operations/remove_old_dumps'
49
+ require 'pg_export/lib/pg_export/transactions/export_dump'
50
+
51
+ remove_old_dumps = Operations::RemoveOldDumps.new(
52
+ gateway_dump_repository: gateway_dump_repository,
53
+ keep: config.keep_dumps
54
+ )
55
+
56
+ PgExport::Transactions::ExportDump.new(
57
+ dump_factory: Factories::DumpFactory.new,
58
+ bash_adapter: bash_adapter,
59
+ encrypt_dump: encrypt_dump,
60
+ open_connection: open_connection,
61
+ remove_old_dumps: remove_old_dumps,
62
+ listeners: plain_listeners
63
+ )
64
+ elsif config.mode == :interactive
65
+ require 'pg_export/lib/pg_export/transactions/import_dump_interactively'
66
+ require 'pg_export/lib/pg_export/ui/interactive/input'
67
+
68
+ decrypt_dump = Operations::DecryptDump.new(cipher_factory: cipher_factory)
69
+
70
+ PgExport::Transactions::ImportDumpInteractively.new(
71
+ input: Ui::Interactive::Input.new,
72
+ bash_adapter: bash_adapter,
73
+ gateway_dump_file_repository: gateway_dump_file_repository,
74
+ gateway_dump_repository: gateway_dump_repository,
75
+ open_connection: open_connection,
76
+ decrypt_dump: decrypt_dump,
77
+ listeners: interactive_listeners
78
+ )
79
+ else
80
+ raise ArgumentError, "Unknown mode #{config.mode}"
81
+ end
82
+ end
83
+
84
+ private
85
+
86
+ def plain_listeners
87
+ require 'pg_export/lib/pg_export/listeners/plain/prepare_params'
88
+ require 'pg_export/lib/pg_export/listeners/plain/build_dump'
89
+ require 'pg_export/lib/pg_export/listeners/plain/close_connection'
90
+ require 'pg_export/lib/pg_export/listeners/plain/decrypt_dump'
91
+ require 'pg_export/lib/pg_export/listeners/plain/download_dump'
92
+ require 'pg_export/lib/pg_export/listeners/plain/encrypt_dump'
93
+ require 'pg_export/lib/pg_export/listeners/plain/fetch_dumps'
94
+ require 'pg_export/lib/pg_export/listeners/plain/open_connection'
95
+ require 'pg_export/lib/pg_export/listeners/plain/remove_old_dumps'
96
+ require 'pg_export/lib/pg_export/listeners/plain/restore'
97
+ require 'pg_export/lib/pg_export/listeners/plain/upload_dump'
98
+
99
+ logger = build_logger(config.logger_format)
100
+
101
+ {
102
+ prepare_params: Listeners::Plain::PrepareParams.new(logger: logger),
103
+ build_dump: Listeners::Plain::BuildDump.new(logger: logger),
104
+ encrypt_dump: Listeners::Plain::EncryptDump.new(logger: logger),
105
+ open_connection: Listeners::Plain::OpenConnection.new(logger: logger),
106
+ upload_dump: Listeners::Plain::UploadDump.new(logger: logger),
107
+ remove_old_dumps: Listeners::Plain::RemoveOldDumps.new(logger: logger),
108
+ close_connection: Listeners::Plain::CloseConnection.new(logger: logger)
109
+ }
110
+ end
111
+
112
+ def interactive_listeners
113
+ require 'pg_export/lib/pg_export/listeners/interactive/open_connection'
114
+ require 'pg_export/lib/pg_export/listeners/interactive/fetch_dumps'
115
+ require 'pg_export/lib/pg_export/listeners/interactive/select_dump'
116
+ require 'pg_export/lib/pg_export/listeners/interactive/download_dump'
117
+ require 'pg_export/lib/pg_export/listeners/interactive/close_connection'
118
+ require 'pg_export/lib/pg_export/listeners/interactive/decrypt_dump'
119
+ require 'pg_export/lib/pg_export/listeners/interactive/select_database'
120
+ require 'pg_export/lib/pg_export/listeners/interactive/restore'
121
+
122
+ {
123
+ open_connection: Listeners::Interactive::OpenConnection.new,
124
+ fetch_dumps: Listeners::Interactive::FetchDumps.new,
125
+ select_dump: Listeners::Interactive::SelectDump.new,
126
+ download_dump: Listeners::Interactive::DownloadDump.new,
127
+ close_connection: Listeners::Interactive::CloseConnection.new,
128
+ decrypt_dump: Listeners::Interactive::DecryptDump.new,
129
+ select_database: Listeners::Interactive::SelectDatabase.new,
130
+ restore: Listeners::Interactive::Restore.new,
131
+ }
132
+ end
133
+
134
+ def build_logger(logger_format)
135
+ require 'logger'
136
+
137
+ formatters = {
138
+ plain: ->(_, _, _, message) { "#{message}\n" },
139
+ muted: ->(*) {},
140
+ timestamped: lambda do |severity, datetime, progname, message|
141
+ "#{datetime} #{Process.pid} TID-#{Thread.current.object_id.to_s(36)}#{progname} #{severity}: #{message}\n"
142
+ end
143
+ }
144
+
145
+ Logger.new($stdout, formatter: formatters.fetch(logger_format))
146
+ end
147
+ end
148
+ end
@@ -4,7 +4,7 @@ require 'open3'
4
4
 
5
5
  class PgExport
6
6
  module Adapters
7
- class BashAdapter
7
+ class ShellAdapter
8
8
  class PgRestoreError < StandardError; end
9
9
  class PgDumpError < StandardError; end
10
10
 
@@ -1,17 +1,25 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry-initializer'
4
- require 'pg_export/lib/pg_export/types'
5
-
6
3
  class PgExport
7
4
  module Entities
8
5
  class Dump
9
- extend Dry::Initializer[undefined: false]
6
+ attr_reader :name, :type, :database, :file
7
+
8
+ def initialize(name: nil, type: nil, database: nil, file: nil)
9
+ @name = String(name)
10
+ raise ArgumentError, 'Dump name must not be empty' if @name.empty?
11
+ raise ArgumentError, 'Dump name does not match criteria' unless /.+_20[0-9]{6}_[0-9]{6}\Z/.match?(@name)
10
12
 
11
- option :name, Types::DumpName
12
- option :type, Types::DumpType
13
- option :database, Types::Strict::String.constrained(filled: true)
14
- option :file, Types::DumpFile, default: proc { PgExport::ValueObjects::DumpFile.new }
13
+ @type = String(type)
14
+ @type = 'plain' if @type.empty?
15
+ raise ArgumentError, 'Dump type must be one of: plain, encrypted' unless %w[plain encrypted].include?(@type)
16
+
17
+ @database = database
18
+
19
+ @file = file
20
+ @file = ValueObjects::DumpFile.new if @file.nil?
21
+ raise ArgumentError, "Invalid file type: #{@file.class}" unless @file.is_a?(ValueObjects::DumpFile)
22
+ end
15
23
 
16
24
  def encrypt(cipher_factory:)
17
25
  self.file = file.copy(cipher: cipher_factory.encryptor)
@@ -32,13 +40,17 @@ class PgExport
32
40
  end
33
41
 
34
42
  def file=(f)
35
- @file = Types::DumpFile[f]
43
+ @file = f
44
+
45
+ raise ArgumentError, "Invalid file type: '#{f}'" unless @file.is_a?(ValueObjects::DumpFile)
36
46
  end
37
47
 
38
48
  protected
39
49
 
40
50
  def type=(t)
41
- @type = Types::DumpType[t]
51
+ @type = t.to_s
52
+
53
+ raise ArgumentError, "Dump type '#{t}' must be one of: plain, encrypted" unless %w[plain encrypted].include?(@type)
42
54
  end
43
55
  end
44
56
  end
@@ -1,12 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'openssl'
4
- require 'pg_export/import'
5
4
 
6
5
  class PgExport
7
6
  module Factories
8
7
  class CipherFactory
9
- include Import['config']
8
+ def initialize(encryption_algorithm:, encryption_key:)
9
+ @encryption_algorithm = encryption_algorithm
10
+ @encryption_key = encryption_key
11
+ end
10
12
 
11
13
  def encryptor
12
14
  build_cipher(:encrypt)
@@ -18,10 +20,12 @@ class PgExport
18
20
 
19
21
  private
20
22
 
23
+ attr_reader :encryption_algorithm, :encryption_key
24
+
21
25
  def build_cipher(type)
22
- cipher = OpenSSL::Cipher.new(config.encryption_algorithm)
26
+ cipher = OpenSSL::Cipher.new(encryption_algorithm)
23
27
  cipher.public_send(type)
24
- cipher.key = config.encryption_key
28
+ cipher.key = encryption_key
25
29
  cipher
26
30
  end
27
31
  end
@@ -4,7 +4,6 @@ require 'open3'
4
4
  require 'tempfile'
5
5
 
6
6
  require 'pg_export/lib/pg_export/entities/dump'
7
- require 'pg_export/import'
8
7
 
9
8
  class PgExport
10
9
  module Factories