cap_db_dump 1.3.0 → 1.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.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/cap_db_dump/recipes.rb +80 -12
  3. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9b17670872f50b5f6e4ced82d27850b86d69f5f544c16ffd2255f9be0550d0f5
4
- data.tar.gz: 95a520425a6edf34da30890fb9cc898fac58b20c9ba5c152b6ca0e7dd7fe89ec
3
+ metadata.gz: 634f242534913169dcad7483e973eabf67248bc7615a3efa44db678195e9a9ae
4
+ data.tar.gz: 87cd8de8ad173684cee9963b6c14717a6135affb8db7c45cba3959978cd1b7ae
5
5
  SHA512:
6
- metadata.gz: 4e9a93f1adcbbf42ceeff9f4da05913f2df61ca31be12afa6c42fb44dd0334258f633cc0ce3f7cf91ad5938668b0031ea27df22962f8f9bafc4874983e7208ba
7
- data.tar.gz: a990d7fc1d50cf589c1d0b0af8be81aa238f6c1e75a7f55855d28170213a3f9357aebcd63fbd248a2988fa5ba5afe8e038aa5d2edfcaa362adb2270fec6cddd9
6
+ metadata.gz: 39108992543cb7bd245f2fbd18ba463599bbd16d5f310675c860b0e5ef3ad37f349bd8f698fe35bb2c5c4180982cb9a354e1169aa110efef200e19a065722e44
7
+ data.tar.gz: 4375688a259683891cf56f77c43e3624b50c7ca024a061f09c813432199922758922f801d3019492565b0644badcbd3eaa1f168e69241ee223467ed3866ffdca
@@ -1,3 +1,6 @@
1
+ require "json"
2
+ require "yaml"
3
+
1
4
  Capistrano::Configuration.instance(:must_exist).load do
2
5
  namespace :database do
