diff --git a/phpBB/config/default/container/services_extensions.yml b/phpBB/config/default/container/services_extensions.yml index 3a2e83f73a..46953ae4a2 100644 --- a/phpBB/config/default/container/services_extensions.yml +++ b/phpBB/config/default/container/services_extensions.yml @@ -18,9 +18,10 @@ services: - @config ext.composer.manager: - class: phpbb\composer\manager + class: phpbb\composer\extension_manager arguments: - @ext.composer.installer + - @ext.manager - phpbb-extension - EXTENSIONS_ diff --git a/phpBB/phpbb/composer/extension_manager.php b/phpBB/phpbb/composer/extension_manager.php new file mode 100644 index 0000000000..ee3ac1aeaf --- /dev/null +++ b/phpBB/phpbb/composer/extension_manager.php @@ -0,0 +1,63 @@ + + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +namespace phpbb\composer; + +use phpbb\composer\exception\runtime_exception; +use phpbb\extension\manager as ext_manager; + +/** + * Class to safely manage extensions through composer. + */ +class extension_manager extends manager +{ + /** + * @var \phpbb\extension\manager + */ + protected $extension_manager; + + /** + * @param installer $installer Installer object + * @param ext_manager $extension_manager phpBB extension manager + * @param string $package_type Composer type of managed packages + * @param string $exception_prefix Exception prefix to use + */ + public function __construct(installer $installer, ext_manager $extension_manager, $package_type, $exception_prefix) + { + $this->extension_manager = $extension_manager; + + parent::__construct($installer, $package_type, $exception_prefix); + } + + /** + * {@inheritdoc} + */ + public function install(array $packages) + { + $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); + } +} diff --git a/phpBB/phpbb/composer/installer.php b/phpBB/phpbb/composer/installer.php index 05c3ef2d68..7256e82d3a 100644 --- a/phpBB/phpbb/composer/installer.php +++ b/phpBB/phpbb/composer/installer.php @@ -86,7 +86,8 @@ class installer { $this->generate_ext_json_file($packages); - putenv('COMPOSER_VENDOR_DIR=' . $this->root_path . '/' . $this->packages_vendor_dir); + $original_vendor_dir = getenv('COMPOSER_VENDOR_DIR'); + putenv('COMPOSER_VENDOR_DIR=' . $this->root_path . $this->packages_vendor_dir); $io = new BufferIO('', OutputInterface::VERBOSITY_DEBUG); $composer = Factory::create($io, $this->get_composer_ext_json_filename(), false); @@ -123,6 +124,10 @@ class installer { throw new runtime_exception('Cannot install packages', [], $e); } + finally + { + putenv('COMPOSER_VENDOR_DIR=' . $original_vendor_dir); + } } /** @@ -134,10 +139,12 @@ class installer */ public function get_installed_packages($type) { + $original_vendor_dir = getenv('COMPOSER_VENDOR_DIR'); + try { $io = new NullIO(); - putenv('COMPOSER_VENDOR_DIR=' . $this->root_path . '/' . $this->packages_vendor_dir); + putenv('COMPOSER_VENDOR_DIR=' . $this->root_path . $this->packages_vendor_dir); $composer = Factory::create($io, $this->get_composer_ext_json_filename(), false); $installed = []; @@ -157,6 +164,10 @@ class installer { return []; } + finally + { + putenv('COMPOSER_VENDOR_DIR=' . $original_vendor_dir); + } } /** diff --git a/phpBB/phpbb/composer/manager.php b/phpBB/phpbb/composer/manager.php index 836f39b509..4ade6e24a0 100644 --- a/phpBB/phpbb/composer/manager.php +++ b/phpBB/phpbb/composer/manager.php @@ -18,7 +18,7 @@ use phpbb\composer\exception\runtime_exception; /** * Class to manage packages through composer. */ -class manager +class manager implements manager_interface { /** * @var installer Composer packages installer @@ -74,6 +74,16 @@ class manager throw new runtime_exception($this->exception_prefix, 'ALREADY_INSTALLED', [implode('|', $already_managed)]); } + $this->do_install($packages); + } + + /** + * Really install the packages. + * + * @param array $packages Packages to install. + */ + protected function do_install($packages) + { $managed_packages = array_merge($this->get_managed_packages(), $packages); ksort($managed_packages); @@ -135,12 +145,12 @@ class manager /** * Tells whether or not a package is managed by Composer. * - * @param string $packages Package name + * @param string $package Package name * @return bool */ - public function is_managed($packages) + public function is_managed($package) { - return array_key_exists($packages, $this->get_managed_packages()); + return array_key_exists($package, $this->get_managed_packages()); } /** @@ -177,11 +187,15 @@ class manager { $normalized_packages = []; - foreach ($packages as $package) + foreach ($packages as $package => $version) { - if (!is_array($package)) + if (is_numeric($package)) { - $normalized_packages[$package] = '*'; + $normalized_packages[$version] = '*'; + } + else + { + $normalized_packages[$package] = $version; } } diff --git a/phpBB/phpbb/composer/manager_interface.php b/phpBB/phpbb/composer/manager_interface.php new file mode 100644 index 0000000000..d4c2b9eb51 --- /dev/null +++ b/phpBB/phpbb/composer/manager_interface.php @@ -0,0 +1,69 @@ +manager = $manager; diff --git a/phpBB/phpbb/console/command/extension/list_available.php b/phpBB/phpbb/console/command/extension/list_available.php index 0b20ce2d5e..107aca3410 100644 --- a/phpBB/phpbb/console/command/extension/list_available.php +++ b/phpBB/phpbb/console/command/extension/list_available.php @@ -17,6 +17,7 @@ use Composer\Package\CompletePackage; use Composer\Package\PackageInterface; use phpbb\composer\installer; use phpbb\composer\manager; +use phpbb\composer\manager_interface; use Symfony\Component\Console\Formatter\OutputFormatter; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; @@ -26,11 +27,11 @@ use Symfony\Component\Console\Style\SymfonyStyle; class list_available extends \phpbb\console\command\command { /** - * @var \phpbb\composer\manager Composer extensions manager + * @var manager_interface Composer extensions manager */ protected $manager; - public function __construct(\phpbb\user $user, manager $manager) + public function __construct(\phpbb\user $user, manager_interface $manager) { $this->manager = $manager; diff --git a/phpBB/phpbb/console/command/extension/remove.php b/phpBB/phpbb/console/command/extension/remove.php index a668322cdf..16a3ad263f 100644 --- a/phpBB/phpbb/console/command/extension/remove.php +++ b/phpBB/phpbb/console/command/extension/remove.php @@ -14,6 +14,7 @@ namespace phpbb\console\command\extension; use phpbb\composer\manager; +use phpbb\composer\manager_interface; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; @@ -22,11 +23,11 @@ use Symfony\Component\Console\Style\SymfonyStyle; class remove extends \phpbb\console\command\command { /** - * @var \phpbb\composer\manager Composer extensions manager + * @var manager_interface Composer extensions manager */ protected $manager; - public function __construct(\phpbb\user $user, manager $manager) + public function __construct(\phpbb\user $user, manager_interface $manager) { $this->manager = $manager; diff --git a/phpBB/phpbb/console/command/extension/update.php b/phpBB/phpbb/console/command/extension/update.php index 01c9db0c28..e3f8935985 100644 --- a/phpBB/phpbb/console/command/extension/update.php +++ b/phpBB/phpbb/console/command/extension/update.php @@ -14,6 +14,7 @@ namespace phpbb\console\command\extension; use phpbb\composer\manager; +use phpbb\composer\manager_interface; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; @@ -22,11 +23,11 @@ use Symfony\Component\Console\Style\SymfonyStyle; class update extends \phpbb\console\command\command { /** - * @var \phpbb\composer\manager Composer extensions manager + * @var manager_interface Composer extensions manager */ protected $manager; - public function __construct(\phpbb\user $user, manager $manager) + public function __construct(\phpbb\user $user, manager_interface $manager) { $this->manager = $manager;