diff -u b/core/lib/Drupal/Core/Extension/ProfileHandler.php b/core/lib/Drupal/Core/Extension/ProfileHandler.php --- b/core/lib/Drupal/Core/Extension/ProfileHandler.php +++ b/core/lib/Drupal/Core/Extension/ProfileHandler.php @@ -151,17 +151,22 @@ // Ensure all dependencies are cleanly merged. $info['dependencies'] = array_merge($info['dependencies'], $base_info['dependencies']); - // Apply excluded dependencies. - $info['dependencies'] = array_diff($info['dependencies'], $info['base profile']['excluded_dependencies']); + if (isset($info['base profile']['excluded_dependencies'])) { + // Apply excluded dependencies. + $info['dependencies'] = array_diff($info['dependencies'], $info['base profile']['excluded_dependencies']); + } // Ensure there's no circular dependency. $info['dependencies'] = array_diff($info['dependencies'], [$profile]); // Ensure all themes are cleanly merged. $info['themes'] = array_unique(array_merge($info['themes'], $base_info['themes'])); - // Apply excluded themes. - $info['themes'] = array_diff($info['themes'], $info['base profile']['excluded_themes']); + if (isset($info['base profile']['excluded_themes'])) { + // Apply excluded themes. + $info['themes'] = array_diff($info['themes'], $info['base profile']['excluded_themes']); + } // Ensure each theme is listed only once. $info['themes'] = array_unique($info['themes']); + } $profile_list[$profile] = $profile; $info['profile_list'] = $profile_list; diff -u b/core/modules/system/src/Form/ModulesUninstallForm.php b/core/modules/system/src/Form/ModulesUninstallForm.php --- b/core/modules/system/src/Form/ModulesUninstallForm.php +++ b/core/modules/system/src/Form/ModulesUninstallForm.php @@ -143,11 +143,10 @@ $form['uninstall'][$module->getName()]['#disabled'] = TRUE; } // All modules which depend on this one must be uninstalled first, before - // we can allow this module to be uninstalled. (The installation profile - // is excluded from this list.) - $dependents = array_diff_key($module->required_by, $profiles); - foreach (array_keys($dependents) as $dependent) { - if (drupal_get_installed_schema_version($dependent) != SCHEMA_UNINSTALLED) { + // we can allow this module to be uninstalled. (Installation profiles are + // excluded from this list.) + foreach (array_keys($module->required_by) as $dependent) { + if (!in_array($dependent, array_keys($profiles)) && drupal_get_installed_schema_version($dependent) != SCHEMA_UNINSTALLED) { $name = isset($modules[$dependent]->info['name']) ? $modules[$dependent]->info['name'] : $dependent; $form['modules'][$module->getName()]['#required_by'][] = $name; $form['uninstall'][$module->getName()]['#disabled'] = TRUE; diff -u b/core/modules/system/system.module b/core/modules/system/system.module --- b/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -1044,15 +1044,17 @@ } // This must be done after _system_rebuild_module_data_ensure_required(). - $profile = drupal_get_profile(); - if ($profile && isset($modules[$profile])) { - // The installation profile is required, if it's a valid module. - $modules[$profile]->info['required'] = TRUE; - // Add a default distribution name if the profile did not provide one. - // @see install_profile_info() - // @see drupal_install_profile_distribution_name() - if (!isset($modules[$profile]->info['distribution']['name'])) { - $modules[$profile]->info['distribution']['name'] = 'Drupal'; + $profiles = \Drupal::service('profile_handler')->getProfiles(); + foreach ($profiles as $profile_name => $profile) { + if (isset($modules[$profile_name])) { + // Installation profiles are required, if it's a valid module. + $modules[$profile_name]->info['required'] = TRUE; + // Add a default distribution name if the profile did not provide one. + // @see install_profile_info() + // @see drupal_install_profile_distribution_name() + if (!isset($modules[$profile_name]->info['distribution']['name'])) { + $modules[$profile_name]->info['distribution']['name'] = 'Drupal'; + } } } diff -u b/core/profiles/testing_inherited/tests/src/Functional/InheritedProfileTest.php b/core/profiles/testing_inherited/tests/src/Functional/InheritedProfileTest.php --- b/core/profiles/testing_inherited/tests/src/Functional/InheritedProfileTest.php +++ b/core/profiles/testing_inherited/tests/src/Functional/InheritedProfileTest.php @@ -21,7 +21,7 @@ /** * Tests inherited installation profile. */ - function testInheritedProfile() { + public function testInheritedProfile() { // Check that the stable_login block exists. $this->assertInstanceOf(BlockInterface::class, Block::load('stable_login')); only in patch2: unchanged: --- a/core/lib/Drupal/Core/EventSubscriber/ConfigImportSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/ConfigImportSubscriber.php @@ -111,16 +111,24 @@ protected function validateModules(ConfigImporter $config_importer) { } } - // Get the install profile from the site's configuration. + // Get the active install profile from the site's configuration. $current_core_extension = $config_importer->getStorageComparer()->getTargetStorage()->read('core.extension'); - $install_profile = isset($current_core_extension['profile']) ? $current_core_extension['profile'] : NULL; + if (isset($current_core_extension['profile'])) { + // Ensure the active profile is not changing. + if ($current_core_extension['profile'] !== $core_extension['profile']) { + $config_importer->logError($this->t('Cannot change the install profile from %new_profile to %profile once Drupal is installed.', ['%profile' => $install_profile, '%new_profile' => $core_extension['profile']])); + } + } + + // Get a list of installed profiles. + $installed_profiles = \Drupal::service('profile_handler')->getProfiles(); // Ensure that all modules being uninstalled are not required by modules // that will be installed after the import. $uninstalls = $config_importer->getExtensionChangelist('module', 'uninstall'); foreach ($uninstalls as $module) { foreach (array_keys($module_data[$module]->required_by) as $dependent_module) { - if ($module_data[$dependent_module]->status && !in_array($dependent_module, $uninstalls, TRUE) && $dependent_module !== $install_profile) { + if ($module_data[$dependent_module]->status && !in_array($dependent_module, $uninstalls, TRUE) && (!array_key_exists($dependent_module, $installed_profiles))) { $module_name = $module_data[$module]->info['name']; $dependent_module_name = $module_data[$dependent_module]->info['name']; $config_importer->logError($this->t('Unable to uninstall the %module module since the %dependent_module module is installed.', ['%module' => $module_name, '%dependent_module' => $dependent_module_name])); @@ -128,15 +136,17 @@ protected function validateModules(ConfigImporter $config_importer) { } } - // Ensure that the install profile is not being uninstalled. - if (in_array($install_profile, $uninstalls, TRUE)) { - $profile_name = $module_data[$install_profile]->info['name']; - $config_importer->logError($this->t('Unable to uninstall the %profile profile since it is the install profile.', ['%profile' => $profile_name])); - } - - // Ensure the profile is not changing. - if ($install_profile !== $core_extension['profile']) { - $config_importer->logError($this->t('Cannot change the install profile from %new_profile to %profile once Drupal is installed.', ['%profile' => $install_profile, '%new_profile' => $core_extension['profile']])); + // Ensure that none of the installed profiles are being uninstalled. + if ($profile_uninstalls = array_intersect_key($installed_profiles, array_flip($uninstalls))) { + foreach ($profile_uninstalls as $profile) { + $profile_names[] = $profile->info['name']; + } + $message = $this->formatPlural(count($profile_names), + 'Unable to uninstall the %profile profile since it is an installed profile.', + 'Unable to uninstall the %profile profiles since they are installed profiles.', + ['%profile' => implode(', ', $profile_names)] + ); + $config_importer->logError($message); } } only in patch2: unchanged: --- a/core/lib/Drupal/Core/Extension/ModuleInstaller.php +++ b/core/lib/Drupal/Core/Extension/ModuleInstaller.php @@ -330,7 +330,7 @@ public function uninstall(array $module_list, $uninstall_dependents = TRUE) { if ($uninstall_dependents) { // Add dependent modules to the list. The new modules will be processed as // the while loop continues. - $profile = drupal_get_profile(); + $profiles = \Drupal::service('profile_handler')->getProfiles(); while (list($module) = each($module_list)) { foreach (array_keys($module_data[$module]->required_by) as $dependent) { if (!isset($module_data[$dependent])) { @@ -338,8 +338,8 @@ public function uninstall(array $module_list, $uninstall_dependents = TRUE) { return FALSE; } - // Skip already uninstalled modules. - if (isset($installed_modules[$dependent]) && !isset($module_list[$dependent]) && $dependent != $profile) { + // Skip already uninstalled modules and dependencies of profiles. + if (isset($installed_modules[$dependent]) && !isset($module_list[$dependent]) && (!array_key_exists($dependent, $profiles))) { $module_list[$dependent] = $dependent; } } only in patch2: unchanged: --- a/core/modules/config/src/Tests/ConfigImportInstallProfileTest.php +++ b/core/modules/config/src/Tests/ConfigImportInstallProfileTest.php @@ -56,7 +56,7 @@ public function testInstallProfileValidation() { $this->drupalPostForm('admin/config/development/configuration', [], t('Import all')); $this->assertText('The configuration cannot be imported because it failed validation for the following reasons:'); - $this->assertText('Unable to uninstall the Testing config import profile since it is the install profile.'); + $this->assertText('Unable to uninstall the Testing config import profile since it is an installed profile.'); // Uninstall dependencies of testing_config_import. $core['module']['testing_config_import'] = 0;