From 119836ad232a6a9bbd16adceea20085af95c0dac Mon Sep 17 00:00:00 2001 From: Wim Leers <44946-wimleers@users.noreply.drupalcode.org> Date: Tue, 9 May 2023 15:59:41 +0000 Subject: [PATCH] =?UTF-8?q?Issue=20#3342817=20by=20Wim=20Leers,=20phenapro?= =?UTF-8?q?xima,=20tedbow:=20Decide=20which=20classes=20should=20be=20inte?= =?UTF-8?q?rnal=20and/or=20final=20=E2=80=94=20delete=20ExcludedPathsTrait?= =?UTF-8?q?,=20make=20CollectPathsToExcludeEvent=20richer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/Event/CollectPathsToExcludeEvent.php | 86 +++++++++++++++- .../src/Event/ExcludedPathsTrait.php | 29 ------ package_manager/src/Event/PostApplyEvent.php | 2 +- package_manager/src/Event/PostCreateEvent.php | 2 +- .../src/Event/PostDestroyEvent.php | 2 +- .../src/Event/PostRequireEvent.php | 2 +- package_manager/src/Event/PreApplyEvent.php | 19 +++- package_manager/src/Event/PreCreateEvent.php | 19 +++- package_manager/src/Event/PreDestroyEvent.php | 2 +- package_manager/src/Event/PreRequireEvent.php | 2 +- .../src/Event/StatusCheckEvent.php | 2 +- .../src/Exception/StageOwnershipException.php | 2 +- .../src/PathExcluder/GitExcluder.php | 19 ++-- .../src/PathExcluder/NodeModulesExcluder.php | 20 +--- .../src/PathExcluder/PathExclusionsTrait.php | 99 ------------------- .../SiteConfigurationExcluder.php | 17 +--- .../src/PathExcluder/SiteFilesExcluder.php | 19 +--- .../PathExcluder/SqliteDatabaseExcluder.php | 19 ++-- .../src/PathExcluder/TestSiteExcluder.php | 19 +--- .../src/PathExcluder/UnknownPathExcluder.php | 17 ++-- .../PathExcluder/VendorHardeningExcluder.php | 14 +-- package_manager/src/StageBase.php | 2 +- package_manager/src/StatusCheckTrait.php | 11 ++- .../src/Validator/ComposerValidator.php | 2 +- .../Validator/DuplicateInfoFileValidator.php | 2 +- .../Validator/StageNotInActiveValidator.php | 2 +- .../src/Validator/SymlinkValidator.php | 2 +- .../SqliteDatabaseExcluderTest.php | 9 +- src/AutomaticUpdatesServiceProvider.php | 7 +- src/ReleaseChooser.php | 5 + src/UpdateStage.php | 5 + src/Validator/RequestedUpdateValidator.php | 7 +- .../StagedDatabaseUpdateValidator.php | 2 +- 33 files changed, 200 insertions(+), 268 deletions(-) delete mode 100644 package_manager/src/Event/ExcludedPathsTrait.php delete mode 100644 package_manager/src/PathExcluder/PathExclusionsTrait.php diff --git a/package_manager/src/Event/CollectPathsToExcludeEvent.php b/package_manager/src/Event/CollectPathsToExcludeEvent.php index fce262b015..facece949a 100644 --- a/package_manager/src/Event/CollectPathsToExcludeEvent.php +++ b/package_manager/src/Event/CollectPathsToExcludeEvent.php @@ -5,7 +5,9 @@ declare(strict_types = 1); namespace Drupal\package_manager\Event; use Drupal\package_manager\StageBase; +use Drupal\package_manager\PathLocator; use PhpTuf\ComposerStager\Domain\Value\PathList\PathListInterface; +use PhpTuf\ComposerStager\Infrastructure\Factory\Path\PathFactoryInterface; use PhpTuf\ComposerStager\Infrastructure\Value\PathList\PathList; /** @@ -14,7 +16,7 @@ use PhpTuf\ComposerStager\Infrastructure\Value\PathList\PathList; * These paths are excluded by Composer Stager and are never copied into the * stage directory from the active directory, or vice-versa. */ -class CollectPathsToExcludeEvent extends StageEvent implements PathListInterface { +final class CollectPathsToExcludeEvent extends StageEvent implements PathListInterface { /** * The list of paths to exclude. @@ -24,9 +26,20 @@ class CollectPathsToExcludeEvent extends StageEvent implements PathListInterface protected PathListInterface $pathList; /** - * {@inheritdoc} + * Constructs a CollectPathsToExcludeEvent object. + * + * @param \Drupal\package_manager\StageBase $stage + * The stage which fired this event. + * @param \Drupal\package_manager\PathLocator $pathLocator + * The path locator service. + * @param \PhpTuf\ComposerStager\Infrastructure\Factory\Path\PathFactoryInterface $pathFactory + * The path factory service. */ - public function __construct(StageBase $stage) { + public function __construct( + StageBase $stage, + protected PathLocator $pathLocator, + protected PathFactoryInterface $pathFactory + ) { parent::__construct($stage); $this->pathList = new PathList([]); } @@ -45,4 +58,71 @@ class CollectPathsToExcludeEvent extends StageEvent implements PathListInterface return $this->pathList->getAll(); } + /** + * Flags paths to be ignored, relative to the web root. + * + * This should only be used for paths that, if they exist at all, are + * *guaranteed* to exist within the web root. + * + * @param string[] $paths + * The paths to ignore. These should be relative to the web root, and will + * be made relative to the project root. + */ + public function addPathsRelativeToWebRoot(array $paths): void { + $web_root = $this->pathLocator->getWebRoot(); + if ($web_root) { + $web_root .= '/'; + } + + foreach ($paths as $path) { + // Make the path relative to the project root by prefixing the web root. + $this->add([$web_root . $path]); + } + } + + /** + * Flags paths to be ignored, relative to the project root. + * + * @param string[] $paths + * The paths to ignore. Absolute paths will be made relative to the project + * root; relative paths will be assumed to already be relative to the + * project root, and ignored as given. + */ + public function addPathsRelativeToProjectRoot(array $paths): void { + $project_root = $this->pathLocator->getProjectRoot(); + + foreach ($paths as $path) { + if ($this->pathFactory->create($path)->isAbsolute()) { + if (!str_starts_with($path, $project_root)) { + throw new \LogicException("$path is not inside the project root: $project_root."); + } + } + + // Make absolute paths relative to the project root. + $path = str_replace($project_root, '', $path); + $path = ltrim($path, '/'); + $this->add([$path]); + } + } + + /** + * Finds all directories in the project root matching the given name. + * + * @param string $directory_name + * The directory name to scan for. + * + * @return string[] + * All discovered absolute paths matching the given directory name. + */ + public function scanForDirectoriesByName(string $directory_name): array { + $flags = \FilesystemIterator::UNIX_PATHS; + $flags |= \FilesystemIterator::CURRENT_AS_SELF; + $directories_tree = new \RecursiveDirectoryIterator($this->pathLocator->getProjectRoot(), $flags); + $filtered_directories = new \RecursiveIteratorIterator($directories_tree, \RecursiveIteratorIterator::SELF_FIRST); + $matched_directories = new \CallbackFilterIterator($filtered_directories, + fn (\RecursiveDirectoryIterator $current) => $current->isDir() && $current->getFilename() === $directory_name + ); + return array_keys(iterator_to_array($matched_directories)); + } + } diff --git a/package_manager/src/Event/ExcludedPathsTrait.php b/package_manager/src/Event/ExcludedPathsTrait.php deleted file mode 100644 index 8e850b0af3..0000000000 --- a/package_manager/src/Event/ExcludedPathsTrait.php +++ /dev/null @@ -1,29 +0,0 @@ -<?php - -declare(strict_types = 1); - -namespace Drupal\package_manager\Event; - -/** - * Common functionality for events which can collect excluded paths. - */ -trait ExcludedPathsTrait { - - /** - * Paths to exclude from the update. - * - * @var string[] - */ - protected $excludedPaths = []; - - /** - * Returns the paths to exclude from the current operation. - * - * @return string[] - * The paths to exclude. - */ - public function getExcludedPaths(): array { - return array_unique($this->excludedPaths); - } - -} diff --git a/package_manager/src/Event/PostApplyEvent.php b/package_manager/src/Event/PostApplyEvent.php index b7ce5c2709..a83057cf72 100644 --- a/package_manager/src/Event/PostApplyEvent.php +++ b/package_manager/src/Event/PostApplyEvent.php @@ -7,5 +7,5 @@ namespace Drupal\package_manager\Event; /** * Event fired after staged changes are synced to the active directory. */ -class PostApplyEvent extends StageEvent { +final class PostApplyEvent extends StageEvent { } diff --git a/package_manager/src/Event/PostCreateEvent.php b/package_manager/src/Event/PostCreateEvent.php index 96ced349d3..b5db572884 100644 --- a/package_manager/src/Event/PostCreateEvent.php +++ b/package_manager/src/Event/PostCreateEvent.php @@ -7,5 +7,5 @@ namespace Drupal\package_manager\Event; /** * Event fired after a stage directory has been created. */ -class PostCreateEvent extends StageEvent { +final class PostCreateEvent extends StageEvent { } diff --git a/package_manager/src/Event/PostDestroyEvent.php b/package_manager/src/Event/PostDestroyEvent.php index 51d72b49c0..b68d214f9e 100644 --- a/package_manager/src/Event/PostDestroyEvent.php +++ b/package_manager/src/Event/PostDestroyEvent.php @@ -12,5 +12,5 @@ namespace Drupal\package_manager\Event; * * @see \Drupal\package_manager\StageBase::destroy() */ -class PostDestroyEvent extends StageEvent { +final class PostDestroyEvent extends StageEvent { } diff --git a/package_manager/src/Event/PostRequireEvent.php b/package_manager/src/Event/PostRequireEvent.php index 3ead93c825..ed92adb40b 100644 --- a/package_manager/src/Event/PostRequireEvent.php +++ b/package_manager/src/Event/PostRequireEvent.php @@ -7,7 +7,7 @@ namespace Drupal\package_manager\Event; /** * Event fired after packages are updated to the stage directory. */ -class PostRequireEvent extends StageEvent { +final class PostRequireEvent extends StageEvent { use RequireEventTrait; diff --git a/package_manager/src/Event/PreApplyEvent.php b/package_manager/src/Event/PreApplyEvent.php index 87fbb05848..9dac5cc54d 100644 --- a/package_manager/src/Event/PreApplyEvent.php +++ b/package_manager/src/Event/PreApplyEvent.php @@ -9,9 +9,24 @@ use Drupal\package_manager\StageBase; /** * Event fired before staged changes are synced to the active directory. */ -class PreApplyEvent extends PreOperationStageEvent { +final class PreApplyEvent extends PreOperationStageEvent { - use ExcludedPathsTrait; + /** + * Paths to exclude from the update. + * + * @var string[] + */ + protected array $excludedPaths = []; + + /** + * Returns the paths to exclude from the current operation. + * + * @return string[] + * The paths to exclude. + */ + public function getExcludedPaths(): array { + return array_unique($this->excludedPaths); + } /** * Constructs a PreApplyEvent object. diff --git a/package_manager/src/Event/PreCreateEvent.php b/package_manager/src/Event/PreCreateEvent.php index 2a369c62ce..9c775cadb4 100644 --- a/package_manager/src/Event/PreCreateEvent.php +++ b/package_manager/src/Event/PreCreateEvent.php @@ -9,9 +9,24 @@ use Drupal\package_manager\StageBase; /** * Event fired before a stage directory is created. */ -class PreCreateEvent extends PreOperationStageEvent { +final class PreCreateEvent extends PreOperationStageEvent { - use ExcludedPathsTrait; + /** + * Paths to exclude from the update. + * + * @var string[] + */ + protected array $excludedPaths = []; + + /** + * Returns the paths to exclude from the current operation. + * + * @return string[] + * The paths to exclude. + */ + public function getExcludedPaths(): array { + return array_unique($this->excludedPaths); + } /** * Constructs a PreCreateEvent object. diff --git a/package_manager/src/Event/PreDestroyEvent.php b/package_manager/src/Event/PreDestroyEvent.php index e9108f7daf..d51e2a76e9 100644 --- a/package_manager/src/Event/PreDestroyEvent.php +++ b/package_manager/src/Event/PreDestroyEvent.php @@ -12,5 +12,5 @@ namespace Drupal\package_manager\Event; * * @see \Drupal\package_manager\StageBase::destroy() */ -class PreDestroyEvent extends PreOperationStageEvent { +final class PreDestroyEvent extends PreOperationStageEvent { } diff --git a/package_manager/src/Event/PreRequireEvent.php b/package_manager/src/Event/PreRequireEvent.php index c9b9905a42..a38478ab34 100644 --- a/package_manager/src/Event/PreRequireEvent.php +++ b/package_manager/src/Event/PreRequireEvent.php @@ -7,7 +7,7 @@ namespace Drupal\package_manager\Event; /** * Event fired before packages are updated to the stage directory. */ -class PreRequireEvent extends PreOperationStageEvent { +final class PreRequireEvent extends PreOperationStageEvent { use RequireEventTrait; diff --git a/package_manager/src/Event/StatusCheckEvent.php b/package_manager/src/Event/StatusCheckEvent.php index 443e2a8856..41dc77cde7 100644 --- a/package_manager/src/Event/StatusCheckEvent.php +++ b/package_manager/src/Event/StatusCheckEvent.php @@ -15,7 +15,7 @@ use Drupal\system\SystemManager; * The event's stage will be set with the type of stage that will perform the * operations. The stage may or may not be currently in use. */ -class StatusCheckEvent extends PreOperationStageEvent { +final class StatusCheckEvent extends PreOperationStageEvent { /** * Returns paths to exclude or NULL if a base requirement is not fulfilled. diff --git a/package_manager/src/Exception/StageOwnershipException.php b/package_manager/src/Exception/StageOwnershipException.php index ad1f176e61..a1dc2608e9 100644 --- a/package_manager/src/Exception/StageOwnershipException.php +++ b/package_manager/src/Exception/StageOwnershipException.php @@ -9,5 +9,5 @@ namespace Drupal\package_manager\Exception; * * Should not be thrown by external code. */ -class StageOwnershipException extends StageException { +final class StageOwnershipException extends StageException { } diff --git a/package_manager/src/PathExcluder/GitExcluder.php b/package_manager/src/PathExcluder/GitExcluder.php index f8e2e77c38..7bc54d4350 100644 --- a/package_manager/src/PathExcluder/GitExcluder.php +++ b/package_manager/src/PathExcluder/GitExcluder.php @@ -7,7 +7,6 @@ namespace Drupal\package_manager\PathExcluder; use Drupal\package_manager\ComposerInspector; use Drupal\package_manager\Event\CollectPathsToExcludeEvent; use Drupal\package_manager\PathLocator; -use PhpTuf\ComposerStager\Infrastructure\Factory\Path\PathFactoryInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** @@ -20,22 +19,18 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface; */ final class GitExcluder implements EventSubscriberInterface { - use PathExclusionsTrait; - /** * Constructs a GitExcluder object. * - * @param \Drupal\package_manager\PathLocator $path_locator + * @param \Drupal\package_manager\PathLocator $pathLocator * The path locator service. * @param \Drupal\package_manager\ComposerInspector $composerInspector * The Composer inspector service. - * @param \PhpTuf\ComposerStager\Infrastructure\Factory\Path\PathFactoryInterface $path_factory - * The path factory service. */ - public function __construct(PathLocator $path_locator, private readonly ComposerInspector $composerInspector, PathFactoryInterface $path_factory) { - $this->pathLocator = $path_locator; - $this->pathFactory = $path_factory; - } + public function __construct( + private readonly PathLocator $pathLocator, + private readonly ComposerInspector $composerInspector + ) {} /** * {@inheritdoc} @@ -77,7 +72,7 @@ final class GitExcluder implements EventSubscriberInterface { $installed_paths[] = $package->path; } } - $paths = $this->scanForDirectoriesByName('.git'); + $paths = $event->scanForDirectoriesByName('.git'); foreach ($paths as $git_directory) { // Don't exclude any `.git` directory that is directly under an installed // package's path, since it means Composer probably installed that package @@ -87,7 +82,7 @@ final class GitExcluder implements EventSubscriberInterface { $paths_to_exclude[] = $git_directory; } } - $this->excludeInProjectRoot($event, $paths_to_exclude); + $event->addPathsRelativeToProjectRoot($paths_to_exclude); } } diff --git a/package_manager/src/PathExcluder/NodeModulesExcluder.php b/package_manager/src/PathExcluder/NodeModulesExcluder.php index 9f07bf205f..a954a0c103 100644 --- a/package_manager/src/PathExcluder/NodeModulesExcluder.php +++ b/package_manager/src/PathExcluder/NodeModulesExcluder.php @@ -5,8 +5,6 @@ declare(strict_types = 1); namespace Drupal\package_manager\PathExcluder; use Drupal\package_manager\Event\CollectPathsToExcludeEvent; -use Drupal\package_manager\PathLocator; -use PhpTuf\ComposerStager\Infrastructure\Factory\Path\PathFactoryInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** @@ -19,21 +17,6 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface; */ class NodeModulesExcluder implements EventSubscriberInterface { - use PathExclusionsTrait; - - /** - * Constructs a NodeModulesExcluder object. - * - * @param \Drupal\package_manager\PathLocator $path_locator - * The path locator service. - * @param \PhpTuf\ComposerStager\Infrastructure\Factory\Path\PathFactoryInterface $path_factory - * The path factory service. - */ - public function __construct(PathLocator $path_locator, PathFactoryInterface $path_factory) { - $this->pathLocator = $path_locator; - $this->pathFactory = $path_factory; - } - /** * Excludes node_modules directories from stage operations. * @@ -41,8 +24,7 @@ class NodeModulesExcluder implements EventSubscriberInterface { * The event object. */ public function excludeNodeModulesFiles(CollectPathsToExcludeEvent $event): void { - $paths = $this->scanForDirectoriesByName('node_modules'); - $this->excludeInProjectRoot($event, $paths); + $event->addPathsRelativeToProjectRoot($event->scanForDirectoriesByName('node_modules')); } /** diff --git a/package_manager/src/PathExcluder/PathExclusionsTrait.php b/package_manager/src/PathExcluder/PathExclusionsTrait.php deleted file mode 100644 index 5a3bb9183e..0000000000 --- a/package_manager/src/PathExcluder/PathExclusionsTrait.php +++ /dev/null @@ -1,99 +0,0 @@ -<?php - -declare(strict_types = 1); - -namespace Drupal\package_manager\PathExcluder; - -use Drupal\package_manager\Event\CollectPathsToExcludeEvent; - -/** - * Contains methods for excluding paths from stage operations. - */ -trait PathExclusionsTrait { - - /** - * The path locator service. - * - * @var \Drupal\package_manager\PathLocator - */ - protected $pathLocator; - - /** - * The path factory service. - * - * @var \PhpTuf\ComposerStager\Infrastructure\Factory\Path\PathFactoryInterface - */ - protected $pathFactory; - - /** - * Flags paths to be excluded, relative to the web root. - * - * This should only be used for paths that, if they exist at all, are - * *guaranteed* to exist within the web root. - * - * @param \Drupal\package_manager\Event\CollectPathsToExcludeEvent|\Drupal\package_manager\Event\StageEvent $event - * The event object. - * @param string[] $paths - * The paths to exclude. These should be relative to the web root, and will - * be made relative to the project root. - */ - protected function excludeInWebRoot(CollectPathsToExcludeEvent $event, array $paths): void { - $web_root = $this->pathLocator->getWebRoot(); - if ($web_root) { - $web_root .= '/'; - } - - foreach ($paths as $path) { - // Make the path relative to the project root by prefixing the web root. - $event->add([$web_root . $path]); - } - } - - /** - * Flags paths to be excluded, relative to the project root. - * - * @param \Drupal\package_manager\Event\CollectPathsToExcludeEvent|\Drupal\package_manager\Event\StageEvent $event - * The event object. - * @param string[] $paths - * The paths to exclude. Absolute paths will be made relative to the project - * root; relative paths will be assumed to already be relative to the - * project root, and excluded as given. - */ - protected function excludeInProjectRoot(CollectPathsToExcludeEvent $event, array $paths): void { - $project_root = $this->pathLocator->getProjectRoot(); - - foreach ($paths as $path) { - if ($this->pathFactory->create($path)->isAbsolute()) { - if (!str_starts_with($path, $project_root)) { - throw new \LogicException("$path is not inside the project root: $project_root."); - } - } - - // Make absolute paths relative to the project root. - $path = str_replace($project_root, '', $path); - $path = ltrim($path, '/'); - $event->add([$path]); - } - } - - /** - * Finds all directories in the project root matching the given name. - * - * @param string $directory_name - * The directory name to scan for. - * - * @return string[] - * All discovered absolute paths matching the given directory name. - */ - protected function scanForDirectoriesByName(string $directory_name): array { - $flags = \FilesystemIterator::UNIX_PATHS; - $flags |= \FilesystemIterator::CURRENT_AS_SELF; - $directories_tree = new \RecursiveDirectoryIterator($this->pathLocator->getProjectRoot(), $flags); - $filtered_directories = new \RecursiveIteratorIterator($directories_tree, \RecursiveIteratorIterator::SELF_FIRST); - $matched_directories = new \CallbackFilterIterator($filtered_directories, - fn (\RecursiveDirectoryIterator $current) => $current->isDir() && $current->getFilename() === $directory_name - ); - return array_keys(iterator_to_array($matched_directories)); - } - -} diff --git a/package_manager/src/PathExcluder/SiteConfigurationExcluder.php b/package_manager/src/PathExcluder/SiteConfigurationExcluder.php index 92b0b43004..7a4df3b2d0 100644 --- a/package_manager/src/PathExcluder/SiteConfigurationExcluder.php +++ b/package_manager/src/PathExcluder/SiteConfigurationExcluder.php @@ -5,8 +5,6 @@ declare(strict_types = 1); namespace Drupal\package_manager\PathExcluder; use Drupal\package_manager\Event\CollectPathsToExcludeEvent; -use Drupal\package_manager\PathLocator; -use PhpTuf\ComposerStager\Infrastructure\Factory\Path\PathFactoryInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** @@ -19,22 +17,13 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface; */ class SiteConfigurationExcluder implements EventSubscriberInterface { - use PathExclusionsTrait; - /** - * Constructs an ExcludedPathsSubscriber. + * Constructs an SiteConfigurationExcluder. * * @param string $sitePath * The current site path, relative to the Drupal root. - * @param \Drupal\package_manager\PathLocator $path_locator - * The path locator service. - * @param \PhpTuf\ComposerStager\Infrastructure\Factory\Path\PathFactoryInterface $path_factory - * The path factory service. */ - public function __construct(protected string $sitePath, PathLocator $path_locator, PathFactoryInterface $path_factory) { - $this->pathLocator = $path_locator; - $this->pathFactory = $path_factory; - } + public function __construct(protected string $sitePath) {} /** * Excludes site configuration files from stage operations. @@ -57,7 +46,7 @@ class SiteConfigurationExcluder implements EventSubscriberInterface { $paths[] = $this->sitePath . '/' . $settings_file; $paths[] = 'sites/default/' . $settings_file; } - $this->excludeInWebRoot($event, $paths); + $event->addPathsRelativeToWebRoot($paths); } /** diff --git a/package_manager/src/PathExcluder/SiteFilesExcluder.php b/package_manager/src/PathExcluder/SiteFilesExcluder.php index ce23ee3756..cf0a71cb03 100644 --- a/package_manager/src/PathExcluder/SiteFilesExcluder.php +++ b/package_manager/src/PathExcluder/SiteFilesExcluder.php @@ -7,8 +7,6 @@ namespace Drupal\package_manager\PathExcluder; use Drupal\Core\StreamWrapper\LocalStream; use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface; use Drupal\package_manager\Event\CollectPathsToExcludeEvent; -use Drupal\package_manager\PathLocator; -use PhpTuf\ComposerStager\Infrastructure\Factory\Path\PathFactoryInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Filesystem\Filesystem; @@ -22,29 +20,18 @@ use Symfony\Component\Filesystem\Filesystem; */ final class SiteFilesExcluder implements EventSubscriberInterface { - use PathExclusionsTrait; - /** * Constructs a SiteFilesExcluder object. * - * @param \Drupal\package_manager\PathLocator $path_locator - * The path locator service. - * @param \PhpTuf\ComposerStager\Infrastructure\Factory\Path\PathFactoryInterface $path_factory - * The path factory service. * @param \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface $streamWrapperManager * The stream wrapper manager service. * @param \Symfony\Component\Filesystem\Filesystem $fileSystem * The Symfony file system service. */ public function __construct( - PathLocator $path_locator, - PathFactoryInterface $path_factory, private readonly StreamWrapperManagerInterface $streamWrapperManager, private readonly Filesystem $fileSystem - ) { - $this->pathLocator = $path_locator; - $this->pathFactory = $path_factory; - } + ) {} /** * {@inheritdoc} @@ -72,10 +59,10 @@ final class SiteFilesExcluder implements EventSubscriberInterface { $path = $wrapper->getDirectoryPath(); if ($this->fileSystem->isAbsolutePath($path)) { - $this->excludeInProjectRoot($event, [realpath($path)]); + $event->addPathsRelativeToProjectRoot([realpath($path)]); } else { - $this->excludeInWebRoot($event, [$path]); + $event->addPathsRelativeToWebRoot([$path]); } } } diff --git a/package_manager/src/PathExcluder/SqliteDatabaseExcluder.php b/package_manager/src/PathExcluder/SqliteDatabaseExcluder.php index 42bb065516..cfcf1fc95b 100644 --- a/package_manager/src/PathExcluder/SqliteDatabaseExcluder.php +++ b/package_manager/src/PathExcluder/SqliteDatabaseExcluder.php @@ -7,7 +7,6 @@ namespace Drupal\package_manager\PathExcluder; use Drupal\Core\Database\Connection; use Drupal\package_manager\Event\CollectPathsToExcludeEvent; use Drupal\package_manager\PathLocator; -use PhpTuf\ComposerStager\Infrastructure\Factory\Path\PathFactoryInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** @@ -20,22 +19,20 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface; */ class SqliteDatabaseExcluder implements EventSubscriberInterface { - use PathExclusionsTrait; - /** * Constructs a SqliteDatabaseExcluder object. * - * @param \Drupal\package_manager\PathLocator $path_locator + * @param \Drupal\package_manager\PathLocator $pathLocator * The path locator service. * @param \Drupal\Core\Database\Connection $database * The database connection. - * @param \PhpTuf\ComposerStager\Infrastructure\Factory\Path\PathFactoryInterface $path_factory - * The path factory service. */ - public function __construct(PathLocator $path_locator, protected Connection $database, PathFactoryInterface $path_factory) { - $this->pathLocator = $path_locator; - $this->pathFactory = $path_factory; - } + public function __construct( + private readonly PathLocator $pathLocator, + // TRICKY: this cannot be private nor readonly for testing purposes. + // @see \Drupal\Tests\package_manager\Kernel\PathExcluder\SqliteDatabaseExcluderTest::mockDatabase() + protected Connection $database + ) {} /** * {@inheritdoc} @@ -61,7 +58,7 @@ class SqliteDatabaseExcluder implements EventSubscriberInterface { if (str_starts_with($options['database'], '/') && !str_starts_with($options['database'], $this->pathLocator->getProjectRoot())) { return; } - $this->excludeInProjectRoot($event, [ + $event->addPathsRelativeToProjectRoot([ $options['database'], $options['database'] . '-shm', $options['database'] . '-wal', diff --git a/package_manager/src/PathExcluder/TestSiteExcluder.php b/package_manager/src/PathExcluder/TestSiteExcluder.php index f3a5080f36..59b9b2edd9 100644 --- a/package_manager/src/PathExcluder/TestSiteExcluder.php +++ b/package_manager/src/PathExcluder/TestSiteExcluder.php @@ -5,8 +5,6 @@ declare(strict_types = 1); namespace Drupal\package_manager\PathExcluder; use Drupal\package_manager\Event\CollectPathsToExcludeEvent; -use Drupal\package_manager\PathLocator; -use PhpTuf\ComposerStager\Infrastructure\Factory\Path\PathFactoryInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** @@ -19,21 +17,6 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface; */ final class TestSiteExcluder implements EventSubscriberInterface { - use PathExclusionsTrait; - - /** - * Constructs a TestSiteExcluder object. - * - * @param \Drupal\package_manager\PathLocator $path_locator - * The path locator service. - * @param \PhpTuf\ComposerStager\Infrastructure\Factory\Path\PathFactoryInterface $path_factory - * The path factory service. - */ - public function __construct(PathLocator $path_locator, PathFactoryInterface $path_factory) { - $this->pathLocator = $path_locator; - $this->pathFactory = $path_factory; - } - /** * {@inheritdoc} */ @@ -52,7 +35,7 @@ final class TestSiteExcluder implements EventSubscriberInterface { public function excludeTestSites(CollectPathsToExcludeEvent $event): void { // Always exclude automated test directories. If they exist, they will be in // the web root. - $this->excludeInWebRoot($event, ['sites/simpletest']); + $event->addPathsRelativeToWebRoot(['sites/simpletest']); } } diff --git a/package_manager/src/PathExcluder/UnknownPathExcluder.php b/package_manager/src/PathExcluder/UnknownPathExcluder.php index 9150bc3c0a..e7295b1891 100644 --- a/package_manager/src/PathExcluder/UnknownPathExcluder.php +++ b/package_manager/src/PathExcluder/UnknownPathExcluder.php @@ -8,7 +8,6 @@ use Drupal\Component\Serialization\Json; use Drupal\package_manager\ComposerInspector; use Drupal\package_manager\Event\CollectPathsToExcludeEvent; use Drupal\package_manager\PathLocator; -use PhpTuf\ComposerStager\Infrastructure\Factory\Path\PathFactoryInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** @@ -31,22 +30,18 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface; */ final class UnknownPathExcluder implements EventSubscriberInterface { - use PathExclusionsTrait; - /** * Constructs a UnknownPathExcluder object. * * @param \Drupal\package_manager\ComposerInspector $composerInspector * The Composer inspector service. - * @param \Drupal\package_manager\PathLocator $path_locator + * @param \Drupal\package_manager\PathLocator $pathLocator * The path locator service. - * @param \PhpTuf\ComposerStager\Infrastructure\Factory\Path\PathFactoryInterface $path_factory - * The path factory service. */ - public function __construct(private readonly ComposerInspector $composerInspector, PathLocator $path_locator, PathFactoryInterface $path_factory) { - $this->pathLocator = $path_locator; - $this->pathFactory = $path_factory; - } + public function __construct( + private readonly ComposerInspector $composerInspector, + private readonly PathLocator $pathLocator, + ) {} /** * {@inheritdoc} @@ -93,7 +88,7 @@ final class UnknownPathExcluder implements EventSubscriberInterface { $paths[] = $path_in_project_root; } } - $this->excludeInProjectRoot($event, $paths); + $event->addPathsRelativeToProjectRoot($paths); } /** diff --git a/package_manager/src/PathExcluder/VendorHardeningExcluder.php b/package_manager/src/PathExcluder/VendorHardeningExcluder.php index 509516390a..2d46271b20 100644 --- a/package_manager/src/PathExcluder/VendorHardeningExcluder.php +++ b/package_manager/src/PathExcluder/VendorHardeningExcluder.php @@ -6,7 +6,6 @@ namespace Drupal\package_manager\PathExcluder; use Drupal\package_manager\Event\CollectPathsToExcludeEvent; use Drupal\package_manager\PathLocator; -use PhpTuf\ComposerStager\Infrastructure\Factory\Path\PathFactoryInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** @@ -19,20 +18,13 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface; */ final class VendorHardeningExcluder implements EventSubscriberInterface { - use PathExclusionsTrait; - /** * Constructs a VendorHardeningExcluder object. * - * @param \Drupal\package_manager\PathLocator $path_locator + * @param \Drupal\package_manager\PathLocator $pathLocator * The path locator service. - * @param \PhpTuf\ComposerStager\Infrastructure\Factory\Path\PathFactoryInterface $path_factory - * The path factory service. */ - public function __construct(PathLocator $path_locator, PathFactoryInterface $path_factory) { - $this->pathLocator = $path_locator; - $this->pathFactory = $path_factory; - } + public function __construct(private readonly PathLocator $pathLocator) {} /** * {@inheritdoc} @@ -54,7 +46,7 @@ final class VendorHardeningExcluder implements EventSubscriberInterface { // is present, it may have written security hardening files in the vendor // directory. They should always be excluded. $vendor_dir = $this->pathLocator->getVendorDirectory(); - $this->excludeInProjectRoot($event, [ + $event->addPathsRelativeToProjectRoot([ $vendor_dir . '/web.config', $vendor_dir . '/.htaccess', ]); diff --git a/package_manager/src/StageBase.php b/package_manager/src/StageBase.php index af98358181..49d57c828e 100644 --- a/package_manager/src/StageBase.php +++ b/package_manager/src/StageBase.php @@ -263,7 +263,7 @@ abstract class StageBase implements LoggerAwareInterface { * @see ::apply() */ protected function getPathsToExclude(): array { - $event = new CollectPathsToExcludeEvent($this); + $event = new CollectPathsToExcludeEvent($this, $this->pathLocator, $this->pathFactory); try { $this->eventDispatcher->dispatch($event); } diff --git a/package_manager/src/StatusCheckTrait.php b/package_manager/src/StatusCheckTrait.php index 3de0a1b6b2..4bad25258d 100644 --- a/package_manager/src/StatusCheckTrait.php +++ b/package_manager/src/StatusCheckTrait.php @@ -6,6 +6,7 @@ namespace Drupal\package_manager; use Drupal\package_manager\Event\CollectPathsToExcludeEvent; use Drupal\package_manager\Event\StatusCheckEvent; +use PhpTuf\ComposerStager\Infrastructure\Factory\Path\PathFactoryInterface; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** @@ -25,15 +26,21 @@ trait StatusCheckTrait { * The stage to run the status check for. * @param \Symfony\Contracts\EventDispatcher\EventDispatcherInterface $event_dispatcher * (optional) The event dispatcher service. + * @param \Drupal\package_manager\PathLocator $path_locator + * (optional) The path locator service. + * @param \PhpTuf\ComposerStager\Infrastructure\Factory\Path\PathFactoryInterface $path_factory + * (optional) The path factory service. * * @return \Drupal\package_manager\ValidationResult[] * The results of the status check. If a readiness check was also done, * its results will be included. */ - protected function runStatusCheck(StageBase $stage, EventDispatcherInterface $event_dispatcher = NULL): array { + protected function runStatusCheck(StageBase $stage, EventDispatcherInterface $event_dispatcher = NULL, PathLocator $path_locator = NULL, PathFactoryInterface $path_factory = NULL): array { $event_dispatcher ??= \Drupal::service('event_dispatcher'); + $path_locator ??= \Drupal::service(PathLocator::class); + $path_factory ??= \Drupal::service(PathFactoryInterface::class); try { - $paths_to_exclude_event = new CollectPathsToExcludeEvent($stage); + $paths_to_exclude_event = new CollectPathsToExcludeEvent($stage, $path_locator, $path_factory); $event_dispatcher->dispatch($paths_to_exclude_event); $event = new StatusCheckEvent($stage, $paths_to_exclude_event->getAll()); } diff --git a/package_manager/src/Validator/ComposerValidator.php b/package_manager/src/Validator/ComposerValidator.php index 09a1123748..e4aa6ced61 100644 --- a/package_manager/src/Validator/ComposerValidator.php +++ b/package_manager/src/Validator/ComposerValidator.php @@ -21,7 +21,7 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface; * at any time without warning. External code should not interact with this * class. */ -class ComposerValidator implements EventSubscriberInterface { +final class ComposerValidator implements EventSubscriberInterface { use BaseRequirementValidatorTrait; use StringTranslationTrait; diff --git a/package_manager/src/Validator/DuplicateInfoFileValidator.php b/package_manager/src/Validator/DuplicateInfoFileValidator.php index beea0bc313..644d37bde4 100644 --- a/package_manager/src/Validator/DuplicateInfoFileValidator.php +++ b/package_manager/src/Validator/DuplicateInfoFileValidator.php @@ -18,7 +18,7 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface; * at any time without warning. External code should not interact with this * class. */ -class DuplicateInfoFileValidator implements EventSubscriberInterface { +final class DuplicateInfoFileValidator implements EventSubscriberInterface { use StringTranslationTrait; diff --git a/package_manager/src/Validator/StageNotInActiveValidator.php b/package_manager/src/Validator/StageNotInActiveValidator.php index 956641452b..d38831097e 100644 --- a/package_manager/src/Validator/StageNotInActiveValidator.php +++ b/package_manager/src/Validator/StageNotInActiveValidator.php @@ -18,7 +18,7 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface; * at any time without warning. External code should not interact with this * class. */ -class StageNotInActiveValidator implements EventSubscriberInterface { +final class StageNotInActiveValidator implements EventSubscriberInterface { use BaseRequirementValidatorTrait { getSubscribedEvents as protected getSubscribedEventsFromTrait; diff --git a/package_manager/src/Validator/SymlinkValidator.php b/package_manager/src/Validator/SymlinkValidator.php index 12d84007a9..e30ac93f3c 100644 --- a/package_manager/src/Validator/SymlinkValidator.php +++ b/package_manager/src/Validator/SymlinkValidator.php @@ -22,7 +22,7 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface; * at any time without warning. External code should not interact with this * class. */ -class SymlinkValidator implements EventSubscriberInterface { +final class SymlinkValidator implements EventSubscriberInterface { use BaseRequirementValidatorTrait; diff --git a/package_manager/tests/src/Kernel/PathExcluder/SqliteDatabaseExcluderTest.php b/package_manager/tests/src/Kernel/PathExcluder/SqliteDatabaseExcluderTest.php index 7d75dbb659..05fa39946e 100644 --- a/package_manager/tests/src/Kernel/PathExcluder/SqliteDatabaseExcluderTest.php +++ b/package_manager/tests/src/Kernel/PathExcluder/SqliteDatabaseExcluderTest.php @@ -10,6 +10,7 @@ use Drupal\package_manager\Event\CollectPathsToExcludeEvent; use Drupal\package_manager\PathExcluder\SqliteDatabaseExcluder; use Drupal\package_manager\PathLocator; use Drupal\Tests\package_manager\Kernel\PackageManagerKernelTestBase; +use PhpTuf\ComposerStager\Infrastructure\Factory\Path\PathFactoryInterface; /** * @covers \Drupal\package_manager\PathExcluder\SqliteDatabaseExcluder @@ -144,22 +145,24 @@ class SqliteDatabaseExcluderTest extends PackageManagerKernelTestBase { * @dataProvider providerPathProcessing */ public function testPathProcessing(string $database_path, array $expected_exclusions): void { + $path_locator = $this->container->get(PathLocator::class); + $path_factory = $this->container->get(PathFactoryInterface::class); // If the database path should be treated as absolute, prefix it with the // path of the active directory. if (str_starts_with($database_path, '/')) { - $database_path = $this->container->get(PathLocator::class)->getProjectRoot() . $database_path; + $database_path = $path_locator->getProjectRoot() . $database_path; } $this->mockDatabase([ 'database' => $database_path, ]); - $event = new CollectPathsToExcludeEvent($this->createStage()); + $event = new CollectPathsToExcludeEvent($this->createStage(), $path_locator, $path_factory); // Invoke the event subscriber directly, so we can check that the database // was correctly excluded. $this->container->get(SqliteDatabaseExcluder::class) ->excludeDatabaseFiles($event); // All of the expected exclusions should be flagged. - $this->assertEmpty(array_diff($expected_exclusions, $event->getAll())); + $this->assertEquals($expected_exclusions, $event->getAll()); } } diff --git a/src/AutomaticUpdatesServiceProvider.php b/src/AutomaticUpdatesServiceProvider.php index cdd97cf7ba..cc6c502523 100644 --- a/src/AutomaticUpdatesServiceProvider.php +++ b/src/AutomaticUpdatesServiceProvider.php @@ -10,8 +10,13 @@ use Drupal\Core\DependencyInjection\ServiceProviderBase; /** * Modifies container services for Automatic Updates. + * + * @internal + * This is an internal part of Automatic Updates and may be changed or removed + * at any time without warning. External code should not interact with this + * class. */ -class AutomaticUpdatesServiceProvider extends ServiceProviderBase { +final class AutomaticUpdatesServiceProvider extends ServiceProviderBase { /** * {@inheritdoc} diff --git a/src/ReleaseChooser.php b/src/ReleaseChooser.php index 83523493e7..caa8cc19f9 100644 --- a/src/ReleaseChooser.php +++ b/src/ReleaseChooser.php @@ -12,6 +12,11 @@ use Drupal\Core\Extension\ExtensionVersion; /** * Defines a class to choose a release of Drupal core to update to. + * + * @internal + * This is an internal part of Automatic Updates and may be changed or removed + * at any time without warning. External code should not interact with this + * class. */ final class ReleaseChooser { diff --git a/src/UpdateStage.php b/src/UpdateStage.php index 9cb2501a8e..f5bf4e0f66 100644 --- a/src/UpdateStage.php +++ b/src/UpdateStage.php @@ -25,6 +25,11 @@ use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; * changing the constraint for either 'drupal/core' or 'drupal/core-recommended' * in the project-level composer.json. If neither package is directly required * in the project-level composer.json, a requirement will be added. + * + * @internal + * This is an internal part of Automatic Updates and may be changed or removed + * at any time without warning. External code should not interact with this + * class. */ class UpdateStage extends StageBase { diff --git a/src/Validator/RequestedUpdateValidator.php b/src/Validator/RequestedUpdateValidator.php index 60e09c88d1..fc3bcea5c9 100644 --- a/src/Validator/RequestedUpdateValidator.php +++ b/src/Validator/RequestedUpdateValidator.php @@ -14,8 +14,13 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** * Validates that requested packages have been updated. + * + * @internal + * This is an internal part of Automatic Updates and may be changed or removed + * at any time without warning. External code should not interact with this + * class. */ -class RequestedUpdateValidator implements EventSubscriberInterface { +final class RequestedUpdateValidator implements EventSubscriberInterface { use StringTranslationTrait; diff --git a/src/Validator/StagedDatabaseUpdateValidator.php b/src/Validator/StagedDatabaseUpdateValidator.php index b3a3bb7854..a2998417dd 100644 --- a/src/Validator/StagedDatabaseUpdateValidator.php +++ b/src/Validator/StagedDatabaseUpdateValidator.php @@ -18,7 +18,7 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface; * at any time without warning. External code should not interact with this * class. */ -class StagedDatabaseUpdateValidator implements EventSubscriberInterface { +final class StagedDatabaseUpdateValidator implements EventSubscriberInterface { use StringTranslationTrait; -- GitLab