data_keeper 0.1.4 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0442b3f4ba1b60c62570ca379d4a5d6f2a2181ec9cb7561107d52a3492b62ec5
4
- data.tar.gz: e7594ccf321cd010c5cf74926ff0dd881d4aee7e6c142b204a58c9f9df137ebd
3
+ metadata.gz: 0666762022ca90ffac33878de1b342661885b9aeecfdac775a729f3de2b48cc3
4
+ data.tar.gz: 0c17de29ea41f6023579bd8e8b6bb1e5bf34e682ff934291686d3c5721af02c2
5
5
  SHA512:
6
- metadata.gz: 12a6f3303abd4528976c51e49361f183b306fc352df0d9bc8cb3c2e44845f61920f8b9bf4e70c438cd42a8a33703dd98693a71c10f0a79e90d5015c8ac2977bb
7
- data.tar.gz: a5b9ecb78feecd034287fd86e34bdbd151d028a61d0be6ea58494b35102c3080d2c7c97eb3c5816d470a66a2f52a44c773a64a96ee2e3d3a01562ad5b8fc101c
6
+ metadata.gz: 6369301be6b94b87e5a8ea26d0e56926d560c9229c3ed7dba6a12e70193324584d7eec1e10ca7f3d02a4de5f5473a2b4fb0a4109094dd7176af5e8f2a5729995
7
+ data.tar.gz: c6ef2e6e5d521def03e06e3eb8c7113f9a8f61376d6b7d3f3e3d2b26fdc4c8ebc5cfba615d84224517fb5955c15d16e89e6a7a170f21bd6eb751aac810fdc975
data/.gitignore CHANGED
@@ -6,5 +6,6 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  /tmp/
9
+ /lib/tmp
9
10
 
10
11
  Gemfile.lock
data/Gemfile CHANGED
@@ -5,3 +5,4 @@ gemspec
5
5
 
6
6
  gem "rake", "~> 12.0"
7
7
  gem "minitest", "~> 5.0"
8
+ gem 'pg'
@@ -1,7 +1,7 @@
1
1
  module DataKeeper
2
2
  module DatabaseConfig
3
3
  def database_connection_config
4
- Rails.configuration.database_configuration[Rails.env]
4
+ @database_connection_config ||= DataKeeper.database_config.call
5
5
  end
6
6
 
7
7
  def psql_env
@@ -33,6 +33,7 @@ module DataKeeper
33
33
  @tables = []
34
34
  @raw_sqls = {}
35
35
  @definition_block = definition_block
36
+ @on_after_load_block = nil
36
37
  end
37
38
 
38
39
  def evaluate!
@@ -48,6 +48,7 @@ module DataKeeper
48
48
  dump_schema(tar)
49
49
  dump_partial_tables(tar)
50
50
  dump_sqls(tar)
51
+ dump_sequences(tar)
51
52
  end
52
53
  end
53
54
 
@@ -136,8 +137,47 @@ module DataKeeper
136
137
  end
137
138
  end
138
139
 
140
+ def dump_sequences(tar)
141
+ Tempfile.create do |sequences_dump_file|
142
+ sequences_dump_file.binmode
143
+
144
+ sequences_args = all_sequences_to_export.map { |table| "-t #{table}" }.join(' ')
145
+ cmd = Terrapin::CommandLine.new(
146
+ 'pg_dump',
147
+ "#{connection_args} -x -Fc :database #{sequences_args} > :output_path",
148
+ environment: psql_env
149
+ )
150
+
151
+ cmd.run(database: database, host: host, port: port, output_path: sequences_dump_file.path)
152
+
153
+ tar.add_file_simple("sequences.dump", 0644, File.size(sequences_dump_file.path)) do |io|
154
+ sequences_dump_file.reopen(sequences_dump_file)
155
+
156
+ while !sequences_dump_file.eof?
157
+ io.write(sequences_dump_file.read(2048))
158
+ end
159
+ end
160
+ end
161
+ end
162
+
139
163
  def filename
140
164
  "#{@dump_name}-#{Time.now.strftime("%Y%m%d-%H%M")}"
141
165
  end
