From e5d8457dece96d3dcb664fa0c2df0d42613f27f7 Mon Sep 17 00:00:00 2001
From: phenaproxima <phenaproxima@205645.no-reply.drupal.org>
Date: Tue, 21 Sep 2021 15:59:39 +0000
Subject: [PATCH] Issue #3232959 by phenaproxima: Make it possible to choose
 which file copier to use

---
 .../config/schema/package_manager.schema.yml  |  7 ++
 package_manager/package_manager.services.yml  |  3 +-
 package_manager/src/FileCopierFactory.php     | 84 +++++++++++++++++++
 .../src/Kernel/FileCopierFactoryTest.php      | 66 +++++++++++++++
 4 files changed, 159 insertions(+), 1 deletion(-)
 create mode 100644 package_manager/config/schema/package_manager.schema.yml
 create mode 100644 package_manager/src/FileCopierFactory.php
 create mode 100644 package_manager/tests/src/Kernel/FileCopierFactoryTest.php

diff --git a/package_manager/config/schema/package_manager.schema.yml b/package_manager/config/schema/package_manager.schema.yml
new file mode 100644
index 0000000000..53cac8d50d
--- /dev/null
+++ b/package_manager/config/schema/package_manager.schema.yml
@@ -0,0 +1,7 @@
+package_manager.settings:
+  type: config_object
+  label: 'Package Manager settings'
+  mapping:
+    file_copier:
+      type: string
+      label: 'Which file copier to use, or NULL to auto-detect'
diff --git a/package_manager/package_manager.services.yml b/package_manager/package_manager.services.yml
index 3c0d4d8c28..2b4c19f733 100644
--- a/package_manager/package_manager.services.yml
+++ b/package_manager/package_manager.services.yml
@@ -44,11 +44,12 @@ services:
       - '@package_manager.symfony_finder'
       - '@package_manager.symfony_finder'
   package_manager.file_copier.factory:
-    class: PhpTuf\ComposerStager\Infrastructure\Process\FileCopier\FileCopierFactory
+    class: Drupal\package_manager\FileCopierFactory
     arguments:
       - '@package_manager.symfony_executable_finder'
       - '@package_manager.file_copier.php'
       - '@package_manager.file_copier.rsync'
+      - '@config.factory'
   package_manager.file_copier:
     class: PhpTuf\ComposerStager\Infrastructure\Process\FileCopier\FileCopierInterface
     factory: ['@package_manager.file_copier.factory', 'create']
