wordmove 5.2.0 → 6.0.0.alpha.2

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 +78 -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 +4 -4
  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 +15 -16
  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 +85 -0
  69. data/lib/wordmove.rb +33 -11
  70. data/wordmove.gemspec +37 -30
  71. metadata +141 -43
  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,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
@@ -0,0 +1,54 @@
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 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::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 = 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::Ssh::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,77 @@
1
+ module Wordmove
2
+ module Actions
3
+ module Ssh
4
+ # Uploads a DB dump to remote host and import it in the remote database over SSH protocol
5
+ class PutAndImportDumpRemotely
6
+ extend ::LightService::Action
7
+ include Wordmove::Actions::Helpers
8
+ include WordpressDirectory::RemoteHelperMethods
9
+ include WordpressDirectory::LocalHelperMethods
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
+ next context if context.database_task == false
28
+
29
+ context.logger.task 'Upload and import adapted DB'
30
+
31
+ result = Wordmove::Actions::PutFile.execute(
32
+ logger: context.logger,
33
+ photocopier: context.photocopier,
34
+ cli_options: context.cli_options,
35
+ command_args: [
36
+ context.db_paths.local.gzipped_adapted_path,
37
+ context.db_paths.remote.gzipped_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
+ logger: context.logger,
45
+ photocopier: context.photocopier,
46
+ command: uncompress_command(file_path: context.db_paths.remote.gzipped_path)
47
+ )
48
+ context.fail_and_return!(result.message) if result.failure?
49
+
50
+ result = Wordmove::Actions::Ssh::RunRemoteCommand.execute(
51
+ cli_options: context.cli_options,
52
+ logger: context.logger,
53
+ photocopier: context.photocopier,
54
+ command: mysql_import_command(
55
+ dump_path: context.db_paths.remote.path,
56
+ env_db_options: context.remote_options[:database]
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.path
66
+ )
67
+ if result.failure?
68
+ context.logger.warning 'Failed to delete remote file ' \
69
+ "#{context.db_paths.remote.path} because: " \
70
+ "#{result.message}" \
71
+ '. Manual intervention required'
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,76 @@
1
+ module Wordmove
2
+ module Actions
3
+ module Ssh
4
+ # Syncs a whole directory over SSH protocol from local host to remote server
5
+ class PutDirectory
6
+ extend LightService::Action
7
+ include Wordmove::Actions::Helpers
8
+ include Wordmove::Actions::Ssh::Helpers
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::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 "Pushing #{context.folder_task}"
32
+
33
+ next context if simulate?(cli_options: context.cli_options)
34
+
35
+ command = 'put_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
+ # `push_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 `"local_#{context.folder_task}_dir"` could
49
+ # not be defined.
50
+ command_args = context.fetch(:command_args) || [
51
+ local_path,
52
+ remote_path,
53
+ push_exclude_paths(
54
+ local_task_dir: send(
55
+ "local_#{context.folder_task}_dir",
56
+ local_options: context.local_options
57
+ ),
58
+ paths_to_exclude: paths_to_exclude(remote_options: context.remote_options)
59
+ ),
60
+ push_include_paths(local_task_dir: send(
61
+ "local_#{context.folder_task}_dir",
62
+ local_options: context.local_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,39 @@
1
+ module Wordmove
2
+ module Actions
3
+ module Ssh
4
+ # Run a command on a remote host using Photocopier
5
+ #
6
+ # @note The remote server is already configured inside the Photocopier object
7
+ # @note This action is *not* meant to be organized, but as a standalone one.
8
+ class RunRemoteCommand
9
+ extend LightService::Action
10
+ include Wordmove::Actions::Helpers
11
+
12
+ expects :photocopier,
13
+ :logger,
14
+ :cli_options,
15
+ :command
16
+
17
+ # @!method execute
18
+ # @param photocopier [Photocopier]
19
+ # @param logger [Wordmove::Logger]
20
+ # @param cli_options [Hash] The hash of command line options
21
+ # @param command [String] the command to run
22
+ # @!scope class
23
+ # @return [LightService::Context] Action's context
24
+ executed do |context|
25
+ context.logger.task_step false, context.command
26
+
27
+ next context if simulate?(cli_options: context.cli_options)
28
+
29
+ _stdout, stderr, exit_code = context.photocopier.exec!(context.command)
30
+
31
+ next context if exit_code.zero?
32
+
33
+ context.fail! "Error code #{exit_code} returned by command "\
34
+ "#{context.command}: #{stderr}"
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -1,6 +1,6 @@
1
1
  <?php
2
2
 
3
- $shared_key = '<%= password %>';
3
+ $shared_key = '<%= token %>';
4
4
  if ($_GET['shared_key'] != $shared_key) {
5
5
  die();
6
6
  }
@@ -214,14 +214,14 @@ class MySQLDump
214
214
 
215
215
  }
216
216
 
217
- $db_host = '<%= escape_php db[:host] %>';
218
- $db_port = '<%= db[:port] %>';
217
+ $db_host = '<%= escape_php(string: remote_db_options[:host]) %>';
218
+ $db_port = '<%= remote_db_options[:port] %>';
219
219
  if (!$db_port) {
220
220
  $db_port = ini_get("mysqli.default_port");
221
221
  }
222
- $db_user = '<%= escape_php db[:user] %>';
223
- $db_password = '<%= escape_php db[:password] %>';
224
- $db_name = '<%= escape_php db[:name] %>';
222
+ $db_user = '<%= escape_php(string: remote_db_options[:user]) %>';
223
+ $db_password = '<%= escape_php(string: remote_db_options[:password]) %>';
224
+ $db_name = '<%= escape_php(string: remote_db_options[:name]) %>';
225
225
 
226
226
  $connection = new mysqli($db_host, $db_user, $db_password, $db_name, $db_port);
227
227
  $dump = new MySQLDump($connection);
@@ -1,6 +1,6 @@
1
1
  <?php
2
2
 
3
- $shared_key = '<%= password %>';
3
+ $shared_key = '<%= token %>';
4
4
  if ($_GET['shared_key'] != $shared_key) {
5
5
  die();
6
6
  }
@@ -43,20 +43,20 @@ error_reporting(E_ALL);
43
43
 
44
44
  // Database configuration
45
45
 
46
- $db_port = '<%= escape_php db[:port] %>';
46
+ $db_port = '<%= escape_php(string: remote_db_options[:port]) %>';
47
47
  if (!$db_port) {
48
48
  $db_port = ini_get("mysqli.default_port");
49
49
  }
50
- $db_server = '<%= escape_php db[:host] %>';
51
- $db_username = '<%= escape_php db[:user] %>';
52
- $db_password = '<%= escape_php db[:password] %>';
53
- $db_name = '<%= escape_php db[:name] %>';
50
+ $db_server = '<%= escape_php(string: remote_db_options[:host]) %>';
51
+ $db_username = '<%= escape_php(string: remote_db_options[:user]) %>';
52
+ $db_password = '<%= escape_php(string: remote_db_options[:password]) %>';
53
+ $db_name = '<%= escape_php(string: remote_db_options[:name]) %>';
54
54
 
55
55
  // Connection charset should be the same as the dump file charset (utf8, latin1, cp1251, koi8r etc.)
56
56
  // See http://dev.mysql.com/doc/refman/5.0/en/charset-charsets.html for the full list
57
57
  // Change this if you have problems with non-latin letters
58
58
 
59
- $db_connection_charset = '<%= db[:charset] || 'utf8' %>';
59
+ $db_connection_charset = '<%= remote_db_options[:charset] || 'utf8' %>';
60
60
 
61
61
  // OPTIONAL SETTINGS
62
62
 
@@ -1,4 +1,6 @@
1
1
  type: map
2
2
  mapping:
3
3
  sql_adapter:
4
+ type: str
4
5
  required: true
6
+ pattern: /\Awpcli\Z/
@@ -162,7 +162,7 @@ mapping:
162
162
  type: bool
163
163
  uploads:
164
164
  type: bool
165
- mu-plugins:
165
+ mu_plugins:
166
166
  type: bool
167
167
  push:
168
168
  type: map
@@ -177,5 +177,5 @@ mapping:
177
177
  type: bool
178
178
  uploads:
179
179
  type: bool
180
- mu-plugins:
180
+ mu_plugins:
181
181
  type: bool
data/lib/wordmove/cli.rb CHANGED
@@ -1,122 +1,183 @@
1
1
  module Wordmove
2
- class CLI < Thor
3
- map %w[--version -v] => :__print_version
2
+ module CLI
3
+ module PullPushShared
4
+ extend ActiveSupport::Concern
5
+ WORDPRESS_OPTIONS = %i[wordpress uploads themes plugins mu_plugins languages db].freeze
6
+
7
+ included do # rubocop:disable Metrics/BlockLength
8
+ option :wordpress, type: :boolean, aliases: %w[w]
9
+ option :uploads, type: :boolean, aliases: %w[u]
10
+ option :themes, type: :boolean, aliases: %w[t]
11
+ option :plugins, type: :boolean, aliases: %w[p]
12
+ option :mu_plugins, type: :boolean, aliases: %w[m]
13
+ option :languages, type: :boolean, aliases: %w[l]
14
+ option :db, type: :boolean, aliases: %w[d]
15
+ option :simulate, type: :boolean
16
+ option :environment, aliases: %w[e]
17
+ option :config, aliases: %w[c]
18
+ option :no_adapt, type: :boolean
19
+ option :all, type: :boolean
20
+ # option :verbose, type: :boolean, aliases: %w[v]
21
+ option :debug, type: :boolean
22
+
23
+ private
24
+
25
+ def ensure_wordpress_options_presence!(cli_options)
26
+ return if (
27
+ cli_options.deep_symbolize_keys.keys &
28
+ (Wordmove::CLI::PullPushShared::WORDPRESS_OPTIONS + [:all])
29
+ ).present?
30
+
31
+ puts 'No options given. See wordmove --help'
32
+ exit 1
33
+ end
4
34
 
5
- desc "--version, -v", "Print the version"
6
- def __print_version
7
- puts Wordmove::VERSION
8
- end
35
+ def initial_context(cli_options)
36
+ cli_options.deep_symbolize_keys!
37
+ movefile = Wordmove::Movefile.new(cli_options)
9
38
 
10
- desc "init", "Generates a brand new movefile.yml"
11
- def init
12
- Wordmove::Generators::Movefile.start
13
- end
39
+ [cli_options, movefile]
40
+ end
14
41
 
15
- desc "doctor", "Do some local configuration and environment checks"
16
- def doctor
17
- Wordmove::Doctor.start
18
- end
42
+ def movefile_from(**cli_options)
43
+ ensure_wordpress_options_presence!(cli_options)
44
+ Wordmove::Movefile.new(cli_options)
45
+ rescue MovefileNotFound => e
46
+ Logger.new($stdout).error(e.message)
47
+ exit 1
48
+ end
49
+
50
+ def call_organizer_with(klass:, movefile:, **cli_options)
51
+ result = klass.call(cli_options: cli_options, movefile: movefile)
19
52
 
20
- shared_options = {
21
- wordpress: { aliases: "-w", type: :boolean },
22
- uploads: { aliases: "-u", type: :boolean },
23
- themes: { aliases: "-t", type: :boolean },
24
- plugins: { aliases: "-p", type: :boolean },
25
- mu_plugins: { aliases: "-m", type: :boolean },
26
- languages: { aliases: "-l", type: :boolean },
27
- db: { aliases: "-d", type: :boolean },
28
- verbose: { aliases: "-v", type: :boolean },
29
- simulate: { aliases: "-s", type: :boolean },
30
- environment: { aliases: "-e" },
31
- config: { aliases: "-c" },
32
- debug: { type: :boolean },
33
- no_adapt: { type: :boolean },
34
- all: { type: :boolean }
35
- }
36
-
37
- no_tasks do
38
- def handle_options(options)
39
- wordpress_options.each do |task|
40
- yield task if options[task] || (options["all"] && options[task] != false)
53
+ exit 0 if result.success?
54
+
55
+ Logger.new($stdout).error(result.message)
56
+ exit 1
41
57
  end
42
58
  end
59
+ end
43
60
 
44
- def wordpress_options
45
- %w[wordpress uploads themes plugins mu_plugins languages db]
46
- end
61
+ module Commands
62
+ extend Dry::CLI::Registry
47
63
 
48
- def ensure_wordpress_options_presence!(options)
49
- return if (options.keys & (wordpress_options + ["all"])).present?
64
+ class Version < Dry::CLI::Command
65
+ desc 'Print the version'
50
66
 
51
- puts "No options given. See wordmove --help"
52
- exit 1
67
+ def call(*)
68
+ puts Wordmove::VERSION
69
+ end
53
70
  end
54
71
 
55
- def logger
56
- Logger.new(STDOUT).tap { |l| l.level = Logger::DEBUG }
72
+ class Init < Dry::CLI::Command
73
+ desc 'Generates a brand new movefile.yml'
74
+
75
+ def call(*)
76
+ Wordmove::Generators::Movefile.generate
77
+ end
57
78
  end
58
- end
59
79
 
60
- desc "list", "List all environments and vhosts"
61
- shared_options.each do |option, args|
62
- method_option option, args
63
- end
64
- def list
65
- Wordmove::EnvironmentsList.print(options)
66
- rescue Wordmove::MovefileNotFound => e
67
- logger.error(e.message)
68
- exit 1
69
- rescue Psych::SyntaxError => e
70
- logger.error("Your movefile is not parsable due to a syntax error: #{e.message}")
71
- exit 1
72
- end
80
+ class Doctor < Dry::CLI::Command
81
+ desc 'Do some local configuration and environment checks'
73
82
 
74
- desc "pull", "Pulls WP data from remote host to the local machine"
75
- shared_options.each do |option, args|
76
- method_option option, args
77
- end
78
- def pull
79
- ensure_wordpress_options_presence!(options)
80
- begin
81
- deployer = Wordmove::Deployer::Base.deployer_for(options.deep_symbolize_keys)
82
- rescue MovefileNotFound => e
83
- logger.error(e.message)
84
- exit 1
83
+ def call(*)
84
+ Wordmove::Doctor.start
85
+ end
85
86
  end
86
87
 
87
- Wordmove::Hook.run(:pull, :before, options)
88
+ class List < Dry::CLI::Command
89
+ desc 'List all environments and vhosts'
88
90
 
89
- guardian = Wordmove::Guardian.new(options: options, action: :pull)
91
+ option :config, aliases: %w[c]
90
92
 
91
- handle_options(options) do |task|
92
- deployer.send("pull_#{task}") if guardian.allows(task.to_sym)
93
+ def call(**cli_options)
94
+ Wordmove::EnvironmentsList.print(cli_options)
95
+ rescue Wordmove::MovefileNotFound => e
96
+ Logger.new($stdout).error(e.message)
97
+ exit 1
98
+ rescue Psych::SyntaxError => e
99
+ Logger.new($stdout)
100
+ .error("Your movefile is not parsable due to a syntax error: #{e.message}")
101
+ exit 1
102
+ end
93
103
  end
94
104
 
95
- Wordmove::Hook.run(:pull, :after, options)
96
- end
105
+ class Pull < Dry::CLI::Command
106
+ desc 'Pulls WP data from remote host to the local machine'
97
107
 
98
- desc "push", "Pushes WP data from local machine to remote host"
99
- shared_options.each do |option, args|
100
- method_option option, args
101
- end
102
- def push
103
- ensure_wordpress_options_presence!(options)
104
- begin
105
- deployer = Wordmove::Deployer::Base.deployer_for(options.deep_symbolize_keys)
106
- rescue MovefileNotFound => e
107
- logger.error(e.message)
108
- exit 1
108
+ include Wordmove::CLI::PullPushShared
109
+
110
+ def call(**cli_options)
111
+ call_pull_organizer_with(**cli_options)
112
+ end
113
+
114
+ private
115
+
116
+ def call_pull_organizer_with(**cli_options)
117
+ movefile = movefile_from(**cli_options)
118
+
119
+ if movefile.options.dig(movefile.environment, :ssh)
120
+ call_organizer_with(
121
+ klass: Wordmove::Organizers::Ssh::Pull,
122
+ movefile: movefile,
123
+ **cli_options
124
+ )
125
+ elsif movefile.options.dig(movefile.environment, :ftp)
126
+ call_organizer_with(
127
+ klass: Wordmove::Organizers::Ftp::Pull,
128
+ movefile: movefile,
129
+ **cli_options
130
+ )
131
+ else
132
+ raise NoAdapterFound, 'No valid adapter found.'
133
+ end
134
+ rescue NoAdapterFound => e
135
+ Logger.new($stdout).error(e.message)
136
+ exit 1
137
+ end
109
138
  end
110
139
 
111
- Wordmove::Hook.run(:push, :before, options)
140
+ class Push < Dry::CLI::Command
141
+ desc 'Pulls WP data from remote host to the local machine'
112
142
 
113
- guardian = Wordmove::Guardian.new(options: options, action: :push)
143
+ include Wordmove::CLI::PullPushShared
114
144
 
115
- handle_options(options) do |task|
116
- deployer.send("push_#{task}") if guardian.allows(task.to_sym)
145
+ def call(**cli_options)
146
+ call_push_organizer_with(**cli_options)
147
+ end
148
+
149
+ private
150
+
151
+ def call_push_organizer_with(**cli_options)
152
+ movefile = movefile_from(**cli_options)
153
+
154
+ if movefile.options.dig(movefile.environment, :ssh)
155
+ call_organizer_with(
156
+ klass: Wordmove::Organizers::Ssh::Push,
157
+ movefile: movefile,
158
+ **cli_options
159
+ )
160
+ elsif movefile.options.dig(movefile.environment, :ftp)
161
+ call_organizer_with(
162
+ klass: Wordmove::Organizers::Ftp::Push,
163
+ movefile: movefile,
164
+ **cli_options
165
+ )
166
+ else
167
+ raise NoAdapterFound, 'No valid adapter found.'
168
+ end
169
+ rescue NoAdapterFound => e
170
+ Logger.new($stdout).error(e.message)
171
+ exit 1
172
+ end
117
173
  end
118
174
 
119
- Wordmove::Hook.run(:push, :after, options)
175
+ register 'version', Version, aliases: %w[v -v --version]
176
+ register 'init', Init
177
+ register 'doctor', Doctor
178
+ register 'list', List
179
+ register 'pull', Pull
180
+ register 'push', Push
120
181
  end
121
182
  end
122
183
  end