dkdeploy-core 8.0.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.
Files changed (84) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +20 -0
  3. data/.rubocop.yml +18 -0
  4. data/Berksfile +3 -0
  5. data/Berksfile.lock +46 -0
  6. data/CONTRIBUTORS.md +16 -0
  7. data/Gemfile +4 -0
  8. data/LICENSE +7 -0
  9. data/README.md +88 -0
  10. data/Rakefile +5 -0
  11. data/Vagrantfile +60 -0
  12. data/config/vm/cookbooks/dkdeploy-core/metadata.rb +10 -0
  13. data/config/vm/cookbooks/dkdeploy-core/recipes/default.rb +56 -0
  14. data/dkdeploy-core.gemspec +34 -0
  15. data/features/apache.feature +35 -0
  16. data/features/assets.feature +100 -0
  17. data/features/bower.feature +52 -0
  18. data/features/current_folder.feature +17 -0
  19. data/features/db.feature +93 -0
  20. data/features/deploy.feature +48 -0
  21. data/features/enhanced_symlinks.feature +17 -0
  22. data/features/error_handlers.feature +59 -0
  23. data/features/file_access.feature +120 -0
  24. data/features/maintenance.feature +25 -0
  25. data/features/project_version.feature +42 -0
  26. data/features/support/env.rb +22 -0
  27. data/features/utils.feature +81 -0
  28. data/lib/capistrano/copy.rb +2 -0
  29. data/lib/capistrano/dkdeploy/core.rb +88 -0
  30. data/lib/dkdeploy/constants.rb +156 -0
  31. data/lib/dkdeploy/copy.rb +121 -0
  32. data/lib/dkdeploy/core/version.rb +15 -0
  33. data/lib/dkdeploy/dsl.rb +23 -0
  34. data/lib/dkdeploy/helpers/assets.rb +50 -0
  35. data/lib/dkdeploy/helpers/common.rb +31 -0
  36. data/lib/dkdeploy/helpers/db.rb +49 -0
  37. data/lib/dkdeploy/helpers/file_system.rb +76 -0
  38. data/lib/dkdeploy/i18n.rb +143 -0
  39. data/lib/dkdeploy/interaction_handler/password.rb +27 -0
  40. data/lib/dkdeploy/rollback_manager.rb +18 -0
  41. data/lib/dkdeploy/tasks/apache.rake +29 -0
  42. data/lib/dkdeploy/tasks/assets.rake +96 -0
  43. data/lib/dkdeploy/tasks/bower.rake +54 -0
  44. data/lib/dkdeploy/tasks/copy.rake +26 -0
  45. data/lib/dkdeploy/tasks/current_folder.rake +16 -0
  46. data/lib/dkdeploy/tasks/db.rake +412 -0
  47. data/lib/dkdeploy/tasks/deploy.rake +77 -0
  48. data/lib/dkdeploy/tasks/enhanced_symlinks.rake +74 -0
  49. data/lib/dkdeploy/tasks/fail.rake +8 -0
  50. data/lib/dkdeploy/tasks/file_access.rake +89 -0
  51. data/lib/dkdeploy/tasks/maintenance.rake +73 -0
  52. data/lib/dkdeploy/tasks/project_version.rake +32 -0
  53. data/lib/dkdeploy/tasks/utils.rake +141 -0
  54. data/lib/dkdeploy.rb +1 -0
  55. data/spec/fixtures/application/Capfile +11 -0
  56. data/spec/fixtures/application/Gemfile +11 -0
  57. data/spec/fixtures/application/Version +1 -0
  58. data/spec/fixtures/application/config/assets_exclude_file.txt +1 -0
  59. data/spec/fixtures/application/config/deploy/dev.rb +35 -0
  60. data/spec/fixtures/application/config/deploy.rb +18 -0
  61. data/spec/fixtures/application/config/etc/apache2/conf/.htaccess.erb +12 -0
  62. data/spec/fixtures/application/config/etc/apache2/conf/dev.htaccess.erb +3 -0
  63. data/spec/fixtures/application/config/preseed/default_content.sql.gz +0 -0
  64. data/spec/fixtures/application/config/preseed/default_structure.sql.gz +0 -0
  65. data/spec/fixtures/application/config/preseed/fileadmin.tar.gz +0 -0
  66. data/spec/fixtures/application/config/preseed/uploads.tar.gz +0 -0
  67. data/spec/fixtures/application/htdocs/.hidden/.gitkeep +0 -0
  68. data/spec/fixtures/application/htdocs/Gemfile +0 -0
  69. data/spec/fixtures/application/htdocs/bower.json +15 -0
  70. data/spec/fixtures/application/htdocs/catalog/.hidden/.gitkeep +0 -0
  71. data/spec/fixtures/application/htdocs/catalog/index.html +1 -0
  72. data/spec/fixtures/application/htdocs/index.html +1 -0
  73. data/spec/fixtures/application/htdocs/stylesheets/test1/config.rb +3 -0
  74. data/spec/fixtures/application/htdocs/stylesheets/test1/css/.gitkeep +0 -0
  75. data/spec/fixtures/application/htdocs/stylesheets/test1/src/source.scss +5 -0
  76. data/spec/fixtures/application/htdocs/stylesheets/test2/config.rb +3 -0
  77. data/spec/fixtures/application/htdocs/stylesheets/test2/css/.gitkeep +0 -0
  78. data/spec/fixtures/application/htdocs/stylesheets/test2/src/source.scss +5 -0
  79. data/spec/fixtures/application/temp/dkdeploy_core.sql.gz +0 -0
  80. data/spec/fixtures/capistrano/configuration/add_output_after_create_symlink.rb +7 -0
  81. data/spec/fixtures/capistrano/configuration/custom_compass_sources.rb +4 -0
  82. data/spec/fixtures/capistrano/configuration/custom_file_access.rb +13 -0
  83. data/spec/fixtures/capistrano/configuration/default_deployment_behaviour.rb +9 -0
  84. metadata +346 -0
