From d6618397bf6a9c2a9ed71f7d1bf7944d27871f49 Mon Sep 17 00:00:00 2001 From: Tristan Darricau Date: Mon, 14 Sep 2015 16:20:33 +0200 Subject: [PATCH] [ticket/11150] Better pre/post action handling, restore ext.json in case of err PHPBB3-11150 --- phpBB/phpbb/composer/extension_manager.php | 116 ++++++++++++++++-- phpBB/phpbb/composer/installer.php | 32 ++++- .../composer/io/translate_composer_trait.php | 43 ++++--- phpBB/phpbb/composer/manager.php | 90 ++++++++++++-- phpBB/phpbb/composer/manager_interface.php | 3 +- 5 files changed, 243 insertions(+), 41 deletions(-) diff --git a/phpBB/phpbb/composer/extension_manager.php b/phpBB/phpbb/composer/extension_manager.php index 04c0af666f..49f27762c2 100644 --- a/phpBB/phpbb/composer/extension_manager.php +++ b/phpBB/phpbb/composer/extension_manager.php @@ -38,6 +38,11 @@ class extension_manager extends manager */ protected $filesystem; + /** + * @var array + */ + private $enabled_extensions; + /** * @param installer $installer Installer object * @param driver_interface $cache Cache object @@ -57,29 +62,112 @@ class extension_manager extends manager /** * {@inheritdoc} */ - public function install(array $packages, IOInterface $io = null) + public function pre_install(array $packages, IOInterface $io = null) { - $packages = $this->normalize_version($packages); - - $already_managed = array_intersect(array_keys($this->get_managed_packages()), array_keys($packages)); - if (count($already_managed) !== 0) - { - throw new runtime_exception($this->exception_prefix, 'ALREADY_INSTALLED', [implode('|', $already_managed)]); - } - $installed_manually = array_intersect(array_keys($this->extension_manager->all_available()), array_keys($packages)); if (count($installed_manually) !== 0) { throw new runtime_exception($this->exception_prefix, 'ALREADY_INSTALLED_MANUALLY', [implode('|', array_keys($installed_manually))]); } - - $this->do_install($packages, $io); } /** * {@inheritdoc} */ - public function start_managing($package) + protected function pre_update(array $packages, IOInterface $io = null) + { + $io->writeError('DISABLING_EXTENSIONS', true, 1); + $this->enabled_extensions = []; + foreach ($packages as $package) + { + try + { + if ($this->extension_manager->is_enabled($package)) + { + $this->enabled_extensions[] = $package; + $this->extension_manager->disable($package); + } + } + catch (\phpbb\exception\runtime_exception $e) + { + $io->writeError([$e->getMessage(), $e->get_parameters()], true, 4); + } + catch (\Exception $e) + { + $io->writeError($e->getMessage(), true, 4); + } + } + } + + /** + * {@inheritdoc} + */ + protected function post_update(array $packages, IOInterface $io = null) + { + $io->writeError('ENABLING_EXTENSIONS', true, 1); + foreach ($this->enabled_extensions as $package) + { + try + { + $this->extension_manager->enable($package); + } + catch (\phpbb\exception\runtime_exception $e) + { + $io->writeError([$e->getMessage(), $e->get_parameters()], true, 4); + } + catch (\Exception $e) + { + $io->writeError($e->getMessage(), true, 4); + } + } + } + + /** + * {@inheritdoc} + */ + public function remove(array $packages, IOInterface $io = null) + { + $packages = $this->normalize_version($packages); + + $not_installed = array_diff(array_keys($packages), array_keys($this->extension_manager->all_available())); + if (count($not_installed) !== 0) + { + throw new runtime_exception($this->exception_prefix, 'NOT_INSTALLED', [implode('|', array_keys($not_installed))]); + } + + parent::remove($packages, $io); + } + + /** + * {@inheritdoc} + */ + public function pre_remove(array $packages, IOInterface $io = null) + { + $io->writeError('DISABLING_EXTENSIONS', true, 1); + foreach ($packages as $package) + { + try + { + if ($this->extension_manager->is_enabled($package)) + { + $this->extension_manager->disable($package); + } + } + catch (\phpbb\exception\runtime_exception $e) + { + $io->writeError([$e->getMessage(), $e->get_parameters()], true, 4); + } + catch (\Exception $e) + { + $io->writeError($e->getMessage(), true, 4); + } + } + } + + /** + * {@inheritdoc} + */ + public function start_managing($package, $io) { if (!$this->extension_manager->is_available($package)) { @@ -95,6 +183,7 @@ class extension_manager extends manager if ($this->extension_manager->is_enabled($package)) { $enabled = true; + $io->writeError('DISABLING_EXTENSION', true, 1); $this->extension_manager->disable($package); } @@ -129,7 +218,8 @@ class extension_manager extends manager { try { - $this->extension_manager->enable($package); + $io->writeError('ENABLING_EXTENSION', true, 1); + $this->extension_manager->enabling($package); } catch (\Exception $e) { diff --git a/phpBB/phpbb/composer/installer.php b/phpBB/phpbb/composer/installer.php index 57e9673049..18e1b6e83b 100644 --- a/phpBB/phpbb/composer/installer.php +++ b/phpBB/phpbb/composer/installer.php @@ -60,10 +60,15 @@ class installer protected $root_path; /** - * @var string Store the original working directory in case it has been changed through move_to_root() + * @var string Stores the original working directory in case it has been changed through move_to_root() */ private $original_cwd; + /** + * @var array Stores the content of the ext json file before generate_ext_json_file() overrides it + */ + private $ext_json_file_backup; + /** * @param \phpbb\config\config $config Config object * @param string $root_path phpBB root path @@ -157,12 +162,14 @@ class installer } catch (\Exception $e) { + $this->restore_ext_json_file(); $this->restore_cwd(); throw new runtime_exception('COMPOSER_CANNOT_INSTALL', [], $e); } if ($result !== 0) { + $this->restore_ext_json_file(); $this->restore_cwd(); throw new runtime_exception($io->get_composer_error(), []); } @@ -444,8 +451,31 @@ class installer ], ]; + $this->ext_json_file_backup = null; $json_file = new JsonFile($this->get_composer_ext_json_filename()); + $ext_json_file_backup = $json_file->read(); $json_file->write($ext_json_data); + $this->ext_json_file_backup = $ext_json_file_backup; + } + + /** + * Restore the json file overridden by generate_ext_json_file() + */ + protected function restore_ext_json_file() + { + if ($this->ext_json_file_backup) + { + try + { + $json_file = new JsonFile($this->get_composer_ext_json_filename()); + $json_file->write($this->ext_json_file_backup); + } + catch (\Exception $e) + { + } + + $this->ext_json_file_backup = null; + } } /** diff --git a/phpBB/phpbb/composer/io/translate_composer_trait.php b/phpBB/phpbb/composer/io/translate_composer_trait.php index b322accafb..0f2d6f8e64 100644 --- a/phpBB/phpbb/composer/io/translate_composer_trait.php +++ b/phpBB/phpbb/composer/io/translate_composer_trait.php @@ -38,9 +38,21 @@ trait translate_composer_trait foreach ($messages as $message) { - $lang_key = $message; - $parameters = []; $level = 0; + if (is_array($message)) + { + $lang_key = $message[0]; + $parameters = $message[1]; + if (count($message) > 2) + { + $level = $message[2]; + } + } + else + { + $lang_key = $message; + $parameters = []; + } $message = trim($this->strip_format($message), "\n\r"); @@ -50,10 +62,6 @@ trait translate_composer_trait $lang_key = 'COMPOSER_DELETING'; $parameters = [$elements[1]]; } - else - { - dump('WRITE | ' . $message); - } //$translated_message = $this->language->lang_array($lang_key, $parameters); $translated_message = call_user_func_array([$this->language, 'lang'], array_merge((array)$lang_key, $parameters)); @@ -90,9 +98,21 @@ trait translate_composer_trait foreach ($messages as $message) { - $lang_key = $message; - $parameters = []; $level = 0; + if (is_array($message)) + { + $lang_key = $message[0]; + $parameters = $message[1]; + if (count($message) > 2) + { + $level = $message[2]; + } + } + else + { + $lang_key = $message; + $parameters = []; + } $message = trim($this->strip_format($message), "\n\r"); @@ -165,13 +185,8 @@ trait translate_composer_trait { continue; } - else - { - dump('WRITE ERROR | ' . $message); - } - //$translated_message = $this->language->lang_array($lang_key, $parameters); - $translated_message = call_user_func_array([$this->language, 'lang'], array_merge((array)$lang_key, $parameters)); + $translated_message = $this->language->lang_array($lang_key, $parameters); switch ($level) { diff --git a/phpBB/phpbb/composer/manager.php b/phpBB/phpbb/composer/manager.php index 64ab0ccb7c..1941e79fff 100644 --- a/phpBB/phpbb/composer/manager.php +++ b/phpBB/phpbb/composer/manager.php @@ -84,25 +84,40 @@ class manager implements manager_interface throw new runtime_exception($this->exception_prefix, 'ALREADY_INSTALLED', [implode('|', $already_managed)]); } - $this->do_install($packages, $io); - } + $this->pre_install($packages, $io); - /** - * Really install the packages. - * - * @param array $packages Packages to install. - * @param IOInterface $io IO object used for the output - */ - protected function do_install($packages, IOInterface $io = null) - { $managed_packages = array_merge($this->get_all_managed_packages(), $packages); ksort($managed_packages); $this->installer->install($managed_packages, array_keys($packages), $io); + $this->post_install($packages, $io); + $this->managed_packages = null; } + /** + * Hook called before installing the packages + * + * @param array $packages Packages to update. + * Each entry may be a name or an array associating a version constraint to a name + * @param IOInterface $io IO object used for the output + */ + protected function pre_install(array $packages, IOInterface $io = null) + { + } + + /** + * Hook called after installing the packages + * + * @param array $packages Packages to update. + * Each entry may be a name or an array associating a version constraint to a name + * @param IOInterface $io IO object used for the output + */ + protected function post_install(array $packages, IOInterface $io = null) + { + } + /** * {@inheritdoc} */ @@ -110,17 +125,42 @@ class manager implements manager_interface { $packages = $this->normalize_version($packages); - // TODO: if the extension is already enabled, we should disabled and re-enable it $not_managed = array_diff_key($packages, $this->get_managed_packages()); if (count($not_managed) !== 0) { throw new runtime_exception($this->exception_prefix, 'NOT_MANAGED', [implode('|', array_keys($not_managed))]); } + $this->pre_update($packages, $io); + $managed_packages = array_merge($this->get_all_managed_packages(), $packages); ksort($managed_packages); $this->installer->install($managed_packages, array_keys($packages), $io); + + $this->post_update($packages, $io); + } + + /** + * Hook called before updating the packages + * + * @param array $packages Packages to update. + * Each entry may be a name or an array associating a version constraint to a name + * @param IOInterface $io IO object used for the output + */ + protected function pre_update(array $packages, IOInterface $io = null) + { + } + + /** + * Hook called after updating the packages + * + * @param array $packages Packages to update. + * Each entry may be a name or an array associating a version constraint to a name + * @param IOInterface $io IO object used for the output + */ + protected function post_update(array $packages, IOInterface $io = null) + { } /** @@ -137,14 +177,40 @@ class manager implements manager_interface throw new runtime_exception($this->exception_prefix, 'NOT_MANAGED', [implode('|', array_keys($not_managed))]); } + $this->pre_remove($packages, $io); + $managed_packages = array_diff_key($this->get_all_managed_packages(), $packages); ksort($managed_packages); $this->installer->install($managed_packages, array_keys($packages), $io); + $this->post_remove($packages, $io); + $this->managed_packages = null; } + /** + * Hook called before removing the packages + * + * @param array $packages Packages to update. + * Each entry may be a name or an array associating a version constraint to a name + * @param IOInterface $io IO object used for the output + */ + protected function pre_remove(array $packages, IOInterface $io = null) + { + } + + /** + * Hook called after removing the packages + * + * @param array $packages Packages to update. + * Each entry may be a name or an array associating a version constraint to a name + * @param IOInterface $io IO object used for the output + */ + protected function post_remove(array $packages, IOInterface $io = null) + { + } + /** * {@inheritdoc} */ @@ -200,7 +266,7 @@ class manager implements manager_interface /** * {@inheritdoc} */ - public function start_managing($package) + public function start_managing($package, $io) { throw new \phpbb\exception\runtime_exception('COMPOSER_UNSUPPORTED_OPERATION', (array) $this->package_type); } diff --git a/phpBB/phpbb/composer/manager_interface.php b/phpBB/phpbb/composer/manager_interface.php index b5d0177342..2572ba0831 100644 --- a/phpBB/phpbb/composer/manager_interface.php +++ b/phpBB/phpbb/composer/manager_interface.php @@ -84,8 +84,9 @@ interface manager_interface * Remove a package installed manually and reinstall it using composer. * * @param string $package Package to manage + * @param IOInterface $io IO object used for the output * * @throws runtime_exception */ - public function start_managing($package); + public function start_managing($package, $io); }