166
+
167
+ def all_sequences_to_export
168
+ cmd = Terrapin::CommandLine.new(
169
+ 'psql',
170
+ "#{connection_args} -d :database -c :sql -A -R ',' -t",
171
+ environment: psql_env
172
+ )
173
+
174
+ sequences = cmd.run(
175
+ database: database,
176
+ host: host,
177
+ port: port,
178
+ sql: "SELECT sequencename from pg_sequences;"
179
+ )
180
+ sequences.split(',').map{|x| x.strip}
181
+ end
142
182
  end
143
183
  end
@@ -7,6 +7,9 @@ module DataKeeper
7
7
  def initialize(dump, file)
8
8
  @dump = dump
9
9
  @file = file
10
+ @psql_version = Terrapin::CommandLine.new('psql', '--version').run
11
+ .match(/[0-9]{1,}\.[0-9]{1,}/)
12
+ .to_s.to_f
10
13
  end
11
14
 
12
15
  def load!
@@ -17,58 +20,68 @@ module DataKeeper
17
20
  end
18
21
 
19
22
  if @dump.on_after_load_block
23
+ ActiveRecord::Base.establish_connection
20
24
  @dump.on_after_load_block.call
21
25
  end
22
26
  end
23
27
 
24
28
  private
25
29
 
26
- def load_full_database!
30
+ def log_redirect
31
+ if Terrapin::CommandLine.logger
32
+ ""
33
+ else
34
+ " 2>/dev/null"
35
+ end
36
+ end
37
+
38
+ def set_ar_internal_metadata!
27
39
  cmd = Terrapin::CommandLine.new(
28
40
  'psql',
29
- "#{connection_args} -d :database -c :command",
41
+ "#{connection_args} -d :database -c :sql",
30
42
  environment: psql_env
31
43
  )
32
- cmd.run(database: database, host: host, port: port, command: "drop schema if exists public")
33
44
 
