psql_toys 0.3.2
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 +7 -0
- data/CHANGELOG.md +22 -0
- data/LICENSE.txt +21 -0
- data/README.md +73 -0
- data/lib/psql_toys.rb +4 -0
- data/lib/psql_toys/template.rb +41 -0
- data/lib/psql_toys/template/_base.rb +61 -0
- data/lib/psql_toys/template/console.rb +21 -0
- data/lib/psql_toys/template/create.rb +27 -0
- data/lib/psql_toys/template/create_extensions.rb +23 -0
- data/lib/psql_toys/template/drop.rb +44 -0
- data/lib/psql_toys/template/dumps.rb +29 -0
- data/lib/psql_toys/template/dumps/_base.rb +32 -0
- data/lib/psql_toys/template/dumps/_dump_file.rb +118 -0
- data/lib/psql_toys/template/dumps/create.rb +48 -0
- data/lib/psql_toys/template/dumps/list.rb +22 -0
- data/lib/psql_toys/template/dumps/restore.rb +85 -0
- data/lib/psql_toys/version.rb +5 -0
- metadata +253 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 75df97b557beb8bb2f82f96a8c1208cabadb0e183d6c8d434b0e02df2452d663
|
4
|
+
data.tar.gz: bd53f9c14644aef52db7766e761093bfa692c8348236d20a5fb64e9b432e5b46
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0e10936aa031bb050bd1c990cb308939155ff903067c0bebd8b48bd6c5619e7a2e05c4eee9f48948a8d09bbb62d8510a3094143c2da149aedaedce412aed6c92
|
7
|
+
data.tar.gz: 9f7df993677af892347ffa6234fd4dfe9e972eccdd0e5d56e1bf2c5a5bf99e70caaafc00af77a677911d26824e8c3206ae09c383c47c540441b286b591f6167c
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
## master (unreleased)
|
4
|
+
|
5
|
+
## 0.3.2 (2020-09-24)
|
6
|
+
|
7
|
+
## 0.3.1 (2020-09-11)
|
8
|
+
|
9
|
+
* Require `memery` where necessary.
|
10
|
+
|
11
|
+
## 0.3.0 (2020-08-23)
|
12
|
+
|
13
|
+
* Update `toys`.
|
14
|
+
|
15
|
+
## 0.2.0 (2020-08-02)
|
16
|
+
|
17
|
+
* Move `subtool_apply` and dependencies requirements inside `tool :database`
|
18
|
+
* Remove `unless include? :exec` condition, there should not be any `include :exec` outside.
|
19
|
+
|
20
|
+
## 0.1.0 (2020-07-13)
|
21
|
+
|
22
|
+
* Initial release.
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2020 Alexander Popov
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
# PSQL Toys
|
2
|
+
|
3
|
+
[](https://cirrus-ci.com/github/AlexWayfer/psql_toys)
|
4
|
+
[](https://codecov.io/gh/AlexWayfer/psql_toys)
|
5
|
+
[](https://codeclimate.com/github/AlexWayfer/psql_toys)
|
6
|
+
[](https://depfu.com/repos/github/AlexWayfer/psql_toys)
|
7
|
+
[](https://inch-ci.org/github/AlexWayfer/psql_toys)
|
8
|
+
[](https://github.com/AlexWayfer/psql_toys/blob/master/LICENSE.txt)
|
9
|
+
[](https://rubygems.org/gems/psql_toys)
|
10
|
+
|
11
|
+
Toys template for actions with PostgreSQL, like dumps.
|
12
|
+
|
13
|
+
## Installation
|
14
|
+
|
15
|
+
Add this line to your application's Gemfile:
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
gem 'psql_toys'
|
19
|
+
```
|
20
|
+
|
21
|
+
And then execute:
|
22
|
+
|
23
|
+
```shell
|
24
|
+
bundle install
|
25
|
+
```
|
26
|
+
|
27
|
+
Or install it yourself as:
|
28
|
+
|
29
|
+
```shell
|
30
|
+
gem install psql_toys
|
31
|
+
```
|
32
|
+
|
33
|
+
## Usage
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
application_proc = proc do
|
37
|
+
require "#{context_directory}/application"
|
38
|
+
MyProject::Application
|
39
|
+
end
|
40
|
+
|
41
|
+
require 'psql_toys'
|
42
|
+
expand PSQLToys::Template,
|
43
|
+
db_config_proc: proc { application_proc.call.config[:database] },
|
44
|
+
db_connection_proc: proc { application_proc.call.db_connection },
|
45
|
+
db_extensions: %w[citext pgcrypto] # this is default, can be changed
|
46
|
+
|
47
|
+
# `database` namespace created
|
48
|
+
# aliases are optional, but handful
|
49
|
+
alias_tool :db, :database
|
50
|
+
```
|
51
|
+
|
52
|
+
`db_config` must have `:database` key, and my have `:host`, `:port`, `:user`,
|
53
|
+
`:superuser` (for database and user creation) and `:password` keys.
|
54
|
+
|
55
|
+
## Development
|
56
|
+
|
57
|
+
After checking out the repo, run `bundle install` to install dependencies.
|
58
|
+
|
59
|
+
Then, run `toys rspec` to run the tests.
|
60
|
+
|
61
|
+
To install this gem onto your local machine, run `toys gem install`.
|
62
|
+
|
63
|
+
To release a new version, run `toys gem release %version%`.
|
64
|
+
See how it works [here](https://github.com/AlexWayfer/gem_toys#release).
|
65
|
+
|
66
|
+
## Contributing
|
67
|
+
|
68
|
+
Bug reports and pull requests are welcome on [GitHub](https://github.com/AlexWayfer/psql_toys).
|
69
|
+
|
70
|
+
## License
|
71
|
+
|
72
|
+
The gem is available as open source under the terms of the
|
73
|
+
[MIT License](https://opensource.org/licenses/MIT).
|
data/lib/psql_toys.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'toys-core'
|
4
|
+
|
5
|
+
module PSQLToys
|
6
|
+
## Define toys for Sequel migrations
|
7
|
+
class Template
|
8
|
+
include Toys::Template
|
9
|
+
|
10
|
+
attr_reader :db_config_proc, :db_connection_proc, :db_extensions
|
11
|
+
|
12
|
+
def initialize(db_config_proc:, db_connection_proc:, db_extensions: %w[citext pgcrypto])
|
13
|
+
@db_config_proc = db_config_proc
|
14
|
+
@db_connection_proc = db_connection_proc
|
15
|
+
@db_extensions = db_extensions
|
16
|
+
end
|
17
|
+
|
18
|
+
on_expand do |template|
|
19
|
+
tool :database do
|
20
|
+
subtool_apply do
|
21
|
+
include :exec, exit_on_nonzero_status: true, log_level: Logger::UNKNOWN
|
22
|
+
end
|
23
|
+
|
24
|
+
require_relative 'template/_base'
|
25
|
+
|
26
|
+
require 'gorilla_patch/inflections'
|
27
|
+
using GorillaPatch::Inflections
|
28
|
+
|
29
|
+
%w[Create CreateExtensions Drop Console Dumps].each do |template_name|
|
30
|
+
require_relative "template/#{template_name.underscore}"
|
31
|
+
expand Template.const_get(template_name, false),
|
32
|
+
db_config_proc: template.db_config_proc,
|
33
|
+
db_connection_proc: template.db_connection_proc,
|
34
|
+
db_extensions: template.db_extensions
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
alias_tool :psql, 'database:psql'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'memery'
|
4
|
+
|
5
|
+
module PSQLToys
|
6
|
+
class Template
|
7
|
+
## Base class for templates
|
8
|
+
class Base
|
9
|
+
include Toys::Template
|
10
|
+
include Memery
|
11
|
+
|
12
|
+
## `db_config_proc` getter for `Dumps` sub-tools
|
13
|
+
attr_reader :db_config_proc, :db_connection_proc, :db_extensions
|
14
|
+
|
15
|
+
def initialize(db_config_proc:, db_connection_proc: nil, db_extensions:)
|
16
|
+
@db_config_proc = db_config_proc
|
17
|
+
@db_connection_proc = db_connection_proc
|
18
|
+
@db_extensions = db_extensions
|
19
|
+
end
|
20
|
+
|
21
|
+
memoize def db_config
|
22
|
+
db_config_proc.call
|
23
|
+
end
|
24
|
+
|
25
|
+
memoize def db_access(superuser: false)
|
26
|
+
user = superuser ? db_config.fetch(:superuser, 'postgres') : db_config[:user]
|
27
|
+
|
28
|
+
{ '-U' => user, '-h' => db_config[:host] }
|
29
|
+
.compact
|
30
|
+
.map { |key, value| "#{key} #{value}" }
|
31
|
+
.join(' ')
|
32
|
+
end
|
33
|
+
|
34
|
+
memoize def db_connection
|
35
|
+
db_connection_proc.call
|
36
|
+
end
|
37
|
+
|
38
|
+
PGPASS_FILE = File.expand_path '~/.pgpass'
|
39
|
+
|
40
|
+
def update_pgpass
|
41
|
+
pgpass_lines =
|
42
|
+
File.exist?(PGPASS_FILE) ? File.read(PGPASS_FILE).split($RS) : []
|
43
|
+
|
44
|
+
return if pgpass_lines&.include? pgpass_line
|
45
|
+
|
46
|
+
File.write PGPASS_FILE, pgpass_lines.push(pgpass_line, nil).join($RS)
|
47
|
+
File.chmod(0o600, PGPASS_FILE)
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
memoize def pgpass_line
|
53
|
+
db_config
|
54
|
+
.fetch_values(:host, :port, :database, :user, :password) { |_key| '*' }
|
55
|
+
.join(':')
|
56
|
+
end
|
57
|
+
|
58
|
+
# db_connection.loggers << Logger.new($stdout)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PSQLToys
|
4
|
+
class Template
|
5
|
+
## Define toys for PSQL console
|
6
|
+
class Console < Base
|
7
|
+
on_expand do |template|
|
8
|
+
tool :console do
|
9
|
+
desc 'Start PSQL console'
|
10
|
+
|
11
|
+
to_run do
|
12
|
+
template.update_pgpass
|
13
|
+
sh "psql #{template.db_access} #{template.db_config[:database]}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
alias_tool :psql, :console
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PSQLToys
|
4
|
+
class Template
|
5
|
+
## Define toys for database creation
|
6
|
+
class Create < Base
|
7
|
+
on_expand do |template|
|
8
|
+
tool :create do
|
9
|
+
desc 'Create empty DB'
|
10
|
+
|
11
|
+
to_run do
|
12
|
+
database = template.db_config[:database]
|
13
|
+
|
14
|
+
sh <<~CMD
|
15
|
+
createdb #{template.db_access(superuser: true)} #{database} \
|
16
|
+
-O #{template.db_config[:user]}
|
17
|
+
CMD
|
18
|
+
|
19
|
+
exec_tool 'db:create_extensions'
|
20
|
+
|
21
|
+
puts "Database #{database} created."
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PSQLToys
|
4
|
+
class Template
|
5
|
+
## Define toys for database extensions creation
|
6
|
+
class CreateExtensions < Base
|
7
|
+
on_expand do |template|
|
8
|
+
tool :create_extensions do
|
9
|
+
desc 'Create extensions for existing DB'
|
10
|
+
|
11
|
+
to_run do
|
12
|
+
db_access = template.db_access(superuser: true)
|
13
|
+
database = template.db_config[:database]
|
14
|
+
|
15
|
+
template.db_extensions.each do |db_extension|
|
16
|
+
sh "psql #{db_access} -c 'CREATE EXTENSION #{db_extension}' #{database}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PSQLToys
|
4
|
+
class Template
|
5
|
+
## Define toys for database drop
|
6
|
+
class Drop < Base
|
7
|
+
on_expand do |template|
|
8
|
+
tool :drop do
|
9
|
+
desc 'Drop DB'
|
10
|
+
|
11
|
+
flag :force, '-f', '--[no-]force'
|
12
|
+
flag :question, '-q', '--[no-]question', default: true
|
13
|
+
|
14
|
+
to_run do
|
15
|
+
@database = template.db_config[:database]
|
16
|
+
|
17
|
+
ask_question if question
|
18
|
+
|
19
|
+
exec_tool 'db:dump' unless force
|
20
|
+
|
21
|
+
template.db_connection.disconnect
|
22
|
+
sh "dropdb --if-exists #{template.db_access} #{@database}"
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def ask_question
|
28
|
+
require 'highline'
|
29
|
+
highline = HighLine.new
|
30
|
+
|
31
|
+
highline.choose do |menu|
|
32
|
+
menu.layout = :one_line
|
33
|
+
|
34
|
+
menu.prompt = "Drop #{@database} ? "
|
35
|
+
|
36
|
+
menu.choice(:yes) {}
|
37
|
+
menu.choice(:no) { abort 'OK' }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PSQLToys
|
4
|
+
class Template
|
5
|
+
## Define toys for PostgreSQL dumps
|
6
|
+
class Dumps < Base
|
7
|
+
on_expand do |template|
|
8
|
+
tool :dumps do
|
9
|
+
require_relative 'dumps/_base'
|
10
|
+
|
11
|
+
subtool_apply do
|
12
|
+
include Dumps::Base::CommonPSQLDumpsCode
|
13
|
+
end
|
14
|
+
|
15
|
+
%w[Create List Restore].each do |template_name|
|
16
|
+
require_relative "dumps/#{template_name.downcase}"
|
17
|
+
expand Dumps.const_get(template_name, false),
|
18
|
+
db_config_proc: template.db_config_proc,
|
19
|
+
db_extensions: template.db_extensions
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
alias_tool :dump, 'dumps:create'
|
24
|
+
alias_tool :dumps, 'dumps:list'
|
25
|
+
alias_tool :restore, 'dumps:restore'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PSQLToys
|
4
|
+
class Template
|
5
|
+
class Dumps
|
6
|
+
## Base class for dumps templates
|
7
|
+
class Base < Template::Base
|
8
|
+
DB_DUMP_FORMATS = %w[custom plain].freeze
|
9
|
+
|
10
|
+
## Common code for dumps toys
|
11
|
+
module CommonPSQLDumpsCode
|
12
|
+
def db_dumps_dir
|
13
|
+
"#{context_directory}/db/dumps"
|
14
|
+
end
|
15
|
+
|
16
|
+
def dump_file_class(db_config)
|
17
|
+
return @dump_file_class if defined? @dump_file_class
|
18
|
+
|
19
|
+
require_relative '_dump_file'
|
20
|
+
|
21
|
+
db_dumps_dir = self.db_dumps_dir
|
22
|
+
|
23
|
+
@dump_file_class = Class.new(DumpFile) do
|
24
|
+
self.db_dumps_dir = db_dumps_dir
|
25
|
+
self.db_config = db_config
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'paint'
|
4
|
+
|
5
|
+
## Class for single DB dump file
|
6
|
+
class DumpFile
|
7
|
+
DB_DUMP_TIMESTAMP = '%Y-%m-%d_%H-%M'
|
8
|
+
|
9
|
+
DB_DUMP_TIMESTAMP_REGEXP_MAP = {
|
10
|
+
'Y' => '\d{4}',
|
11
|
+
'm' => '\d{2}',
|
12
|
+
'd' => '\d{2}',
|
13
|
+
'H' => '\d{2}',
|
14
|
+
'M' => '\d{2}'
|
15
|
+
}.freeze
|
16
|
+
|
17
|
+
missing_keys =
|
18
|
+
DB_DUMP_TIMESTAMP.scan(/%(\w)/).flatten -
|
19
|
+
DB_DUMP_TIMESTAMP_REGEXP_MAP.keys
|
20
|
+
|
21
|
+
if missing_keys.any?
|
22
|
+
raise "`DB_DUMP_TIMESTAMP_REGEXP_MAP` doesn't contain keys" \
|
23
|
+
" #{missing_keys} for `DB_DUMP_TIMESTAMP`"
|
24
|
+
end
|
25
|
+
|
26
|
+
DB_DUMP_TIMESTAMP_REGEXP =
|
27
|
+
DB_DUMP_TIMESTAMP_REGEXP_MAP
|
28
|
+
.each_with_object(DB_DUMP_TIMESTAMP.dup) do |(key, value), result|
|
29
|
+
result.gsub! "%#{key}", value
|
30
|
+
end
|
31
|
+
|
32
|
+
DB_DUMP_EXTENSIONS = {
|
33
|
+
'plain' => '.sql',
|
34
|
+
'custom' => '.dump'
|
35
|
+
}.freeze
|
36
|
+
|
37
|
+
missing_formats = PSQLToys::Template::Dumps::Base::DB_DUMP_FORMATS.reject do |db_dump_format|
|
38
|
+
DB_DUMP_EXTENSIONS[db_dump_format]
|
39
|
+
end
|
40
|
+
|
41
|
+
if missing_formats.any?
|
42
|
+
raise "`DB_DUMP_EXTENSIONS` has no keys for #{missing_formats}" \
|
43
|
+
' from `DB_DUMP_FORMATS`'
|
44
|
+
end
|
45
|
+
|
46
|
+
class << self
|
47
|
+
attr_accessor :db_dumps_dir, :db_config
|
48
|
+
|
49
|
+
def db_dump_regexp
|
50
|
+
return unless db_config
|
51
|
+
return @db_dump_regexp if defined?(@db_dump_regexp)
|
52
|
+
|
53
|
+
regexp_escaped_db_dump_extensions =
|
54
|
+
DB_DUMP_EXTENSIONS.values.map do |db_dump_extension|
|
55
|
+
Regexp.escape(db_dump_extension)
|
56
|
+
end
|
57
|
+
|
58
|
+
@db_dump_regexp = /^
|
59
|
+
#{db_dumps_dir}#{Regexp.escape(File::SEPARATOR)}
|
60
|
+
#{db_config[:database]}_#{DB_DUMP_TIMESTAMP_REGEXP}
|
61
|
+
(#{regexp_escaped_db_dump_extensions.join('|')})
|
62
|
+
$/xo
|
63
|
+
end
|
64
|
+
|
65
|
+
def all
|
66
|
+
Dir[File.join(db_dumps_dir, '*')]
|
67
|
+
.select { |file| file.match?(db_dump_regexp) }
|
68
|
+
.map! { |file| new filename: file }
|
69
|
+
.sort!
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
attr_reader :version, :timestamp, :format
|
74
|
+
|
75
|
+
def initialize(filename: nil, format: 'custom')
|
76
|
+
if filename
|
77
|
+
@extension = File.extname(filename)
|
78
|
+
@format = DB_DUMP_EXTENSIONS.key(@extension)
|
79
|
+
self.version = filename[/#{DB_DUMP_TIMESTAMP_REGEXP}/o]
|
80
|
+
else
|
81
|
+
@format = format
|
82
|
+
@extension = DB_DUMP_EXTENSIONS[@format]
|
83
|
+
self.timestamp = Time.now
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def <=>(other)
|
88
|
+
timestamp <=> other.timestamp
|
89
|
+
end
|
90
|
+
|
91
|
+
def to_s
|
92
|
+
"#{readable_timestamp} #{format}"
|
93
|
+
end
|
94
|
+
|
95
|
+
def print
|
96
|
+
puts to_s
|
97
|
+
end
|
98
|
+
|
99
|
+
def path
|
100
|
+
File.join self.class.db_dumps_dir, "#{self.class.db_config[:database]}_#{version}#{@extension}"
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
def version=(value)
|
106
|
+
@version = value
|
107
|
+
@timestamp = Time.strptime(version, DB_DUMP_TIMESTAMP)
|
108
|
+
end
|
109
|
+
|
110
|
+
def timestamp=(value)
|
111
|
+
@timestamp = value
|
112
|
+
@version = timestamp.strftime(DB_DUMP_TIMESTAMP)
|
113
|
+
end
|
114
|
+
|
115
|
+
def readable_timestamp
|
116
|
+
Paint[timestamp.strftime('%F %R'), :cyan]
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PSQLToys
|
4
|
+
class Template
|
5
|
+
class Dumps
|
6
|
+
## Define toys for PSQL dumps creation
|
7
|
+
class Create < Base
|
8
|
+
on_expand do |template|
|
9
|
+
tool :create do
|
10
|
+
desc 'Make DB dump'
|
11
|
+
|
12
|
+
flag :format, '-f', '--format=VALUE',
|
13
|
+
default: DB_DUMP_FORMATS.first,
|
14
|
+
handler: (lambda do |value, _previous|
|
15
|
+
DB_DUMP_FORMATS.find do |db_dump_format|
|
16
|
+
db_dump_format.start_with? value
|
17
|
+
end
|
18
|
+
end)
|
19
|
+
|
20
|
+
to_run do
|
21
|
+
require 'benchmark'
|
22
|
+
|
23
|
+
template.update_pgpass
|
24
|
+
|
25
|
+
sh "mkdir -p #{db_dumps_dir}"
|
26
|
+
|
27
|
+
filename = dump_file_class(template.db_config).new(format: format).path
|
28
|
+
|
29
|
+
relative_filename = filename.gsub("#{context_directory}/", '')
|
30
|
+
|
31
|
+
puts "Creating dump #{relative_filename}..."
|
32
|
+
|
33
|
+
time = Benchmark.realtime do
|
34
|
+
## https://github.com/rubocop-hq/rubocop/issues/7884
|
35
|
+
# rubocop:disable Layout/IndentationStyle
|
36
|
+
sh "pg_dump #{template.db_access} -F#{format.chr}" \
|
37
|
+
" #{template.db_config[:database]} > #{filename}"
|
38
|
+
# rubocop:enable Layout/IndentationStyle
|
39
|
+
end
|
40
|
+
|
41
|
+
puts "Done in #{time.round(2)} s."
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PSQLToys
|
4
|
+
class Template
|
5
|
+
class Dumps
|
6
|
+
## Define toys for PSQL dumps listing
|
7
|
+
class List < Base
|
8
|
+
include Toys::Template
|
9
|
+
|
10
|
+
on_expand do |template|
|
11
|
+
tool :list do
|
12
|
+
desc 'List DB dumps'
|
13
|
+
|
14
|
+
to_run do
|
15
|
+
dump_file_class(template.db_config).all.each(&:print)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PSQLToys
|
4
|
+
class Template
|
5
|
+
class Dumps
|
6
|
+
## Define toys for PSQL dumps restoring
|
7
|
+
class Restore < Base
|
8
|
+
on_expand do |template|
|
9
|
+
tool :restore do
|
10
|
+
desc 'Restore DB dump'
|
11
|
+
|
12
|
+
optional_arg :step, accept: Integer, default: -1
|
13
|
+
|
14
|
+
to_run do
|
15
|
+
@template = template
|
16
|
+
|
17
|
+
@template.update_pgpass
|
18
|
+
|
19
|
+
@dump_file = dump_file_class(@template.db_config).all[step]
|
20
|
+
|
21
|
+
abort 'Dump file not found' unless @dump_file
|
22
|
+
|
23
|
+
ask_question
|
24
|
+
|
25
|
+
drop_if_exists
|
26
|
+
|
27
|
+
exec_tool 'db:create'
|
28
|
+
|
29
|
+
restore
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def ask_question
|
35
|
+
require 'highline'
|
36
|
+
highline = HighLine.new
|
37
|
+
|
38
|
+
highline.choose do |menu|
|
39
|
+
menu.layout = :one_line
|
40
|
+
|
41
|
+
menu.prompt = "Restore #{@dump_file} ? "
|
42
|
+
|
43
|
+
menu.choice(:yes) {}
|
44
|
+
menu.choice(:no) { abort 'OK' }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def drop_if_exists
|
49
|
+
return unless sh(
|
50
|
+
"psql #{@template.db_access} -l | grep '^\s#{@template.db_config[:database]}\s'"
|
51
|
+
)
|
52
|
+
|
53
|
+
exec_tool 'db:dump'
|
54
|
+
exec_tool 'db:drop'
|
55
|
+
end
|
56
|
+
|
57
|
+
def restore
|
58
|
+
case @dump_file.format
|
59
|
+
when 'custom'
|
60
|
+
pg_restore
|
61
|
+
when 'plain'
|
62
|
+
## https://github.com/rubocop-hq/rubocop/issues/7884
|
63
|
+
# rubocop:disable Layout/IndentationStyle
|
64
|
+
sh "psql #{@template.db_access}" \
|
65
|
+
" #{@template.db_config[:database]} < #{@dump_file.path}"
|
66
|
+
# rubocop:enable Layout/IndentationStyle
|
67
|
+
else
|
68
|
+
raise 'Unknown DB dump file format'
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def pg_restore
|
73
|
+
## https://github.com/rubocop-hq/rubocop/issues/7884
|
74
|
+
# rubocop:disable Layout/IndentationStyle
|
75
|
+
sh "pg_restore #{@template.db_access} -n public" \
|
76
|
+
" -d #{@template.db_config[:database]} #{@dump_file.path}" \
|
77
|
+
' --jobs=4 --clean --if-exists'
|
78
|
+
# rubocop:enable Layout/IndentationStyle
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
metadata
ADDED
@@ -0,0 +1,253 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: psql_toys
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Alexander Popov
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-09-23 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: alt_memery
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: gorilla_patch
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3'
|
34
|
+
- - "<"
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '5'
|
37
|
+
type: :runtime
|
38
|
+
prerelease: false
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">"
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '3'
|
44
|
+
- - "<"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '5'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: toys-core
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.11.0
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: 0.11.0
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: pry-byebug
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '3.9'
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '3.9'
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: bundler
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - "~>"
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '2.0'
|
82
|
+
type: :development
|
83
|
+
prerelease: false
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - "~>"
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '2.0'
|
89
|
+
- !ruby/object:Gem::Dependency
|
90
|
+
name: gem_toys
|
91
|
+
requirement: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - "~>"
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: 0.3.0
|
96
|
+
type: :development
|
97
|
+
prerelease: false
|
98
|
+
version_requirements: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - "~>"
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: 0.3.0
|
103
|
+
- !ruby/object:Gem::Dependency
|
104
|
+
name: toys
|
105
|
+
requirement: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - "~>"
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 0.11.0
|
110
|
+
type: :development
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - "~>"
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: 0.11.0
|
117
|
+
- !ruby/object:Gem::Dependency
|
118
|
+
name: codecov
|
119
|
+
requirement: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - "~>"
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: 0.2.0
|
124
|
+
type: :development
|
125
|
+
prerelease: false
|
126
|
+
version_requirements: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - "~>"
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: 0.2.0
|
131
|
+
- !ruby/object:Gem::Dependency
|
132
|
+
name: rspec
|
133
|
+
requirement: !ruby/object:Gem::Requirement
|
134
|
+
requirements:
|
135
|
+
- - "~>"
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: '3.9'
|
138
|
+
type: :development
|
139
|
+
prerelease: false
|
140
|
+
version_requirements: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - "~>"
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '3.9'
|
145
|
+
- !ruby/object:Gem::Dependency
|
146
|
+
name: simplecov
|
147
|
+
requirement: !ruby/object:Gem::Requirement
|
148
|
+
requirements:
|
149
|
+
- - "~>"
|
150
|
+
- !ruby/object:Gem::Version
|
151
|
+
version: 0.19.0
|
152
|
+
type: :development
|
153
|
+
prerelease: false
|
154
|
+
version_requirements: !ruby/object:Gem::Requirement
|
155
|
+
requirements:
|
156
|
+
- - "~>"
|
157
|
+
- !ruby/object:Gem::Version
|
158
|
+
version: 0.19.0
|
159
|
+
- !ruby/object:Gem::Dependency
|
160
|
+
name: rubocop
|
161
|
+
requirement: !ruby/object:Gem::Requirement
|
162
|
+
requirements:
|
163
|
+
- - "~>"
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: 0.89.1
|
166
|
+
type: :development
|
167
|
+
prerelease: false
|
168
|
+
version_requirements: !ruby/object:Gem::Requirement
|
169
|
+
requirements:
|
170
|
+
- - "~>"
|
171
|
+
- !ruby/object:Gem::Version
|
172
|
+
version: 0.89.1
|
173
|
+
- !ruby/object:Gem::Dependency
|
174
|
+
name: rubocop-performance
|
175
|
+
requirement: !ruby/object:Gem::Requirement
|
176
|
+
requirements:
|
177
|
+
- - "~>"
|
178
|
+
- !ruby/object:Gem::Version
|
179
|
+
version: '1.0'
|
180
|
+
type: :development
|
181
|
+
prerelease: false
|
182
|
+
version_requirements: !ruby/object:Gem::Requirement
|
183
|
+
requirements:
|
184
|
+
- - "~>"
|
185
|
+
- !ruby/object:Gem::Version
|
186
|
+
version: '1.0'
|
187
|
+
- !ruby/object:Gem::Dependency
|
188
|
+
name: rubocop-rspec
|
189
|
+
requirement: !ruby/object:Gem::Requirement
|
190
|
+
requirements:
|
191
|
+
- - "~>"
|
192
|
+
- !ruby/object:Gem::Version
|
193
|
+
version: '1.0'
|
194
|
+
type: :development
|
195
|
+
prerelease: false
|
196
|
+
version_requirements: !ruby/object:Gem::Requirement
|
197
|
+
requirements:
|
198
|
+
- - "~>"
|
199
|
+
- !ruby/object:Gem::Version
|
200
|
+
version: '1.0'
|
201
|
+
description: 'Toys template for actions with PostgreSQL, like dumps.
|
202
|
+
|
203
|
+
'
|
204
|
+
email:
|
205
|
+
- alex.wayfer@gmail.com
|
206
|
+
executables: []
|
207
|
+
extensions: []
|
208
|
+
extra_rdoc_files: []
|
209
|
+
files:
|
210
|
+
- CHANGELOG.md
|
211
|
+
- LICENSE.txt
|
212
|
+
- README.md
|
213
|
+
- lib/psql_toys.rb
|
214
|
+
- lib/psql_toys/template.rb
|
215
|
+
- lib/psql_toys/template/_base.rb
|
216
|
+
- lib/psql_toys/template/console.rb
|
217
|
+
- lib/psql_toys/template/create.rb
|
218
|
+
- lib/psql_toys/template/create_extensions.rb
|
219
|
+
- lib/psql_toys/template/drop.rb
|
220
|
+
- lib/psql_toys/template/dumps.rb
|
221
|
+
- lib/psql_toys/template/dumps/_base.rb
|
222
|
+
- lib/psql_toys/template/dumps/_dump_file.rb
|
223
|
+
- lib/psql_toys/template/dumps/create.rb
|
224
|
+
- lib/psql_toys/template/dumps/list.rb
|
225
|
+
- lib/psql_toys/template/dumps/restore.rb
|
226
|
+
- lib/psql_toys/version.rb
|
227
|
+
homepage: https://github.com/AlexWayfer/psql_toys
|
228
|
+
licenses:
|
229
|
+
- MIT
|
230
|
+
metadata:
|
231
|
+
source_code_uri: https://github.com/AlexWayfer/psql_toys
|
232
|
+
homepage_uri: https://github.com/AlexWayfer/psql_toys
|
233
|
+
changelog_uri: https://github.com/AlexWayfer/psql_toys/blob/master/CHANGELOG.md
|
234
|
+
post_install_message:
|
235
|
+
rdoc_options: []
|
236
|
+
require_paths:
|
237
|
+
- lib
|
238
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
239
|
+
requirements:
|
240
|
+
- - ">="
|
241
|
+
- !ruby/object:Gem::Version
|
242
|
+
version: '2.5'
|
243
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
244
|
+
requirements:
|
245
|
+
- - ">="
|
246
|
+
- !ruby/object:Gem::Version
|
247
|
+
version: '0'
|
248
|
+
requirements: []
|
249
|
+
rubygems_version: 3.1.2
|
250
|
+
signing_key:
|
251
|
+
specification_version: 4
|
252
|
+
summary: Toys template for actions with PostgreSQL, like dumps.
|
253
|
+
test_files: []
|