diff --git a/package_manager/src/FileCopierFactory.php b/package_manager/src/FileCopierFactory.php
new file mode 100644
index 0000000000..27f26ef219
--- /dev/null
+++ b/package_manager/src/FileCopierFactory.php
@@ -0,0 +1,84 @@
+<?php
+
+namespace Drupal\package_manager;
+
+use Drupal\Core\Config\ConfigFactoryInterface;
+use PhpTuf\ComposerStager\Infrastructure\Process\FileCopier\FileCopierFactory as StagerFileCopierFactory;
+use PhpTuf\ComposerStager\Infrastructure\Process\FileCopier\FileCopierFactoryInterface;
+use PhpTuf\ComposerStager\Infrastructure\Process\FileCopier\FileCopierInterface;
+use PhpTuf\ComposerStager\Infrastructure\Process\FileCopier\PhpFileCopierInterface;
+use PhpTuf\ComposerStager\Infrastructure\Process\FileCopier\RsyncFileCopierInterface;
+use Symfony\Component\Process\ExecutableFinder;
+
+/**
+ * A file copier factory which returns file copiers according to configuration.
+ */
+class FileCopierFactory implements FileCopierFactoryInterface {
+
+  /**
+   * The decorated file copier factory.
+   *
+   * @var \PhpTuf\ComposerStager\Infrastructure\Process\FileCopier\FileCopierFactoryInterface
+   */
+  protected $decorated;
+
+  /**
+   * The PHP file copier service.
+   *
+   * @var \PhpTuf\ComposerStager\Infrastructure\Process\FileCopier\PhpFileCopierInterface
+   */
+  protected $phpFileCopier;
+
+  /**
+   * The rsync file copier service.
+   *
+   * @var \PhpTuf\ComposerStager\Infrastructure\Process\FileCopier\RsyncFileCopierInterface
+   */
+  protected $rsyncFileCopier;
+
+  /**
+   * The config factory service.
+   *
+   * @var \Drupal\Core\Config\ConfigFactoryInterface
+   */
+  protected $configFactory;
+
+  /**
+   * Constructs a FileCopierFactory object.
+   *
+   * @param \Symfony\Component\Process\ExecutableFinder $executable_finder
+   *   The Symfony executable finder.
+   * @param \PhpTuf\ComposerStager\Infrastructure\Process\FileCopier\PhpFileCopierInterface $php_file_copier
+   *   The PHP file copier service.
+   * @param \PhpTuf\ComposerStager\Infrastructure\Process\FileCopier\RsyncFileCopierInterface $rsync_file_copier
+   *   The rsync file copier service.
+   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
+   *   The config factory service.
+   */
+  public function __construct(ExecutableFinder $executable_finder, PhpFileCopierInterface $php_file_copier, RsyncFileCopierInterface $rsync_file_copier, ConfigFactoryInterface $config_factory) {
+    $this->decorated = new StagerFileCopierFactory($executable_finder, $php_file_copier, $rsync_file_copier);
+    $this->phpFileCopier = $php_file_copier;
+    $this->rsyncFileCopier = $rsync_file_copier;
+    $this->configFactory = $config_factory;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function create(): FileCopierInterface {
+    $copier = $this->configFactory->get('package_manager.settings')
+      ->get('file_copier');
+
+    switch ($copier) {
+      case 'rsync':
+        return $this->rsyncFileCopier;
+
+      case 'php':
+        return $this->phpFileCopier;
+
+      default:
+        return $this->decorated->create();
+    }
+  }
+
+}
diff --git a/package_manager/tests/src/Kernel/FileCopierFactoryTest.php b/package_manager/tests/src/Kernel/FileCopierFactoryTest.php
new file mode 100644
index 0000000000..b992ebc1c1
--- /dev/null
+++ b/package_manager/tests/src/Kernel/FileCopierFactoryTest.php
@@ -0,0 +1,66 @@
+<?php
+
+namespace Drupal\Tests\package_manager\Kernel;
+
+use Drupal\KernelTests\KernelTestBase;
+
+/**
+ * @covers \Drupal\package_manager\FileCopierFactory
+ *
+ * @group package_manager
+ */
+class FileCopierFactoryTest extends KernelTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = ['package_manager'];
+
+  /**
+   * Data provider for ::testFactory().
+   *
+   * @return mixed[][]
+   *   Sets of arguments to pass to the test method.
+   */
+  public function providerFactory(): array {
+    return [
+      ['rsync'],
+      ['php'],
+      [NULL],
+    ];
+  }
+
+  /**
+   * Tests creating a file copier using our specialized factory class.
+   *
+   * @param string|null $configured_copier
+   *   The copier to use, as configured in automatic_updates.settings. Can be
+   *   'rsync', 'php', or NULL.
+   *
+   * @dataProvider providerFactory
+   */
+  public function testFactory(?string $configured_copier): void {
+    $factory = $this->container->get('package_manager.file_copier.factory');
+
+    switch ($configured_copier) {
+      case 'rsync':
+        $expected_copier = $this->container->get('package_manager.file_copier.rsync');
+        break;
+
+      case 'php':
+        $expected_copier = $this->container->get('package_manager.file_copier.php');
+        break;
+
+      default:
+        $expected_copier = $factory->create();
+        break;
+    }
+
+    $this->config('package_manager.settings')
+      ->set('file_copier', $configured_copier)
+      ->save();
+
+    $this->assertSame($expected_copier, $factory->create());
+  }
+
+}
-- 
GitLab