pg_export 0.3.2 → 0.4.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1c28369f4ecffa9479ea9f20505f09b7354ae5c6
4
- data.tar.gz: d833bbf0099e4b6640fdc8adca851aeb559a453f
3
+ metadata.gz: 58c84b5c514c736a005d23eb4bf21f68961d88b1
4
+ data.tar.gz: 1db3a0a02ffabc82a48da0e5213955d8411ab0bc
5
5
  SHA512:
6
- metadata.gz: 24db2448717fa02e6a35273ae53b356f1906441cad18e38fbf1c52eedd141dfc680e7d0be3c232c8fcc9dd282f24483199c29f8f81f7643230c1ec2497731c1e
7
- data.tar.gz: 7fe5392339e1acea375ac7e235ee09652c9f0f72a8ced4aa80061f0c3dac90b532a9b04a88e9955faf220a8e291d005ca0f1f3d12d5914f994aeac04add52b26
6
+ metadata.gz: 5f90ff4abce09f0d34cdc1dd94b5dd545e2b953e9e4acfd10d3ee30c4134bca68ce6b7bb41428796f65e23e58a709d6338533b5d7bc4ee47cb430368c1810165
7
+ data.tar.gz: 028ff0080d2068d1bdd1d3cd3fba39ceddff98b2845506817d8749202e04e0b6268e3833654264bb81360ac7f839beba8d5f80cf5673f451574560e7eebf228a
data/.rubocop.yml CHANGED
@@ -3,23 +3,11 @@ AllCops:
3
3
  Exclude:
4
4
  - 'spec/spec_helper.rb'
5
5
 
6
- Style/ClassAndModuleChildren:
7
- Enabled: false
8
-
9
6
  Metrics/LineLength:
10
7
  Max: 200
11
8
 
12
9
  Metrics/AbcSize:
13
10
  Max: 20
14
- Exclude:
15
- - 'lib/pg_export.rb'
16
-
17
- Lint/NestedMethodDefinition:
18
- Enabled: false
19
-
20
- Lint/HandleExceptions:
21
- Exclude:
22
- - 'spec/services/utils_spec.rb'
23
11
 
24
12
  Lint/AmbiguousOperator:
25
13
  Exclude:
@@ -29,18 +17,8 @@ Style/AlignArray:
29
17
  Exclude:
30
18
  - 'spec/configuration_spec.rb'
31
19
 
32
- Style/GuardClause:
33
- Exclude:
34
- - '*.gemspec'
35
-
36
- Style/AndOr:
37
- Enabled: false
38
-
39
20
  Style/ParallelAssignment:
40
21
  Enabled: false
41
22
 
42
23
  Documentation:
43
24
  Enabled: false
44
-
45
- CaseIndentation:
46
- Enabled: false
data/.travis.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  sudo: false
2
2
  language: ruby
3
3
  rvm:
4
- - 2.3.0
4
+ - 2.1.8
5
5
  before_install: gem install bundler -v 1.13.3
