backupper 0.5.2 → 0.6.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
  SHA256:
3
- metadata.gz: 427e5d2913d10307c2a02b49cf8948aec658561267d602553b1c8a2f02af113a
4
- data.tar.gz: cf4a1a6fe666551223bea18ed1a53d8a6aa170d23e1a5bcc52f92c6282f5fea6
3
+ metadata.gz: a381517df098479aaa0237669fe34e93eb27616af160d6b2d60ea055d70c1835
4
+ data.tar.gz: 45d9d097401c396d046646003876f0a4078f25ec77cde66d84450e4f02eb3e96
5
5
  SHA512:
6
- metadata.gz: 72cca9939837dd3d45ac6853ba2985349ac53659a8e34195b61b9133b08ffb35846346e3b656e933b587badbd27ff585124a9071c805fc7e80ca1f64ea19262e
7
- data.tar.gz: 8a743ab45a61dfbf13c6f31511d4e8339a2f905c25c5602049073153ea09c0d1795daea96148d81c83fdd0ae72bf4296b26a32a0844c5c6e0a882f4c1fa67025
6
+ metadata.gz: 4c4ebcb074e0f30928d4952b0c80f0617d3bbe7bfe0277d1ef0cb26dbad0f6bc1c14bd012dff0aec880bcf35db2c09267e5087de56432e94221dfc8adc3aa7fb
7
+ data.tar.gz: 3bb3d1486bf4cc093175aa5fd28cb6afe5f6f7691d72d116dc730e333904b0a61b7637abd687d8e90609e5a9d76824f938f837949e122c790dec61ad33528504
data/Gemfile.lock CHANGED
@@ -1,38 +1,47 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- backupper (0.5.1)
5
- mail (~> 2.7)
6
- sshkit (~> 1.15)
4
+ backupper (0.6.0)
5
+ mail (~> 2.9)
6
+ sshkit (~> 1.25)
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
- byebug (11.0.1)
12
- date (3.3.3)
13
- mail (2.8.0)
11
+ base64 (0.3.0)
12
+ date (3.5.1)
13
+ logger (1.7.0)
14
+ mail (2.9.1)
15
+ logger
14
16
  mini_mime (>= 0.1.1)
15
17
  net-imap
16
18
  net-pop
17
19
  net-smtp
18
- mini_mime (1.1.2)
19
- net-imap (0.3.4)
20
+ mini_mime (1.1.5)
21
+ net-imap (0.6.4.1)
20
22
  date
21
23
  net-protocol
22
24
  net-pop (0.1.2)
23
25
  net-protocol
24
- net-protocol (0.2.1)
26
+ net-protocol (0.2.2)
25
27
  timeout
26
- net-scp (4.0.0)
28
+ net-scp (4.1.0)
27
29
  net-ssh (>= 2.6.5, < 8.0.0)
28
- net-smtp (0.3.3)
30
+ net-sftp (4.0.0)
31
+ net-ssh (>= 5.0.0, < 8.0.0)
32
+ net-smtp (0.5.1)
29
33
  net-protocol
30
- net-ssh (7.0.1)
31
- rake (10.5.0)
32
- sshkit (1.21.3)
34
+ net-ssh (7.3.3)
35
+ ostruct (0.6.3)
36
+ rake (13.4.2)
37
+ sshkit (1.25.0)
38
+ base64
39
+ logger
33
40
  net-scp (>= 1.1.2)
41
+ net-sftp (>= 2.1.2)
34
42
  net-ssh (>= 2.8.0)
35
- timeout (0.3.1)
43
+ ostruct
44
+ timeout (0.6.1)
36
45
 
37
46
  PLATFORMS
38
47
  ruby
@@ -40,9 +49,8 @@ PLATFORMS
40
49
 
41
50
  DEPENDENCIES
42
51
  backupper!
43
- bundler (~> 2)
44
- byebug (~> 11)
45
- rake (~> 10.0)
52
+ bundler
53
+ rake
46
54
 
47
55
  BUNDLED WITH
48
- 2.3.8
56
+ 4.0.15
data/README.md CHANGED
@@ -20,6 +20,10 @@ mailer:
20
20
  to: pioz@email.com # Send report email to this address
