wordmove 5.2.2 → 6.0.0.alpha.4

Sign up to get free protection for your applications and to get access to all the features.
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 +101 -0
  10. data/lib/wordmove/actions/adapt_remote_db.rb +88 -0
  11. data/lib/wordmove/actions/backup_local_db.rb +56 -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 +81 -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 +73 -0
  33. data/lib/wordmove/actions/ssh/backup_remote_db.rb +49 -0
  34. data/lib/wordmove/actions/ssh/cleanup_after_adapt.rb +54 -0
  35. data/lib/wordmove/actions/ssh/download_remote_db.rb +81 -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 +75 -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 +5 -5
  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 +53 -0
  62. data/lib/wordmove/organizers/ftp/push.rb +54 -0
  63. data/lib/wordmove/organizers/ssh/pull.rb +53 -0
  64. data/lib/wordmove/organizers/ssh/push.rb +54 -0
  65. data/lib/wordmove/version.rb +1 -1
  66. data/lib/wordmove/wordpress_directory.rb +76 -8
  67. data/lib/wordmove/wpcli.rb +88 -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,26 @@
1
+ module Wordmove
2
+ module Actions
3
+ # Runs after push hooks by invoking the external service
4
+ # Wordmove::Hook
5
+ class RunAfterPushHook
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
+ :push,
19
+ :after,
20
+ movefile: context.movefile,
21
+ simulate: simulate?(cli_options: context.cli_options)
22
+ )
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,26 @@
1
+ module Wordmove
2
+ module Actions
3
+ # Runs before pull hooks by invoking the external service
4
+ # Wordmove::Hook
5
+ class RunBeforePullHook
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
+ :before,
20
+ movefile: context.movefile,
21
+ simulate: simulate?(cli_options: context.cli_options)
22
+ )
23
+ end
24
+ end
25
+ end
26
+ 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 RunBeforePushHook
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
+ :push,
19
+ :before,
20
+ movefile: context.movefile,
21
+ simulate: simulate?(cli_options: context.cli_options)
22
+ )
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,34 @@
1
+ require 'English'
2
+
3
+ module Wordmove
4
+ module Actions
5
+ # Run a command on the local system.
6
+ # Command won't be run if +--simulate+ flag is present on CLI.
7
+ # @note This action is *not* meant to be organized, but as a standalone one.
8
+ class RunLocalCommand
9
+ extend LightService::Action
10
+ include Wordmove::Actions::Helpers
11
+
12
+ expects :command,
13
+ :cli_options,
14
+ :logger
15
+
16
+ # @!method execute
17
+ # @param command [String] The command to run
18
+ # @param cli_options [Hash]
19
+ # @param logger [Wordmove::Logger]
20
+ # @return [LightService::Context] Action's context
21
+ executed do |context|
22
+ context.logger.task_step true, context.command
23
+
24
+ next context if simulate?(cli_options: context.cli_options)
25
+
26
+ begin
27
+ system(context.command, exception: true)
28
+ rescue RuntimeError, SystemExit => e
29
+ context.fail!("Local command status reports an error: #{e.message}")
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,73 @@
1
+ module Wordmove
2
+ module Actions
3
+ class SetupContextForDb
4
+ extend ::LightService::Action
5
+ include Wordmove::Actions::Helpers
6
+ include Wordmove::Actions::Ftp::Helpers
7
+ include WordpressDirectory::LocalHelperMethods
8
+ include WordpressDirectory::RemoteHelperMethods
9
+
10
+ expects :cli_options,
11
+ :local_options,
12
+ :remote_options,
13
+ :logger,
14
+ :movefile,
15
+ :database_task
16
+ promises :db_paths
17
+
18
+ executed do |context| # rubocop:disable Metrics/BlockLength
19
+ next context if simulate?(cli_options: context.cli_options)
20
+
21
+ content_dir = local_wp_content_dir(local_options: context.local_options)
22
+
23
+ token = remote_php_scripts_token
24
+
25
+ DbPathsConfig.local.path = content_dir.path('dump.sql')
26
+ DbPathsConfig.local.gzipped_path = "#{DbPathsConfig.local.path}.gz"
27
+ DbPathsConfig.remote.path = remote_wp_content_dir(
28
+ remote_options: context.remote_options
29
+ ).path('dump.sql')
30
+ DbPathsConfig.remote.gzipped_path = "#{DbPathsConfig.remote.path}.gz"
31
+ DbPathsConfig.local.adapted_path = content_dir.path('search_replace_dump.sql')
32
+ DbPathsConfig.local.gzipped_adapted_path = "#{DbPathsConfig.local.adapted_path}.gz"
33
+ DbPathsConfig.backup.local.path = content_dir.path("local-backup-#{Time.now.to_i}.sql")
34
+ DbPathsConfig.backup.local.gzipped_path = "#{DbPathsConfig.backup.local.path}.gz"
35
+ DbPathsConfig.backup.remote.path =
36
+ content_dir.path("#{context.movefile.environment}-backup-#{Time.now.to_i}.sql")
37
+ DbPathsConfig.backup.remote.gzipped_path = "#{DbPathsConfig.backup.remote.path}.gz"
38
+
39
+ DbPathsConfig.ftp.remote.dump_script_path = remote_wp_content_dir(
40
+ remote_options: context.remote_options
41
+ ).path('dump.php')
42
+ DbPathsConfig.ftp.remote.dumped_path = remote_wp_content_dir(
43
+ remote_options: context.remote_options
44
+ ).path('dump.mysql')
45
+ DbPathsConfig.ftp.remote.dump_script_url = remote_wp_content_dir(
46
+ remote_options: context.remote_options
47
+ ).url('dump.php')
48
+ DbPathsConfig.ftp.remote.import_script_path = remote_wp_content_dir(
49
+ remote_options: context.remote_options
50
+ ).path('import.php')
51
+ DbPathsConfig.ftp.remote.import_script_url = remote_wp_content_dir(
52
+ remote_options: context.remote_options
53
+ ).url('import.php')
54
+ DbPathsConfig.ftp.local.generated_dump_script_path = generate_dump_script(
55
+ remote_db_options: context.remote_options[:database],
56
+ token: token
57
+ )
58
+ DbPathsConfig.ftp.local.generated_import_script_path = generate_import_script(
59
+ remote_db_options: context.remote_options[:database],
60
+ token: token
61
+ )
62
+ DbPathsConfig.ftp.local.temp_path = local_wp_content_dir(
63
+ local_options: context.local_options
64
+ ).path('log.html')
65
+ # I know this is not a path, but it's used to generate
66
+ # a URL to dump the DB, so it's somewhat in context
67
+ DbPathsConfig.ftp.token = token
68
+
69
+ context.db_paths = DbPathsConfig
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,49 @@
1
+ module Wordmove
2
+ module Actions
3
+ module Ssh
4
+ # Bakups an alrady downloaded remote dump
5
+ class BackupRemoteDb
6
+ extend ::LightService::Action
7
+ include Wordmove::Actions::Helpers
8
+
9
+ expects :cli_options,
10
+ :logger,
11
+ :db_paths
12
+
13
+ # @!method execute
14
+ # @param cli_options [Hash] Command line options (with symbolized keys)
15
+ # @param logger [Wordmove::Logger]
16
+ # @param db_paths [BbPathsConfig] Configuration object for database
17
+ # @!scope class
18
+ # @return [LightService::Context] Action's context
19
+ executed do |context|
20
+ context.logger.task 'Backup remote DB'
21
+
22
+ if simulate?(cli_options: context.cli_options)
23
+ context.logger.info 'A backup of the remote DB would have been saved into ' \
24
+ "#{context.db_paths.backup.remote.gzipped_path}, " \
25
+ 'but you\'re simulating'
26
+ next context
27
+ end
28
+
29
+ # Most of the expectations are needed to be proxied to `DownloadRemoteDb`
30
+ # Wordmove::Actions::Ssh::DownloadRemoteDb.execute(context)
31
+ # DownloadRemoteDB will save the file in `db_paths.local.gzipped_path`
32
+
33
+ begin
34
+ FileUtils.mv(
35
+ context.db_paths.local.gzipped_path,
36
+ context.db_paths.backup.remote.gzipped_path
37
+ )
38
+
39
+ context.logger.success(
40
+ "Backup saved at #{context.db_paths.backup.remote.gzipped_path}"
41
+ )
42
+ rescue Errno::ENOENT => e
43
+ context.fail_and_return!("Remote DB backup failed with: #{e.message}. Aborting.")
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,54 @@
1
+ module Wordmove
2
+ module Actions
3
+ module Ssh
4
+ # Cleanup file created during DB push/pull operations
5
+ class CleanupAfterAdapt
6
+ extend ::LightService::Action
7
+ include Wordmove::Actions::Helpers
8
+
9
+ expects :db_paths,
10
+ :cli_options,
11
+ :logger
12
+
13
+ # @!method execute
14
+ # @param db_paths [BbPathsConfig] Configuration object for database
15
+ # @param cli_options [Hash] Command line options (with symbolized keys)
16
+ # @param logger [Wordmove::Logger]
17
+ # @!scope class
18
+ # @return [LightService::Context] Action's context
19
+ executed do |context| # rubocop:disable Metrics/BlockLength
20
+ context.logger.task 'Cleanup'
21
+
22
+ if simulate?(cli_options: context.cli_options)
23
+ context.logger.info 'No cleanup during simulation'
24
+ next context
25
+ end
26
+
27
+ result = Wordmove::Actions::DeleteLocalFile.execute(
28
+ logger: context.logger,
29
+ cli_options: context.cli_options,
30
+ file_path: context.db_paths.local.path
31
+ )
32
+ if result.failure?
33
+ context.logger.warning 'Failed to delete local file ' \
34
+ "#{context.db_paths.local.path} because: " \
35
+ "#{result.message}" \
36
+ '. Manual intervention required'
37
+ end
38
+
39
+ result = Wordmove::Actions::DeleteLocalFile.execute(
40
+ cli_options: context.cli_options,
41
+ logger: context.logger,
42
+ file_path: context.db_paths.local.gzipped_adapted_path
43
+ )
44
+ if result.failure?
45
+ context.logger.warning 'Failed to delete local file ' \
46
+ "#{context.db_paths.local.gzipped_adapted_path} because: " \
47
+ "#{result.message}" \
48
+ '. Manual intervention required'
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,81 @@
1
+ module Wordmove
2
+ module Actions
3
+ module Ssh
4
+ # Downloads the remote DB over SSH protocol
5
+ class DownloadRemoteDb
6
+ extend ::LightService::Action
7
+ include Wordmove::Actions::Helpers
8
+ include WordpressDirectory::LocalHelperMethods
9
+ include WordpressDirectory::RemoteHelperMethods
10
+
11
+ expects :remote_options,
12
+ :cli_options,
13
+ :logger,
14
+ :photocopier,
15
+ :db_paths
16
+
17
+ # @!method execute
18
+ # @param remote_options [Hash] Remote host options fetched from
19
+ # movefile (with symbolized keys)
20
+ # @param cli_options [Hash] Command line options (with symbolized keys)
21
+ # @param logger [Wordmove::Logger]
22
+ # @param photocopier [Photocopier::SSH]
23
+ # @param db_paths [BbPathsConfig] Configuration object for database
24
+ # @!scope class
25
+ # @return [LightService::Context] Action's context
26
+ executed do |context| # rubocop:disable Metrics/BlockLength
27
+ context.logger.task 'Download remote DB'
28
+
29
+ next context if simulate?(cli_options: context.cli_options)
30
+
31
+ result = Wordmove::Actions::Ssh::RunRemoteCommand.execute(
32
+ cli_options: context.cli_options,
33
+ photocopier: context.photocopier,
34
+ logger: context.logger,
35
+ command: mysql_dump_command(
36
+ env_db_options: context.remote_options[:database],
37
+ save_to_path: context.db_paths.remote.path
38
+ )
39
+ )
40
+ context.fail_and_return!(result.message) if result.failure?
41
+
42
+ result = Wordmove::Actions::Ssh::RunRemoteCommand.execute(
43
+ cli_options: context.cli_options,
44
+ photocopier: context.photocopier,
45
+ logger: context.logger,
46
+ command: compress_command(file_path: context.db_paths.remote.path)
47
+ )
48
+ context.fail_and_return!(result.message) if result.failure?
49
+
50
+ result = Wordmove::Actions::GetFile.execute(
51
+ photocopier: context.photocopier,
52
+ logger: context.logger,
53
+ cli_options: context.cli_options,
54
+ command_args: [
55
+ context.db_paths.remote.gzipped_path,
56
+ context.db_paths.local.gzipped_path
57
+ ]
58
+ )
59
+ context.fail_and_return!(result.message) if result.failure?
60
+
61
+ result = Wordmove::Actions::DeleteRemoteFile.execute(
62
+ photocopier: context.photocopier,
63
+ logger: context.logger,
64
+ cli_options: context.cli_options,
65
+ remote_file: context.db_paths.remote.gzipped_path
66
+ )
67
+ if result.failure?
68
+ context.logger.warning 'Failed to delete remote file ' \
69
+ "#{context.db_paths.remote.gzipped_path} because: " \
70
+ "#{result.message}" \
71
+ '. Manual intervention required'
72
+ end
73
+
74
+ context.logger.success(
75
+ "Remote DB dump downloaded in #{context.db_paths.local.gzipped_path}"
76
+ )
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,76 @@
1
+ module Wordmove
2
+ module Actions
3
+ module Ssh
4
+ # Syncs a whole directory over SSH protocol from the remote server to local host
5
+ class GetDirectory
6
+ extend LightService::Action
7
+ include Wordmove::Actions::Helpers
8
+ include Wordmove::Actions::Ssh::Helpers
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::SSH]
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
+ # For this action `local_path` and `remote_path` will always be
37
+ # `:wordpress_path`; specific folder for `context.folder_task` will be included by
38
+ # `pull_include_paths`
39
+ local_path = context.local_options[:wordpress_path]
40
+ remote_path = context.remote_options[:wordpress_path]
41
+
42
+ # This action can generate `command_args` by itself,
43
+ # but it gives the context the chance to ovveride it.
44
+ # By the way this variable is not `expects`ed.
45
+ # Note that we do not use the second argument to `fetch`
46
+ # to express a default value, because it would be greedly interpreted
47
+ # but if `command_args` is already defined by context, then it's
48
+ # possible that `"remote_#{context.folder_task}_dir"` could
49
+ # not be defined.
50
+ command_args = context.fetch(:command_args) || [
51
+ remote_path,
52
+ local_path,
53
+ pull_exclude_paths(
54
+ remote_task_dir: send(
55
+ "remote_#{context.folder_task}_dir",
56
+ remote_options: context.remote_options
57
+ ),
58
+ paths_to_exclude: paths_to_exclude(remote_options: context.remote_options)
59
+ ),
60
+ pull_include_paths(remote_task_dir: send(
61
+ "remote_#{context.folder_task}_dir",
62
+ remote_options: context.remote_options
63
+ ))
64
+ ]
65
+
66
+ context.logger.task_step false, "#{command}: #{command_args.join(' ')}"
67
+ result = context.photocopier.send(command, *command_args)
68
+
69
+ next context if result == true
70
+
71
+ context.fail!("Failed to push #{context.folder_task}")
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,128 @@
1
+ require 'pathname'
2
+
3
+ # rubocop:disable Metrics/BlockLength
4
+ module Wordmove
5
+ module Actions
6
+ module Ssh
7
+ module Helpers
8
+ extend ActiveSupport::Concern
9
+
10
+ class_methods do
11
+ #
12
+ # Utility method to retrieve and augment ssh options from the superset of remote options.
13
+ # This is useful most because it appends +--dy-run+ rsync's flag to ssh options based
14
+ # on +--simulate+ flag presence
15
+ #
16
+ # @param [Hash] remote_options Remote host options fetcehd from movefile
17
+ # @param [Bool] simulate Tell the moethod if you're in a simulated operation
18
+ #
19
+ # @return [Hash] Ssh options
20
+ #
21
+ def ssh_options(remote_options:, simulate: false)
22
+ ssh_options = remote_options[:ssh]
23
+
24
+ if simulate == true && ssh_options[:rsync_options]
25
+ ssh_options[:rsync_options].concat(' --dry-run')
26
+ elsif simulate == true
27
+ ssh_options[:rsync_options] = '--dry-run'
28
+ end
29
+
30
+ ssh_options
31
+ end
32
+
33
+ #
34
+ # Given the directory you're pushing/pulling, generates an array of path to be included
35
+ # by rsync while pushing. Note that by design include paths are always required but are
36
+ # only programmatically deduced and never user configured.
37
+ #
38
+ # @note The business logic behind how these paths are produced should be deepened
39
+ #
40
+ # @param [WordpressDirectory] local_task_dir An object representing a wordpress folder
41
+ #
42
+ # @return [Array<String>] The array of path to be included by rsync
43
+ #
44
+ def push_include_paths(local_task_dir:)
45
+ Pathname.new(local_task_dir.relative_path)
46
+ .ascend
47
+ .each_with_object([]) do |directory, array|
48
+ path = directory.to_path
49
+ path.prepend('/') unless path.match? %r{^/}
50
+ path.concat('/') unless path.match? %r{/$}
51
+ array << path
52
+ end
53
+ end
54
+
55
+ #
56
+ # Given the directory you're pushing/pulling and the user configured exclude list,
57
+ # generates an array of path to be excluded
58
+ # by rsync while pushing. Note that by design exclude some paths are always required
59
+ # even when the user does not confiure any exclusion.
60
+ #
61
+ # @note The business logic behind how these paths are produced should be deepened
62
+ #
63
+ # @param [WordpressDirectory] local_task_dir An object representing a wordpress folder
64
+ # @param [Array<String>] pats_to_exclude An array of paths
65
+ #
66
+ # @return [Array<String>] The array of path to be included by rsync
67
+ #
68
+ def push_exclude_paths(local_task_dir:, paths_to_exclude:)
69
+ Pathname.new(local_task_dir.relative_path)
70
+ .dirname
71
+ .ascend
72
+ .each_with_object([]) do |directory, array|
73
+ path = directory.to_path
74
+ path.prepend('/') unless path.match? %r{^/}
75
+ path.concat('/') unless path.match? %r{/$}
76
+ path.concat('*')
77
+ array << path
78
+ end
79
+ .concat(paths_to_exclude)
80
+ .concat(['/*'])
81
+ end
82
+
83
+ #
84
+ # Same as Wordmove::Actions::Ssh::Helpers.push_include_path but for pull actions
85
+ #
86
+ # @param [WordpressDirectory] local_task_dir An object representing a wordpress folder
87
+ #
88
+ # @return [Array<String>] An array of paths
89
+ #
90
+ def pull_include_paths(remote_task_dir:)
91
+ Pathname.new(remote_task_dir.relative_path)
92
+ .ascend
93
+ .each_with_object([]) do |directory, array|
94
+ path = directory.to_path
95
+ path.prepend('/') unless path.match? %r{^/}
96
+ path.concat('/') unless path.match? %r{/$}
97
+ array << path
98
+ end
99
+ end
100
+
101
+ #
102
+ # Same as Wordmove::Actions::Ssh::Helpers.push_exclude_path but for pull actions
103
+ #
104
+ # @param [WordpressDirectory] local_task_dir An object representing a wordpress folder
105
+ # @param [Array<String>] paths_to_exclude User configured array of paths to exclude
106
+ #
107
+ # @return [Array<String>] Array of paths to be excluded
108
+ #
109
+ def pull_exclude_paths(remote_task_dir:, paths_to_exclude:)
110
+ Pathname.new(remote_task_dir.relative_path)
111
+ .dirname
112
+ .ascend
113
+ .each_with_object([]) do |directory, array|
114
+ path = directory.to_path
115
+ path.prepend('/') unless path.match? %r{^/}
116
+ path.concat('/') unless path.match? %r{/$}
117
+ path.concat('*')
118
+ array << path
119
+ end
120
+ .concat(paths_to_exclude)
121
+ .concat(['/*'])
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
128
+ # rubocop:enable Metrics/BlockLength
@@ -0,0 +1,56 @@
1
+ module Wordmove
2
+ module Actions
3
+ module Ssh
4
+ # Syncs wordpress folder (usually root folder), exluding +wp-content/+ folder, over SSH
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::SSH]
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::Ssh::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