data/README.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # PgExport
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/pg_export.svg)](https://badge.fury.io/rb/pg_export)
4
+ [![Build Status](https://travis-ci.org/maicher/pg_export.svg?branch=master)](https://travis-ci.org/maicher/pg_export)
5
+ [![Code Climate](https://codeclimate.com/github/maicher/pg_export/badges/gpa.svg)](https://codeclimate.com/github/maicher/pg_export)
6
+
3
7
  CLI for creating and exporting PostgreSQL dumps to FTP.
4
8
 
5
9
  Can be used for backups or synchronizing databases between production and development environments.
@@ -8,20 +12,23 @@ Example:
8
12
 
9
13
  pg_export --database database_name -keep 5
10
14
 
11
- Above command will perform database dump, gzip it, upload it to FTP and remove old dumps from FTP, keeping newest 5.
15
+ Above command will perform database dump, encrypt it, upload it to FTP and remove old dumps from FTP, keeping newest 5.
12
16
 
13
- FTP connection params are configured by env variables.
17
+ FTP connection params and encryption key are configured by env variables.
14
18
 
15
19
  Features:
16
20
 
17
- - uses shell command pg_dump
21
+ - uses shell command `pg_dump` and `pg_restore`
18
22
  - no external gem dependencies
23
+ - encrypts dumps by OpenSSL
19
24
  - uses ruby tempfiles, so local dumps are garbage collected automatically
25
+ - easy restoring dumps through interactive mode
20
26
 
21
27
  ## Dependencies
22
28
 
23
29
  * Ruby >= 2.1
24
30
  * $ pg_dump
31
+ * $ pg_restore
25
32
 
26
33
  ## Installation
27
34
 
@@ -47,6 +54,7 @@ Or install it yourself as:
47
54
  -d, --database DATABASE [Required] Name of the database to export
48
55
  -k, --keep [KEEP] [Optional] Number of dump files to keep on FTP (default: 10)
49
56
  -t, --timestamped [Optional] Enables log messages with timestamps
57
+ -i, --interactive Interactive, command line mode, for restoring dumps into databases
50
58
  -h, --help Show this message
51
59
 
52
60
  Setting can be verified by running following commands:
@@ -55,43 +63,55 @@ Or install it yourself as:
55
63
 
56
64
  ## How to start
57
65
 
58
- __Step 1.__ Prepare FTP account and put configuration into env variables.
66
+ __Step 1.__ Prepare FTP account and put configuration into env variables. Dumps will be exported into that location.
59
67
 
60
- # /etc/enviranment
68
+ # /etc/environment
61
69
  BACKUP_FTP_HOST="yourftp.example.com"
62
70
  BACKUP_FTP_USER="user"
63
71
  BACKUP_FTP_PASSWORD="password"
64
72
 
65
- Password cannot include `#` sign, [more info](http://serverfault.com/questions/539730/environment-variable-in-etc-environment-with-pound-hash-sign-in-the-value).
73
+ __Step 2.__ Put dump encryption key into env variable (at least 16 characters). Dumps will be SSL(AES-128-CBC) encrypted using that key.
74
+
75
+ # /etc/environment
76
+ DUMP_ENCRYPTION_KEY="1234567890abcdef"
77
+
78
+ Variables cannot include `#` sign, [more info](http://serverfault.com/questions/539730/environment-variable-in-etc-environment-with-pound-hash-sign-in-the-value).
66
79
 
67
- __Step 2.__ Configure other variables (optional).
80
+ __Step 3.__ Configure how many dumps should be kept in FTP (optional).
68
81
 
69
82
  # /etc/environment
70
83
  KEEP_DUMPS=5 # default: 10
71
84
 
72
- __Step 3.__ Print the configuration to verify whether env variables has been loaded.
85
+ __Step 4.__ Print the configuration to verify whether env variables has been loaded.
73
86
 
74
87
  $ pg_export --configuration
75
88
  => database:
76
89
  keep_dumps: 5
90
+ dump_password: k40***
77
91
  ftp_host: yourftp.example.com
78
92
  ftp_user: user
79
93
  ftp_password: pass***
80
94
 
81
- __Step 4.__ Try connecting to FTP to verify the connection.
95
+ __Step 5.__ Try connecting to FTP to verify the connection.
82
96
 
83
97
  $ pg_export --ftp
84
98
  => Connect to yourftp.example.com
85
99
  Close FTP
86
100
 
87
- __Step 5.__ Perform database export.
101
+ __Step 6.__ Perform database export.
88
102
 
89
103
  $ pg_export -d your_database
90
104
  => Create Dump Tempfile (1.36MB)
91
- Create Compressed Dump Tempfile (1.34MB)
105
+ Create Encrypted Dump Tempfile (1.34MB)
92
106
  Connect to yourftp.example.com
93
- Export Compressed Dump Tempfile (1.34MB) your_database_20161020_125747.gz to yourftp.example.com
107
+ Export Encrypted Dump Tempfile (1.34MB) your_database_20161020_125747 to yourftp.example.com
94
108
  Close FTP
109
+
110
+ ## How to restore a dump?
111
+
112
+ Go to interactive mode and follow the instructions:
113
+
114
+ pg_export -i
95
115
 
96
116
  ## Development
97
117
 
data/bin/pg_export CHANGED
@@ -3,9 +3,13 @@
3
3
  require 'optparse'
4
4
  require 'ostruct'
5
5
  require 'pg_export'
6
+ require 'pg_export/interactive'
6
7
 
8
+ LOGS_DEFAULT = ->(_, _, _, message) { "#{message}\n" }
7
9
  LOGS_TIMESTAMPED = ->(severity, datetime, progname, message) { "#{datetime} #{Process.pid} TID-#{Thread.current.object_id.to_s(36)}#{progname} #{severity}: #{message}\n" }
8
- LOGS_NORMAL = ->(_, _, _, message) { "#{message}\n" }
10
+ LOGS_MUTED = ->(_, _, _, _) {}
11
+
12
+ PgExport::Logging.logger.formatter = LOGS_DEFAULT
9
13
 
10
14
  options = OpenStruct.new
11
15
  option_parser = OptionParser.new do |opts|
@@ -23,6 +27,10 @@ option_parser = OptionParser.new do |opts|
23
27
  options.timestamped = true
24
28
  end
25
29
 
30
+ opts.on('-i', '--interactive', 'Interactive, command line mode, for restoring dumps into databases') do
31
+ options.interactive = true
32
+ end
33
+
26
34
  opts.on('-h', '--help', 'Show this message') do
27
35
  puts opts
28
36
  exit
@@ -36,7 +44,6 @@ option_parser = OptionParser.new do |opts|
36
44
  end
37
45
 
38
46
  opts.on('-f', '--ftp', 'Tries connecting to FTP to verify the connection') do
39
- PgExport::Logging.logger.formatter = LOGS_NORMAL
40
47
  PgExport::FtpService.new(PgExport::Configuration.new.ftp_params)
41
48
  exit
42
49
  end
@@ -45,12 +52,18 @@ end
45
52
  begin
46
53
  option_parser.parse!
47
54
 
48
- PgExport::Logging.logger.formatter = options.timestamped ? LOGS_TIMESTAMPED : LOGS_NORMAL
55
+ options.database ||= 'undefined' if options.interactive
56
+ PgExport::Logging.logger.formatter = LOGS_TIMESTAMPED if options.timestamped
57
+ PgExport::Logging.logger.formatter = LOGS_MUTED if options.interactive
49
58
 
50
- PgExport.new do |config|
59
+ pg_export = PgExport.new do |config|
51
60
  config.database = options.database if options.database
52
61
  config.keep_dumps = options.keep if options.keep
53
- end.call
62
+ end
63
+ pg_export.extend(PgExport::Interactive) if options.interactive
64
+
65
+ pg_export.call
66
+
54
67
  rescue OptionParser::MissingArgument, PgExport::InvalidConfigurationError => e
55
68
  puts "Error: #{e}"
56
69
  puts option_parser
data/codeclimate.yml ADDED
@@ -0,0 +1,15 @@
1
+ engines:
2
+ duplication:
3
+ enabled: true
4
+ config:
5
+ languages:
6
+ - ruby
7
+ fixme:
8
+ enabled: true
9
+ rubocop:
10
+ enabled: true
11
+ ratings:
12
+ paths:
13
+ - "**.rb"
14
+ exclude_paths:
15
+ - spec/
data/lib/pg_export.rb CHANGED
@@ -2,7 +2,11 @@ require 'logger'
2
2
  require 'tempfile'
3
3
  require 'zlib'
4
4
  require 'net/ftp'
5
+ require 'openssl'
5
6
  require 'forwardable'
7
+ require 'open3'
8
+
9
+ require 'cli_spinnable'
6
10
 
7
11
  require 'pg_export/version'
8
12
  require 'pg_export/logging'
@@ -11,12 +15,13 @@ require 'pg_export/configuration'
11
15
  require 'pg_export/concurrency'
12
16
  require 'pg_export/entities/dump/size_human'
13
17
  require 'pg_export/entities/dump/base'
14
- require 'pg_export/entities/sql_dump'
15
- require 'pg_export/entities/compressed_dump'
18
+ require 'pg_export/entities/plain_dump'
19
+ require 'pg_export/entities/encrypted_dump'
16
20
  require 'pg_export/services/ftp_service'
17
21
  require 'pg_export/services/ftp_service/connection'
18
22
  require 'pg_export/services/utils'
19
23
  require 'pg_export/services/dump_storage'
24
+ require 'pg_export/services/aes'
20
25
 
21
26
  class PgExport
22
27
  include Concurrency
@@ -42,14 +47,22 @@ class PgExport
42
47
  attr_reader :config
43
48
  attr_accessor :dump, :dump_storage
44
49
 
50
+ def create_dump
51
+ sql_dump = utils.create_dump(config.database)
52
+ enc_dump = utils.encrypt(sql_dump)
53
+ self.dump = enc_dump
54
+ end
55
+
45
56
  def initialize_dump_storage
46
57
  ftp_service = FtpService.new(config.ftp_params)
47
58
  self.dump_storage = DumpStorage.new(ftp_service, config.database)
59
+ self
48
60
  end
49
61
 
50
- def create_dump
51
- sql_dump = Utils.create_dump(config.database)
52
- compressed_dump = Utils.compress(sql_dump)
53
- self.dump = compressed_dump
62
+ def utils
63
+ @utils ||= Utils.new(
64
+ Aes.encryptor(config.dump_encryption_key),
65
+ Aes.decryptor(config.dump_encryption_key)
66
+ )
54
67
  end
55
68
  end
@@ -3,6 +3,7 @@ class PgExport
3
3
  DEFAULTS = {
4
4
  database: nil,
5
5
  keep_dumps: ENV['KEEP_DUMPS'] || 10,
6
+ dump_encryption_key: ENV['DUMP_ENCRYPTION_KEY'],
6
7
  ftp_host: ENV['BACKUP_FTP_HOST'],
7
8
  ftp_user: ENV['BACKUP_FTP_USER'],
8
9
  ftp_password: ENV['BACKUP_FTP_PASSWORD']
@@ -20,6 +21,7 @@ class PgExport
20
21
  DEFAULTS.keys.each do |field|
21
22
  raise InvalidConfigurationError, "Field #{field} is required" if send(field).nil?
22
23
  end
24
+ raise InvalidConfigurationError, 'Dump password is to short. It should have at least 16 characters' if dump_encryption_key.length < 16
23
25
  end
24
26
 
25
27
  def ftp_params
@@ -37,7 +39,7 @@ class PgExport
37
39
  private
38
40
 
39
41
  def print_attr(key)
40
- if key == :ftp_password
42
+ if %i(ftp_password dump_encryption_key).include?(key)
41
43
  if send(key)
42
44
  "#{key}: #{send(key)[0..2]}***\n"
43
45
  else
@@ -6,18 +6,28 @@ class PgExport
6
6
 
7
7
  CHUNK_SIZE = (2**16).freeze
8
8
 
9
- def_delegators :file, :path, :read, :write, :rewind, :size, :eof?
9
+ def_delegators :file, :path, :read, :write, :<<, :rewind, :close, :size, :eof?
10
10
 
11
11
  def initialize
12
12
  @file = Tempfile.new('dump')
13
13
  end
14
14
 
15
15
  def ext
16
- raise 'Overwrite it'
16
+ ''
17
17
  end
18
18
 
19
- def open
20
- raise 'Overwrite it'
19
+ def open(operation_type, &block)
20
+ case operation_type.to_sym
21
+ when :read then File.open(path, 'r', &block)
22
+ when :write then File.open(path, 'w', &block)
23
+ else raise ArgumentError, 'Operation type can be only :read or :write'
24
+ end
25
+ end
26
+
27
+ def each_chunk
28
+ open(:read) do |file|
29
+ yield file.read(CHUNK_SIZE) until file.eof?
30
+ end
21
31
  end
22
32
 
23
33
  def to_s
@@ -0,0 +1,7 @@
1
+ class PgExport
2
+ class EncryptedDump < Dump::Base
3
+ def name
4
+ 'Encrypted Dump'
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ class PgExport
2
+ class PlainDump < Dump::Base
3
+ def name
4
+ 'Dump'
5
+ end
6
+ end
7
+ end
@@ -1,4 +1,5 @@
1
1
  class PgExport
2
2
  class InvalidConfigurationError < StandardError; end
3
3
  class PgDumpError < StandardError; end
4
+ class PgRestoreError < StandardError; end
4
5
  end
@@ -0,0 +1,83 @@
1
+ require 'pg_export/interactive/refinements/colourable_string'
2
+
3
+ class PgExport
4
+ module Interactive
5
+ include CliSpinnable
6
+ using ColourableString
7
+
8
+ def self.extended(_)
9
+ puts 'Interactive mode, for restoring dump into database.'.green
10
+ end
11
+
12
+ def call
13
+ initialize_dump_storage
14
+ print_all_dumps
15
+ download_selected_dump
16
+ restore_downloaded_dump
17
+ puts 'Success'.green
18
+ self
19
+ end
20
+
21
+ private
22
+
23
+ def initialize_dump_storage
24
+ with_spinner do |cli|
25
+ cli.print 'Connecting to FTP'
26
+ super
27
+ cli.tick
28
+ end
29
+ end
30
+
31
+ def print_all_dumps
32
+ dumps.each.with_index(0) do |name, i|
33
+ print "(#{i}) "
34
+ puts name.to_s.gray
35
+ end
36
+ self
37
+ end
38
+
39
+ def download_selected_dump
40
+ puts 'Which dump would you like to import?'
41
+ print "Type from 1 to #{dumps.count - 1} (0): "
42
+ name = dumps.fetch(gets.chomp.to_i)
43
+ with_spinner do |cli|
44
+ cli.print 'Downloading dump'
45
+ encrypted_dump = dump_storage.download(name)
46
+ cli.print " (#{encrypted_dump.size_human})"
47
+ cli.tick
48
+ cli.print 'Decrypting dump'
49
+ self.dump = utils.decrypt(encrypted_dump)
50
+ cli.print " (#{dump.size_human})"
51
+ cli.tick
52
+ end
53
+ self
54
+ rescue OpenSSL::Cipher::CipherError => e
55
+ puts "Problem decrypting dump file: #{e}. Try again.".red
56
+ retry
57
+ end
58
+
59
+ def restore_downloaded_dump
60
+ puts 'To which database you would like to restore the downloaded dump?'
61
+ if config.database == 'undefined'
62
+ print 'Enter a local database name: '
63
+ else
64
+ print "Enter a local database name (#{config.database}): "
65
+ end
66
+ database = gets.chomp
67
+ database = database.empty? ? config.database : database
68
+ with_spinner do |cli|
69
+ cli.print "Restoring dump to #{database} database"
70
+ utils.restore_dump(dump, database)
71
+ cli.tick
72
+ end
73
+ self
74
+ rescue PgRestoreError => e
75
+ puts e.to_s.red
76
+ retry
77
+ end
78
+
79
+ def dumps
80
+ @dumps ||= dump_storage.all
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,19 @@
1
+ class PgExport
2
+ module Interactive
3
+ module ColourableString
4
+ refine String do
5
+ def red
6
+ "\e[31m#{self}\e[0m"
7
+ end
8
+
9
+ def green
10
+ "\e[0;32;49m#{self}\e[0m"
11
+ end
12
+
13
+ def gray
14
+ "\e[37m#{self}\e[0m"
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,21 @@
1
+ class PgExport
2
+ class Aes
3
+ ALG = 'AES-128-CBC'.freeze
4
+
5
+ def self.encryptor(key)
6
+ initialize_aes(:encrypt, key)
7
+ end
8
+
9
+ def self.decryptor(key)
10
+ initialize_aes(:decrypt, key)
11
+ end
12
+
13
+ def self.initialize_aes(mode, key)
14
+ raise ArgumentError, 'Only :encrypt or :decrypt are allowed' unless %i(encrypt decrypt).include?(mode)
15
+ aes = OpenSSL::Cipher::Cipher.new(ALG)
16
+ aes.public_send(mode.to_sym)
17
+ aes.key = key
18
+ aes
19
+ end
20
+ end
21
+ end
@@ -12,16 +12,31 @@ class PgExport
12
12
  def upload(dump)
13
13
  dump_name = timestamped_name(dump)
14
14
  ftp_service.upload_file(dump.path, dump_name)
15
- logger.info "Export #{dump} #{dump_name} to #{ftp_service}"
15
+ logger.info "Upload #{dump} #{dump_name} to #{ftp_service}"
16
+ end
17
+
18
+ def download(name)
19
+ dump = EncryptedDump.new
20
+ ftp_service.download_file(dump.path, name)
21
+ logger.info "Download #{dump} #{name} from #{ftp_service}"
22
+ dump
16
23
  end
17
24
 
18
25
  def remove_old(keep:)
19
- ftp_service.list(ftp_regex).drop(keep.to_i).each do |filename|
26
+ find_by_name(name).drop(keep.to_i).each do |filename|
20
27
  ftp_service.delete(filename)
21
- logger.info "Remove #{filename} from FTP"
28
+ logger.info "Remove #{filename} from #{ftp_service}"
22
29
  end
23
30
  end
24
31
 
32
+ def find_by_name(s)
33
+ ftp_service.list(s + '_*')
34
+ end
35
+
36
+ def all
37
+ ftp_service.list('*')
38
+ end
39
+
25
40
  private
26
41
 
27
42
  attr_reader :ftp_service, :name
@@ -29,9 +44,5 @@ class PgExport
29
44
  def timestamped_name(dump)
30
45
  name + Time.now.strftime(TIMESTAMP) + dump.ext
31
46
  end
32
-
33
- def ftp_regex
34
- name + '_*'
35
- end
36
47
  end
37
48
  end
@@ -9,8 +9,8 @@ class PgExport
9
9
  ObjectSpace.define_finalizer(self, proc { connection.close })
10
10
  end
11
11
 
12
- def list(regexp)
13
- ftp.list(regexp).map { |item| item.split(' ').last }.sort.reverse
12
+ def list(regex_string)
13
+ ftp.list(regex_string).map { |item| item.split(' ').last }.sort.reverse
14
14
  end
15
15
 
16
16
  def delete(filename)
@@ -21,6 +21,10 @@ class PgExport
21
21
  ftp.putbinaryfile(path.to_s, name, CHUNK_SIZE)
22
22
  end
23
23
 
24
+ def download_file(path, name)
25
+ ftp.getbinaryfile(name, path.to_s, CHUNK_SIZE)
26
+ end
27
+
24
28
  def to_s
25
29
  host
26
30
  end
@@ -1,37 +1,57 @@
1
1
  class PgExport
2
2
  class Utils
3
- extend Logging
3
+ include Logging
4
4
 
5
- def self.create_dump(database_name)
6
- dump = SqlDump.new
7
- out = `pg_dump -Fc --file #{dump.path} #{database_name} 2>&1`
8
- raise PgDumpError, out if /FATAL/ =~ out
5
+ def initialize(encryptor, decryptor)
6
+ @encryptor, @decryptor = encryptor, decryptor
7
+ end
8
+
9
+ def create_dump(database_name)
10
+ dump = PlainDump.new
11
+ Open3.popen3("pg_dump -Fc --file #{dump.path} #{database_name}") do |_, _, err|
12
+ error = err.read
13
+ raise PgDumpError, error unless error.empty?
14
+ end
9
15
  logger.info "Create #{dump}"
10
16
  dump
11
17
  end
12
18
 
13
- def self.compress(dump)
14
- dump_gz = CompressedDump.new
15
- dump.open(:read) do |f|
16
- dump_gz.open(:write) do |gz|
17
- gz.write(f.read(Dump::Base::CHUNK_SIZE)) until f.eof?
18
- end
19
+ def restore_dump(dump, database_name)
20
+ Open3.popen3("pg_restore -c -d #{database_name} #{dump.path}") do |_, _, err|
21
+ error = err.read
22
+ raise PgRestoreError, error if /FATAL/ =~ error
19
23
  end
20
-
21
- logger.info "Create #{dump_gz}"
22
- dump_gz
24
+ logger.info "Restore #{dump}"
25
+ self
23
26
  end
24
27
 
25
- def self.decompress(dump_gz)
26
- dump = SqlDump.new
27
- dump_gz.open(:read) do |gz|
28
- dump.open(:write) do |f|
29
- f.write(gz.readpartial(Dump::Base::CHUNK_SIZE)) until gz.eof?
30
- end
31
- end
28
+ def encrypt(dump)
29
+ enc_dump = EncryptedDump.new
30
+ copy_using(encryptor, from: dump, to: enc_dump)
31
+ logger.info "Create #{enc_dump}"
32
+ enc_dump
33
+ end
32
34
 
35
+ def decrypt(enc_dump)
36
+ dump = PlainDump.new
37
+ copy_using(decryptor, from: enc_dump, to: dump)
33
38
  logger.info "Create #{dump}"
34
39
  dump
35
40
  end
41
+
42
+ private
43
+
44
+ attr_reader :encryptor, :decryptor
45
+
46
+ def copy_using(aes, from:, to:)
47
+ aes.reset
48
+ to.open(:write) do |f|
49
+ from.each_chunk do |chunk|
50
+ f << aes.update(chunk)
51
+ end
52
+ f << aes.final
53
+ end
54
+ self
55
+ end
36
56
  end
37
57
  end
@@ -1,3 +1,3 @@
1
1
  class PgExport
2
- VERSION = '0.3.2'.freeze
2
+ VERSION = '0.4.0'.freeze
3
3
  end
data/pg_export.gemspec CHANGED
@@ -20,6 +20,8 @@ Gem::Specification.new do |spec|
20
20
  spec.require_paths = ['lib']
21
21
  spec.required_ruby_version = '>= 2.1.0'
22
22
 
23
+ spec.add_dependency 'cli_spinnable', '~> 0.2'
24
+
23
25
  spec.add_development_dependency 'bundler', '~> 1.10'
24
26
  spec.add_development_dependency 'rubocop', '~> 0.44'
25
27
  spec.add_development_dependency 'rake', '~> 10.0'
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pg_export
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Krzysztof Maicher
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-10-25 00:00:00.000000000 Z
11
+ date: 2016-11-24 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: cli_spinnable
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.2'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: bundler
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -116,15 +130,19 @@ files:
116
130
  - bin/console
117
131
  - bin/pg_export
118
132
  - bin/setup
133
+ - codeclimate.yml
119
134
  - lib/pg_export.rb
120
135
  - lib/pg_export/concurrency.rb
121
136
  - lib/pg_export/configuration.rb
122
- - lib/pg_export/entities/compressed_dump.rb
123
137
  - lib/pg_export/entities/dump/base.rb
124
138
  - lib/pg_export/entities/dump/size_human.rb
125
- - lib/pg_export/entities/sql_dump.rb
139
+ - lib/pg_export/entities/encrypted_dump.rb
140
+ - lib/pg_export/entities/plain_dump.rb
126
141
  - lib/pg_export/errors.rb
142
+ - lib/pg_export/interactive.rb
143
+ - lib/pg_export/interactive/refinements/colourable_string.rb
127
144
  - lib/pg_export/logging.rb
145
+ - lib/pg_export/services/aes.rb
128
146
  - lib/pg_export/services/dump_storage.rb
129
147
  - lib/pg_export/services/ftp_service.rb
130
148
  - lib/pg_export/services/ftp_service/connection.rb
@@ -1,19 +0,0 @@
1
- class PgExport
2
- class CompressedDump < Dump::Base
3
- def name
4
- 'Compressed Dump'
5
- end
6
-
7
- def ext
8
- '.gz'
9
- end
10
-
11
- def open(operation_type, &block)
12
- case operation_type.to_sym
13
- when :read then Zlib::GzipReader.open(path, &block)
14
- when :write then Zlib::GzipWriter.open(path, &block)
15
- else raise ArgumentError, 'Operation type can be only :read or :write'
16
- end
17
- end
18
- end
19
- end
@@ -1,19 +0,0 @@
1
- class PgExport
2
- class SqlDump < Dump::Base
3
- def name
4
- 'Dump'
5
- end
6
-
7
- def ext
8
- ''
9
- end
10
-
11
- def open(operation_type, &block)
12
- case operation_type.to_sym
13
- when :read then File.open(path, 'r', &block)
14
- when :write then File.open(path, 'w', &block)
15
- else raise ArgumentError, 'Operation type can be only :read or :write'
16
- end
17
- end
18
- end
19
- end