21
21
  password: Pa$$w0rD # Gmail account password
22
22
 
23
+ default: # options here are merged into all database configurations below
24
+ port: 22
25
+ db_username: backup
26
+
23
27
  db1:
24
28
  disabled: false # true to disable this backup
25
29
  dump: '/home/backup/db1' # path where to save the dump of the database
@@ -27,12 +31,13 @@ db1:
27
31
  username: user # server ssh username
28
32
  host: '1.2.3.4' # server ssh ip
29
33
  port: 22 # server ssh port
30
- password: Pa$$w0rD # server ssh password
31
- adapter: mysql # database to backup (supported are mysql or postgresql)
34
+ password: Pa$$w0rD # server ssh password (also used as sudo password when sudo is true)
35
+ sudo: false # true to run the dump command with sudo
36
+ adapter: mysql # adapter to use to perform the backup (mysql, postgresql or mydumper)
32
37
  database: db_name # database name
33
38
  db_username: db_user # database username
34
39
  db_password: db_Pa$$w0rD # database password
35
- dump_options: '--single-transaction --quick' # dump command extra options
40
+ dump_options: '--single-transaction --quick' # dump command extra options (shell-style quoted or YAML array)
36
41
 
37
42
  db2:
38
43
  disabled: false
@@ -55,12 +60,25 @@ After done all backups a report email is sent to you using gmail smtp service (r
55
60
  To backup only specific databases you can pass the option `-o db1,db3`. In this way only databases under the key `db1` and `db3` will be backupped,
56
61
  ignoring the others configuration keys.
57
62
 
58
- ## Resources
59
- * [Blog post about Backupper](https://tech.uqido.com/2018/07/16/backupper-tool-backup-database/) (italian only).
63
+ ## Custom adapters
64
+
65
+ An adapter is just a module method of `DumpCommand` that returns the shell command used to dump the database:
66
+
67
+ ```ruby
68
+ def self.myadapter(database:, username: 'root', password: nil, dump_options: nil, working_dir: nil, outfile:)
69
+ return "mydump #{database} -u #{username} > #{outfile}"
70
+ end
71
+ ```
72
+
73
+ All the values arrive already shell-escaped: interpolate them as they are, without wrapping them in quotes. `dump_options` is parsed as shell-style arguments, then each argument is escaped before it reaches the adapter. The command must write the dump to `outfile`; `working_dir` is an empty temporary directory you can use as scratch space (both are removed from the server after the download). If your adapter produces a file format different from `.sql.bz2`, add its extension to `DumpCommand::EXTENSIONS`.
60
74
 
61
75
  ## Contributing
62
76
 
63
- Bug reports and pull requests are welcome on GitHub at https://github.com/uqido/backupper.
77
+ Bug reports and pull requests are welcome on GitHub at https://github.com/pioz/backupper.
78
+
79
+ ## Resources
80
+ * [Blog post about Backupper](https://tech.uqido.com/2018/07/16/backupper-tool-backup-database/) (italian only).
81
+
64
82
 
65
83
  ## License
66
84
 
data/Rakefile CHANGED
@@ -1,2 +1 @@
1
1
  require 'bundler/gem_tasks'
2
- task default: :spec
data/backupper.gemspec CHANGED
@@ -6,11 +6,11 @@ Gem::Specification.new do |spec|
6
6
  spec.name = 'backupper'
7
7
  spec.version = Backupper::VERSION
8
8
  spec.authors = ['pioz']
9
- spec.email = ['enrico.pilotto@uqido.com']
9
+ spec.email = ['epilotto@gmx.com']
10
10
 
11
11
  spec.summary = 'Tool to backup databases'
12
12
  spec.description = 'Backupper is a tool to backup all your databases spread all over the world'
13
- spec.homepage = 'https://github.com/uqido/backupper'
13
+ spec.homepage = 'https://github.com/pioz/backupper'
14
14
  spec.license = 'MIT'
15
15
 
16
16
  # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
@@ -28,10 +28,10 @@ Gem::Specification.new do |spec|
28
28
  spec.executables = spec.files.grep(/^bin\//) { |f| File.basename(f) }
29
29
  spec.require_paths = ['lib']
30
30
 
31
- spec.add_runtime_dependency 'mail', '~> 2.7'
32
- spec.add_runtime_dependency 'sshkit', '~> 1.15'
31
+ spec.required_ruby_version = '>= 2.5'
32
+ spec.add_runtime_dependency 'mail', '~> 2.9'
33
+ spec.add_runtime_dependency 'sshkit', '~> 1.25'
33
34
 
34
- spec.add_development_dependency 'bundler', '~> 2'
35
- spec.add_development_dependency 'byebug', '~> 11'
36
- spec.add_development_dependency 'rake', '~> 10.0'
35
+ spec.add_development_dependency 'bundler'
36
+ spec.add_development_dependency 'rake'
37
37
  end
@@ -1,10 +1,12 @@
1
1
  require 'fileutils'
2
+ require 'shellwords'
2
3
  require 'sshkit'
3
4
  require 'sshkit/dsl'
4
5
  require 'yaml'
5
6
 
6
7
  require_relative 'dump_command'
7
8
  require_relative 'mailer'
9
+ require_relative 'sshkit'
8
10
 
9
11
  class Backupper
10
12
  include SSHKit::DSL
@@ -28,7 +30,14 @@ class Backupper
28
30
 
29
31
  def backup!(only_these_keys = nil)
30
32
  filtered_conf = @conf
31
- filtered_conf = @conf.slice(*only_these_keys) if only_these_keys
33
+ if only_these_keys
34
+ filtered_conf = @conf.slice(*only_these_keys)
35
+ (only_these_keys - @conf.keys).each do |k|
36
+ err = "Configuration key '#{k}' not found or disabled!"
37
+ error(k, err)
38
+ @logger.error err
39
+ end
40
+ end
32
41
  filtered_conf.each do |k, options|
33
42
  @logger.info "[#{Time.now}] ⬇️ backing up #{k}..."
34
43
  o, err = setup_options(options)
@@ -38,7 +47,7 @@ class Backupper
38
47
  next
39
48
  end
40
49
  begin
41
- download_dump(
50
+ do_and_download_dump(
42
51
  key: k,
43
52
  adapter: o['adapter'],
44
53
  url: o['url'],
@@ -47,6 +56,7 @@ class Backupper
47
56
  db_username: o['db_username'],
48
57
  db_password: o['db_password'],
49
58
  dump_options: o['dump_options'],
59
+ sudo: o['sudo'],
50
60
  outdir: o['outdir'],
51
61
  extra_copy: o['extra_copy']
52
62
  )
@@ -58,31 +68,45 @@ class Backupper
58
68
  send_report_email!
59
69
  end
60
70
 
61
- def download_dump(key:, adapter: 'mysql', url:, password: nil, database:, db_username: 'root', db_password: nil, dump_options: nil, outdir:, extra_copy: nil)
62
- t = Process.clock_gettime(Process::CLOCK_MONOTONIC)
63
- path = nil
64
- filename = "#{key}__#{database}.sql.bz2"
65
- tempfile = File.join('/tmp', filename)
66
- dumpname = "#{Time.now.strftime('%Y-%m-%d_%H-%M-%S')}__#{filename}"
67
- path = File.join(outdir, dumpname)
68
- on(url) do |client|
69
- client.password = password
70
- execute 'set -o pipefail; ' + DumpCommand.send(adapter, database: database, username: db_username, password: db_password, dump_options: dump_options, outfile: tempfile)
71
- download! tempfile, path
72
- execute :rm, tempfile
73
- end
74
- extra_copy = check_dir(extra_copy)
75
- FileUtils.cp(path, extra_copy) if extra_copy
76
- @report[key] = {
77
- path: File.absolute_path(path),
78
- size: (File.size(path).to_f / 2**20).round(2),
79
- time: (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t).round(2)
80
- }
81
- @report[key].merge!({ extra_copy: File.absolute_path(File.join(extra_copy, dumpname)) }) if extra_copy
82
- end
83
-
84
71
  private
85
72
 
73
+ def do_and_download_dump(key:, adapter: 'mysql', url:, password: nil, database:, db_username: 'root', db_password: nil, dump_options: nil, sudo: false, outdir:, extra_copy: nil)
74
+ t = Process.clock_gettime(Process::CLOCK_MONOTONIC)
75
+ filename = "#{key}__#{database}#{DumpCommand::EXTENSIONS[adapter]}"
76
+ temp_file = File.join('/tmp', filename)
77
+ working_dirname = "#{key}__#{database}"
78
+ temp_working_dir = File.join('/tmp', working_dirname)
79
+ dump_name = "#{Time.now.strftime('%Y-%m-%d_%H-%M-%S')}__#{filename}"
80
+ path = File.join(outdir, dump_name)
81
+ outfile = Shellwords.escape(temp_file)
82
+ working_dir = Shellwords.escape(temp_working_dir)
83
+ on(url) do |host|
84
+ host.password = password
85
+ sudo_execute :mkdir, '-p', working_dir, password: password, sudo: sudo
86
+ command = DumpCommand.public_send(
87
+ adapter,
88
+ database: Shellwords.escape(database),
89
+ username: Shellwords.escape(db_username),
90
+ password: db_password && Shellwords.escape(db_password),
91
+ dump_options: dump_options,
92
+ working_dir: working_dir,
93
+ outfile: outfile
94
+ )
95
+ sudo_execute 'set -o pipefail; ' + command, password: password, sudo: sudo
96
+ download! temp_file, path
97
+ sudo_execute :rm, outfile, password: password, sudo: sudo
98
+ sudo_execute :rm, '-r', working_dir, password: password, sudo: sudo
99
+ end
100
+ extra_copy = check_dir(extra_copy)
101
+ FileUtils.cp(path, extra_copy) if extra_copy
102
+ @report[key] = {
103
+ path: File.absolute_path(path),
104
+ size: (File.size(path).to_f / 2**20).round(2),
105
+ time: (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t).round(2)
106
+ }
107
+ @report[key][:extra_copy] = File.absolute_path(File.join(extra_copy, dump_name)) if extra_copy
108
+ end
109
+
86
110
  def setup_options(options)
87
111
  o = @default.merge(options)
88
112
  o['outdir'] = check_dir(o['dump'].to_s)
@@ -94,17 +118,38 @@ class Backupper
94
118
  o['url'] = "#{o['username']}@#{o['url']}" if o['username']
95
119
  o['url'] = "#{o['url']}:#{o['port']}" if o['port']
96
120
  o['adapter'] ||= 'mysql'
97
- unless DumpCommand.respond_to?(o['adapter'])
98
- return nil, "Cannot handle adapter '#{o['adapter']}'"
121
+ unless DumpCommand.singleton_methods(false).map(&:to_s).include?(o['adapter'])
122
+ return nil, "Cannot handle adapter '#{o['adapter']}' (supported: #{DumpCommand.singleton_methods(false).join(', ')})"
123
+ end
124
+ begin
125
+ shellescape_dump_options(o['dump_options'])
126
+ rescue ArgumentError => e
127
+ return nil, e.message
99
128
  end
100
129
 
101
130
  return o, nil
102
131
  end
103
132
 
133
+ def shellescape_dump_options(dump_options)
134
+ return nil if dump_options.nil?
135
+
136
+ options =
137
+ if dump_options.is_a?(Array)
138
+ dump_options.map(&:to_s)
139
+ else
140
+ Shellwords.split(dump_options.to_s)
141
+ end
142
+ return nil if options.empty?
143
+
144
+ return options.map { |option| Shellwords.escape(option) }.join(' ')
145
+ rescue ArgumentError => e
146
+ raise ArgumentError, "Invalid dump_options: #{e.message}"
147
+ end
148
+
104
149
  def send_report_email!
105
150
  if @report.any? && @mailer['from'] && @mailer['to'] && @mailer['password']
106
151
  begin
107
- Mailer.send(@report, from: @mailer['from'], to: @mailer['to'], password: @mailer['password'], address: @mailer['address'] || 'smtp.gmail.com', port: @mailer['port'] || 587, authentication: @mailer['authentication'] || 'plain')
152
+ Mailer.deliver(@report, from: @mailer['from'], to: @mailer['to'], password: @mailer['password'], address: @mailer['address'] || 'smtp.gmail.com', port: @mailer['port'] || 587, authentication: @mailer['authentication'] || 'plain')
108
153
  rescue Net::SMTPAuthenticationError => e
109
154
  @logger.error e
110
155
  end
@@ -1,16 +1,27 @@
1
1
  module DumpCommand
2
- def self.mysql(database:, username: 'root', password: nil, dump_options: nil, outfile:)
2
+ # Extension of the file produced by each adapter ('.sql.bz2' if not listed here)
3
+ EXTENSIONS = Hash.new('.sql.bz2').update('mydumper' => '.tar.bz2').freeze
4
+
5
+ def self.mysql(database:, username: 'root', password: nil, dump_options: nil, working_dir: nil, outfile:)
6
+ params = []
7
+ params << "-u#{username}"
8
+ params << "-p#{password}" if password
9
+ params << dump_options if dump_options
10
+ return "mysqldump #{database} #{params.join(' ')} | bzip2 > #{outfile}"
11
+ end
12
+
13
+ def self.postgresql(database:, username: 'root', password: nil, dump_options: nil, working_dir: nil, outfile:)
3
14
  params = []
4
- params << "-u'#{username}'"
5
- params << "-p'#{password}'" if password
15
+ params << "-U #{username}"
6
16
  params << dump_options if dump_options
7
- return "mysqldump '#{database}' #{params.join(' ')} | bzip2 > '#{outfile}'"
17
+ return "PGPASSWORD=#{password} pg_dump #{database} #{params.join(' ')} | bzip2 > #{outfile}"
8
18
  end
9
19
 
10
- def self.postgresql(database:, username: 'root', password: nil, dump_options: nil, outfile:)
20
+ def self.mydumper(database:, username: 'root', password: nil, dump_options: nil, working_dir: nil, outfile:)
11
21
  params = []
12
- params << "-U '#{username}'"
22
+ params << "--user #{username}"
23
+ params << "--password #{password}" if password
13
24
  params << dump_options if dump_options
14
- return "PGPASSWORD='#{password}' pg_dump '#{database}' #{params.join(' ')} | bzip2 > '#{outfile}'"
25
+ return "mydumper --database #{database} #{params.join(' ')} --outputdir #{working_dir} && tar -cjf #{outfile} -C #{File.dirname(working_dir)} #{File.basename(working_dir)}"
15
26
  end
16
27
  end
@@ -1,7 +1,7 @@
1
1
  require 'mail'
2
2
 
3
3
  class Mailer
4
- def self.send(report, from:, to:, password:, address:, port:, authentication:)
4
+ def self.deliver(report, from:, to:, password:, address:, port:, authentication:)
5
5
  Mail.defaults do
6
6
  delivery_method :smtp, {
7
7
  address: address,
@@ -12,7 +12,7 @@ class Mailer
12
12
  enable_starttls_auto: true
13
13
  }
14
14
  end
15
- Mail.deliver(to: to, from: from, subject: generate_subject(report), body: generate_body(report))
15
+ Mail.deliver(to: to, from: from, subject: generate_subject(report), body: generate_body(report), charset: 'UTF-8')
16
16
  end
17
17
 
18
18
  class << self
@@ -0,0 +1,23 @@
1
+ require 'shellwords'
2
+ require 'sshkit'
3
+
4
+ module SSHKitSudoExecute
5
+ def sudo_execute(*command, password: nil, sudo: false, **options)
6
+ return execute(*command, options) unless sudo
7
+
8
+ prompt = 'SSHKitSudoPassword'
9
+ execute(
10
+ :sudo,
11
+ '-S',
12
+ '-p', prompt,
13
+ '--',
14
+ 'bash', '-c', command.map(&:to_s).join(' ').shellescape,
15
+ options.merge(
16
+ interaction_handler: {
17
+ /#{Regexp.escape(prompt)}/ => "#{password}\n"
18
+ }
19
+ )
20
+ )
21
+ end
22
+ end
23
+ SSHKit::Backend::Abstract.include(SSHKitSudoExecute)
@@ -1,3 +1,3 @@
1
1
  class Backupper
2
- VERSION = '0.5.2'.freeze
2
+ VERSION = '0.6.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: backupper
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.2
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - pioz
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-02-02 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: mail
@@ -16,74 +15,60 @@ dependencies:
16
15
  requirements:
17
16
  - - "~>"
18
17
  - !ruby/object:Gem::Version
19
- version: '2.7'
18
+ version: '2.9'
20
19
  type: :runtime
21
20
  prerelease: false
22
21
  version_requirements: !ruby/object:Gem::Requirement
23
22
  requirements:
24
23
  - - "~>"
25
24
  - !ruby/object:Gem::Version
26
- version: '2.7'
25
+ version: '2.9'
27
26
  - !ruby/object:Gem::Dependency
28
27
  name: sshkit
29
28
  requirement: !ruby/object:Gem::Requirement
30
29
  requirements:
31
30
  - - "~>"
32
31
  - !ruby/object:Gem::Version
33
- version: '1.15'
32
+ version: '1.25'
34
33
  type: :runtime
35
34
  prerelease: false
36
35
  version_requirements: !ruby/object:Gem::Requirement
37
36
  requirements:
38
37
  - - "~>"
39
38
  - !ruby/object:Gem::Version
40
- version: '1.15'
39
+ version: '1.25'
41
40
  - !ruby/object:Gem::Dependency
42
41
  name: bundler
43
42
  requirement: !ruby/object:Gem::Requirement
44
43
  requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '2'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '2'
55
- - !ruby/object:Gem::Dependency
56
- name: byebug
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
44
+ - - ">="
60
45
  - !ruby/object:Gem::Version
61
- version: '11'
46
+ version: '0'
62
47
  type: :development
63
48
  prerelease: false
64
49
  version_requirements: !ruby/object:Gem::Requirement
65
50
  requirements:
66
- - - "~>"
51
+ - - ">="
67
52
  - !ruby/object:Gem::Version
68
- version: '11'
53
+ version: '0'
69
54
  - !ruby/object:Gem::Dependency
70
55
  name: rake
71
56
  requirement: !ruby/object:Gem::Requirement
72
57
  requirements:
73
- - - "~>"
58
+ - - ">="
74
59
  - !ruby/object:Gem::Version
75
- version: '10.0'
60
+ version: '0'
76
61
  type: :development
77
62
  prerelease: false
78
63
  version_requirements: !ruby/object:Gem::Requirement
79
64
  requirements:
80
- - - "~>"
65
+ - - ">="
81
66
  - !ruby/object:Gem::Version
82
- version: '10.0'
67
+ version: '0'
83
68
  description: Backupper is a tool to backup all your databases spread all over the
84
69
  world
85
70
  email:
86
- - enrico.pilotto@uqido.com
71
+ - epilotto@gmx.com
87
72
  executables:
88
73
  - backupper
89
74
  extensions: []
@@ -101,13 +86,13 @@ files:
101
86
  - lib/backupper/backupper.rb
102
87
  - lib/backupper/dump_command.rb
103
88
  - lib/backupper/mailer.rb
89
+ - lib/backupper/sshkit.rb
104
90
  - lib/backupper/version.rb
105
- homepage: https://github.com/uqido/backupper
91
+ homepage: https://github.com/pioz/backupper
106
92
  licenses:
107
93
  - MIT
108
94
  metadata:
109
95
  allowed_push_host: https://rubygems.org
110
- post_install_message:
111
96
  rdoc_options: []
112
97
  require_paths:
113
98
  - lib
@@ -115,15 +100,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
115
100
  requirements:
116
101
  - - ">="
117
102
  - !ruby/object:Gem::Version
118
- version: '0'
103
+ version: '2.5'
119
104
  required_rubygems_version: !ruby/object:Gem::Requirement
120
105
  requirements:
121
106
  - - ">="
122
107
  - !ruby/object:Gem::Version
123
108
  version: '0'
124
109
  requirements: []
125
- rubygems_version: 3.5.3
126
- signing_key:
110
+ rubygems_version: 4.0.15
127
111
  specification_version: 4
128
112
  summary: Tool to backup databases
129
113
  test_files: []