Loading core/modules/package_manager/package_manager.services.yml +1 −0 Original line number Diff line number Diff line parameters: package_manager.skip_procedural_hook_scan: true package_manager.allow_overwrite: ['|^/recipes/.|'] services: _defaults: Loading core/modules/package_manager/src/Validator/OverwriteExistingPackagesValidator.php +15 −0 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ use Drupal\package_manager\ComposerInspector; use Drupal\package_manager\Event\PreApplyEvent; use Drupal\package_manager\PathLocator; use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** Loading @@ -22,6 +23,12 @@ * https://packages.drupal.org/8 currently uses the `metapackage` type for * submodules of Drupal projects. * * This validator can accept an optional list of regular expressions matching * paths which are allowed to be overwritten. This is most useful when a recipe * is installed, since recipes are normally removed from Composer's awareness by * the drupal/core-recipe-unpack plugin and can therefore run afoul of this * validator. * * @internal * This is an internal part of Package Manager and may be changed or removed * at any time without warning. External code should not interact with this Loading @@ -36,6 +43,8 @@ final class OverwriteExistingPackagesValidator implements EventSubscriberInterfa public function __construct( private readonly PathLocator $pathLocator, private readonly ComposerInspector $composerInspector, #[Autowire(param: 'package_manager.allow_overwrite')] private readonly array $allowOverwrite = [], ) {} /** Loading @@ -57,6 +66,12 @@ public function validate(PreApplyEvent $event): void { continue; } $relative_path = str_replace($stage_dir, '', $package->path); foreach ($this->allowOverwrite as $pattern) { if (preg_match($pattern, $relative_path)) { continue 2; } } if (is_dir($active_dir . DIRECTORY_SEPARATOR . $relative_path)) { $event->addError([ $this->t('The new package @package will be installed in the directory @path, which already exists but is not managed by Composer.', [ Loading core/modules/package_manager/tests/src/Kernel/OverwriteExistingPackagesValidatorTest.php +29 −0 Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ namespace Drupal\Tests\package_manager\Kernel; use Drupal\Core\Recipe\Recipe; use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\fixture_manipulator\ActiveFixtureManipulator; use Drupal\package_manager\ComposerInspector; Loading Loading @@ -165,4 +166,32 @@ public function testNewPackagesOverwriteExisting(): void { $this->assertResults($expected_results, PreApplyEvent::class); } /** * Tests that things in the `recipes` directory can be overwritten. */ public function testRecipeOverwriteIsAllowed(): void { (new ActiveFixtureManipulator()) ->addProjectAtPath('recipes/test_recipe', file_name: 'recipe.yml') ->commitChanges(); $stage_manipulator = $this->getStageFixtureManipulator(); // This should not raise an error because, even though it's going to // overwrite an existing directory, it's at a path which specifically allows // that. $stage_manipulator->addPackage( [ 'name' => 'drupal/test_recipe', 'version' => '1.0.0', 'type' => Recipe::COMPOSER_PROJECT_TYPE, ], FALSE, TRUE ); $installer_paths = [ 'recipes/test_recipe' => ['drupal/test_recipe'], ]; $this->setInstallerPaths($installer_paths, $this->container->get(PathLocator::class)->getProjectRoot()); $this->assertResults([], PreApplyEvent::class); } } Loading
core/modules/package_manager/package_manager.services.yml +1 −0 Original line number Diff line number Diff line parameters: package_manager.skip_procedural_hook_scan: true package_manager.allow_overwrite: ['|^/recipes/.|'] services: _defaults: Loading
core/modules/package_manager/src/Validator/OverwriteExistingPackagesValidator.php +15 −0 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ use Drupal\package_manager\ComposerInspector; use Drupal\package_manager\Event\PreApplyEvent; use Drupal\package_manager\PathLocator; use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** Loading @@ -22,6 +23,12 @@ * https://packages.drupal.org/8 currently uses the `metapackage` type for * submodules of Drupal projects. * * This validator can accept an optional list of regular expressions matching * paths which are allowed to be overwritten. This is most useful when a recipe * is installed, since recipes are normally removed from Composer's awareness by * the drupal/core-recipe-unpack plugin and can therefore run afoul of this * validator. * * @internal * This is an internal part of Package Manager and may be changed or removed * at any time without warning. External code should not interact with this Loading @@ -36,6 +43,8 @@ final class OverwriteExistingPackagesValidator implements EventSubscriberInterfa public function __construct( private readonly PathLocator $pathLocator, private readonly ComposerInspector $composerInspector, #[Autowire(param: 'package_manager.allow_overwrite')] private readonly array $allowOverwrite = [], ) {} /** Loading @@ -57,6 +66,12 @@ public function validate(PreApplyEvent $event): void { continue; } $relative_path = str_replace($stage_dir, '', $package->path); foreach ($this->allowOverwrite as $pattern) { if (preg_match($pattern, $relative_path)) { continue 2; } } if (is_dir($active_dir . DIRECTORY_SEPARATOR . $relative_path)) { $event->addError([ $this->t('The new package @package will be installed in the directory @path, which already exists but is not managed by Composer.', [ Loading
core/modules/package_manager/tests/src/Kernel/OverwriteExistingPackagesValidatorTest.php +29 −0 Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ namespace Drupal\Tests\package_manager\Kernel; use Drupal\Core\Recipe\Recipe; use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\fixture_manipulator\ActiveFixtureManipulator; use Drupal\package_manager\ComposerInspector; Loading Loading @@ -165,4 +166,32 @@ public function testNewPackagesOverwriteExisting(): void { $this->assertResults($expected_results, PreApplyEvent::class); } /** * Tests that things in the `recipes` directory can be overwritten. */ public function testRecipeOverwriteIsAllowed(): void { (new ActiveFixtureManipulator()) ->addProjectAtPath('recipes/test_recipe', file_name: 'recipe.yml') ->commitChanges(); $stage_manipulator = $this->getStageFixtureManipulator(); // This should not raise an error because, even though it's going to // overwrite an existing directory, it's at a path which specifically allows // that. $stage_manipulator->addPackage( [ 'name' => 'drupal/test_recipe', 'version' => '1.0.0', 'type' => Recipe::COMPOSER_PROJECT_TYPE, ], FALSE, TRUE ); $installer_paths = [ 'recipes/test_recipe' => ['drupal/test_recipe'], ]; $this->setInstallerPaths($installer_paths, $this->container->get(PathLocator::class)->getProjectRoot()); $this->assertResults([], PreApplyEvent::class); } }