3
6
  DATABASE_ENGINES = [
@@ -12,6 +15,9 @@ Capistrano::Configuration.instance(:must_exist).load do
12
15
  set :database_engine, :mysql # specify :mysql | :psql
13
16
  # https://www.postgresql.org/docs/12/app-pgdump.html
14
17
  set :pg_dump_format, :c # specify c: 'compressed' (aka -Fc), :d 'directory', or set to nil for plain text
18
+ # :yaml reads config/database.yml as plain YAML, :rails asks `rails runner` on the server for the
19
+ # resolved config, and :auto uses :yaml unless database.yml contains ERB.
20
+ set :database_config_source, :auto
15
21
 
16
22
  module CapDbDumpHelpers
17
23
  def dump_path
@@ -50,6 +56,32 @@ Capistrano::Configuration.instance(:must_exist).load do
50
56
  @database_yml ||= read_db_yml
51
57
  end
52
58
 
59
+ def database_yml_path
60
+ "#{current_path}/config/database.yml"
61
+ end
62
+
63
+ def database_config_from_yaml(yaml)
64
+ YAML.safe_load(yaml, aliases: true)
65
+ end
66
+
67
+ # rvm-capistrano wraps commands in `rvm-shell '...' -c '...'`, so this must not contain single quotes.
68
+ def rails_runner_database_config_command
69
+ ruby = "puts :CAP_DB_DUMP_CONFIG_BEGIN, ActiveRecord::Base.connection_db_config.configuration_hash.to_json, :CAP_DB_DUMP_CONFIG_END"
70
+ "cd #{current_path} && RAILS_ENV=#{rails_env} bundle exec rails runner \"#{ruby}\""
71
+ end
72
+
73
+ # No pty, so stderr stays out of the captured output and the output (which has the password) isn't echoed.
74
+ def database_config_from_rails
75
+ output = capture(rails_runner_database_config_command, :pty => false)
76
+ json = output[/CAP_DB_DUMP_CONFIG_BEGIN\s*(\{.*?\})\s*CAP_DB_DUMP_CONFIG_END/m, 1]
77
+
78
+ unless json
79
+ raise "Could not find the database config in the output of rails runner"
80
+ end
81
+
82
+ { rails_env.to_s => JSON.parse(json) }
83
+ end
84
+
53
85
  def tasks_matching_for_db_dump
54
86
  { :only => { :db_dump => true } }
55
87
  end
@@ -63,27 +95,61 @@ Capistrano::Configuration.instance(:must_exist).load do
63
95
  raise "Cannot be run in dry_run mode!"
64
96
  end
65
97
 
66
- yaml = capture("cat #{current_path}/config/database.yml")
67
- YAML.safe_load(yaml, aliases: true)
98
+ case database_config_source.to_sym
99
+ when :yaml
100
+ database_config_from_yaml(capture("cat #{database_yml_path}"))
101
+ when :rails
102
+ database_config_from_rails
103
+ when :auto
104
+ yaml = capture("cat #{database_yml_path}")
105
+ yaml.include?("<%") ? database_config_from_rails : database_config_from_yaml(yaml)
106
+ else
107
+ raise "Unknown database_config_source. use one of: [:yaml, :rails, :auto]"
108
+ end
68
109
  end
69
110
  end
70
111
 
112
+ def database_password?
113
+ database_password && !database_password.to_s.empty?
114
+ end
115
+
116
+ # --defaults-extra-file must be the first option given to mysqldump
71
117
  def mysql_password_field
72
- database_password && database_password.length > 0 ? "-p#{database_password}" : ""
118
+ database_password? ? "--defaults-extra-file=/dev/stdin" : ""
119
+ end
120
+
121
+ def mysql_password_stdin
122
+ escaped_password = database_password.to_s.gsub("\\") { "\\\\" }
123
+ "[client]\npassword=\"#{escaped_password}\"\n"
124
+ end
125
+
126
+ def database_port?
127
+ database_port && !database_port.to_s.strip.empty?
73
128
  end
74
129
 
75
130
  def postgres_port
76
- database_port ? "-p #{database_port}" : ""
131
+ database_port? ? "-p #{database_port}" : ""
77
132
  end
78
133
 
79
134
  def pg_password
80
- database_password && !database_password.empty? ?
81
- "PGPASSWORD=#{database_password}" :
82
- ""
135
+ database_password? ? "IFS= read -r PGPASSWORD && export PGPASSWORD &&" : ""
136
+ end
137
+
138
+ def pg_password_stdin
139
+ "#{database_password}\n"
140
+ end
141
+
142
+ # A pty would echo the password on stdin back into the (logged) output.
143
+ def run_with_password(command, stdin_data)
144
+ if database_password?
145
+ run command, :data => stdin_data, :eof => true, :pty => false
146
+ else
147
+ run command
148
+ end
83
149
  end
84
150
 
85
151
  def pg_port
86
- database_port && !database_port.empty? ? "-p #{database_port}" : ""
152
+ database_port? ? "-p #{database_port}" : ""
87
153
  end
88
154
 
89
155
  task :create_dump, tasks_matching_for_db_dump do
@@ -94,9 +160,10 @@ Capistrano::Configuration.instance(:must_exist).load do
94
160
 
95
161
  ignored_tables = ignored_tables.join(" ")
96
162
 
97
- command = "mysqldump -u #{database_username} -h #{database_host} #{mysql_password_field} -Q "
163
+ command = "mysqldump #{mysql_password_field} -u #{database_username} -h #{database_host} -Q "
98
164
  command << "--add-drop-table -O add-locks=FALSE --lock-tables=FALSE --single-transaction "
99
165
  command << "#{ignored_tables} #{database_name} > #{dump_path}"
166
+ password_stdin = mysql_password_stdin
100
167
  elsif database_engine == POSTGRES
101
168
  ignored_tables = schema_only_tables.map { |table_name|
102
169
  "--exclude-table=#{database_name}.#{table_name}"
@@ -109,13 +176,14 @@ Capistrano::Configuration.instance(:must_exist).load do
109
176
  command << "-F#{pg_dump_format} "
110
177
  end
111
178
  command << "#{ignored_tables} #{database_name} > #{dump_path}"
179
+ password_stdin = pg_password_stdin
112
180
  else
113
181
  raise "Unknown database engine. use one of: #{DATABASE_ENGINES.inspect}"
114
182
  end
115
183
 
116
184
  give_description "About to dump production DB"
117
185
 
118
- run command
186
+ run_with_password command, password_stdin
119
187
  dump_schema_tables if schema_only_tables.any?
120
188
  end
121
189
 
@@ -124,7 +192,7 @@ Capistrano::Configuration.instance(:must_exist).load do
124
192
  table_names = schema_only_tables.join(" ")
125
193
 
126
194
  if database_engine == MYSQL
127
- command = "mysqldump -u #{database_username} -h #{database_host} #{mysql_password_field} "
195
+ command = "mysqldump #{mysql_password_field} -u #{database_username} -h #{database_host} "
128
196
  command << "-Q --add-drop-table --single-transaction --no-data #{database_name} #{table_names} >> #{dump_path}"
129
197
  elsif database_engine == POSTGRES
130
198
  raise "not yet supported. PR's welcome! (https://github.com/smtlaissezfaire/cap_db_dump)"
@@ -133,7 +201,7 @@ Capistrano::Configuration.instance(:must_exist).load do
133
201
  end
134
202
 
135
203
  give_description "Dumping schema for tables: #{schema_only_tables.join(", ")}"
136
- run command
204
+ run_with_password command, mysql_password_stdin
137
205
  end
138
206
  end
139
207
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cap_db_dump
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Scott Taylor
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-05-24 00:00:00.000000000 Z
11
+ date: 2026-10-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: capistrano