@@ -0,0 +1,96 @@
1
+ require 'i18n'
2
+ require 'dkdeploy/i18n'
3
+ require 'dkdeploy/helpers/common'
4
+ require 'dkdeploy/helpers/assets'
5
+ require 'dkdeploy/interaction_handler/password'
6
+ require 'dkdeploy/constants'
7
+
8
+ include Capistrano::DSL
9
+ include SSHKit::DSL
10
+ include Dkdeploy::Helpers::Common
11
+ include Dkdeploy::Helpers::Assets
12
+ include Dkdeploy::Constants
13
+
14
+ namespace :assets do
15
+ desc 'Compiles sass files'
16
+ task :compile_compass, :compass_sources, :compass_compile_arguments do |_, args|
17
+ compass_sources = ask_array_variable(args, :compass_sources, 'questions.compass_sources')
18
+ compass_compile_arguments = ask_array_variable(args, :compass_compile_arguments, 'questions.compass_compile_arguments')
19
+ compass_sources.each do |path|
20
+ config_path = File.join path, 'config.rb'
21
+ run_locally do
22
+ # noinspection RubyArgCount
23
+ if test "[ -f #{config_path} ]"
24
+ execute :compass, 'compile', path, '--config', config_path, *compass_compile_arguments
25
+ else
26
+ error I18n.t('file.not_exists', file: config_path, scope: :dkdeploy)
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ desc 'Add .htpasswd file to assets folder'
33
+ task :add_htpasswd, :username, :password do |_, args|
34
+ username = ask_variable(args, :username, 'questions.username') { |question| question.default = 'dkdeploy' }
35
+ password = ask_variable(args, :password, 'questions.password') { |question| question.echo = '*' }
36
+ htpasswd_path = File.join(shared_path, '.htpasswd')
37
+
38
+ if password.empty?
39
+ run_locally do
40
+ error I18n.t('errors.password_was_empty', scope: :dkdeploy)
41
+ exit 1
42
+ end
43
+ end
44
+
45
+ on release_roles :web do
46
+ info I18n.t('directory.create', scope: :dkdeploy)
47
+ execute :mkdir, '-p', shared_path
48
+ execute :htpasswd, '-c', htpasswd_path, username, interaction_handler: Dkdeploy::InteractionHandler::Password.new(password)
49
+ info I18n.t('tasks.assets.add_htpasswd.successfully_created', scope: :dkdeploy)
50
+ end
51
+ end
52
+
53
+ desc 'remove contents of the shared assets folder on the server'
54
+ task :cleanup, :asset_folders do |_, args|
55
+ asset_folders = ask_array_variable(args, :asset_folders, 'questions.asset_folder')
56
+
57
+ on release_roles :web do
58
+ asset_folders.each do |asset_folder|
59
+ info I18n.t('tasks.assets.cleanup', folder: asset_folder, scope: :dkdeploy)
60
+ path = File.join assets_path, asset_folder
61
+ execute :rm, '-rf', path
62
+ execute :mkdir, '-p', path
63
+ end
64
+ end
65
+ end
66
+
67
+ desc 'Copy contents of the configured asset folders on the server to the local ./temp/assets directory'
68
+ task :download, :asset_folders do |_, args|
69
+ asset_folders = ask_array_variable(args, :asset_folders, 'questions.asset_folders')
70
+
71
+ asset_folders.each do |folder|
72
+ assets_download folder
73
+ end
74
+ end
75
+
76
+ desc 'Copy asset contents from the local ./temp/assets directory to the server'
77
+ task :update, :asset_folders do |_, args|
78
+ asset_folders = ask_array_variable(args, :asset_folders, 'questions.asset_folders')
79
+
80
+ asset_folders.each do |tar|
81
+ assets_upload tar
82
+ end
83
+ end
84
+
85
+ desc 'Add default content from ./config/preseed/'
86
+ task :add_default_content, :asset_default_content do |_, args|
87
+ asset_default_content = ask_array_variable(args, :asset_default_content, 'questions.asset_default_content')
88
+
89
+ config_path = File.join 'config', 'preseed'
90
+ on release_roles :web do
91
+ asset_default_content.each do |asset|
92
+ assets_upload asset, config_path
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,54 @@
1
+ require 'capistrano/i18n'
2
+ require 'dkdeploy/i18n'
3
+
4
+ include Capistrano::DSL
5
+ include SSHKit::DSL
6
+
7
+ namespace :bower do
8
+ desc 'Runs given Bower command in given path'
9
+ task :run, :bower_command, :bower_path do |_, args|
10
+ bower_command = ask_variable(args, :bower_command, 'questions.bower.command') { |question| question.default = 'help' }
11
+ bower_path = ask_variable(args, :bower_path, 'questions.bower.path') { |question| question.default = 'htdocs' }
12
+
13
+ run_locally do
14
+ if test("[ -d #{bower_path} ]")
15
+ bower_file_path = File.join(bower_path, 'bower.json')
16
+ if test("[ -f #{bower_file_path} ]")
17
+ within bower_path do
18
+ execute :bower, bower_command
19
+ end
20
+ else
21
+ warn I18n.t('tasks.bower.skipping_directory_with_missing_bower_file', bower_path: bower_path, scope: :dkdeploy)
22
+ next
23
+ end
24
+ else
25
+ warn I18n.t('tasks.bower.skipping_missing_directory', bower_path: bower_path, scope: :dkdeploy)
26
+ next
27
+ end
28
+ end
29
+ end
30
+
31
+ task :run_all, :bower_command, :bower_paths do |_, args|
32
+ bower_command = ask_variable(args, :bower_command, 'questions.bower.command') { |question| question.default = 'help' }
33
+ bower_paths = ask_array_variable(args, :bower_paths, 'questions.bower.paths')
34
+
35
+ run_locally do
36
+ bower_paths.each do |bower_path|
37
+ if test("[ -d #{bower_path} ]")
38
+ current_bower_file_path = File.join(bower_path, 'bower.json')
39
+ if test("[ -f #{current_bower_file_path} ]")
40
+ within bower_path do
41
+ execute :bower, bower_command
42
+ end
43
+ else
44
+ warn I18n.t('tasks.bower.skipping_directory_with_missing_bower_file', bower_path: bower_path, scope: :dkdeploy)
45
+ next
46
+ end
47
+ else
48
+ warn I18n.t('tasks.bower.skipping_missing_directory', bower_path: bower_path, scope: :dkdeploy)
49
+ next
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,26 @@
1
+ require_relative '../copy'
2
+
3
+ include Capistrano::DSL
4
+
5
+ namespace :copy do
6
+ # Getter for copy strategy
7
+ #
8
+ def strategy
9
+ @strategy ||= Dkdeploy::Copy.new(self, fetch(:copy_strategy, Dkdeploy::Copy::DefaultStrategy))
10
+ end
11
+
12
+ desc 'Check if all configuration variables and copy sources exist'
13
+ task :check do
14
+ strategy.check
15
+ end
16
+
17
+ desc 'Upload the source repository to releases'
18
+ task :create_release do
19
+ strategy.release
20
+ end
21
+
22
+ desc 'Determine the revision that will be deployed'
23
+ task :set_current_revision do
24
+ set :current_revision, strategy.fetch_revision
25
+ end
26
+ end
@@ -0,0 +1,16 @@
1
+ include Capistrano::DSL
2
+
3
+ require 'dkdeploy/i18n'
4
+
5
+ namespace :current_folder do
6
+ desc "Delete current folder unless it's a symlink"
7
+ task :remove_unlesss_symlinked do
8
+ on release_roles :all do
9
+ if test "[[ -d #{current_path} && ! -L #{current_path} ]]"
10
+ execute :rm, '-rf', current_path
11
+ else
12
+ info I18n.t('info.ignoring_current_folder', scope: :dkdeploy)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,412 @@
1
+ require 'dkdeploy/constants'
2
+ require 'dkdeploy/helpers/common'
3
+ require 'dkdeploy/helpers/db'
4
+ require 'dkdeploy/interaction_handler/password'
5
+ require 'digest/md5'
6
+ require 'yaml'
7
+
8
+ include Dkdeploy::Constants
9
+ include Dkdeploy::Helpers::Common
10
+ include Dkdeploy::Helpers::DB
11
+ include Capistrano::DSL
12
+
13
+ namespace :db do
14
+ task :read_db_settings do
15
+ FileUtils.mkdir_p 'temp'
16
+ on release_roles :app do
17
+ unless test("[ -f #{remote_database_config_path} ]")
18
+ error I18n.t('errors.database_config_file_missing', scope: :dkdeploy)
19
+ exit 1
20
+ end
21
+
22
+ set :db_settings, read_db_settings_for_context(self)
23
+ set :db_host, fetch(:db_settings).fetch('host')
24
+ set :db_port, fetch(:db_settings).fetch('port')
25
+ set :db_name, fetch(:db_settings).fetch('name')
26
+ set :db_username, fetch(:db_settings).fetch('username')
27
+ set :db_password, fetch(:db_settings).fetch('password')
28
+ set :db_charset, fetch(:db_settings).fetch('charset')
29
+ end
30
+
31
+ File.write local_database_config_path, db_settings_hash.to_yaml
32
+ end
33
+
34
+ desc 'Upload database settings file'
35
+ task :upload_settings, :db_host, :db_port, :db_name, :db_username, :db_password, :db_charset do |_, args|
36
+ set :db_host, ask_variable(args, :db_host, 'questions.database.host') { |question| question.default = '127.0.0.1' }
37
+ set :db_port, ask_variable(args, :db_port, 'questions.database.port') { |question| question.default = '3306' }
38
+ set :db_name, ask_variable(args, :db_name, 'questions.database.name') { |question| question.default = [fetch(:application), fetch(:stage)].join('_').tr('-', '_') }
39
+ set :db_username, ask_variable(args, :db_username, 'questions.database.username') { |question| question.default = 'root' }
40
+ set :db_password, ask_variable(args, :db_password, 'questions.database.password') { |question| question.echo = '*' }
41
+ set :db_charset, ask_variable(args, :db_charset, 'questions.database.charset') { |question| question.default = 'utf8' }
42
+
43
+ if fetch(:db_password).empty?
44
+ run_locally do
45
+ error I18n.t('errors.password_was_empty', scope: :dkdeploy)
46
+ exit 1
47
+ end
48
+ end
49
+
50
+ on release_roles :app do
51
+ begin
52
+ execute :mysql,
53
+ '-u', fetch(:db_username),
54
+ '-p', '-h', fetch(:db_host), '-P', fetch(:db_port), '-e', 'exit',
55
+ interaction_handler: Dkdeploy::InteractionHandler::Password.new(fetch(:db_password))
56
+ rescue SSHKit::Command::Failed
57
+ error I18n.t('errors.connection_failed', scope: :dkdeploy)
58
+ exit 1
59
+ end
60
+ execute :mkdir, '-p', File.join(shared_path, 'config')
61
+ execute :rm, '-f', remote_database_config_path
62
+ upload! StringIO.new(db_settings_hash.to_yaml), remote_database_config_path
63
+ info I18n.t('success.settings_uploaded', scope: :dkdeploy)
64
+ end
65
+ end
66
+
67
+ desc 'Upload, unzip and execute database script'
68
+ task :update, :file_path, :zipped_db_file do |_, args|
69
+ file_path = ask_variable(args, :file_path, 'questions.path') { |question| question.default = 'temp' }
70
+ zipped_db_file = ask_variable(args, :zipped_db_file, 'questions.database.zipped_db_file') { |question| question.default = 'database.sql.gz' }
71
+
72
+ local_zipped_file_name = File.join(file_path, zipped_db_file)
73
+ remote_zipped_file_name = File.join(fetch(:deploy_to), zipped_db_file)
74
+ remote_file_name = File.join(fetch(:deploy_to), zipped_db_file.slice(0..-4)) # we assume file name ending .sql.gz
75
+
76
+ unless File.exist?(local_zipped_file_name)
77
+ run_locally do
78
+ error I18n.t('errors.file_not_found', scope: :dkdeploy)
79
+ exit 1
80
+ end
81
+ end
82
+
83
+ on primary :backend do
84
+ begin
85
+ db_settings = read_db_settings_for_context(self)
86
+ execute :rm, '-f', remote_zipped_file_name
87
+ execute :rm, '-f', remote_file_name
88
+ upload! local_zipped_file_name, remote_zipped_file_name, via: :scp
89
+ execute :gunzip, remote_zipped_file_name
90
+ execute :mysql,
91
+ "--default-character-set=#{db_settings.fetch('charset')}",
92
+ '-u', db_settings.fetch('username'),
93
+ '-p',
94
+ '-h', db_settings.fetch('host'), '-P', db_settings.fetch('port'), db_settings.fetch('name'),
95
+ '-e', "'source #{remote_file_name}'",
96
+ interaction_handler: Dkdeploy::InteractionHandler::Password.new(db_settings.fetch('password'))
97
+ ensure
98
+ execute :rm, '-f', remote_zipped_file_name
99
+ execute :rm, '-f', remote_file_name
100
+ end
101
+ end
102
+ end
103
+
104
+ desc 'Dump complete database without cache table content to local temp folder'
105
+ task download: [:download_structure, :download_content]
106
+
107
+ desc 'Dumps complete database structure without content'
108
+ task :download_structure do
109
+ FileUtils.mkdir_p 'temp'
110
+
111
+ dump_file = db_dump_file_structure
112
+ remote_dump_file = File.join(fetch(:deploy_to), dump_file)
113
+ remote_zipped_dump_file = "#{remote_dump_file}.gz"
114
+
115
+ on primary :backend do
116
+ begin
117
+ db_settings = read_db_settings_for_context(self)
118
+ execute :rm, '-f', remote_dump_file
119
+ execute :rm, '-f', remote_zipped_dump_file
120
+ execute :mysqldump,
121
+ '--no-data', '--skip-set-charset',
122
+ "--default-character-set=#{db_settings.fetch('charset')}",
123
+ '-u', db_settings.fetch('username'),
124
+ '-p',
125
+ '-h', db_settings.fetch('host'), '-P', db_settings.fetch('port'), db_settings.fetch('name'),
126
+ '>', remote_dump_file,
127
+ interaction_handler: Dkdeploy::InteractionHandler::Password.new(db_settings.fetch('password'))
128
+ execute :gzip, remote_dump_file
129
+ download! remote_zipped_dump_file, 'temp', via: :scp
130
+ ensure
131
+ execute :rm, '-f', remote_dump_file
132
+ execute :rm, '-f', remote_zipped_dump_file
133
+ end
134
+ end
135
+ end
136
+
137
+ desc 'Dump complete database content without cache tables and structure to local temp folder'
138
+ task :download_content do
139
+ FileUtils.mkdir_p 'temp'
140
+
141
+ dump_file = db_dump_file_content
142
+ remote_dump_file = File.join(fetch(:deploy_to), dump_file)
143
+ remote_zipped_dump_file = "#{remote_dump_file}.gz"
144
+
145
+ on primary :backend do
146
+ begin
147
+ db_settings = read_db_settings_for_context(self)
148
+ execute :rm, '-f', remote_dump_file
149
+ execute :rm, '-f', remote_zipped_dump_file
150
+
151
+ ignore_tables_command_line = ignore_tables.inject('') do |command_line, table|
152
+ command_line << " --ignore-table=#{db_settings.fetch('name')}.#{table}"
153
+ end
154
+
155
+ execute :mysqldump,
156
+ "--default-character-set=#{db_settings.fetch('charset')}",
157
+ '--skip-set-charset',
158
+ '-u', db_settings.fetch('username'),
159
+ '-p',
160
+ '-h', db_settings.fetch('host'), '-P', db_settings.fetch('port'), ignore_tables_command_line, db_settings.fetch('name'),
161
+ '>', remote_dump_file,
162
+ interaction_handler: Dkdeploy::InteractionHandler::Password.new(db_settings.fetch('password'))
163
+ execute :gzip, remote_dump_file
164
+ download! remote_zipped_dump_file, 'temp', via: :scp
165
+ ensure
166
+ execute :rm, '-f', remote_dump_file
167
+ execute :rm, '-f', remote_zipped_dump_file
168
+ end
169
+ end
170
+ end
171
+
172
+ desc 'Dump content of a database table to local temp folder'
173
+ task :dump_table, :table_name do |_, args|
174
+ table_name = ask_variable(args, :table_name, 'questions.database.table_name')
175
+
176
+ FileUtils.mkdir_p 'temp'
177
+
178
+ dump_file = db_dump_file table_name
179
+ zipped_dump_file = File.join('temp', "#{dump_file}.gz")
180
+ remote_dump_file = File.join(deploy_to, dump_file)
181
+ remote_zipped_dump_file = "#{remote_dump_file}.gz"
182
+
183
+ on primary :backend do
184
+ begin
185
+ db_settings = read_db_settings_for_context(self)
186
+ execute :rm, '-f', remote_dump_file
187
+ execute :rm, '-f', remote_zipped_dump_file
188
+ execute :mysqldump,
189
+ '--no-data', '--skip-set-charset',
190
+ "--default-character-set=#{db_settings.fetch('charset')}",
191
+ '-u', db_settings.fetch('username'),
192
+ '-p',
193
+ '-h', db_settings.fetch('host'), '-P', db_settings.fetch('port'), db_settings.fetch('name'), table_name,
194
+ '>', remote_dump_file,
195
+ interaction_handler: Dkdeploy::InteractionHandler::Password.new(db_settings.fetch('password'))
196
+ execute :gzip, remote_dump_file
197
+ download! remote_zipped_dump_file, zipped_dump_file, via: :scp
198
+ ensure
199
+ execute :rm, '-f', remote_dump_file
200
+ execute :rm, '-f', remote_zipped_dump_file
201
+ end
202
+ end
203
+ end
204
+
205
+ desc 'Dump content of a list of database tables to a local folder'
206
+ task :dump_tables, :table_names, :file_path, :file_name do |_, args|
207
+ table_names = ask_array_variable(args, :table_names, 'questions.database.table_names')
208
+ file_path = ask_variable(args, :file_path, 'questions.path') { |question| question.default = 'temp' }
209
+ file_name = ask_variable(args, :file_name, 'questions.file_name') { |question| question.default = [fetch(:application), fetch(:stage), table_names].join('_') }
210
+
211
+ local_file_name = File.join(file_path, file_name)
212
+ local_zipped_file = "#{local_file_name}.gz"
213
+ remote_file_name = File.join(fetch(:deploy_to), file_name)
214
+ remote_zipped_file = "#{remote_file_name}.gz"
215
+
216
+ FileUtils.mkdir_p file_path
217
+
218
+ on primary :backend do
219
+ begin
220
+ db_settings = read_db_settings_for_context(self)
221
+ execute :rm, '-f', remote_file_name
222
+ execute :rm, '-f', remote_zipped_file
223
+ execute :mysqldump,
224
+ '--no-data', '--skip-set-charset',
225
+ '--no-create-info', '--skip-comments',
226
+ '--skip-extended-insert', '--skip-set-charset',
227
+ "--default-character-set=#{db_settings.fetch('charset')}",
228
+ '-u', db_settings.fetch('username'),
229
+ '-p',
230
+ '-h', db_settings.fetch('host'), '-P', db_settings.fetch('port'),
231
+ db_settings.fetch('name'), table_names.join(' '),
232
+ '>', remote_file_name,
233
+ interaction_handler: Dkdeploy::InteractionHandler::Password.new(db_settings.fetch('password'))
234
+ execute :gzip, remote_file_name
235
+ download! remote_zipped_file, local_zipped_file, via: :scp
236
+ ensure
237
+ execute :rm, '-f', remote_file_name
238
+ execute :rm, '-f', remote_zipped_file
239
+ end
240
+ end
241
+
242
+ run_locally do
243
+ execute :gunzip, local_zipped_file
244
+ end
245
+ end
246
+
247
+ desc 'Add default content from config/preseed/default_content.sql.gz to database'
248
+ task :add_default_content do
249
+ local_zipped_default_content_file = File.join('config', 'preseed', 'default_content.sql.gz')
250
+ remote_default_content_file = File.join(fetch(:deploy_to), 'default_content.sql')
251
+ remote_zipped_default_content_file = "#{remote_default_content_file}.gz"
252
+
253
+ on primary :backend do
254
+ begin
255
+ db_settings = read_db_settings_for_context(self)
256
+ execute :rm, '-f', remote_default_content_file
257
+ execute :rm, '-f', remote_zipped_default_content_file
258
+ upload! local_zipped_default_content_file, remote_zipped_default_content_file, via: :scp
259
+ execute :gunzip, remote_zipped_default_content_file
260
+ execute :mysql,
261
+ "--default-character-set=#{db_settings.fetch('charset')}",
262
+ '-u', db_settings.fetch('username'),
263
+ '-p',
264
+ '-h', db_settings.fetch('host'), '-P', db_settings.fetch('port'), db_settings.fetch('name'),
265
+ '-e', "'source #{remote_default_content_file}'",
266
+ interaction_handler: Dkdeploy::InteractionHandler::Password.new(db_settings.fetch('password'))
267
+ ensure
268
+ execute :rm, '-f', remote_default_content_file
269
+ execute :rm, '-f', remote_zipped_default_content_file
270
+ end
271
+ end
272
+ end
273
+
274
+ desc 'Add structure content from config/preseed/default_structure.sql.gz to database'
275
+ task :add_default_structure do
276
+ local_zipped_default_structure_file = File.join('config', 'preseed', 'default_structure.sql.gz')
277
+ remote_default_structure_file = File.join(fetch(:deploy_to), 'default_structure.sql')
278
+ remote_zipped_default_structure_file = "#{remote_default_structure_file}.gz"
279
+
280
+ on primary :backend do
281
+ begin
282
+ db_settings = read_db_settings_for_context(self)
283
+ execute :rm, '-f', remote_default_structure_file
284
+ execute :rm, '-f', remote_zipped_default_structure_file
285
+ upload! local_zipped_default_structure_file, remote_zipped_default_structure_file, via: :scp
286
+ execute :gunzip, remote_zipped_default_structure_file
287
+ execute :mysql,
288
+ "--default-character-set=#{db_settings.fetch('charset')}",
289
+ '-u', db_settings.fetch('username'), '-p',
290
+ '-h', db_settings.fetch('host'), '-P', db_settings.fetch('port'), db_settings.fetch('name'),
291
+ '-e', "'source #{remote_default_structure_file}'",
292
+ interaction_handler: Dkdeploy::InteractionHandler::Password.new(db_settings.fetch('password'))
293
+ ensure
294
+ execute :rm, '-f', remote_default_structure_file
295
+ execute :rm, '-f', remote_zipped_default_structure_file
296
+ end
297
+ end
298
+ end
299
+
300
+ desc 'Download database tables'
301
+ task :download_tables, :table_names, :file_path, :file_name do |_, args|
302
+ table_names = ask_array_variable(args, :table_names, 'questions.database.table_names')
303
+ file_path = ask_variable(args, :file_path, 'questions.path') { |question| question.default = 'temp' }
304
+ file_name = ask_variable(args, :file_name, 'questions.file_name') { |question| question.default = [fetch(:application), fetch(:stage), table_names].join('_') }
305
+ table_names = table_names.join(' ')
306
+
307
+ FileUtils.mkdir_p file_path
308
+
309
+ remote_file_name = File.join(fetch(:deploy_to), file_name)
310
+ remote_zipped_file = "#{remote_file_name}.gz"
311
+ local_file_name = File.join(file_path, file_name)
312
+ local_zipped_file = "#{local_file_name}.gz"
313
+
314
+ on primary :backend do
315
+ begin
316
+ db_settings = read_db_settings_for_context(self)
317
+ execute :rm, '-f', remote_file_name
318
+ execute :rm, '-f', remote_zipped_file
319
+ execute :mysqldump,
320
+ "--default-character-set=#{db_settings.fetch('charset')}",
321
+ '--no-create-info', '--skip-comments',
322
+ '--skip-extended-insert', '--skip-set-charset',
323
+ '--complete-insert',
324
+ '-u', db_settings.fetch('username'),
325
+ '-p',
326
+ '-h', db_settings.fetch('host'), '-P', db_settings.fetch('port'),
327
+ db_settings.fetch('name'), table_names,
328
+ '>', remote_file_name,
329
+ interaction_handler: Dkdeploy::InteractionHandler::Password.new(db_settings.fetch('password'))
330
+ execute :gzip, remote_file_name
331
+ download! remote_zipped_file, local_zipped_file, via: :scp
332
+ ensure
333
+ execute :rm, '-f', remote_file_name
334
+ execute :rm, '-f', remote_zipped_file
335
+ end
336
+ end
337
+
338
+ run_locally do
339
+ execute :rm, '-f', local_file_name # Delete local file, before unzip
340
+ execute :gunzip, local_zipped_file
341
+ end
342
+
343
+ sql = File.read(local_file_name)
344
+ File.open(local_file_name, 'w') do |io|
345
+ table_names.split(' ').each do |table|
346
+ io.write("TRUNCATE TABLE #{table};\n")
347
+ end
348
+ io.write(sql)
349
+ end
350
+ end
351
+
352
+ desc 'Update database tables'
353
+ task :upload_tables, :file_path, :file_name do |task, args|
354
+ file_path = ask_variable(args, :file_path, 'questions.path') { |question| question.default = 'temp' }
355
+ file_name = ask_variable(args, :file_name, 'questions.file_name') { |question| question.default = [fetch(:application), fetch(:stage)].join('_') }
356
+
357
+ sql_dump_file = File.join(file_path, file_name)
358
+ remote_db_path = File.join(shared_path, '/db')
359
+ remote_dump_file = File.join(remote_db_path, file_name)
360
+ remote_dump_md5_file = File.join("#{remote_dump_file}.md5")
361
+ local_md5 = Digest::MD5.file(sql_dump_file).hexdigest
362
+
363
+ on primary :backend do
364
+ execute :mkdir, '-p', remote_db_path
365
+ end
366
+
367
+ run_locally do
368
+ info I18n.t('info.local_md5', md5_hash: local_md5, scope: :dkdeploy)
369
+ end
370
+
371
+ remote_md5 = '' # to allow assignment in block and later comparison
372
+ on primary :backend do
373
+ if test("[ -f #{remote_dump_md5_file} ]")
374
+ remote_md5 = capture("cat #{remote_dump_md5_file}")
375
+ end
376
+ end
377
+
378
+ run_locally do
379
+ info I18n.t('info.remote_md5', md5_hash: remote_md5, scope: :dkdeploy)
380
+ end
381
+
382
+ if local_md5 == remote_md5
383
+ run_locally do
384
+ info I18n.t('info.md5_match', scope: :dkdeploy)
385
+ end
386
+ next
387
+ end
388
+
389
+ begin
390
+ on primary :backend do
391
+ db_settings = read_db_settings_for_context(self)
392
+ upload! StringIO.new(local_md5), remote_dump_md5_file
393
+ upload! sql_dump_file, remote_dump_file
394
+ execute :mysql,
395
+ "--default-character-set=#{db_settings.fetch('charset')}",
396
+ '-u', db_settings.fetch('username'),
397
+ '-p',
398
+ '-h', db_settings.fetch('host'), '-P', db_settings.fetch('port'), db_settings.fetch('name'),
399
+ '-e', "'source #{remote_dump_file}'",
400
+ interaction_handler: Dkdeploy::InteractionHandler::Password.new(db_settings.fetch('password'))
401
+ end
402
+ rescue SSHKit::Command::Failed => exception
403
+ run_locally do
404
+ error "Removing #{remote_dump_file} and #{remote_dump_md5_file}"
405
+ execute :rm, '-f', remote_dump_md5_file
406
+ execute :rm, '-f', remote_dump_file
407
+ end
408
+ task.reenable
409
+ raise "upload_tables failed: #{exception.message}"
410
+ end
411
+ end
412
+ end