From c40344cbdbdba806fb69775f71852f3321fe8937 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ph=C3=A9na=20Proxima?= <adam@phenaproxima.net>
Date: Fri, 17 Dec 2021 12:08:43 -0500
Subject: [PATCH] Revert "Issue #3254616 by phenaproxima, tedbow: Update
 Composer Stager to 0.3.0"

This reverts commit a941773cb0fad28bb4e3ea7028ea9059feb95c32.
---
 composer.json                                 |   2 +-
 package_manager/package_manager.services.yml  |  10 +-
 .../src/Event/ExcludedPathsTrait.php          |  17 +-
 .../ComposerExecutableValidator.php           |  10 +-
 .../ExcludedPathsSubscriber.php               | 169 ++++++------------
 package_manager/src/FileSyncerFactory.php     |  14 +-
 .../tests/fixtures/fake_site/vendor/.htaccess |   1 -
 .../package_manager_bypass/src/Beginner.php   |   4 +-
 .../package_manager_bypass/src/Committer.php  |   4 +-
 .../package_manager_bypass/src/Stager.php     |   4 +-
 .../src/Functional/ExcludedPathsTest.php      |  60 +++----
 .../ComposerExecutableValidatorTest.php       |   4 +-
 .../Kernel/ComposerSettingsValidatorTest.php  |   1 -
 .../src/Kernel/DiskSpaceValidatorTest.php     |   1 -
 .../Kernel/ExcludedPathsSubscriberTest.php    |   8 +-
 .../WritableFileSystemValidatorTest.php       |   1 -
 tests/src/Build/UpdateTestBase.php            |   5 +-
 .../StagedProjectsValidatorTest.php           |   1 -
 tests/src/Kernel/UpdaterTest.php              |   1 -
 19 files changed, 120 insertions(+), 197 deletions(-)
 delete mode 100644 package_manager/tests/fixtures/fake_site/vendor/.htaccess

