diff --git a/core/lib/Drupal/Core/EventSubscriber/ConfigImportSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/ConfigImportSubscriber.php index 28af01b..6a69082 100644 --- a/core/lib/Drupal/Core/EventSubscriber/ConfigImportSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/ConfigImportSubscriber.php @@ -13,6 +13,7 @@ use Drupal\Core\Config\ConfigImportValidateEventSubscriberBase; use Drupal\Core\Config\ConfigNameException; use Drupal\Core\Extension\ThemeHandlerInterface; +use Drupal\Core\Site\Settings; /** * Config import subscriber for config import events. @@ -116,18 +117,27 @@ protected function validateModules(ConfigImporter $config_importer) { } } + // Settings is safe to use because settings.php is written before any module + // is installed. + $install_profile = Settings::get('install_profile'); // 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)) { + if ($module_data[$dependent_module]->status && !in_array($dependent_module, $uninstalls, TRUE) && $dependent_module !== $install_profile) { $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.', array('%module' => $module_name, '%dependent_module' => $dependent_module_name))); } } } + + // Ensure that the install profile is not being uninstalled. + if (in_array($install_profile, $uninstalls)) { + $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.', array('%profile' => $profile_name))); + } } /** diff --git a/core/modules/config/src/Tests/ConfigImportInstallProfileTest.php b/core/modules/config/src/Tests/ConfigImportInstallProfileTest.php new file mode 100644 index 0000000..64b2d5d --- /dev/null +++ b/core/modules/config/src/Tests/ConfigImportInstallProfileTest.php @@ -0,0 +1,84 @@ +webUser = $this->drupalCreateUser(array('synchronize configuration')); + $this->drupalLogin($this->webUser); + $this->copyConfig($this->container->get('config.storage'), $this->container->get('config.storage.staging')); + } + + /** + * Tests config importer cannot uninstall install profiles. + * + * @see \Drupal\Core\EventSubscriber\ConfigImportSubscriber + */ + public function testInstallProfileValidation() { + $staging = $this->container->get('config.storage.staging'); + $this->copyConfig($this->container->get('config.storage'), $staging); + $core = $staging->read('core.extension'); + + // Ensure install profiles can not be uninstalled. + unset($core['module']['testing_config_import']); + $staging->write('core.extension', $core); + + $this->drupalPostForm('admin/config/development/configuration', array(), 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.'); + + // Uninstall dependencies of testing_config_import. + $core['module']['testing_config_import'] = 0; + unset($core['module']['syslog']); + unset($core['theme']['stark']); + $core['theme']['classy'] = 0; + $staging->write('core.extension', $core); + $staging->deleteAll('syslog.'); + $theme = $staging->read('system.theme'); + $theme['default'] = 'classy'; + $staging->write('system.theme', $theme); + $this->drupalPostForm('admin/config/development/configuration', array(), t('Import all')); + $this->assertText('The configuration was imported successfully.'); + $this->rebuildContainer(); + $this->assertFalse(\Drupal::moduleHandler()->moduleExists('syslog'), 'The syslog module has been uninstalled.'); + $this->assertFalse(\Drupal::service('theme_handler')->themeExists('stark'), 'The stark theme has been uninstalled.'); + $this->assertTrue(\Drupal::service('theme_handler')->themeExists('classy'), 'The classy theme has been installed.'); + } + +} diff --git a/core/modules/config/src/Tests/ConfigImporterTest.php b/core/modules/config/src/Tests/ConfigImporterTest.php index c830b45..ad21c78 100644 --- a/core/modules/config/src/Tests/ConfigImporterTest.php +++ b/core/modules/config/src/Tests/ConfigImporterTest.php @@ -648,4 +648,29 @@ public function testMissingCoreExtension() { } } + /** + * Tests install profile validation during configuration import. + * + * @see \Drupal\Core\EventSubscriber\ConfigImportSubscriber + */ + public function testInstallProfile() { + $staging = $this->container->get('config.storage.staging'); + + $extensions = $staging->read('core.extension'); + // Add an install profile. + $extensions['module']['standard'] = 0; + + $staging->write('core.extension', $extensions); + try { + $this->configImporter->reset()->import(); + $this->fail('ConfigImporterException not thrown; an invalid import was not stopped due to missing dependencies.'); + } + catch (ConfigImporterException $e) { + $this->assertEqual($e->getMessage(), 'There were errors validating the config synchronization.'); + $error_log = $this->configImporter->getErrors(); + // Install profiles should not even be scanned at this point. + $this->assertEqual(['Unable to install the standard module since it does not exist.'], $error_log); + } + } + } diff --git a/core/profiles/testing_config_import/testing_config_import.info.yml b/core/profiles/testing_config_import/testing_config_import.info.yml new file mode 100644 index 0000000..2bfba5c --- /dev/null +++ b/core/profiles/testing_config_import/testing_config_import.info.yml @@ -0,0 +1,10 @@ +name: 'Testing config import' +type: profile +description: 'Tests install profiles in the config importer.' +version: VERSION +core: 8.x +hidden: true +dependencies: + - syslog +themes: + - stark