From 16967de833225c75b467775a11a7ea6ec01da9e7 Mon Sep 17 00:00:00 2001
From: Alex Pott <alex.a.pott@googlemail.com>
Date: Tue, 10 Dec 2024 08:29:23 +0000
Subject: [PATCH] Issue #3492705 by catch, nicxvan, mikelutz, longwave: Install
 modules with container_rebuild_true set by themselves

---
 core/includes/install.core.inc                   | 16 +++++++++++-----
 .../Drupal/Core/Extension/ModuleInstaller.php    | 12 +++++++++---
 .../Core/Extension/ModuleInstallerTest.php       | 14 +++++++-------
 3 files changed, 27 insertions(+), 15 deletions(-)

diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index 311fdb410c8a..6ef977a5a334 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -1610,18 +1610,24 @@ function install_profile_modules(&$install_state) {
   $batch_builder = new BatchBuilder();
 
   // Put modules into groups of up to the maximum batch size, or until a module
-  // states that it needs a container rebuild immediately after install.
+  // states that it needs a container rebuild before and after install.
   $index = 0;
   $module_groups = [];
   foreach (array_keys($required + $non_required) as $module) {
+    // If the container needs to be rebuilt, ensure this happens both before and
+    // after the module is installed.
+    // @todo Consider reversing this logic so that modules must explicitly
+    // state that they need a container build.
+    // @see https://www.drupal.org/project/drupal/issues/3492235
+    $container_rebuild_required = !isset($files[$module]->info['container_rebuild_required']) || $files[$module]->info['container_rebuild_required'];
+    if ($container_rebuild_required && !empty($module_groups[$index])) {
+      $index++;
+    }
     $module_groups[$index][] = $module;
     if (count($module_groups[$index]) === Settings::get('core.multi_module_install_batch_size', 20)) {
       $index++;
     }
-    // @todo Consider reversing this logic so that modules must explicitly
-    // state that they need a container build.
-    // @see https://www.drupal.org/project/drupal/issues/3492235
-    elseif (!isset($files[$module]->info['container_rebuild_required']) || $files[$module]->info['container_rebuild_required']) {
+    elseif ($container_rebuild_required) {
       $index++;
     }
   }
diff --git a/core/lib/Drupal/Core/Extension/ModuleInstaller.php b/core/lib/Drupal/Core/Extension/ModuleInstaller.php
index 1ae9ac54f261..4ec7515961c0 100644
--- a/core/lib/Drupal/Core/Extension/ModuleInstaller.php
+++ b/core/lib/Drupal/Core/Extension/ModuleInstaller.php
@@ -208,16 +208,22 @@ public function install(array $module_list, $enable_dependencies = TRUE) {
     // exceptions if the configuration is not valid.
     $config_installer->checkConfigurationToInstall('module', $module_list);
 
-    // Some modules require a container rebuild immediately after install.
+    // Some modules require a container rebuild before and after install.
     // Group modules such that as many are installed together as possible until
     // one needs a container rebuild.
     $module_groups = [];
     $index = 0;
     foreach ($module_list as $module) {
-      $module_groups[$index][] = $module;
+      // Ensure the container is rebuilt both before and after a module that
+      // requires a container rebuild is installed.
       // @todo Consider reversing the behavior when the info key is not set.
       // See https://www.drupal.org/project/drupal/issues/3492235
-      if (!isset($module_data[$module]->info['container_rebuild_required']) || $module_data[$module]->info['container_rebuild_required']) {
+      $container_rebuild_required = !isset($module_data[$module]->info['container_rebuild_required']) || $module_data[$module]->info['container_rebuild_required'];
+      if ($container_rebuild_required && !empty($module_groups[$index])) {
+        $index++;
+      }
+      $module_groups[$index][] = $module;
+      if ($container_rebuild_required) {
         $index++;
       }
     }
diff --git a/core/tests/Drupal/KernelTests/Core/Extension/ModuleInstallerTest.php b/core/tests/Drupal/KernelTests/Core/Extension/ModuleInstallerTest.php
index 8e29eae7dd53..f2dddc48770d 100644
--- a/core/tests/Drupal/KernelTests/Core/Extension/ModuleInstallerTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Extension/ModuleInstallerTest.php
@@ -192,14 +192,14 @@ public static function containerRebuildRequiredProvider(): array {
       [['container_rebuild_required_true'], 1],
       [['container_rebuild_required_false'], 1],
       [['container_rebuild_required_false', 'container_rebuild_required_false_2'], 1],
-      [['container_rebuild_required_false', 'container_rebuild_required_false_2', 'container_rebuild_required_true'], 1],
-      [['container_rebuild_required_false', 'container_rebuild_required_false_2', 'container_rebuild_required_true', 'container_rebuild_required_true_2'], 2],
+      [['container_rebuild_required_false', 'container_rebuild_required_false_2', 'container_rebuild_required_true'], 2],
+      [['container_rebuild_required_false', 'container_rebuild_required_false_2', 'container_rebuild_required_true', 'container_rebuild_required_true_2'], 3],
       [['container_rebuild_required_true', 'container_rebuild_required_false', 'container_rebuild_required_false_2'], 2],
-      [['container_rebuild_required_false', 'container_rebuild_required_true', 'container_rebuild_required_false_2'], 2],
-      [['container_rebuild_required_false', 'container_rebuild_required_true', 'container_rebuild_required_false_2', 'container_rebuild_required_true_2'], 2],
-      [['container_rebuild_required_true', 'container_rebuild_required_false', 'container_rebuild_required_true_2', 'container_rebuild_required_false_2'], 3],
-      [['container_rebuild_required_false_2', 'container_rebuild_required_dependency_false'], 2],
-      [['container_rebuild_required_false_2', 'container_rebuild_required_dependency_false', 'container_rebuild_required_true'], 2],
+      [['container_rebuild_required_false', 'container_rebuild_required_true', 'container_rebuild_required_false_2'], 3],
+      [['container_rebuild_required_false', 'container_rebuild_required_true', 'container_rebuild_required_false_2', 'container_rebuild_required_true_2'], 4],
+      [['container_rebuild_required_true', 'container_rebuild_required_false', 'container_rebuild_required_true_2', 'container_rebuild_required_false_2'], 4],
+      [['container_rebuild_required_false_2', 'container_rebuild_required_dependency_false'], 3],
+      [['container_rebuild_required_false_2', 'container_rebuild_required_dependency_false', 'container_rebuild_required_true'], 3],
     ];
   }
 
-- 
GitLab