wordmove 5.2.2 → 6.0.0.alpha.4
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.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +12 -5
- data/.rubocop.yml +2 -5
- data/.ruby-version +1 -1
- data/.yardopts +1 -0
- data/CONTRIBUTING.md +15 -0
- data/Rakefile +4 -3
- data/exe/wordmove +2 -1
- data/lib/wordmove/actions/adapt_local_db.rb +101 -0
- data/lib/wordmove/actions/adapt_remote_db.rb +88 -0
- data/lib/wordmove/actions/backup_local_db.rb +56 -0
- data/lib/wordmove/actions/delete_local_file.rb +34 -0
- data/lib/wordmove/actions/delete_remote_file.rb +43 -0
- data/lib/wordmove/actions/filter_and_setup_tasks_to_run.rb +42 -0
- data/lib/wordmove/actions/ftp/backup_remote_db.rb +54 -0
- data/lib/wordmove/actions/ftp/cleanup_after_adapt.rb +70 -0
- data/lib/wordmove/actions/ftp/download_remote_db.rb +69 -0
- data/lib/wordmove/actions/ftp/get_directory.rb +67 -0
- data/lib/wordmove/actions/ftp/helpers.rb +91 -0
- data/lib/wordmove/actions/ftp/pull_wordpress.rb +56 -0
- data/lib/wordmove/actions/ftp/push_wordpress.rb +54 -0
- data/lib/wordmove/actions/ftp/put_and_import_dump_remotely.rb +81 -0
- data/lib/wordmove/actions/ftp/put_directory.rb +67 -0
- data/lib/wordmove/actions/get_file.rb +38 -0
- data/lib/wordmove/actions/helpers.rb +142 -0
- data/lib/wordmove/actions/put_file.rb +48 -0
- data/lib/wordmove/actions/run_after_pull_hook.rb +26 -0
- data/lib/wordmove/actions/run_after_push_hook.rb +26 -0
- data/lib/wordmove/actions/run_before_pull_hook.rb +26 -0
- data/lib/wordmove/actions/run_before_push_hook.rb +26 -0
- data/lib/wordmove/actions/run_local_command.rb +34 -0
- data/lib/wordmove/actions/setup_context_for_db.rb +73 -0
- data/lib/wordmove/actions/ssh/backup_remote_db.rb +49 -0
- data/lib/wordmove/actions/ssh/cleanup_after_adapt.rb +54 -0
- data/lib/wordmove/actions/ssh/download_remote_db.rb +81 -0
- data/lib/wordmove/actions/ssh/get_directory.rb +76 -0
- data/lib/wordmove/actions/ssh/helpers.rb +128 -0
- data/lib/wordmove/actions/ssh/pull_wordpress.rb +56 -0
- data/lib/wordmove/actions/ssh/push_wordpress.rb +54 -0
- data/lib/wordmove/actions/ssh/put_and_import_dump_remotely.rb +75 -0
- data/lib/wordmove/actions/ssh/put_directory.rb +76 -0
- data/lib/wordmove/actions/ssh/run_remote_command.rb +39 -0
- data/lib/wordmove/assets/dump.php.erb +6 -6
- data/lib/wordmove/assets/import.php.erb +7 -7
- data/lib/wordmove/assets/wordmove_schema_global.yml +2 -0
- data/lib/wordmove/cli.rb +152 -91
- data/lib/wordmove/db_paths_config.rb +44 -0
- data/lib/wordmove/doctor/movefile.rb +8 -8
- data/lib/wordmove/doctor/mysql.rb +18 -15
- data/lib/wordmove/doctor/rsync.rb +2 -2
- data/lib/wordmove/doctor/ssh.rb +3 -3
- data/lib/wordmove/doctor/wpcli.rb +5 -5
- data/lib/wordmove/environments_list.rb +4 -4
- data/lib/wordmove/exceptions.rb +13 -0
- data/lib/wordmove/generators/movefile.rb +7 -5
- data/lib/wordmove/generators/movefile_adapter.rb +11 -5
- data/lib/wordmove/guardian.rb +5 -5
- data/lib/wordmove/hook.rb +13 -14
- data/lib/wordmove/logger.rb +11 -10
- data/lib/wordmove/movefile.rb +63 -59
- data/lib/wordmove/organizers/ftp/pull.rb +53 -0
- data/lib/wordmove/organizers/ftp/push.rb +54 -0
- data/lib/wordmove/organizers/ssh/pull.rb +53 -0
- data/lib/wordmove/organizers/ssh/push.rb +54 -0
- data/lib/wordmove/version.rb +1 -1
- data/lib/wordmove/wordpress_directory.rb +76 -8
- data/lib/wordmove/wpcli.rb +88 -0
- data/lib/wordmove.rb +33 -11
- data/wordmove.gemspec +37 -30
- metadata +139 -35
- data/lib/wordmove/deployer/base.rb +0 -193
- data/lib/wordmove/deployer/ftp.rb +0 -160
- data/lib/wordmove/deployer/ssh/default_sql_adapter.rb +0 -47
- data/lib/wordmove/deployer/ssh/wpcli_sql_adapter.rb +0 -55
- data/lib/wordmove/deployer/ssh.rb +0 -169
- data/lib/wordmove/sql_adapter/default.rb +0 -68
- data/lib/wordmove/sql_adapter/wpcli.rb +0 -54
- 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
|