wordmove 5.2.1 → 6.0.0.alpha.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +12 -5
  3. data/.rubocop.yml +2 -5
  4. data/.ruby-version +1 -1
  5. data/.yardopts +1 -0
  6. data/CONTRIBUTING.md +15 -0
  7. data/Rakefile +4 -3
  8. data/exe/wordmove +2 -1
  9. data/lib/wordmove/actions/adapt_local_db.rb +103 -0
  10. data/lib/wordmove/actions/adapt_remote_db.rb +90 -0
  11. data/lib/wordmove/actions/backup_local_db.rb +58 -0
  12. data/lib/wordmove/actions/delete_local_file.rb +34 -0
  13. data/lib/wordmove/actions/delete_remote_file.rb +43 -0
  14. data/lib/wordmove/actions/filter_and_setup_tasks_to_run.rb +42 -0
  15. data/lib/wordmove/actions/ftp/backup_remote_db.rb +56 -0
  16. data/lib/wordmove/actions/ftp/cleanup_after_adapt.rb +72 -0
  17. data/lib/wordmove/actions/ftp/download_remote_db.rb +71 -0
  18. data/lib/wordmove/actions/ftp/get_directory.rb +67 -0
  19. data/lib/wordmove/actions/ftp/helpers.rb +91 -0
  20. data/lib/wordmove/actions/ftp/pull_wordpress.rb +56 -0
  21. data/lib/wordmove/actions/ftp/push_wordpress.rb +54 -0
  22. data/lib/wordmove/actions/ftp/put_and_import_dump_remotely.rb +83 -0
  23. data/lib/wordmove/actions/ftp/put_directory.rb +67 -0
  24. data/lib/wordmove/actions/get_file.rb +38 -0
  25. data/lib/wordmove/actions/helpers.rb +142 -0
  26. data/lib/wordmove/actions/put_file.rb +48 -0
  27. data/lib/wordmove/actions/run_after_pull_hook.rb +26 -0
  28. data/lib/wordmove/actions/run_after_push_hook.rb +26 -0
  29. data/lib/wordmove/actions/run_before_pull_hook.rb +26 -0
  30. data/lib/wordmove/actions/run_before_push_hook.rb +26 -0
  31. data/lib/wordmove/actions/run_local_command.rb +34 -0
  32. data/lib/wordmove/actions/setup_context_for_db.rb +78 -0
  33. data/lib/wordmove/actions/ssh/backup_remote_db.rb +51 -0
  34. data/lib/wordmove/actions/ssh/cleanup_after_adapt.rb +56 -0
  35. data/lib/wordmove/actions/ssh/download_remote_db.rb +83 -0
  36. data/lib/wordmove/actions/ssh/get_directory.rb +76 -0
  37. data/lib/wordmove/actions/ssh/helpers.rb +128 -0
  38. data/lib/wordmove/actions/ssh/pull_wordpress.rb +56 -0
  39. data/lib/wordmove/actions/ssh/push_wordpress.rb +54 -0
  40. data/lib/wordmove/actions/ssh/put_and_import_dump_remotely.rb +77 -0
  41. data/lib/wordmove/actions/ssh/put_directory.rb +76 -0
  42. data/lib/wordmove/actions/ssh/run_remote_command.rb +39 -0
  43. data/lib/wordmove/assets/dump.php.erb +6 -6
  44. data/lib/wordmove/assets/import.php.erb +7 -7
  45. data/lib/wordmove/assets/wordmove_schema_global.yml +2 -0
  46. data/lib/wordmove/assets/wordmove_schema_remote.yml +2 -2
  47. data/lib/wordmove/cli.rb +152 -91
  48. data/lib/wordmove/db_paths_config.rb +44 -0
  49. data/lib/wordmove/doctor/movefile.rb +8 -8
  50. data/lib/wordmove/doctor/mysql.rb +18 -15
  51. data/lib/wordmove/doctor/rsync.rb +2 -2
  52. data/lib/wordmove/doctor/ssh.rb +3 -3
  53. data/lib/wordmove/doctor/wpcli.rb +5 -5
  54. data/lib/wordmove/environments_list.rb +4 -4
  55. data/lib/wordmove/exceptions.rb +13 -0
  56. data/lib/wordmove/generators/movefile.rb +7 -5
  57. data/lib/wordmove/generators/movefile_adapter.rb +11 -5
  58. data/lib/wordmove/guardian.rb +5 -5
  59. data/lib/wordmove/hook.rb +13 -14
  60. data/lib/wordmove/logger.rb +11 -10
  61. data/lib/wordmove/movefile.rb +63 -59
  62. data/lib/wordmove/organizers/ftp/pull.rb +52 -0
  63. data/lib/wordmove/organizers/ftp/push.rb +53 -0
  64. data/lib/wordmove/organizers/ssh/pull.rb +52 -0
  65. data/lib/wordmove/organizers/ssh/push.rb +53 -0
  66. data/lib/wordmove/version.rb +1 -1
  67. data/lib/wordmove/wordpress_directory.rb +76 -8
  68. data/lib/wordmove/wpcli.rb +88 -0
  69. data/lib/wordmove.rb +33 -11
  70. data/wordmove.gemspec +37 -30
  71. metadata +139 -35
  72. data/lib/wordmove/deployer/base.rb +0 -193
  73. data/lib/wordmove/deployer/ftp.rb +0 -160
  74. data/lib/wordmove/deployer/ssh/default_sql_adapter.rb +0 -47
  75. data/lib/wordmove/deployer/ssh/wpcli_sql_adapter.rb +0 -55
  76. data/lib/wordmove/deployer/ssh.rb +0 -169
  77. data/lib/wordmove/sql_adapter/default.rb +0 -68
  78. data/lib/wordmove/sql_adapter/wpcli.rb +0 -54
  79. data/lib/wordmove/wordpress_directory/path.rb +0 -11