34
- pg_restore = Terrapin::CommandLine.new(
35
- 'pg_restore',
36
- "#{connection_args} -j 4 --no-owner --dbname #{database} #{@file.path} 2>/dev/null",
37
- environment: psql_env
45
+ cmd.run(
46
+ database: database,
47
+ host: host,
48
+ port: port,
49
+ sql: "DELETE from ar_internal_metadata"
38
50
  )
39
51
 
40
- pg_restore.run(
52
+ cmd.run(
41
53
  database: database,
42
54
  host: host,
43
- port: port
55
+ port: port,
56
+ sql: "INSERT into ar_internal_metadata (key, value, created_at, updated_at) VALUES ('environment', 'development', '2020-04-03 12:25:54.094209', '2020-04-03 12:25:54.094209')"
44
57
  )
58
+ end
45
59
 
46
- cmd = Terrapin::CommandLine.new(
47
- 'psql',
48
- "#{connection_args} -d :database -c :sql",
60
+ def load_full_database!
61
+ ensure_schema_compatibility!
62
+
63
+ pg_restore = Terrapin::CommandLine.new(
64
+ 'pg_restore',
65
+ "#{connection_args} -j 4 --no-owner --dbname #{database} #{@file.path}#{log_redirect}",
49
66
  environment: psql_env
50
67
  )
51
68
 
52
- cmd.run(
69
+ pg_restore.run(
53
70
  database: database,
54
71
  host: host,
55
- port: port,
56
- sql: "UPDATE ar_internal_metadata SET value = 'development'"
72
+ port: port
57
73
  )
74
+
75
+ set_ar_internal_metadata!
58
76
  end
59
77
 
60
78
  def load_partial_database!
61
- inflate(@file.path) do |schema_path, tables_path, sql_files|
62
- cmd = Terrapin::CommandLine.new(
63
- 'psql',
64
- "#{connection_args} -d :database -c :command",
65
- environment: psql_env
66
- )
67
- cmd.run(database: database, host: host, port: port, command: "drop schema if exists public")
79
+ ensure_schema_compatibility!
68
80
 
81
+ inflate(@file.path) do |schema_path, tables_path, sql_files, sequences_path|
69
82
  pg_restore = Terrapin::CommandLine.new(
70
83
  'pg_restore',
71
- "#{connection_args} -j 4 --no-owner --dbname :database #{schema_path} 2>/dev/null",
84
+ "#{connection_args} -j 4 --no-owner -s --dbname :database #{schema_path}#{log_redirect}",
72
85
  environment: psql_env
73
86
  )
74
87
 
@@ -80,7 +93,7 @@ module DataKeeper
80
93
 
81
94
  pg_restore = Terrapin::CommandLine.new(
82
95
  'pg_restore',
83
- "#{connection_args} --data-only -j 4 --no-owner --disable-triggers --dbname :database #{tables_path} 2>/dev/null",
96
+ "#{connection_args} --data-only -j 4 --no-owner --disable-triggers --dbname :database #{tables_path}#{log_redirect}",
84
97
  environment: psql_env
85
98
  )
86
99
 
@@ -106,7 +119,33 @@ module DataKeeper
106
119
  )
107
120
  end
108
121
 
109
- Rake::Task['db:environment:set'].invoke
122
+ pg_restore = Terrapin::CommandLine.new(
123
+ 'pg_restore',
124
+ "#{connection_args} --data-only -j 4 --no-owner --disable-triggers --dbname :database #{sequences_path}#{log_redirect}",
125
+ environment: psql_env
126
+ )
127
+
128
+ pg_restore.run(
129
+ database: database,
130
+ host: host,
131
+ port: port
132
+ )
133
+
134
+ set_ar_internal_metadata!
135
+ end
136
+ end
137
+
138
+ def ensure_schema_compatibility!
139
+ cmd = Terrapin::CommandLine.new(
140
+ 'psql',
141
+ "#{connection_args} -d :database -c :command",
142
+ environment: psql_env
143
+ )
144
+
145
+ if @psql_version >= 11.0
146
+ cmd.run(database: database, host: host, port: port, command: "drop schema if exists public")
147
+ else
148
+ cmd.run(database: database, host: host, port: port, command: "create schema if not exists public")
110
149
  end
111
150
  end
112
151
 
@@ -124,9 +163,8 @@ module DataKeeper
124
163
 
125
164
  validate("Schema file is missing") { !!schema_path } &&
126
165
  validate("Tables file is missing") { !!tables_path } &&
127
- validate("Not all sql custom dumps are present") do
128
- sql_dumps.size == @dump.sqls.keys.size
129
- end
166
+ validate("Not all sql custom dumps are present") { sql_dumps.size == @dump.sqls.keys.size } &&
167
+ validate("Sequences file is missing") { !!sequences_path }
130
168
  end
131
169
 
132
170
  def schema_path
@@ -137,6 +175,10 @@ module DataKeeper
137
175
  @tables_path ||= @paths.find { |x| File.basename(x) == "tables.dump" }
138
176
  end
139
177
 
178
+ def sequences_path
179
+ @sequences_path ||= @paths.find { |x| File.basename(x) == "sequences.dump" }
180
+ end
181
+
140
182
  def sql_dumps
141
183
  @sql_dumps ||= @dump.sqls.map do |name, (table, _proc)|
142
184
  path = @paths.find { |x| File.basename(x) == "#{name}.csv" }
@@ -166,7 +208,8 @@ module DataKeeper
166
208
  yield(
167
209
  inflated_files.schema_path,
168
210
  inflated_files.tables_path,
169
- inflated_files.sql_dumps
211
+ inflated_files.sql_dumps,
212
+ inflated_files.sequences_path
170
213
  )
171
214
  end
172
215
  end
@@ -21,14 +21,15 @@ module DataKeeper
21
21
  def retrieve(dump_name)
22
22
  tempfile = Tempfile.new
23
23
  local_store_dir = @local_store_dir
24
+ last_dump_filename = nil
24
25
 
25
26
  on complete_host do
26
- last_dump = capture :ls, "-1t #{File.join(local_store_dir, dump_name.to_s)} | head -n 1"
27
+ last_dump_filename = capture :ls, "-1t #{File.join(local_store_dir, dump_name.to_s)} | head -n 1"
27
28
 
28
- download! File.join(local_store_dir, dump_name.to_s, last_dump), tempfile.path
29
+ download! File.join(local_store_dir, dump_name.to_s, last_dump_filename), tempfile.path
29
30
  end
30
31
 
31
- yield(tempfile)
32
+ yield(tempfile, last_dump_filename)
32
33
  ensure
33
34
  tempfile.delete
34
35
  end
@@ -78,7 +78,7 @@ module DataKeeper
78
78
  end
79
79
 
80
80
  def retrieve(dump_name)
81
- prefix = "#{@store_dir}#{dump_name.to_s}"
81
+ prefix = "#{@store_dir}#{dump_name.to_s}/"
82
82
  last_dump = s3_client.list_contents(prefix).sort_by(&:last_modified).reverse.first
83
83
 
84
84
  Tempfile.create do |tmp_file|
@@ -86,7 +86,7 @@ module DataKeeper
86
86
  s3_client.stream_to_io(last_dump.key, tmp_file)
87
87
  tmp_file.flush
88
88
 
89
- yield(tmp_file)
89
+ yield(tmp_file, File.basename(last_dump.key))
90
90
  end
91
91
  end
92
92
 
@@ -35,4 +35,15 @@ namespace :data_keeper do
35
35
 
36
36
  DataKeeper.load_dump!(name, path)
37
37
  end
38
+
39
+ desc "Downloads the given dump raw file in the current directory"
40
+ task :download, [:name] => [:environment] do |_t, args|
41
+ name = args[:name]
42
+
43
+ if name.blank? || !DataKeeper.dump?(name)
44
+ raise "Please use this rake task giving a name of a configured dump. Ex: bin/rake data_keeper:pull[full]"
45
+ end
46
+
47
+ DataKeeper.download_dump!(name, ".")
48
+ end
38
49
  end
@@ -1,3 +1,3 @@
1
1
  module DataKeeper
2
- VERSION = "0.1.4"
2
+ VERSION = "0.1.8"
3
3
  end
data/lib/data_keeper.rb CHANGED
@@ -17,6 +17,7 @@ module DataKeeper
17
17
 
18
18
  @dump_definition_builders = {}
19
19
  @storage = nil
20
+ @database_config = -> { Rails.configuration.database_configuration[Rails.env] }
20
21
 
21
22
  def self.define_dump(name, type = :partial, &block)
22
23
  @dump_definition_builders[name.to_sym] = DefinitionBuilder.new(type, block)
@@ -43,6 +44,15 @@ module DataKeeper
43
44
  end
44
45
  end
45
46
 
47
+ def self.download_dump!(name, path)
48
+ raise DumpDoesNotExist unless dump?(name)
49
+ raise NoStorageDefined if @storage.nil?
50
+
51
+ @storage.retrieve(name) do |file, filename|
52
+ FileUtils.cp file.path, File.join(path, filename)
53
+ end
54
+ end
55
+
46
56
  def self.load_dump!(name, path)
47
57
  raise DumpDoesNotExist unless File.file?(path)
48
58
  raise NoStorageDefined if @storage.nil?
@@ -59,6 +69,14 @@ module DataKeeper
59
69
  @storage = value
60
70
  end
61
71
 
72
+ def self.database_config=(value)
73
+ @database_config = value
74
+ end
75
+
76
+ def self.database_config
77
+ @database_config
78
+ end
79
+
62
80
  def self.clear_dumps!
63
81
  @dump_definition_builders = {}
64
82
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: data_keeper
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Roger Campos
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-08-08 00:00:00.000000000 Z
11
+ date: 2021-12-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -100,7 +100,7 @@ licenses:
100
100
  - MIT
101
101
  metadata:
102
102
  homepage_uri: https://github.com/rogercampos/data_keeper
103
- post_install_message:
103
+ post_install_message:
104
104
  rdoc_options: []
105
105
  require_paths:
106
106
  - lib
@@ -115,8 +115,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
115
115
  - !ruby/object:Gem::Version
116
116
  version: '0'
117
117
  requirements: []
118
- rubygems_version: 3.0.3
119
- signing_key:
118
+ rubygems_version: 3.1.6
119
+ signing_key:
120
120
  specification_version: 4
121
121
  summary: Easy management of database dumps for dev env
122
122
  test_files: []