From 41b8fbb3332557dd78967606765ac0cd49da31ab Mon Sep 17 00:00:00 2001 From: Julian Bustamante Date: Thu, 8 Aug 2024 02:08:13 -0500 Subject: [PATCH] Refactor generate installation commands --- .../class-marketplace-command-helper.php | 225 +++++++----------- .../class-marketplace-software-factory.php | 4 +- .../class-marketplace-software-manager.php | 8 +- .../class-marketplace-plugin-installer.php | 87 ++++--- .../class-marketplace-product-installer.php | 142 ++++++++++- .../class-marketplace-theme-installer.php | 84 +++---- .../class-marketplace-product-software.php | 19 +- 7 files changed, 318 insertions(+), 251 deletions(-) diff --git a/projects/plugins/wpcomsh/wpcom-marketplace/software/class-marketplace-command-helper.php b/projects/plugins/wpcomsh/wpcom-marketplace/software/class-marketplace-command-helper.php index 6cb2428db8b33..1afb2b56ada29 100644 --- a/projects/plugins/wpcomsh/wpcom-marketplace/software/class-marketplace-command-helper.php +++ b/projects/plugins/wpcomsh/wpcom-marketplace/software/class-marketplace-command-helper.php @@ -12,17 +12,14 @@ class Marketplace_Command_Helper { /** - * Generate the commands that install a plugin, some dependencies, and a possible theme. + * Generate the commands to install the dependencies of a product. * - * @param string|null $plugin_slug_or_url The plugin slug or URL to install. - * @param array $plugin_dependencies List of plugins the product depends on. - * @param array $theme_dependencies List of themes the product depends on. - * @param string|null $theme_slug The theme slug to install. - * @param bool|null $use_managed Whether to use the managed version of the product or not. + * @param array $plugin_dependencies List of plugins the product depends on. + * @param array $theme_dependencies List of themes the product depends on. * * @return string[] */ - public function generate_install_commands( ?string $plugin_slug_or_url, array $plugin_dependencies, array $theme_dependencies, ?string $theme_slug = null, ?bool $use_managed = true ): array { + public function generate_dependency_install_commands( array $plugin_dependencies, array $theme_dependencies ) { /** * This can be extended in the future to support advanced dependency trees or multiple types of products. * @@ -32,128 +29,112 @@ public function generate_install_commands( ?string $plugin_slug_or_url, array $p $plugin_dependency_commands = \array_map( fn( $plugin ) => \sprintf( $dependency_command_template, $plugin, 'plugin' ), $plugin_dependencies ); $theme_dependency_commands = \array_map( fn( $theme ) => \sprintf( $dependency_command_template, $theme, 'theme' ), $theme_dependencies ); - $required_plugins_regex = \array_map( fn( $plugin ) => \sprintf( "-e '^%1\$s$'", $plugin ), $plugin_dependencies ); - $required_plugins_regex = implode( ' ', $required_plugins_regex ); - - $required_themes_regex = \array_map( fn( $theme ) => \sprintf( "-e '^%1\$s$'", $theme ), $theme_dependencies ); - $required_themes_regex = implode( ' ', $required_themes_regex ); + return array_merge( $plugin_dependency_commands, $theme_dependency_commands ); + } - $dependency_commands = array_merge( $plugin_dependency_commands, $theme_dependency_commands ); + /** + * Get the list of installed plugins. + * + * @return string + */ + public function get_installed_plugins_names_command(): string { + return '--skip-themes --skip-plugins plugin list --field=name'; + } - if ( empty( $plugin_slug_or_url ) && empty( $theme_slug ) ) { - return array( ...$dependency_commands ); - } + /** + * Get the list of installed themes. + * + * @return string + */ + public function get_installed_themes_names_command(): string { + return '--skip-themes --skip-plugins theme list --field=name'; + } - /** - * Generate the command that installs and activates the plugins. This handles plugins that are from wp.org repo, managed or paid from remote urls. - * - * To make sure that there are no 3rd party plugins that might interfere in the installation process, this command is executing by skipping non-required plugins and themes. - * 1. We get a list of themes or plugins by name - * 2. We pipe the result to grep to exclude dependencies that are required - * 3. We pipe the result to tr to escape space characters - * 4. We pipe the result to tr to created a comma separated list - */ - $command_template = ''; + /** + * Generate the commands to install a plugin. + * + * @param string $software_slug_or_url The plugin slug or URL to install. + * @param bool $is_managed Whether to use the managed version of the plugin or not. + * @param array $skip_plugins List of plugins to skip when installing the plugin. + * @param array $skip_themes List of themes to skip when installing the plugin. + * + * @return string[] + */ + public function generate_plugin_install_commands( string $software_slug_or_url, bool $is_managed, array $skip_plugins, array $skip_themes ) { + $skip_plugins = implode( ',', $skip_plugins ); + $skip_themes = implode( ',', $skip_themes ); - if ( array() === $theme_dependencies ) { - $command_template .= ' --skip-themes'; - } else { - $command_template .= " --skip-themes=\"$(wp --skip-themes --skip-plugins theme list --field=name | grep -v %2\$s | tr '\n' ',')\""; + $skip_plugins_parameter = '--skip-plugins'; + if ( ! empty( $skip_plugins ) ) { + $skip_plugins_parameter .= '="' . $skip_plugins . '" '; } - if ( array() === $plugin_dependencies ) { - $command_template .= ' --skip-plugins'; - } else { - $command_template .= " --skip-plugins=\"$(wp --skip-themes --skip-plugins plugin list --field=name | grep -v %3\$s | tr '\n' ',')\""; + $skip_themes_parameter = '--skip-themes'; + if ( ! empty( $skip_themes ) ) { + $skip_themes_parameter .= '="' . $skip_themes . '" '; } - $commands = array( - ...$dependency_commands, + $plugin_install_commands = array( + 'add_managed_plugin_command' => ' atomic plugin use-managed %1$s --remove-existing', + 'activate_plugin_command' => ' plugin activate %1$s', ); - // If we have a plugin slug, install and activate the plugin. - if ( ! empty( $plugin_slug_or_url ) ) { - $software_commands = array( - 'add_managed_plugin_command' => ' atomic plugin use-managed %1$s --remove-existing', - 'activate_plugin_command' => ' plugin activate %1$s', - ); - - if ( ! $use_managed ) { - $software_commands = array( - 'add_remote_plugin_command' => ' plugin install "%1$s" --activate --force', - ); - } - - // Append the dependencies first so that they are installed before the actual product. - $commands = array( - ...$dependency_commands, - ...array_map( fn( $command ) => sprintf( $command_template . $command, $plugin_slug_or_url, $required_themes_regex, $required_plugins_regex ), array_values( $software_commands ) ), + if ( ! $is_managed ) { + $plugin_install_commands = array( + 'add_remote_plugin_command' => ' plugin install "%1$s" --activate --force', ); } - // We can bail early if we don't need to install a theme. - if ( empty( $theme_slug ) ) { - return $commands; - } - - // Install a theme either from remote url or use managed version and activate - if ( ! $use_managed ) { - $commands[] = sprintf( $command_template . ' theme install "%1$s" --force', $theme_slug, $required_themes_regex, $required_plugins_regex ); - } else { - $commands[] = sprintf( $command_template . ' atomic theme use-managed %1$s --remove-existing', $theme_slug, $required_themes_regex, $required_plugins_regex ); - } - - return $commands; + return array( + ...array_map( + fn( $command ) => sprintf( $skip_plugins_parameter . $skip_themes_parameter . $command, $software_slug_or_url ), + array_values( $plugin_install_commands ) + ), + ); } /** - * Verify that the product software is installed and activated. + * Generate the command to install a theme. * - * @param array $expected_plugins A list of plugins that will be checked. - * @param array $expected_themes A list of themes that will be checked. - * @param string|null $expected_theme The theme that will be checked. + * @param string $theme_slug The theme slug to install. + * @param bool $is_managed Whether to use the managed version of the theme or not. + * @param array $skip_plugins List of plugins to skip when installing the theme. + * @param array $skip_themes List of themes to skip when installing the theme. * - * @return bool|WP_Error + * @return string */ - public function verify_installation( array $expected_plugins, array $expected_themes, string $expected_theme = null ) { - $plugins_verification = $this->verify_plugins_software_is_installed( $expected_plugins, $expected_themes ); - - if ( ! $plugins_verification || \is_wp_error( $plugins_verification ) ) { - return new \WP_Error( - 'software_not_installed', - 'Failed to verify plugin activation', - array( - 'verification_result' => $plugins_verification, - ) - ); + public function generate_theme_install_command( string $theme_slug, bool $is_managed, array $skip_plugins, array $skip_themes ) { + $skip_plugins = implode( ',', $skip_plugins ); + $skip_themes = implode( ',', $skip_themes ); + + $skip_plugins_parameter = '--skip-plugins'; + if ( ! empty( $skip_plugins ) ) { + $skip_plugins_parameter .= '="' . $skip_plugins . '" '; } - if ( null !== $expected_theme ) { - $theme_verification = $this->verify_theme_software_is_installed( $expected_theme ); - - if ( false === $theme_verification || \is_wp_error( $theme_verification ) ) { - return new \WP_Error( - 'software_not_installed', - 'Failed to verify theme activation', - array( - 'verification_result' => $theme_verification, - ) - ); - } + $skip_themes_parameter = '--skip-themes'; + if ( ! empty( $skip_themes ) ) { + $skip_themes_parameter .= '="' . $skip_themes . '" '; } - return true; + if ( ! $is_managed ) { + $command = sprintf( $skip_plugins_parameter . $skip_themes_parameter . ' theme install "%s" --force', $theme_slug ); + } else { + $command = sprintf( $skip_plugins_parameter . $skip_themes_parameter . ' atomic theme use-managed %s --remove-existing', $theme_slug ); + } + + return $command; } /** - * Check if the given plugins are activated on the Atomic site. + * Generate the commands to verify the installation of the plugins. * * @param array $expected_plugins A list of plugins that will be checked. * @param array $expected_themes A list of themes that will be checked. * * @return bool|WP_Error */ - private function verify_plugins_software_is_installed( array $expected_plugins, array $expected_themes ) { + public function generate_verify_plugin_installation_commands( array $expected_plugins, array $expected_themes ) { $expected_plugins = \array_filter( $expected_plugins ); if ( empty( $expected_plugins ) ) { @@ -161,62 +142,26 @@ private function verify_plugins_software_is_installed( array $expected_plugins, } $plugin_commands = \array_map( - fn( $plugin_slug ) => 'wp --skip-themes --skip-plugins plugin get ' . $plugin_slug . ' --field=status', + fn( $plugin_slug ) => '--skip-themes --skip-plugins plugin get ' . $plugin_slug . ' --field=status', $expected_plugins ); $theme_commands = \array_map( - fn( $plugin_slug ) => 'wp --skip-themes --skip-plugins theme get ' . $plugin_slug . ' --field=status', + fn( $plugin_slug ) => '--skip-themes --skip-plugins theme get ' . $plugin_slug . ' --field=status', $expected_themes ); - $commands = array( ...$plugin_commands, ...$theme_commands ); - return $this->run_verify_commands( $commands ); + return array( ...$plugin_commands, ...$theme_commands ); } /** - * Check if the given theme is activated on the Atomic site. + * Generate the command to verify the theme installation. * * @param string $expected_theme The theme that will be checked. * - * @return bool|WP_Error - */ - private function verify_theme_software_is_installed( string $expected_theme ) { - $commands = array( 'wp --skip-themes --skip-plugins theme get ' . $expected_theme . ' --field=status' ); - - return $this->run_verify_commands( $commands, true ); - } - - /** - * Run the commands that verifies if the software is either installed/active or installed/inactive. - * - * @param array $commands The list of verification commands to be run. - * @param bool $verify_only_installation Whether to verify only installation or installation and activation. - * - * @return bool|WP_Error + * @return string */ - private function run_verify_commands( array $commands, bool $verify_only_installation = false ) { - $command = \implode( ' && ', $commands ); - - WP_CLI::debug( 'Running command: ' . $command ); - $result = WP_CLI::runcommand( - $command, - array( - 'launch' => false, - 'exit_error' => false, - ) - ); - - if ( \is_wp_error( $result ) ) { - return $result; - } - - if ( $verify_only_installation ) { - // Only verify installation, we can return true as the command did not return any errors - return true; - } - - // Returns true if the output displays "active" for each $software item. - return \substr_count( $result->stdout, 'active' ) === \count( $commands ); + public function generate_verify_theme_installation_command( string $expected_theme ) { + return '--skip-themes --skip-plugins theme get ' . $expected_theme . ' --field=status'; } } diff --git a/projects/plugins/wpcomsh/wpcom-marketplace/software/class-marketplace-software-factory.php b/projects/plugins/wpcomsh/wpcom-marketplace/software/class-marketplace-software-factory.php index c68a95551a6f4..ac7fdea73f3b9 100644 --- a/projects/plugins/wpcomsh/wpcom-marketplace/software/class-marketplace-software-factory.php +++ b/projects/plugins/wpcomsh/wpcom-marketplace/software/class-marketplace-software-factory.php @@ -86,11 +86,11 @@ public static function get_product_installer( Marketplace_Product_Software $prod $command_helper = new Marketplace_Command_Helper(); if ( $product_software instanceof Marketplace_Plugin_Software ) { - return new Marketplace_Plugin_Installer( $command_helper ); + return new Marketplace_Plugin_Installer( $command_helper, $product_software ); } if ( $product_software instanceof Marketplace_Theme_Software ) { - return new Marketplace_Theme_Installer( $command_helper ); + return new Marketplace_Theme_Installer( $command_helper, $product_software ); } return new WP_Error( 'invalid_product_type', 'Invalid product type.' ); diff --git a/projects/plugins/wpcomsh/wpcom-marketplace/software/class-marketplace-software-manager.php b/projects/plugins/wpcomsh/wpcom-marketplace/software/class-marketplace-software-manager.php index 14c3aea4b0cf6..8cee984c7d874 100644 --- a/projects/plugins/wpcomsh/wpcom-marketplace/software/class-marketplace-software-manager.php +++ b/projects/plugins/wpcomsh/wpcom-marketplace/software/class-marketplace-software-manager.php @@ -37,7 +37,7 @@ public function install_marketplace_software() { $installer = Marketplace_Software_Factory::get_product_installer( $product_software ); $installation = $installer->install( $product_software ); if ( is_wp_error( $installation ) ) { - WPCOMSH_Log::unsafe_direct_log( $installation->get_error_message() ); + WPCOMSH_Log::unsafe_direct_log( $installation->get_error_message(), $installation->get_error_data() ); } } @@ -46,16 +46,12 @@ public function install_marketplace_software() { /** * Get the marketplace software from Atomic Persist Data. This data is persisted by the - * woa_post_transfer_wpcomsh_cli_flags_install_marketplace_software_filter. + * woa_post_transfer_wpcomsh_cli_flags_install_marketplace_software_filter on WPCOM. * * @return array|WP_Error */ protected function get_apd_marketplace_software() { $atomic_persist_data = new Atomic_Persistent_Data(); - if ( ! $atomic_persist_data ) { - return new WP_Error( 'atomic_persist_data_not_found', 'Atomic persist data not found.' ); - } - if ( empty( $atomic_persist_data->WPCOM_MARKETPLACE_SOFTWARE ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase return new WP_Error( 'marketplace_software_not_found', 'WPCOM_Marketplace_Software Atomic persist data is empty. No Marketplace Software installed.' ); } diff --git a/projects/plugins/wpcomsh/wpcom-marketplace/software/installers/class-marketplace-plugin-installer.php b/projects/plugins/wpcomsh/wpcom-marketplace/software/installers/class-marketplace-plugin-installer.php index 70e14d883b450..ce9a8863156bc 100644 --- a/projects/plugins/wpcomsh/wpcom-marketplace/software/installers/class-marketplace-plugin-installer.php +++ b/projects/plugins/wpcomsh/wpcom-marketplace/software/installers/class-marketplace-plugin-installer.php @@ -12,63 +12,58 @@ class Marketplace_Plugin_Installer extends Marketplace_Product_Installer { /** - * Install the product. + * Install the plugin. * - * @param Marketplace_Product_Software $product_software The product to install. + * @return WP_Error|bool */ - public function install( Marketplace_Product_Software $product_software ) { - $commands = $this->command_helper->generate_install_commands( - $product_software->get_software_slug(), - $product_software->get_plugin_dependencies(), - $product_software->get_theme_dependencies(), - null, - $product_software->is_managed() - ); - - foreach ( $commands as $command ) { - if ( str_contains( $command, '||' ) ) { - $conditional_commands = explode( '||', $command ); + public function install() { + $install_dependencies = $this->install_dependencies(); + if ( is_wp_error( $install_dependencies ) ) { + return $install_dependencies; + } - foreach ( $conditional_commands as $conditional_command ) { - $result = WP_CLI::runcommand( - $conditional_command, - array( - 'return' => 'all', - 'parse' => 'json', - 'launch' => true, - 'exit_error' => false, - ) - ); + $skip_plugins = $this->get_skip_plugins(); + if ( is_wp_error( $skip_plugins ) ) { + return $skip_plugins; + } - $this->results[] = $result; + $skip_themes = $this->get_skip_themes(); + if ( is_wp_error( $skip_themes ) ) { + return $skip_themes; + } - // If the command was successful, the remaining commands are not executed. - if ( $result->return_code === 0 ) { - continue 2; - } - } + $plugin_install_commands = $this->command_helper->generate_plugin_install_commands( + $this->product_software->get_product_slug_or_url(), + $this->product_software->is_managed(), + $skip_plugins, + $skip_themes + ); - // If all conditional commands failed, return an error. - return new WP_Error( 'plugin_installation_failed', 'Plugin installation failed.', $this->results ); + foreach ( $plugin_install_commands as $command ) { + $plugin_install = $this->run_command( $command ); + if ( is_wp_error( $plugin_install ) ) { + return $plugin_install; } + } - $result = WP_CLI::runcommand( - $commands, - array( - 'return' => 'all', // Return 'STDOUT'; use 'all' for full object. - 'parse' => 'json', // Parse captured STDOUT to JSON array. - 'launch' => true, // Reuse the current process. - 'exit_error' => false, // Halt script execution on error. - ) - ); + $expected_plugins = array_filter( array( ...$this->product_software->get_plugin_dependencies(), $this->product_software->get_software_slug() ) ); + $verify_plugin_installation_commands = $this->command_helper->generate_verify_plugin_installation_commands( $expected_plugins, $this->product_software->get_theme_dependencies() ); - if ( $result->return_code !== 0 ) { - return new WP_Error( 'plugin_installation_failed', 'Plugin installation failed.' ); + foreach ( $verify_plugin_installation_commands as $command ) { + $verify_installation = $this->run_command( $command ); + if ( is_wp_error( $verify_installation ) ) { + return $verify_installation; } - } - $expected_plugins = array_filter( array( ...$product_software->get_plugin_dependencies(), $product_software->get_software_slug() ) ); + if ( $verify_installation->stdout !== 'active' ) { + return new WP_Error( + 'plugin_installation_failed', + sprintf( '%s: Plugin installation failed. The plugin is not active.', $this->product_software->get_software_slug() ), + $this->results + ); + } + } - return $this->command_helper->verify_installation( $expected_plugins, $product_software->get_theme_dependencies() ); + return true; } } diff --git a/projects/plugins/wpcomsh/wpcom-marketplace/software/installers/class-marketplace-product-installer.php b/projects/plugins/wpcomsh/wpcom-marketplace/software/installers/class-marketplace-product-installer.php index fa029def14daf..0f5e25da18f16 100644 --- a/projects/plugins/wpcomsh/wpcom-marketplace/software/installers/class-marketplace-product-installer.php +++ b/projects/plugins/wpcomsh/wpcom-marketplace/software/installers/class-marketplace-product-installer.php @@ -20,26 +20,28 @@ abstract class Marketplace_Product_Installer { protected Marketplace_Command_Helper $command_helper; /** - * List of command results. + * Product software. * - * @var array + * @var Marketplace_Product_Software */ - protected array $results = array(); + protected Marketplace_Product_Software $product_software; /** - * List of installed products. + * List of command results. * * @var array */ - protected array $installed_products = array(); + protected array $results = array(); /** * Marketplace_Product_Installer constructor. * - * @param Marketplace_Command_Helper $command_helper The command helper. + * @param Marketplace_Command_Helper $command_helper The command helper. + * @param Marketplace_Product_Software $product_software The product software. */ - public function __construct( Marketplace_Command_Helper $command_helper ) { - $this->command_helper = $command_helper; + public function __construct( Marketplace_Command_Helper $command_helper, Marketplace_Product_Software $product_software ) { + $this->command_helper = $command_helper; + $this->product_software = $product_software; } /** @@ -47,9 +49,127 @@ public function __construct( Marketplace_Command_Helper $command_helper ) { * * This method generates and run the installation commands depending on the product type. * - * @param Marketplace_Product_Software $product_software The product to install. - * * @return WP_Error|bool */ - abstract public function install( Marketplace_Product_Software $product_software ); + abstract public function install(); + + /** + * Get the list of plugins to skip when installing the product. + * To make sure that there are no 3rd party plugins that might interfere in the installation process, + * this method gets the list of installed plugins and filters out the ones that are dependencies of the product. + * + * @return array + */ + protected function get_skip_plugins() { + if ( empty( $this->product_software->get_plugin_dependencies() ) ) { + return array(); + } + + $installed_plugins_names_command = $this->command_helper->get_installed_plugins_names_command(); + $installed_plugins_names = $this->run_command( $installed_plugins_names_command ); + if ( is_wp_error( $installed_plugins_names ) ) { + return $installed_plugins_names; + } + + $plugin_dependencies = $this->product_software->get_plugin_dependencies(); + return array_filter( + explode( PHP_EOL, $installed_plugins_names->stdout ), + function ( $plugin_name ) use ( $plugin_dependencies ) { + return ! in_array( $plugin_name, $plugin_dependencies, true ); + }, + ); + } + + /** + * Get the list of themes to skip when installing the product. + * To make sure that there are no 3rd party themes that might interfere in the installation process, + * this method gets the list of installed themes and filters out the ones that are dependencies of the product. + * + * @return array + */ + protected function get_skip_themes() { + if ( empty( $this->product_software->get_theme_dependencies() ) ) { + return array(); + } + + $installed_themes_names_command = $this->command_helper->get_installed_themes_names_command(); + $installed_themes_names = $this->run_command( $installed_themes_names_command ); + if ( is_wp_error( $installed_themes_names ) ) { + return $installed_themes_names; + } + + $theme_dependencies = $this->product_software->get_theme_dependencies(); + return array_filter( + explode( PHP_EOL, $installed_themes_names->stdout ), + function ( $theme_name ) use ( $theme_dependencies ) { + return ! in_array( $theme_name, $theme_dependencies, true ); + }, + ); + } + + /** + * Install the product dependencies. + * + * This method installs the dependencies of the product. + */ + protected function install_dependencies() { + $dependency_commands = $this->command_helper->generate_dependency_install_commands( + $this->product_software->get_plugin_dependencies(), + $this->product_software->get_theme_dependencies() + ); + + foreach ( $dependency_commands as $command ) { + $conditional_commands = explode( '||', $command ); + + foreach ( $conditional_commands as $conditional_command ) { + $dependency_installation = $this->run_command( $conditional_command ); + + // If the command failed, continue to the next command. + if ( is_wp_error( $dependency_installation ) ) { + continue; + } + + // If the command was successful, the remaining commands are not executed. + if ( $dependency_installation->return_code === 0 ) { + continue 2; + } + } + + // If all conditional commands failed, return an error. + return new WP_Error( + 'plugin_installation_failed', + sprintf( '%s: Plugin installation failed. A dependency could not be installed ', $this->product_software->get_software_slug() ), + $this->results + ); + } + + return true; + } + + /** + * Wrapper for WP_CLI::runcommand that logs the command and the result. + * + * @param string $command The command to run. + * + * @return WP_Error|object + */ + protected function run_command( string $command ) { + $result = WP_CLI::runcommand( + $command, + array( + 'return' => 'all', + 'parse' => 'json', + 'launch' => true, + 'exit_error' => false, + ) + ); + + $this->results[] = $result; + + if ( $result->return_code !== 0 ) { + return new WP_Error( 'command_failed', 'Command failed.', $result ); + } + + return $result; + } } diff --git a/projects/plugins/wpcomsh/wpcom-marketplace/software/installers/class-marketplace-theme-installer.php b/projects/plugins/wpcomsh/wpcom-marketplace/software/installers/class-marketplace-theme-installer.php index f5385a38fdf37..a0881b9c92c83 100644 --- a/projects/plugins/wpcomsh/wpcom-marketplace/software/installers/class-marketplace-theme-installer.php +++ b/projects/plugins/wpcomsh/wpcom-marketplace/software/installers/class-marketplace-theme-installer.php @@ -12,61 +12,55 @@ class Marketplace_Theme_Installer extends Marketplace_Product_Installer { /** - * Install the product. + * Install the theme. * - * @param Marketplace_Product_Software $product_software The product to install. + * @return WP_Error|bool */ - public function install( Marketplace_Product_Software $product_software ) { - $commands = $this->command_helper->generate_install_commands( - null, - $product_software->get_plugin_dependencies(), - $product_software->get_theme_dependencies(), - $product_software->get_theme_slug(), - $product_software->is_managed() - ); + public function install() { + if ( ! $this->product_software instanceof Marketplace_Theme_Software ) { + return new WP_Error( 'invalid_product_software', 'Invalid product software.' ); + } - foreach ( $commands as $command ) { - if ( str_contains( $command, '||' ) ) { - $conditional_commands = explode( '||', $command ); + $install_dependencies = $this->install_dependencies(); + if ( is_wp_error( $install_dependencies ) ) { + return $install_dependencies; + } + + $skip_plugins = $this->get_skip_plugins(); + if ( is_wp_error( $skip_plugins ) ) { + return $skip_plugins; + } - foreach ( $conditional_commands as $conditional_command ) { - $result = WP_CLI::runcommand( - $conditional_command, - array( - 'return' => 'all', - 'parse' => 'json', - 'launch' => true, - 'exit_error' => false, - ) - ); + $skip_themes = $this->get_skip_themes(); + if ( is_wp_error( $skip_themes ) ) { + return $skip_themes; + } - $this->results[] = $result; + $theme_install_command = $this->command_helper->generate_theme_install_command( + $this->product_software->get_theme_slug(), + $this->product_software->is_managed(), + $skip_plugins, + $skip_themes + ); - // If the command was successful, the remaining commands are not executed. - if ( $result->return_code === 0 ) { - continue 2; - } - } + $theme_install = $this->run_command( $theme_install_command ); + if ( is_wp_error( $theme_install ) ) { + return $theme_install; + } - // If all conditional commands failed, return an error. - return new WP_Error( 'theme_installation_failed', 'Theme installation failed.', $this->results ); - } + $verify_theme_installation_command = $this->command_helper->generate_verify_theme_installation_command( $this->product_software->get_theme_slug() ); + $verify_theme_installation = $this->run_command( $verify_theme_installation_command ); + if ( is_wp_error( $verify_theme_installation ) ) { + return $verify_theme_installation; + } - $result = WP_CLI::runcommand( - $command, - array( - 'return' => 'all', // Return 'STDOUT'; use 'all' for full object. - 'parse' => 'json', // Parse captured STDOUT to JSON array. - 'launch' => true, // Reuse the current process. - 'exit_error' => false, // Halt script execution on error. - ) + if ( $verify_theme_installation->stdout !== 'active' ) { + return new WP_Error( + 'theme_installation_failed', + 'Theme installation failed.' ); - - if ( $result->return_code !== 0 ) { - return new WP_Error( 'theme_installation_failed', 'Theme installation failed.' ); - } } - return $this->command_helper->verify_installation( $product_software->get_plugin_dependencies(), array(), $product_software->get_theme_slug() ); + return true; } } diff --git a/projects/plugins/wpcomsh/wpcom-marketplace/software/products/class-marketplace-product-software.php b/projects/plugins/wpcomsh/wpcom-marketplace/software/products/class-marketplace-product-software.php index dce282bf69a06..7ae84b4ffb16d 100644 --- a/projects/plugins/wpcomsh/wpcom-marketplace/software/products/class-marketplace-product-software.php +++ b/projects/plugins/wpcomsh/wpcom-marketplace/software/products/class-marketplace-product-software.php @@ -1,12 +1,19 @@ is_managed; } + + /** + * Get the product slug or URL depending on whether the product is managed. + * If the product is managed, the slug is returned. Otherwise, the download URL is returned. + * + * @return string + */ + public function get_product_slug_or_url() { + return $this->is_managed ? $this->software_slug : $this->download_url; + } }