wordmove 5.2.2 → 6.0.0.alpha.1

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 (78) 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 +95 -0
  10. data/lib/wordmove/actions/adapt_remote_db.rb +87 -0
  11. data/lib/wordmove/actions/backup_local_db.rb +54 -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 +54 -0
  16. data/lib/wordmove/actions/ftp/cleanup_after_adapt.rb +70 -0
  17. data/lib/wordmove/actions/ftp/download_remote_db.rb +69 -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 +74 -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 +79 -0
  33. data/lib/wordmove/actions/ssh/backup_remote_db.rb +49 -0
  34. data/lib/wordmove/actions/ssh/cleanup_after_adapt.rb +42 -0
  35. data/lib/wordmove/actions/ssh/download_remote_db.rb +76 -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 +70 -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/cli.rb +152 -91
  47. data/lib/wordmove/db_paths_config.rb +44 -0
  48. data/lib/wordmove/doctor/movefile.rb +8 -8
  49. data/lib/wordmove/doctor/mysql.rb +18 -15
  50. data/lib/wordmove/doctor/rsync.rb +2 -2
  51. data/lib/wordmove/doctor/ssh.rb +3 -3
  52. data/lib/wordmove/doctor/wpcli.rb +4 -4
  53. data/lib/wordmove/environments_list.rb +4 -4
  54. data/lib/wordmove/exceptions.rb +13 -0
  55. data/lib/wordmove/generators/movefile.rb +7 -5
  56. data/lib/wordmove/generators/movefile_adapter.rb +11 -5
  57. data/lib/wordmove/guardian.rb +5 -5
  58. data/lib/wordmove/hook.rb +13 -14
  59. data/lib/wordmove/logger.rb +11 -10
  60. data/lib/wordmove/movefile.rb +63 -59
  61. data/lib/wordmove/organizers/ftp/pull.rb +52 -0
  62. data/lib/wordmove/organizers/ftp/push.rb +53 -0
  63. data/lib/wordmove/organizers/ssh/pull.rb +52 -0
  64. data/lib/wordmove/organizers/ssh/push.rb +53 -0
  65. data/lib/wordmove/version.rb +1 -1
  66. data/lib/wordmove/wordpress_directory.rb +76 -8
  67. data/lib/wordmove/wpcli.rb +85 -0
  68. data/lib/wordmove.rb +33 -11
  69. data/wordmove.gemspec +37 -30
  70. metadata +139 -35
  71. data/lib/wordmove/deployer/base.rb +0 -193
  72. data/lib/wordmove/deployer/ftp.rb +0 -160
  73. data/lib/wordmove/deployer/ssh/default_sql_adapter.rb +0 -47
  74. data/lib/wordmove/deployer/ssh/wpcli_sql_adapter.rb +0 -55
  75. data/lib/wordmove/deployer/ssh.rb +0 -169
  76. data/lib/wordmove/sql_adapter/default.rb +0 -68
  77. data/lib/wordmove/sql_adapter/wpcli.rb +0 -54
  78. data/lib/wordmove/wordpress_directory/path.rb +0 -11
@@ -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,74 @@
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
+ context.logger.task 'Upload and import adapted DB'
29
+
30
+ result = Wordmove::Actions::PutFile.execute(
31
+ logger: context.logger,
32
+ photocopier: context.photocopier,
33
+ cli_options: context.cli_options,
34
+ command_args: [
35
+ context.db_paths.local.adapted_path,
36
+ context.db_paths.remote.path
37
+ ]
38
+ )
39
+ context.fail_and_return!(result.message) if result.failure?
40
+
41
+ result = Wordmove::Actions::PutFile.execute(
42
+ logger: context.logger,
43
+ photocopier: context.photocopier,
44
+ cli_options: context.cli_options,
45
+ command_args: [
46
+ context.db_paths.ftp.local.generated_import_script_path,
47
+ context.db_paths.ftp.remote.import_script_path
48
+ ]
49
+ )
50
+ context.fail_and_return!(result.message) if result.failure?
51
+
52
+ import_url = [
53
+ context.db_paths.ftp.remote.import_script_url,
54
+ '?shared_key=',
55
+ context.db_paths.ftp.token,
56
+ '&start=1&foffset=0&totalqueries=0&fn=dump.sql'
57
+ ].join
58
+
59
+ download(url: import_url, local_path: context.db_paths.ftp.local.temp_path)
60
+
61
+ if context.cli_options[:debug]
62
+ context.logger.debug "Operation log located at: #{context.db_paths.ftp.local.temp_path}"
63
+ else
64
+ Wordmove::Actions::DeleteLocalFile.execute(
65
+ cli_options: context.cli_options,
66
+ logger: context.logger,
67
+ file_path: context.db_paths.ftp.local.temp_path
68
+ )
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ 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
@@ -0,0 +1,48 @@
1
+ module Wordmove
2
+ module Actions
3
+ # Upload a single file to 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 PutFile
8
+ extend LightService::Action
9
+ include Wordmove::Actions::Helpers
10
+
11
+ expects :photocopier,
12
+ :logger,
13
+ :command_args,
14
+ :cli_options
15
+
16
+ # @!method execute
17
+ # @param photocopier [Photocopier]
18
+ # @param logger [Wordmove::Logger]
19
+ # @param command_args ((String) local file path, (String) remote file path)
20
+ # @return [LightService::Context] Action's context
21
+ executed do |context|
22
+ command = 'put'
23
+
24
+ # First argument could be a file or a content string. Do not log if the latter
25
+ message = if File.exist?(context.command_args.first)
26
+ context.command_args.join(' ')
27
+ else
28
+ context.command_args.second
29
+ end
30
+
31
+ context.logger.task_step false, "#{command}: #{message}"
32
+
33
+ result = if simulate?(cli_options: context.cli_options)
34
+ true
35
+ else
36
+ context.photocopier.send(command, *context.command_args)
37
+ end
38
+
39
+ next context if result == true
40
+ # We can't trust the return from the fotocopier method when using FTP. Keep on
41
+ # and have faith.
42
+ next context if context.photocopier.is_a? Photocopier::FTP
43
+
44
+ context.fail! "Failed to upload file: #{context.command_args.first}"
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,26 @@
1
+ module Wordmove
2
+ module Actions
3
+ # Runs before push hooks by invoking the external service
4
+ # Wordmove::Hook
5
+ class RunAfterPullHook
6
+ extend ::LightService::Action
7
+ include Wordmove::Actions::Helpers
8
+
9
+ expects :movefile,
10
+ :cli_options
11
+
12
+ # @!method execute
13
+ # @param movefile [Wordmove::Movefile]
14
+ # @param cli_options [Hash]
15
+ # @return [LightService::Context] Action's context
16
+ executed do |context|
17
+ Wordmove::Hook.run(
18
+ :pull,
19
+ :after,
20
+ movefile: context.movefile,
21
+ simulate: simulate?(cli_options: context.cli_options)
22
+ )
23
+ end
24
+ end
25
+ end
26
+ end