diff --git a/composer.json b/composer.json
index 39bd124972..36692bf5da 100644
--- a/composer.json
+++ b/composer.json
@@ -13,7 +13,7 @@
   "require": {
     "ext-json": "*",
     "drupal/core": "^9.2",
-    "php-tuf/composer-stager": "0.3.0",
+    "php-tuf/composer-stager": "0.2.3",
     "composer/composer": "^2"
   },
   "config": {
diff --git a/package_manager/package_manager.services.yml b/package_manager/package_manager.services.yml
index f5e04442d0..d2b01442f1 100644
--- a/package_manager/package_manager.services.yml
+++ b/package_manager/package_manager.services.yml
@@ -4,6 +4,8 @@ services:
     class: Symfony\Component\Filesystem\Filesystem
   package_manager.symfony_executable_finder:
     class: Symfony\Component\Process\ExecutableFinder
+  package_manager.symfony_finder:
+    class: Symfony\Component\Finder\Finder
 
   # Basic infrastructure services.
   package_manager.process_factory:
@@ -43,6 +45,8 @@ services:
     class: PhpTuf\ComposerStager\Infrastructure\FileSyncer\PhpFileSyncer
     arguments:
       - '@package_manager.file_system'
+      - '@package_manager.symfony_finder'
+      - '@package_manager.symfony_finder'
   package_manager.file_syncer.factory:
     class: Drupal\package_manager\FileSyncerFactory
     arguments:
@@ -51,7 +55,7 @@ services:
       - '@package_manager.file_syncer.rsync'
       - '@config.factory'
   package_manager.file_syncer:
-    class: PhpTuf\ComposerStager\Domain\FileSyncer\FileSyncerInterface
+    class: PhpTuf\ComposerStager\Infrastructure\FileSyncer\FileSyncerInterface
     factory: ['@package_manager.file_syncer.factory', 'create']
 
   # Domain services.
@@ -123,10 +127,10 @@ services:
   package_manager.excluded_paths_subscriber:
     class: Drupal\package_manager\EventSubscriber\ExcludedPathsSubscriber
     arguments:
+      - '%app.root%'
       - '%site.path%'
-      - '@package_manager.symfony_file_system'
+      - '@file_system'
       - '@stream_wrapper_manager'
       - '@database'
-      - '@package_manager.path_locator'
     tags:
       - { name: event_subscriber }
diff --git a/package_manager/src/Event/ExcludedPathsTrait.php b/package_manager/src/Event/ExcludedPathsTrait.php
index fc7e690440..3648446b80 100644
--- a/package_manager/src/Event/ExcludedPathsTrait.php
+++ b/package_manager/src/Event/ExcludedPathsTrait.php
@@ -15,23 +15,12 @@ trait ExcludedPathsTrait {
   protected $excludedPaths = [];
 
   /**
-   * Adds a path to exclude from the current operation.
+   * Adds an absolute path to exclude from the current operation.
    *
-   * If called on an instance of \Drupal\package_manager\Event\PreCreateEvent,
-   * excluded paths will not be copied into the staging area when the stage is
-   * created. If called on an instance of
-   * \Drupal\package_manager\Event\PreApplyEvent, excluded paths will not be
-   * deleted from the active directory when staged changes are applied. So,
-   * to ensure that a given path is never staged, but also preserved in the
-   * active directory, it should be passed to this method on both PreCreateEvent
-   * and PreApplyEvent. See
-   * \Drupal\package_manager\EventSubscriber\ExcludedPathsSubscriber for an
-   * example.
+   * @todo This should only accept paths relative to the active directory.
    *
    * @param string $path
-   *   The path to exclude, relative to the project root.
-   *
-   * @see \Drupal\package_manager\EventSubscriber\ExcludedPathsSubscriber
+   *   The path to exclude.
    */
   public function excludePath(string $path): void {
     $this->excludedPaths[] = $path;
diff --git a/package_manager/src/EventSubscriber/ComposerExecutableValidator.php b/package_manager/src/EventSubscriber/ComposerExecutableValidator.php
index f91e852930..a4df9a3591 100644
--- a/package_manager/src/EventSubscriber/ComposerExecutableValidator.php
+++ b/package_manager/src/EventSubscriber/ComposerExecutableValidator.php
@@ -7,21 +7,21 @@ use Drupal\package_manager\Event\PreOperationStageEvent;
 use Drupal\Core\Extension\ExtensionVersion;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Drupal\Core\StringTranslation\TranslationInterface;
-use PhpTuf\ComposerStager\Domain\Process\OutputCallbackInterface;
-use PhpTuf\ComposerStager\Domain\Process\Runner\ComposerRunnerInterface;
+use PhpTuf\ComposerStager\Domain\Output\ProcessOutputCallbackInterface;
 use PhpTuf\ComposerStager\Exception\ExceptionInterface;
+use PhpTuf\ComposerStager\Infrastructure\Process\Runner\ComposerRunnerInterface;
 
 /**
  * Validates that the Composer executable can be found in the correct version.
  */
-class ComposerExecutableValidator implements PreOperationStageValidatorInterface, OutputCallbackInterface {
+class ComposerExecutableValidator implements PreOperationStageValidatorInterface, ProcessOutputCallbackInterface {
 
   use StringTranslationTrait;
 
   /**
    * The Composer runner.
    *
-   * @var \PhpTuf\ComposerStager\Domain\Process\Runner\ComposerRunnerInterface
+   * @var \PhpTuf\ComposerStager\Infrastructure\Process\Runner\ComposerRunnerInterface
    */
   protected $composer;
 
@@ -35,7 +35,7 @@ class ComposerExecutableValidator implements PreOperationStageValidatorInterface
   /**
    * Constructs a ComposerExecutableValidator object.
    *
-   * @param \PhpTuf\ComposerStager\Domain\Process\Runner\ComposerRunnerInterface $composer
+   * @param \PhpTuf\ComposerStager\Infrastructure\Process\Runner\ComposerRunnerInterface $composer
    *   The Composer runner.
    * @param \Drupal\Core\StringTranslation\TranslationInterface $translation
    *   The translation service.
diff --git a/package_manager/src/EventSubscriber/ExcludedPathsSubscriber.php b/package_manager/src/EventSubscriber/ExcludedPathsSubscriber.php
index b65ff7a709..4663284c79 100644
--- a/package_manager/src/EventSubscriber/ExcludedPathsSubscriber.php
+++ b/package_manager/src/EventSubscriber/ExcludedPathsSubscriber.php
@@ -3,20 +3,25 @@
 namespace Drupal\package_manager\EventSubscriber;
 
 use Drupal\Core\Database\Connection;
+use Drupal\Core\File\FileSystemInterface;
 use Drupal\Core\StreamWrapper\LocalStream;
 use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface;
 use Drupal\package_manager\Event\PreApplyEvent;
 use Drupal\package_manager\Event\PreCreateEvent;
-use Drupal\package_manager\Event\StageEvent;
-use Drupal\package_manager\PathLocator;
 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-use Symfony\Component\Filesystem\Filesystem;
 
 /**
  * Defines an event subscriber to exclude certain paths from staging areas.
  */
 class ExcludedPathsSubscriber implements EventSubscriberInterface {
 
+  /**
+   * The Drupal root.
+   *
+   * @var string
+   */
+  protected $appRoot;
+
   /**
    * The current site path, relative to the Drupal root.
    *
@@ -25,9 +30,9 @@ class ExcludedPathsSubscriber implements EventSubscriberInterface {
   protected $sitePath;
 
   /**
-   * The Symfony file system service.
+   * The file system service.
    *
-   * @var \Symfony\Component\Filesystem\Filesystem
+   * @var \Drupal\Core\File\FileSystemInterface
    */
   protected $fileSystem;
 
@@ -45,157 +50,91 @@ class ExcludedPathsSubscriber implements EventSubscriberInterface {
    */
   protected $database;
 
-  /**
-   * The path locator service.
-   *
-   * @var \Drupal\package_manager\PathLocator
-   */
-  protected $pathLocator;
-
   /**
    * Constructs an ExcludedPathsSubscriber.
    *
+   * @param string $app_root
+   *   The Drupal root.
    * @param string $site_path
    *   The current site path, relative to the Drupal root.
-   * @param \Symfony\Component\Filesystem\Filesystem $file_system
-   *   The Symfony file system service.
+   * @param \Drupal\Core\File\FileSystemInterface $file_system
+   *   The file system service.
    * @param \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface $stream_wrapper_manager
    *   The stream wrapper manager service.
    * @param \Drupal\Core\Database\Connection $database
    *   The database connection.
-   * @param \Drupal\package_manager\PathLocator $path_locator
-   *   The path locator service.
    */
-  public function __construct(string $site_path, Filesystem $file_system, StreamWrapperManagerInterface $stream_wrapper_manager, Connection $database, PathLocator $path_locator) {
+  public function __construct(string $app_root, string $site_path, FileSystemInterface $file_system, StreamWrapperManagerInterface $stream_wrapper_manager, Connection $database) {
+    $this->appRoot = $app_root;
     $this->sitePath = $site_path;
     $this->fileSystem = $file_system;
     $this->streamWrapperManager = $stream_wrapper_manager;
     $this->database = $database;
-    $this->pathLocator = $path_locator;
   }
 
   /**
-   * 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.
+   * Reacts before staged changes are committed the active directory.
    *
-   * @param \Drupal\package_manager\Event\PreCreateEvent|\Drupal\package_manager\Event\PreApplyEvent $event
+   * @param \Drupal\package_manager\Event\PreApplyEvent $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(StageEvent $event, array $paths): void {
-    $web_root = $this->pathLocator->getWebRoot();
-    if ($web_root) {
-      $web_root .= '/';
-    }
+  public function preApply(PreApplyEvent $event): void {
+    // Don't copy anything from the staging area's sites/default.
+    // @todo Make this a lot smarter in https://www.drupal.org/i/3228955.
+    $event->excludePath('sites/default');
 
-    foreach ($paths as $path) {
-      // Make the path relative to the project root by prefixing the web root.
-      $event->excludePath($web_root . $path);
-    }
+    // If the core-vendor-hardening plugin (used in the legacy-project template)
+    // is present, it may have written a web.config file into the vendor
+    // directory. We don't want to copy that.
+    $event->excludePath('web.config');
   }
 
   /**
-   * Flags paths to be excluded, relative to the project root.
+   * Excludes paths from a staging area before it is created.
    *
-   * @param \Drupal\package_manager\Event\PreCreateEvent|\Drupal\package_manager\Event\PreApplyEvent $event
+   * @param \Drupal\package_manager\Event\PreCreateEvent $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(StageEvent $event, array $paths): void {
-    $project_root = $this->pathLocator->getProjectRoot();
-
-    foreach ($paths as $path) {
-      // Make absolute paths relative to the project root.
-      $path = str_replace($project_root, NULL, $path);
-      $path = ltrim($path, '/');
-      $event->excludePath($path);
+  public function preCreate(PreCreateEvent $event): void {
+    // Automated test site directories should never be staged.
+    $event->excludePath('sites/simpletest');
+
+    // Windows server configuration files, like web.config, should never be
+    // staged either. (These can be written in the vendor directory by the
+    // core-vendor-hardening plugin, which is used in the drupal/legacy-project
+    // template.)
+    $event->excludePath('web.config');
+
+    if ($public = $this->getFilesPath('public')) {
+      $event->excludePath($public);
     }
-  }
-
-  /**
-   * Excludes common paths from staging operations.
-   *
-   * @param \Drupal\package_manager\Event\PreApplyEvent|\Drupal\package_manager\Event\PreCreateEvent $event
-   *   The event object.
-   *
-   * @see \Drupal\package_manager\Event\ExcludedPathsTrait::excludePath()
-   */
-  public function ignoreCommonPaths(StageEvent $event): void {
-    // Compile two lists of paths to exclude: paths that are relative to the
-    // project root, and paths that are relative to the web root.
-    $web = $project = [];
-
-    // Always ignore automated test directories. If they exist, they will be in
-    // the web root.
-    $web[] = 'sites/simpletest';
-
-    // If the core-vendor-hardening plugin (used in the legacy-project template)
-    // is present, it may have written security hardening files in the vendor
-    // directory. They should always be ignored.
-    $vendor_dir = $this->pathLocator->getVendorDirectory();
-    $project[] = $vendor_dir . '/web.config';
-    $project[] = $vendor_dir . '/.htaccess';
-
-    // Ignore public and private files. These paths could be either absolute or
-    // relative, depending on site settings. If they are absolute, treat them
-    // as relative to the project root. Otherwise, treat them as relative to
-    // the web root.
-    $files = array_filter([
-      $this->getFilesPath('public'),
-      $this->getFilesPath('private'),
-    ]);
-    foreach ($files as $path) {
-      if ($this->fileSystem->isAbsolutePath($path)) {
-        $project[] = $path;
-      }
-      else {
-        $web[] = $path;
-      }
+    if ($private = $this->getFilesPath('private')) {
+      $event->excludePath($private);
     }
 
-    // Ignore site-specific settings files, which are always in the web root.
+    // Exclude site-specific settings files.
     $settings_files = [
       'settings.php',
       'settings.local.php',
       'services.yml',
     ];
+    $default_site = 'sites' . DIRECTORY_SEPARATOR . 'default';
+
     foreach ($settings_files as $settings_file) {
-      $web[] = $this->sitePath . '/' . $settings_file;
-      $web[] = 'sites/default/' . $settings_file;
+      $event->excludePath($this->sitePath . DIRECTORY_SEPARATOR . $settings_file);
+      $event->excludePath($default_site . DIRECTORY_SEPARATOR . $settings_file);
     }
 
     // If the database is SQLite, it might be located in the active directory
-    // and we should ignore it. Always treat it as relative to the project root.
+    // and we should not stage it.
     if ($this->database->driver() === 'sqlite') {
       $options = $this->database->getConnectionOptions();
-      $project[] = $options['database'];
-      $project[] = $options['database'] . '-shm';
-      $project[] = $options['database'] . '-wal';
+      $database = str_replace($this->appRoot, NULL, $options['database']);
+      $database = ltrim($database, '/');
+      $event->excludePath($database);
+      $event->excludePath("$database-shm");
+      $event->excludePath("$database-wal");
     }
-
-    $this->excludeInWebRoot($event, $web);
-    $this->excludeInProjectRoot($event, $project);
-  }
-
-  /**
-   * Reacts before staged changes are committed the active directory.
-   *
-   * @param \Drupal\package_manager\Event\PreApplyEvent $event
-   *   The event object.
-   */
-  public function preApply(PreApplyEvent $event): void {
-    // Don't copy anything from the staging area's sites/default.
-    // @todo Make this a lot smarter in https://www.drupal.org/i/3228955.
-    $this->excludeInWebRoot($event, ['sites/default']);
-
-    $this->ignoreCommonPaths($event);
   }
 
   /**
@@ -226,7 +165,7 @@ class ExcludedPathsSubscriber implements EventSubscriberInterface {
    */
   public static function getSubscribedEvents() {
     return [
-      PreCreateEvent::class => 'ignoreCommonPaths',
+      PreCreateEvent::class => 'preCreate',
       PreApplyEvent::class => 'preApply',
     ];
   }
diff --git a/package_manager/src/FileSyncerFactory.php b/package_manager/src/FileSyncerFactory.php
index ee96aa1e57..727620a248 100644
--- a/package_manager/src/FileSyncerFactory.php
+++ b/package_manager/src/FileSyncerFactory.php
@@ -3,9 +3,9 @@
 namespace Drupal\package_manager;
 
 use Drupal\Core\Config\ConfigFactoryInterface;
-use PhpTuf\ComposerStager\Domain\FileSyncer\FileSyncerFactoryInterface;
-use PhpTuf\ComposerStager\Domain\FileSyncer\FileSyncerInterface;
+use PhpTuf\ComposerStager\Infrastructure\FileSyncer\FileSyncerFactoryInterface;
 use PhpTuf\ComposerStager\Infrastructure\FileSyncer\FileSyncerFactory as StagerFileSyncerFactory;
+use PhpTuf\ComposerStager\Infrastructure\FileSyncer\FileSyncerInterface;
 use Symfony\Component\Process\ExecutableFinder;
 
 /**
@@ -16,21 +16,21 @@ class FileSyncerFactory implements FileSyncerFactoryInterface {
   /**
    * The decorated file syncer factory.
    *
-   * @var \PhpTuf\ComposerStager\Domain\FileSyncer\FileSyncerFactoryInterface
+   * @var \PhpTuf\ComposerStager\Infrastructure\FileSyncer\FileSyncerFactoryInterface
    */
   protected $decorated;
 
   /**
    * The PHP file syncer service.
    *
-   * @var \PhpTuf\ComposerStager\Domain\FileSyncer\FileSyncerInterface
+   * @var \PhpTuf\ComposerStager\Infrastructure\FileSyncer\FileSyncerInterface
    */
   protected $phpFileSyncer;
 
   /**
    * The rsync file syncer service.
    *
-   * @var \PhpTuf\ComposerStager\Domain\FileSyncer\FileSyncerInterface
+   * @var \PhpTuf\ComposerStager\Infrastructure\FileSyncer\FileSyncerInterface
    */
   protected $rsyncFileSyncer;
 
@@ -46,9 +46,9 @@ class FileSyncerFactory implements FileSyncerFactoryInterface {
    *
    * @param \Symfony\Component\Process\ExecutableFinder $executable_finder
    *   The Symfony executable finder.
-   * @param \PhpTuf\ComposerStager\Domain\FileSyncer\FileSyncerInterface $php_file_syncer
+   * @param \PhpTuf\ComposerStager\Infrastructure\FileSyncer\FileSyncerInterface $php_file_syncer
    *   The PHP file syncer service.
-   * @param \PhpTuf\ComposerStager\Domain\FileSyncer\FileSyncerInterface $rsync_file_syncer
+   * @param \PhpTuf\ComposerStager\Infrastructure\FileSyncer\FileSyncerInterface $rsync_file_syncer
    *   The rsync file syncer service.
    * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
    *   The config factory service.
diff --git a/package_manager/tests/fixtures/fake_site/vendor/.htaccess b/package_manager/tests/fixtures/fake_site/vendor/.htaccess
deleted file mode 100644
index e11552b41d..0000000000
--- a/package_manager/tests/fixtures/fake_site/vendor/.htaccess
+++ /dev/null
@@ -1 +0,0 @@
-# This file should never be staged.
diff --git a/package_manager/tests/modules/package_manager_bypass/src/Beginner.php b/package_manager/tests/modules/package_manager_bypass/src/Beginner.php
index e9ff25509f..742d38bd85 100644
--- a/package_manager/tests/modules/package_manager_bypass/src/Beginner.php
+++ b/package_manager/tests/modules/package_manager_bypass/src/Beginner.php
@@ -3,7 +3,7 @@
 namespace Drupal\package_manager_bypass;
 
 use PhpTuf\ComposerStager\Domain\BeginnerInterface;
-use PhpTuf\ComposerStager\Domain\Process\OutputCallbackInterface;
+use PhpTuf\ComposerStager\Domain\Output\ProcessOutputCallbackInterface;
 
 /**
  * Defines an update beginner which doesn't do anything.
@@ -13,7 +13,7 @@ class Beginner extends InvocationRecorderBase implements BeginnerInterface {
   /**
    * {@inheritdoc}
    */
-  public function begin(string $activeDir, string $stagingDir, ?array $exclusions = [], ?OutputCallbackInterface $callback = NULL, ?int $timeout = 120): void {
+  public function begin(string $activeDir, string $stagingDir, ?array $exclusions = [], ?ProcessOutputCallbackInterface $callback = NULL, ?int $timeout = 120): void {
     $this->saveInvocationArguments($activeDir, $stagingDir, $exclusions);
   }
 
diff --git a/package_manager/tests/modules/package_manager_bypass/src/Committer.php b/package_manager/tests/modules/package_manager_bypass/src/Committer.php
index 2feb0d0f70..3518237b5b 100644
--- a/package_manager/tests/modules/package_manager_bypass/src/Committer.php
+++ b/package_manager/tests/modules/package_manager_bypass/src/Committer.php
@@ -3,7 +3,7 @@
 namespace Drupal\package_manager_bypass;
 
 use PhpTuf\ComposerStager\Domain\CommitterInterface;
-use PhpTuf\ComposerStager\Domain\Process\OutputCallbackInterface;
+use PhpTuf\ComposerStager\Domain\Output\ProcessOutputCallbackInterface;
 
 /**
  * Defines an update committer which doesn't do any actual committing.
@@ -30,7 +30,7 @@ class Committer extends InvocationRecorderBase implements CommitterInterface {
   /**
    * {@inheritdoc}
    */
-  public function commit(string $stagingDir, string $activeDir, ?array $exclusions = [], ?OutputCallbackInterface $callback = NULL, ?int $timeout = 120): void {
+  public function commit(string $stagingDir, string $activeDir, ?array $exclusions = [], ?ProcessOutputCallbackInterface $callback = NULL, ?int $timeout = 120): void {
     $this->saveInvocationArguments($activeDir, $stagingDir, $exclusions);
   }
 
diff --git a/package_manager/tests/modules/package_manager_bypass/src/Stager.php b/package_manager/tests/modules/package_manager_bypass/src/Stager.php
index 237eccab38..bb93e47271 100644
--- a/package_manager/tests/modules/package_manager_bypass/src/Stager.php
+++ b/package_manager/tests/modules/package_manager_bypass/src/Stager.php
@@ -2,7 +2,7 @@
 
 namespace Drupal\package_manager_bypass;
 
-use PhpTuf\ComposerStager\Domain\Process\OutputCallbackInterface;
+use PhpTuf\ComposerStager\Domain\Output\ProcessOutputCallbackInterface;
 use PhpTuf\ComposerStager\Domain\StagerInterface;
 
 /**
@@ -13,7 +13,7 @@ class Stager extends InvocationRecorderBase implements StagerInterface {
   /**
    * {@inheritdoc}
    */
-  public function stage(array $composerCommand, string $stagingDir, ?OutputCallbackInterface $callback = NULL, ?int $timeout = 120): void {
+  public function stage(array $composerCommand, string $stagingDir, ?ProcessOutputCallbackInterface $callback = NULL, ?int $timeout = 120): void {
     $this->saveInvocationArguments($composerCommand, $stagingDir);
   }
 
diff --git a/package_manager/tests/src/Functional/ExcludedPathsTest.php b/package_manager/tests/src/Functional/ExcludedPathsTest.php
index dbc3dab973..2870806996 100644
--- a/package_manager/tests/src/Functional/ExcludedPathsTest.php
+++ b/package_manager/tests/src/Functional/ExcludedPathsTest.php
@@ -117,44 +117,38 @@ class ExcludedPathsTest extends BrowserTestBase {
     };
     $stage::$stagingRoot = $this->siteDirectory . '/stage';
     $stage_dir = $stage::$stagingRoot . DIRECTORY_SEPARATOR . $stage->create();
-    $this->assertDirectoryExists($stage_dir);
 
-    $ignore = [
-      'sites/simpletest',
-      'vendor/.htaccess',
-      'vendor/web.config',
-      "$site_path/files/ignore.txt",
-      'private/ignore.txt',
-      "$site_path/settings.php",
-      "$site_path/settings.local.php",
-      "$site_path/services.yml",
-      // SQLite databases and their support files should always be ignored.
-      "$site_path/db.sqlite",
-      "$site_path/db.sqlite-shm",
-      "$site_path/db.sqlite-wal",
-      // Default site-specific settings files should be ignored.
-      'sites/default/settings.php',
-      'sites/default/settings.local.php',
-      'sites/default/services.yml',
-    ];
-    foreach ($ignore as $path) {
-      $this->assertFileExists("$active_dir/$path");
-      $this->assertFileDoesNotExist("$stage_dir/$path");
-    }
+    $this->assertDirectoryExists($stage_dir);
+    $this->assertDirectoryDoesNotExist("$stage_dir/sites/simpletest");
+    $this->assertFileDoesNotExist("$stage_dir/vendor/web.config");
+    $this->assertDirectoryDoesNotExist("$stage_dir/$site_path/files");
+    $this->assertDirectoryDoesNotExist("$stage_dir/private");
+    $this->assertFileDoesNotExist("$stage_dir/$site_path/settings.php");
+    $this->assertFileDoesNotExist("$stage_dir/$site_path/settings.local.php");
+    $this->assertFileDoesNotExist("$stage_dir/$site_path/services.yml");
+    // SQLite databases and their support files should never be staged.
+    $this->assertFileDoesNotExist("$stage_dir/$site_path/db.sqlite");
+    $this->assertFileDoesNotExist("$stage_dir/$site_path/db.sqlite-shm");
+    $this->assertFileDoesNotExist("$stage_dir/$site_path/db.sqlite-wal");
+    // Default site-specific settings files should never be staged.
+    $this->assertFileDoesNotExist("$stage_dir/sites/default/settings.php");
+    $this->assertFileDoesNotExist("$stage_dir/sites/default/settings.local.php");
+    $this->assertFileDoesNotExist("$stage_dir/sites/default/services.yml");
     // A non-excluded file in the default site directory should be staged.
     $this->assertFileExists("$stage_dir/sites/default/stage.txt");
 
-    // A new file added to the staging area in an excluded directory, should not
-    // be copied to the active directory.
-    $file = "$stage_dir/sites/default/no-copy.txt";
-    touch($file);
-    $this->assertFileExists($file);
+    $files = [
+      'sites/default/no-copy.txt',
+      'web.config',
+    ];
+    foreach ($files as $file) {
+      $file = "$stage_dir/$file";
+      touch($file);
+      $this->assertFileExists($file);
+    }
     $stage->apply();
-    $this->assertFileDoesNotExist("$active_dir/sites/default/no-copy.txt");
-
-    // The ignored files should still be in the active directory.
-    foreach ($ignore as $path) {
-      $this->assertFileExists("$active_dir/$path");
+    foreach ($files as $file) {
+      $this->assertFileDoesNotExist("$active_dir/$file");
     }
   }
 
diff --git a/package_manager/tests/src/Kernel/ComposerExecutableValidatorTest.php b/package_manager/tests/src/Kernel/ComposerExecutableValidatorTest.php
index bc57b4fa75..8905f788ed 100644
--- a/package_manager/tests/src/Kernel/ComposerExecutableValidatorTest.php
+++ b/package_manager/tests/src/Kernel/ComposerExecutableValidatorTest.php
@@ -112,8 +112,8 @@ class ComposerExecutableValidatorTest extends PackageManagerKernelTestBase {
     // Mock the output of `composer --version`, will be passed to the validator,
     // which is itself a callback function that gets called repeatedly as
     // Composer produces output.
-    /** @var \PhpTuf\ComposerStager\Domain\Process\Runner\ComposerRunnerInterface|\Prophecy\Prophecy\ObjectProphecy $runner */
-    $runner = $this->prophesize('\PhpTuf\ComposerStager\Domain\Process\Runner\ComposerRunnerInterface');
+    /** @var \PhpTuf\ComposerStager\Infrastructure\Process\Runner\ComposerRunnerInterface|\Prophecy\Prophecy\ObjectProphecy $runner */
+    $runner = $this->prophesize('\PhpTuf\ComposerStager\Infrastructure\Process\Runner\ComposerRunnerInterface');
 
     $runner->run(['--version'], Argument::type(ComposerExecutableValidator::class))
       // Whatever is passed to ::run() will be passed to this mock callback in
diff --git a/package_manager/tests/src/Kernel/ComposerSettingsValidatorTest.php b/package_manager/tests/src/Kernel/ComposerSettingsValidatorTest.php
index ff09f97428..fae703f6e0 100644
--- a/package_manager/tests/src/Kernel/ComposerSettingsValidatorTest.php
+++ b/package_manager/tests/src/Kernel/ComposerSettingsValidatorTest.php
@@ -85,7 +85,6 @@ class ComposerSettingsValidatorTest extends PackageManagerKernelTestBase {
     $locator = $this->prophesize(PathLocator::class);
     $locator->getActiveDirectory()->willReturn($active_dir);
     $locator->getProjectRoot()->willReturn($active_dir);
-    $locator->getWebRoot()->willReturn('');
     $locator->getVendorDirectory()->willReturn($active_dir);
     $this->container->set('package_manager.path_locator', $locator->reveal());
 
diff --git a/package_manager/tests/src/Kernel/DiskSpaceValidatorTest.php b/package_manager/tests/src/Kernel/DiskSpaceValidatorTest.php
index 3195b51d3a..ea15bb086e 100644
--- a/package_manager/tests/src/Kernel/DiskSpaceValidatorTest.php
+++ b/package_manager/tests/src/Kernel/DiskSpaceValidatorTest.php
@@ -168,7 +168,6 @@ class DiskSpaceValidatorTest extends PackageManagerKernelTestBase {
   public function testDiskSpaceValidation(bool $shared_disk, array $free_space, array $expected_results): void {
     $path_locator = $this->prophesize('\Drupal\package_manager\PathLocator');
     $path_locator->getProjectRoot()->willReturn('root');
-    $path_locator->getWebRoot()->willReturn('');
     $path_locator->getActiveDirectory()->willReturn('root');
     $path_locator->getVendorDirectory()->willReturn('vendor');
     $this->container->set('package_manager.path_locator', $path_locator->reveal());
diff --git a/package_manager/tests/src/Kernel/ExcludedPathsSubscriberTest.php b/package_manager/tests/src/Kernel/ExcludedPathsSubscriberTest.php
index 538232d5b5..b44f7811d6 100644
--- a/package_manager/tests/src/Kernel/ExcludedPathsSubscriberTest.php
+++ b/package_manager/tests/src/Kernel/ExcludedPathsSubscriberTest.php
@@ -83,15 +83,15 @@ class ExcludedPathsSubscriberTest extends PackageManagerKernelTestBase {
     $connection->getConnectionOptions()->willReturn(['database' => $database]);
 
     $subscriber = new ExcludedPathsSubscriber(
+      $this->getDrupalRoot(),
       'sites/default',
-      $this->container->get('package_manager.symfony_file_system'),
+      $this->container->get('file_system'),
       $this->container->get('stream_wrapper_manager'),
-      $connection->reveal(),
-      $this->container->get('package_manager.path_locator')
+      $connection->reveal()
     );
 
     $event = new PreCreateEvent($this->createStage());
-    $subscriber->ignoreCommonPaths($event);
+    $subscriber->preCreate($event);
     // All of the expected exclusions should be flagged.
     $this->assertEmpty(array_diff($expected_exclusions, $event->getExcludedPaths()));
   }
diff --git a/package_manager/tests/src/Kernel/WritableFileSystemValidatorTest.php b/package_manager/tests/src/Kernel/WritableFileSystemValidatorTest.php
index 871d42c4aa..136d6b37cb 100644
--- a/package_manager/tests/src/Kernel/WritableFileSystemValidatorTest.php
+++ b/package_manager/tests/src/Kernel/WritableFileSystemValidatorTest.php
@@ -113,7 +113,6 @@ class WritableFileSystemValidatorTest extends PackageManagerKernelTestBase {
 
     $path_locator = $this->prophesize(PathLocator::class);
     $path_locator->getActiveDirectory()->willReturn($root->url());
-    $path_locator->getProjectRoot()->willReturn($root->url());
     $path_locator->getWebRoot()->willReturn('');
     $path_locator->getVendorDirectory()->willReturn($vendor->url());
     $this->container->set('package_manager.path_locator', $path_locator->reveal());
diff --git a/tests/src/Build/UpdateTestBase.php b/tests/src/Build/UpdateTestBase.php
index 367e0f8241..e33f5ed6a3 100644
--- a/tests/src/Build/UpdateTestBase.php
+++ b/tests/src/Build/UpdateTestBase.php
@@ -220,7 +220,10 @@ END;
     // Packagist.
     $repositories['packagist.org'] = FALSE;
 
-    $repositories['drupal/automatic_updates'] = $this->createPathRepository(__DIR__ . '/../../..');
+    $repositories['drupal/automatic_updates'] = [
+      'type' => 'path',
+      'url' => __DIR__ . '/../../..',
+    ];
     // Use whatever the current branch of automatic_updates is.
     $data['require']['drupal/automatic_updates'] = '*';
 
diff --git a/tests/src/Kernel/ReadinessValidation/StagedProjectsValidatorTest.php b/tests/src/Kernel/ReadinessValidation/StagedProjectsValidatorTest.php
index 6a2dc5aebf..1b21d13605 100644
--- a/tests/src/Kernel/ReadinessValidation/StagedProjectsValidatorTest.php
+++ b/tests/src/Kernel/ReadinessValidation/StagedProjectsValidatorTest.php
@@ -64,7 +64,6 @@ class StagedProjectsValidatorTest extends AutomaticUpdatesKernelTestBase {
 
     $locator->getActiveDirectory()->willReturn($active_dir);
     $locator->getProjectRoot()->willReturn($active_dir);
-    $locator->getWebRoot()->willReturn('');
     $locator->getVendorDirectory()->willReturn($active_dir);
 
     $stage_dir_exists = is_dir($stage_dir);
diff --git a/tests/src/Kernel/UpdaterTest.php b/tests/src/Kernel/UpdaterTest.php
index 5881d85144..034514a3b9 100644
--- a/tests/src/Kernel/UpdaterTest.php
+++ b/tests/src/Kernel/UpdaterTest.php
@@ -51,7 +51,6 @@ class UpdaterTest extends AutomaticUpdatesKernelTestBase {
     $locator = $this->prophesize(PathLocator::class);
     $locator->getActiveDirectory()->willReturn($fixture_dir);
     $locator->getProjectRoot()->willReturn($fixture_dir);
-    $locator->getWebRoot()->willReturn('');
     $locator->getVendorDirectory()->willReturn($fixture_dir);
     $this->container->set('package_manager.path_locator', $locator->reveal());
 
-- 
GitLab