@@ -0,0 +1,71 @@
1
+ module Wordmove
2
+ module Actions
3
+ module Ftp
4
+ # Downloads the remote DB over FTP protocol
5
+ class DownloadRemoteDb
6
+ extend ::LightService::Action
7
+ include Wordmove::Actions::Helpers
8
+ include Wordmove::Actions::Ftp::Helpers
9
+ include WordpressDirectory::LocalHelperMethods
10
+ include WordpressDirectory::RemoteHelperMethods
11
+
12
+ expects :remote_options,
13
+ :cli_options,
14
+ :logger,
15
+ :photocopier,
16
+ :db_paths
17
+
18
+ # @!method execute
19
+ # @param remote_options [Hash] Remote host options fetched from
20
+ # movefile (with symbolized keys)
21
+ # @param cli_options [Hash] Command line options (with symbolized keys)
22
+ # @param logger [Wordmove::Logger]
23
+ # @param photocopier [Photocopier::FTP]
24
+ # @param db_paths [BbPathsConfig] Configuration object for database
25
+ # @!scope class
26
+ # @return [LightService::Context] Action's context
27
+ executed do |context| # rubocop:disable Metrics/BlockLength
28
+ next context if context.database_task == false
29
+
30
+ context.logger.task 'Download remote DB'
31
+
32
+ if simulate?(cli_options: context.cli_options)
33
+ context.logger.info 'A dump of the remote DB would have been saved into ' \
34
+ "#{context.db_paths.local.path}, " \
35
+ 'but you\'re simulating'
36
+ next context
37
+ end
38
+
39
+ result = Wordmove::Actions::PutFile.execute(
40
+ photocopier: context.photocopier,
41
+ logger: context.logger,
42
+ cli_options: context.cli_options,
43
+ command_args: [
44
+ context.db_paths.ftp.local.generated_dump_script_path,
45
+ context.db_paths.ftp.remote.dump_script_path
46
+ ]
47
+ )
48
+ context.fail_and_return!(result.message) if result.failure?
49
+
50
+ dump_url = [
51
+ context.db_paths.ftp.remote.dump_script_url,
52
+ '?shared_key=',
53
+ context.db_paths.ftp.token
54
+ ].join
55
+
56
+ begin
57
+ download(url: dump_url, local_path: context.db_paths.local.path)
58
+ rescue => _e # rubocop:disable Style/RescueStandardError
59
+ context.fail_and_return!(e.message)
60
+ end
61
+
62
+ unless File.exist? context.db_paths.local.path
63
+ context.fail_and_return!('Download of remote DB failed')
64
+ end
65
+
66
+ context.logger.success "Remote DB dump downloaded in #{context.db_paths.local.path}"
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,67 @@
1
+ module Wordmove
2
+ module Actions
3
+ module Ftp
4
+ # Syncs a whole directory over FTP protocol from the remote server to local host
5
+ class GetDirectory
6
+ extend LightService::Action
7
+ include Wordmove::Actions::Helpers
8
+ include WordpressDirectory::RemoteHelperMethods
9
+ include WordpressDirectory::LocalHelperMethods
10
+
11
+ # :folder_task is expected to be one symbol from Wordmove::CLI.wordpress_options array
12
+ expects :logger,
13
+ :local_options,
14
+ :remote_options,
15
+ :cli_options,
16
+ :photocopier,
17
+ :folder_task
18
+
19
+ # @!method execute
20
+ # @param logger [Wordmove::Logger]
21
+ # @param local_options [Hash] Local host options fetched from
22
+ # movefile (with symbolized keys)
23
+ # @param remote_options [Hash] Remote host options fetched from
24
+ # movefile (with symbolized keys)
25
+ # @param cli_options [Hash] Command line options (with symbolized keys)
26
+ # @param photocopier [Photocopier::FTP]
27
+ # @param folder_task [Symbol] Symbolazied folder name
28
+ # @!scope class
29
+ # @return [LightService::Context] Action's context
30
+ executed do |context|
31
+ context.logger.task "Pulling #{context.folder_task}"
32
+
33
+ next context if simulate?(cli_options: context.cli_options)
34
+
35
+ command = 'get_directory'
36
+
37
+ # This action can generate `command_args` by itself,
38
+ # but it gives the context the chance to ovveride it.
39
+ # By the way this variable is not `expects`ed.
40
+ # Note that we do not use the second argument to `fetch`
41
+ # to express a default value, because it would be greedly interpreted
42
+ # but if `command_args` is already defined by context, then it's
43
+ # possible that `"remote_#{context.folder_task}_dir"` could
44
+ # not be defined.
45
+ command_args = context.fetch(:command_args) || [
46
+ send(
47
+ "remote_#{context.folder_task}_dir",
48
+ remote_options: context.remote_options
49
+ ).path,
50
+ send(
51
+ "local_#{context.folder_task}_dir",
52
+ local_options: context.local_options
53
+ ).path,
54
+ paths_to_exclude(remote_options: context.remote_options)
55
+ ]
56
+
57
+ context.logger.task_step false, "#{command}: #{command_args.join(' ')}"
58
+ result = context.photocopier.send(command, *command_args)
59
+
60
+ next context if result == true
61
+
62
+ context.fail!("Failed to pull #{context.folder_task}")
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,91 @@
1
+ module Wordmove
2
+ module Actions
3
+ module Ftp
4
+ module Helpers
5
+ extend ActiveSupport::Concern
6
+
7
+ class_methods do # rubocop:disable Metrics/BlockLength
8
+ #
9
+ # (In)Utility method to retrieve ftp options from the superset of remote options
10
+ #
11
+ # @param [Hash] remote_options Remote host options fetched from movefile
12
+ # (with symbolized keys)
13
+ #
14
+ # @return [Hash] Ftp options from the movefile
15
+ #
16
+ def ftp_options(remote_options:)
17
+ remote_options[:ftp]
18
+ end
19
+
20
+ #
21
+ # Escape a string to be printed into PHP files
22
+ #
23
+ # @param [String] string The string to escape
24
+ #
25
+ # @return [String] The escaped string
26
+ #
27
+ def escape_php(string:)
28
+ return '' unless string
29
+
30
+ # replaces \ with \\
31
+ # replaces ' with \'
32
+ string.gsub('\\', '\\\\\\').gsub(/'/, '\\\\\'')
33
+ end
34
+
35
+ #
36
+ # Generate a token
37
+ #
38
+ # @return [String] A random hexadecimal string
39
+ #
40
+ def remote_php_scripts_token
41
+ SecureRandom.hex(40)
42
+ end
43
+
44
+ #
45
+ # Generate THE PHP dump script, protected by a token to ensure only Wordmove will run it
46
+ #
47
+ # @param [Hash] remote_db_options The remote DB configurations fetched from movefile
48
+ # @param [String] token The token that will be used to protect the execution of the script
49
+ #
50
+ # @return [String] The PHP file as string
51
+ #
52
+ def generate_dump_script(remote_db_options:, token:)
53
+ template = ERB.new(
54
+ File.read(File.join(File.dirname(__FILE__), '../../assets/dump.php.erb'))
55
+ )
56
+ template.result(binding)
57
+ end
58
+
59
+ #
60
+ # Generate THE PHP import script, protected by a token to ensure only Wordmove will run it
61
+ #
62
+ # @param [Hash] remote_db_options The remote DB configurations fetched from movefile
63
+ # @param [String] token The token that will be used to protect the execution of the script
64
+ #
65
+ # @return [String] The PHP file as string
66
+ #
67
+ def generate_import_script(remote_db_options:, token:)
68
+ template = ERB.new(
69
+ File.read(File.join(File.dirname(__FILE__), '../../assets/import.php.erb'))
70
+ )
71
+ template.result(binding)
72
+ end
73
+
74
+ #
75
+ # Download a file from the internet making a simple GET request
76
+ #
77
+ # @param [String] url The URL of the resource to download
78
+ # @param [String] local_path The local path where the resource will be saved
79
+ #
80
+ # @return [nil]
81
+ #
82
+ def download(url:, local_path:)
83
+ File.open(local_path, 'w') do |file|
84
+ file << URI.parse(url).read
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,56 @@
1
+ module Wordmove
2
+ module Actions
3
+ module Ftp
4
+ # Syncs wordpress folder (usually root folder), exluding +wp-content/+ folder, over FTP
5
+ # protocol from the remote server to local host
6
+ class PullWordpress
7
+ extend ::LightService::Action
8
+ include Wordmove::Actions::Helpers
9
+ include WordpressDirectory::RemoteHelperMethods
10
+
11
+ expects :remote_options,
12
+ :local_options,
13
+ :logger,
14
+ :photocopier
15
+
16
+ # @!method execute
17
+ # @param remote_options [Hash] Remote host options fetched from
18
+ # movefile (with symbolized keys)
19
+ # @param local_options [Hash] Local host options fetched from
20
+ # movefile (with symbolized keys)
21
+ # @param logger [Wordmove::Logger]
22
+ # @param photocopier [Photocopier::FTP]
23
+ # @!scope class
24
+ # @return [LightService::Context] Action's context
25
+ executed do |context|
26
+ local_path = context.local_options[:wordpress_path]
27
+
28
+ remote_path = context.remote_options[:wordpress_path]
29
+
30
+ wp_content_relative_path = remote_wp_content_dir(
31
+ remote_options: context.remote_options
32
+ ).relative_path
33
+
34
+ exclude_wp_content = exclude_dir_contents(
35
+ path: wp_content_relative_path
36
+ )
37
+
38
+ exclude_paths = paths_to_exclude(
39
+ remote_options: context.remote_options
40
+ ).push(exclude_wp_content)
41
+
42
+ result = Wordmove::Actions::Ftp::GetDirectory.execute(
43
+ photocopier: context.photocopier,
44
+ logger: context.logger,
45
+ command_args: [remote_path, local_path, exclude_paths],
46
+ folder_task: :wordpress,
47
+ local_options: context.local_options,
48
+ remote_options: context.remote_options,
49
+ cli_options: context.cli_options
50
+ )
51
+ context.fail!(result.message) if result.failure?
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,54 @@
1
+ module Wordmove
2
+ module Actions
3
+ module Ftp
4
+ # Syncs wordpress folder (usually root folder), exluding +wp-content/+ folder, over FTP
5
+ # protocol from local host to the remote server
6
+ class PushWordpress
7
+ extend ::LightService::Action
8
+ include Wordmove::Actions::Helpers
9
+ include WordpressDirectory::LocalHelperMethods
10
+
11
+ expects :remote_options,
12
+ :local_options,
13
+ :logger,
14
+ :photocopier
15
+
16
+ # @!method execute
17
+ # @param remote_options [Hash] Remote host options fetched from
18
+ # movefile (with symbolized keys)
19
+ # @param local_options [Hash] Local host options fetched from
20
+ # movefile (with symbolized keys)
21
+ # @param logger [Wordmove::Logger]
22
+ # @param photocopier [Photocopier::FTP]
23
+ # @!scope class
24
+ # @return [LightService::Context] Action's context
25
+ executed do |context|
26
+ local_path = context.local_options[:wordpress_path]
27
+
28
+ remote_path = context.remote_options[:wordpress_path]
29
+
30
+ wp_content_relative_path = local_wp_content_dir(
31
+ local_options: context.local_options
32
+ ).relative_path
33
+
34
+ exclude_wp_content = exclude_dir_contents(path: wp_content_relative_path)
35
+
36
+ exclude_paths = paths_to_exclude(
37
+ remote_options: context.remote_options
38
+ ).push(exclude_wp_content)
39
+
40
+ result = Wordmove::Actions::Ftp::PutDirectory.execute(
41
+ photocopier: context.photocopier,
42
+ logger: context.logger,
43
+ command_args: [local_path, remote_path, exclude_paths],
44
+ folder_task: :wordpress,
45
+ local_options: context.local_options,
46
+ remote_options: context.remote_options,
47
+ cli_options: context.cli_options
48
+ )
49
+ context.fail!(result.message) if result.failure?
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,83 @@
1
+ module Wordmove
2
+ module Actions
3
+ module Ftp
4
+ # Uploads a DB dump to remote host and import it in the remote database over FTP protocol
5
+ class PutAndImportDumpRemotely
6
+ extend ::LightService::Action
7
+ include Wordmove::Actions::Helpers
8
+ include Wordmove::Actions::Ftp::Helpers
9
+ include WordpressDirectory::RemoteHelperMethods
10
+ include WordpressDirectory::LocalHelperMethods
11
+
12
+ expects :remote_options,
13
+ :cli_options,
14
+ :logger,
15
+ :photocopier,
16
+ :db_paths
17
+
18
+ # @!method execute
19
+ # @param logger [Wordmove::Logger]
20
+ # @param cli_options [Hash] Command line options (with symbolized keys)
21
+ # @param remote_options [Hash] Remote host options fetched from
22
+ # movefile (with symbolized keys)
23
+ # @param db_paths [BbPathsConfig] Configuration object for database
24
+ # @param photocopier [Photocopier::FTP]
25
+ # @!scope class
26
+ # @return [LightService::Context] Action's context
27
+ executed do |context| # rubocop:disable Metrics/BlockLength
28
+ next context if context.database_task == false
29
+
30
+ context.logger.task 'Upload and import adapted DB'
31
+
32
+ result = Wordmove::Actions::PutFile.execute(
33
+ logger: context.logger,
34
+ photocopier: context.photocopier,
35
+ cli_options: context.cli_options,
36
+ command_args: [
37
+ context.db_paths.local.adapted_path,
38
+ context.db_paths.remote.path
39
+ ]
40
+ )
41
+ context.fail_and_return!(result.message) if result.failure?
42
+
43
+ result = Wordmove::Actions::PutFile.execute(
44
+ logger: context.logger,
45
+ photocopier: context.photocopier,
46
+ cli_options: context.cli_options,
47
+ command_args: [
48
+ context.db_paths.ftp.local.generated_import_script_path,
49
+ context.db_paths.ftp.remote.import_script_path
50
+ ]
51
+ )
52
+ context.fail_and_return!(result.message) if result.failure?
53
+
54
+ import_url = [
55
+ context.db_paths.ftp.remote.import_script_url,
56
+ '?shared_key=',
57
+ context.db_paths.ftp.token,
58
+ '&start=1&foffset=0&totalqueries=0&fn=dump.sql'
59
+ ].join
60
+
61
+ download(url: import_url, local_path: context.db_paths.ftp.local.temp_path)
62
+
63
+ if context.cli_options[:debug]
64
+ context.logger.debug "Operation log located at: #{context.db_paths.ftp.local.temp_path}"
65
+ else
66
+ result = Wordmove::Actions::DeleteLocalFile.execute(
67
+ cli_options: context.cli_options,
68
+ logger: context.logger,
69
+ file_path: context.db_paths.ftp.local.temp_path
70
+ )
71
+
72
+ if result.failure?
73
+ context.logger.warning 'Failed to delete local file ' \
74
+ "#{context.db_paths.ftp.local.temp_path} because: " \
75
+ "#{result.message}" \
76
+ '. Manual intervention required'
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,67 @@
1
+ module Wordmove
2
+ module Actions
3
+ module Ftp
4
+ # Syncs a whole directory over FTP protocol from local host to remote server
5
+ class PutDirectory
6
+ extend LightService::Action
7
+ include Wordmove::Actions::Helpers
8
+ include WordpressDirectory::LocalHelperMethods
9
+ include WordpressDirectory::RemoteHelperMethods
10
+
11
+ # :folder_task is expected to be one symbol from Wordmove::CLI.wordpress_options array
12
+ expects :logger,
13
+ :local_options,
14
+ :remote_options,
15
+ :cli_options,
16
+ :photocopier,
17
+ :folder_task
18
+
19
+ # @!method execute
20
+ # @param logger [Wordmove::Logger]
21
+ # @param local_options [Hash] Local host options fetched from
22
+ # movefile (with symbolized keys)
23
+ # @param remote_options [Hash] Remote host options fetched from
24
+ # movefile (with symbolized keys)
25
+ # @param cli_options [Hash] Command line options (with symbolized keys)
26
+ # @param photocopier [Photocopier::FTP]
27
+ # @param folder_task [Symbol] Symbolazied folder name
28
+ # @!scope class
29
+ # @return [LightService::Context] Action's context
30
+ executed do |context|
31
+ context.logger.task "Pushing #{context.folder_task}"
32
+
33
+ next context if simulate?(cli_options: context.cli_options)
34
+
35
+ command = 'put_directory'
36
+
37
+ # This action can generate `command_args` by itself,
38
+ # but it gives the context the chance to ovveride it.
39
+ # By the way this variable is not `expects`ed.
40
+ # Note that we do not use the second argument to `fetch`
41
+ # to express a default value, because it would be greedly interpreted
42
+ # but if `command_args` is already defined by context, then it's
43
+ # possible that `"local_#{context.folder_task}_dir"` could
44
+ # not be defined.
45
+ command_args = context.fetch(:command_args) || [
46
+ send(
47
+ "local_#{context.folder_task}_dir",
48
+ local_options: context.local_options
49
+ ).path,
50
+ send(
51
+ "remote_#{context.folder_task}_dir",
52
+ remote_options: context.remote_options
53
+ ).path,
54
+ paths_to_exclude(remote_options: context.remote_options)
55
+ ]
56
+
57
+ context.logger.task_step false, "#{command}: #{command_args.join(' ')}"
58
+ result = context.photocopier.send(command, *command_args)
59
+
60
+ next context if result == true
61
+
62
+ context.fail!("Failed to push #{context.folder_task}")
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,38 @@
1
+ module Wordmove
2
+ module Actions
3
+ # Download a single file from the remote server.
4
+ #
5
+ # @note The remote server is already configured inside the Photocopier object
6
+ # @note This action is *not* meant to be organized, but as a standalone one.
7
+ class GetFile
8
+ extend LightService::Action
9
+ include Wordmove::Actions::Helpers
10
+
11
+ expects :photocopier,
12
+ :logger,
13
+ :cli_options,
14
+ :command_args
15
+
16
+ # @!method execute
17
+ # @param photocopier [Photocopier::SSH|Photocopier::FTP]
18
+ # @param logger [Wordmove::Logger]
19
+ # @param cli_options [Hash] Command line options (with symbolized keys)
20
+ # @param command_args ((String) remote file path, (String) local file path)
21
+ # @!scope class
22
+ # @return [LightService::Context] Action's context
23
+ executed do |context|
24
+ command = 'get'
25
+
26
+ context.logger.task_step false, "#{command}: #{context.command_args.join(' ')}"
27
+
28
+ next context if simulate?(cli_options: context.cli_options)
29
+
30
+ result = context.photocopier.send(command, *context.command_args)
31
+
32
+ next context if result == true
33
+
34
+ context.fail! "Failed to download file: #{context.command_args.first}"
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,142 @@
1
+ module Wordmove
2
+ module Actions
3
+ # Helpers for +Wordmove::Actions+
4
+ #
5
+ # All helpers methos are class methods; this way we force avoiding the use
6
+ # of persistence. All actions have to be approached more as functional code
7
+ # than OO code. Thus helpers are condidered as functional code too.
8
+ module Helpers
9
+ extend ActiveSupport::Concern
10
+
11
+ # rubocop:disable Metrics/BlockLength
12
+ class_methods do
13
+ # Determines if we're running a simulated command. Actually this is a
14
+ # wrapper around command line arguments set by the user.
15
+ #
16
+ # @param cli_options [Hash] Command line options hash (deep symbolized).
17
+ # Generally you will find this into action's context
18
+ # @return [Boolean]
19
+ # @!scope class
20
+ def simulate?(cli_options:)
21
+ cli_options.fetch(:simulate, false)
22
+ end
23
+
24
+ # Returns the path to be excluded as per movefile.yml configuration.
25
+ # `remote_options` is always valid for both push and pull actions,
26
+ # because path exclusions are configured only on remote environments
27
+ #
28
+ # @param remote_options [Hash] The options hash for the selected remote
29
+ # remote environment. Generally you will find this into action's context.
30
+ # @return [Array<String>]
31
+ # @!scope class
32
+ def paths_to_exclude(remote_options:)
33
+ remote_options.fetch(:exclude, [])
34
+ end
35
+
36
+ # Given a path, it will append the `/*` string to it. This is how
37
+ # folder content - thus not the folder itself - is represented by rsync.
38
+ # The name of this method is not explicative nor expressive, but we retain
39
+ # it for backward compatibility.
40
+ #
41
+ # @param path [String]
42
+ # @return [String]
43
+ # @!scope class
44
+ def exclude_dir_contents(path:)
45
+ "#{path}/*"
46
+ end
47
+
48
+ # Construct the mysql dump command as a string
49
+ #
50
+ # @param env_db_options [Hash] This hash is defined by the user through movefile.yml
51
+ # @param save_to_path [String] The path where the db dump will be saved
52
+ # @return [String] The full composed mysql command
53
+ # @!scope class
54
+ def mysql_dump_command(env_db_options:, save_to_path:)
55
+ command = ['mysqldump']
56
+
57
+ if env_db_options[:host].present?
58
+ command << "--host=#{Shellwords.escape(env_db_options[:host])}"
59
+ end
60
+
61
+ if env_db_options[:port].present?
62
+ command << "--port=#{Shellwords.escape(env_db_options[:port])}"
63
+ end
64
+
65
+ if env_db_options[:user].present?
66
+ command << "--user=#{Shellwords.escape(env_db_options[:user])}"
67
+ end
68
+
69
+ if env_db_options[:password].present?
70
+ command << "--password=#{Shellwords.escape(env_db_options[:password])}"
71
+ end
72
+
73
+ command << "--result-file=\"#{save_to_path}\""
74
+
75
+ if env_db_options[:mysqldump_options].present?
76
+ command << Shellwords.split(env_db_options[:mysqldump_options])
77
+ end
78
+
79
+ command << Shellwords.escape(env_db_options[:name])
80
+
81
+ command.join(' ')
82
+ end
83
+
84
+ # Construct the mysql import command as a string
85
+ #
86
+ # @param dump_path [String] The path where the dump to import is located
87
+ # @param env_db_options [Hash] This hash is defined by the user through movefile.yml
88
+ # @return [String] The full composed mysql command
89
+ # @!scope class
90
+ def mysql_import_command(dump_path:, env_db_options:)
91
+ command = ['mysql']
92
+ %i[host port user].each do |option|
93
+ if env_db_options[option].present?
94
+ command << "--#{option}=#{Shellwords.escape(env_db_options[option])}"
95
+ end
96
+ end
97
+ if env_db_options[:password].present?
98
+ command << "--password=#{Shellwords.escape(env_db_options[:password])}"
99
+ end
100
+ command << "--database=#{Shellwords.escape(env_db_options[:name])}"
101
+ if env_db_options[:mysql_options].present?
102
+ command << Shellwords.split(env_db_options[:mysql_options])
103
+ end
104
+ command << "--execute=\"SET autocommit=0;SOURCE #{dump_path};COMMIT\""
105
+ command.join(' ')
106
+ end
107
+
108
+ # Construct the command to compress a file as a string. The command will be wrapped
109
+ # as argument to the +nice+ command, in order to lower the process priority and do
110
+ # not lock the system while compressing large files.
111
+ #
112
+ # @param file_path [String] The path where the file to be compressed is located
113
+ # @return [String] the command
114
+ # @!scope class
115
+ def compress_command(file_path:)
116
+ command = ['nice']
117
+ command << '-n'
118
+ command << '0'
119
+ command << 'gzip'
120
+ command << '-9'
121
+ command << '-f'
122
+ command << "\"#{file_path}\""
123
+ command.join(' ')
124
+ end
125
+
126
+ # Construct the command to deflate a compressed file as a string.
127
+ #
128
+ # @param file_path [String] The path where the file to be deflated is located
129
+ # @return [String] the command
130
+ # @!scope class
131
+ def uncompress_command(file_path:)
132
+ command = ['gzip']
133
+ command << '-d'
134
+ command << '-f'
135
+ command << "\"#{file_path}\""
136
+ command.join(' ')
137
+ end
138
+ end
139
+ # rubocop:enable Metrics/BlockLength
140
+ end
141
+ end
142
+ end