diff --git a/core/includes/config.inc b/core/includes/config.inc index 31f6e5b..32ba50d 100644 --- a/core/includes/config.inc +++ b/core/includes/config.inc @@ -22,12 +22,6 @@ * The name of the module or theme to install default configuration for. */ function config_install_default_config($type, $name) { - // If this module defines any ConfigEntity types then create an empty - // manifest file for each of them. - foreach (config_get_module_config_entities($name) as $entity_info) { - config('manifest.' . $entity_info['config_prefix'])->save(); - } - $config_dir = drupal_get_path($type, $name) . '/config'; if (is_dir($config_dir)) { $source_storage = new FileStorage($config_dir); @@ -60,12 +54,6 @@ function config_uninstall_default_config($type, $name) { foreach ($config_names as $config_name) { config($config_name)->delete(); } - - // If this module defines any ConfigEntity types, then delete the manifest - // file for each of them. - foreach (config_get_module_config_entities($name) as $entity_type) { - config('manifest.' . $entity_info['config_prefix'])->delete(); - } } /** diff --git a/core/includes/update.inc b/core/includes/update.inc index e1f35be..6053cee 100644 --- a/core/includes/update.inc +++ b/core/includes/update.inc @@ -1455,29 +1455,6 @@ function update_variables_to_config($config_name, array $variable_map) { } /** - * Adds entries in a configuration entity manifest file during updates. - * - * @param string $config_prefix - * The configuration entity prefix from the annotation. - * @param array $ids - * An array of configuration entities to add to the manifest. - */ -function update_config_manifest_add($config_prefix, array $ids) { - $manifest = config('manifest.' . $config_prefix); - - // Add record to manifest for each config entity. Operate on the data array - // as a whole, because $manifest->get() would treat dots in ids as nesting. - $data = $manifest->get(); - foreach ($ids as $id) { - $data[$id] = array('name' => $config_prefix . '.' . $id); - } - $manifest->setData($data); - - // Write manifest to disk. - $manifest->save(); -} - -/** * Installs a default configuration file into the active store. * * Provide a generalised method to save a default configuration object for an diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php b/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php index 1ce4456..79554d6 100644 --- a/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php +++ b/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php @@ -373,15 +373,6 @@ public function delete(array $entities) { foreach ($entities as $id => $entity) { $config = $this->configFactory->get($this->getConfigPrefix() . $entity->id()); $config->delete(); - - // Remove the entity from the manifest file. Entity IDs can contain a dot - // so we can not use Config::clear() to remove the entity from the - // manifest. - $manifest = $this->configFactory->get('manifest.' . $this->entityInfo['config_prefix']); - $manifest_data = $manifest->get(); - unset($manifest_data[$entity->id()]); - $manifest->setData($manifest_data); - $manifest->save(); } $this->postDelete($entities); @@ -452,28 +443,6 @@ public function save(EntityInterface $entity) { $this->invokeHook('insert', $entity); } - $update_manifest = FALSE; - $config = $this->configFactory->get('manifest.' . $this->entityInfo['config_prefix']); - $manifest = $config->get(); - // If the save operation resulted in a rename remove the old entity id from - // the manifest file. - if ($id !== $entity->id()) { - // Entity IDs can contain a dot so we can not use Config::clear() to - // remove the entity from the manifest. - unset($manifest[$id]); - $update_manifest = TRUE; - } - // Add this entity to the manifest file if necessary. - if (!isset($manifest[$entity->id()])) { - $manifest[$entity->id()] = array( - 'name' => $this->getConfigPrefix() . $entity->id(), - ); - $update_manifest = TRUE; - } - if ($update_manifest) { - $config->setData($manifest)->save(); - } - unset($entity->original); return $return; diff --git a/core/lib/Drupal/Core/Config/StorageComparer.php b/core/lib/Drupal/Core/Config/StorageComparer.php index c7fa957..834f439 100644 --- a/core/lib/Drupal/Core/Config/StorageComparer.php +++ b/core/lib/Drupal/Core/Config/StorageComparer.php @@ -139,13 +139,10 @@ public function addChangelistCreate() { */ public function addChangelistUpdate() { foreach (array_intersect($this->getSourceNames(), $this->getTargetNames()) as $name) { - // Ignore manifest files. - if (substr($name, 0, 9) != 'manifest.') { - $source_config_data = $this->sourceStorage->read($name); - $target_config_data = $this->targetStorage->read($name); - if ($source_config_data !== $target_config_data) { - $this->addChangeList('update', array($name)); - } + $source_config_data = $this->sourceStorage->read($name); + $target_config_data = $this->targetStorage->read($name); + if ($source_config_data !== $target_config_data) { + $this->addChangeList('update', array($name)); } } return $this; diff --git a/core/lib/Drupal/Core/Config/StorageComparerManifest.php b/core/lib/Drupal/Core/Config/StorageComparerManifest.php deleted file mode 100644 index 2f8836d..0000000 --- a/core/lib/Drupal/Core/Config/StorageComparerManifest.php +++ /dev/null @@ -1,105 +0,0 @@ -getTargetManifestData(), $this->getSourceManifestData()) as $value) { - $this->addChangeList('delete', array($value['name'])); - } - return $this; - } - - /** - * {@inheritdoc} - */ - public function addChangelistCreate() { - foreach (array_diff_key($this->getSourceManifestData(), $this->getTargetManifestData()) as $value) { - $this->addChangeList('create', array($value['name'])); - } - return $this; - } - - /** - * Gets the list of config entities from the source storage's manifest files. - * - * @return array - * The list of config entities in the source storage whose entity type has a - * manifest in the source storage. - */ - protected function getSourceManifestData() { - if (empty($this->sourceManifestData)) { - foreach ($this->getSourceStorage()->listAll('manifest') as $name) { - if ($source_manifest_data = $this->getSourceStorage()->read($name)) { - $this->sourceManifestData = array_merge($this->sourceManifestData, $source_manifest_data); - } - } - } - return $this->sourceManifestData; - } - - /** - * Gets the list of config entities from the target storage's manifest files. - * - * @see \Drupal\Core\Config\ConfigImporter::getSourceManifestData() - * - * @return array - * The list of config entities in the target storage whose entity type has a - * manifest in the source storage. - */ - protected function getTargetManifestData() { - if (empty($this->targetManifestData)) { - foreach ($this->getSourceStorage()->listAll('manifest') as $name) { - if ($target_manifest_data = $this->targetStorage->read($name)) { - $this->targetManifestData = array_merge($this->targetManifestData, $target_manifest_data); - } - } - } - return $this->targetManifestData; - } - - /** - * {@inheritdoc} - */ - public function reset() { - $this->sourceManifestData = $this->targetManifestData = array(); - return parent::reset(); - } - -} diff --git a/core/modules/block/block.install b/core/modules/block/block.install index 8e0d224..485df95 100644 --- a/core/modules/block/block.install +++ b/core/modules/block/block.install @@ -271,7 +271,6 @@ function block_update_8008() { 'type' => 'text_textarea_with_summary', )) ->save(); - update_config_manifest_add('entity.form_display', array($form_display->get('id'))); // Initialize state for future calls. $sandbox['last'] = 0; diff --git a/core/modules/config/config.admin.inc b/core/modules/config/config.admin.inc index a961286..3a9e6f1 100644 --- a/core/modules/config/config.admin.inc +++ b/core/modules/config/config.admin.inc @@ -9,7 +9,7 @@ use Drupal\Core\Ajax\OpenModalDialogCommand; use Drupal\Core\Config\ConfigException; use Drupal\Core\Config\ConfigImporter; -use Drupal\Core\Config\StorageComparerManifest; +use Drupal\Core\Config\StorageComparer; use Drupal\Core\Config\StorageInterface; /** @@ -27,16 +27,8 @@ */ function config_admin_sync_form(array &$form, array &$form_state, StorageInterface $source_storage) { $source_list = $source_storage->listAll(); - if (empty($source_list)) { - $form['no_changes'] = array( - '#markup' => t('There is no configuration to import.'), - ); - $form['actions']['#access'] = FALSE; - return $form; - } - - $config_comparer = new StorageComparerManifest(Drupal::service('config.storage.staging'), Drupal::service('config.storage')); - if (!$config_comparer->createChangelist()->hasChanges()) { + $config_comparer = new StorageComparer(Drupal::service('config.storage.staging'), Drupal::service('config.storage')); + if (empty($source_list) || !$config_comparer->createChangelist()->hasChanges()) { $form['no_changes'] = array( '#markup' => t('There are no configuration changes.'), ); @@ -146,14 +138,6 @@ function config_admin_import_form_submit($form, &$form_state) { $config_importer->import(); drupal_flush_all_caches(); drupal_set_message(t('The configuration was imported successfully.')); - - // Once a sync completes, we empty the staging directory. This prevents - // changes from being accidentally overwritten by stray files getting - // imported later. - $source_storage = $config_importer->getStorageComparer()->getSourceStorage(); - foreach ($source_storage->listAll() as $name) { - $source_storage->delete($name); - } } catch (ConfigException $e) { // Return a negative result for UI purposes. We do not differentiate between diff --git a/core/modules/config/config.module b/core/modules/config/config.module index 8bb9d21..6ea0406 100644 --- a/core/modules/config/config.module +++ b/core/modules/config/config.module @@ -37,6 +37,19 @@ function config_permission() { } /** + * Implements hook_file_download(). + */ +function config_file_download($uri) { + $scheme = file_uri_scheme($uri); + $target = file_uri_target($uri); + if ($scheme == 'temporary' && $target == 'config.tar.gz') { + return array( + 'Content-disposition' => 'attachment; filename="config.tar.gz"', + ); + } +} + +/** * Implements hook_menu(). */ function config_menu() { @@ -48,6 +61,16 @@ function config_menu() { 'access arguments' => array('synchronize configuration'), 'file' => 'config.admin.inc', ); + $items['admin/config/development/export'] = array( + 'title' => 'Configuration export', + 'description' => 'Export your site configuration', + 'route_name' => 'config_export', + ); + $items['admin/config/development/import'] = array( + 'title' => 'Configuration import', + 'description' => 'Import configuration for your site', + 'route_name' => 'config_import', + ); $items['admin/config/development/sync/diff/%'] = array( 'title' => 'Configuration file diff', 'description' => 'Diff between active and staged configuraiton.', diff --git a/core/modules/config/config.routing.yml b/core/modules/config/config.routing.yml index 505539d..53c860c 100644 --- a/core/modules/config/config.routing.yml +++ b/core/modules/config/config.routing.yml @@ -4,3 +4,21 @@ config_diff: _content: '\Drupal\config\Controller\ConfigController::diff' requirements: _permission: 'synchronize configuration' +config_export_download: + pattern: '/admin/config/development/export-download' + defaults: + _controller: '\Drupal\config\Controller\ConfigController::downloadExport' + requirements: + _permission: 'export configuration' +config_export: + pattern: '/admin/config/development/export' + defaults: + _form: '\Drupal\config\Form\ConfigExportForm' + requirements: + _permission: 'export configuration' +config_import: + pattern: '/admin/config/development/import' + defaults: + _form: '\Drupal\config\Form\ConfigImportForm' + requirements: + _permission: 'import configuration' diff --git a/core/modules/config/lib/Drupal/config/Controller/ConfigController.php b/core/modules/config/lib/Drupal/config/Controller/ConfigController.php index 477268c..af9dda3 100644 --- a/core/modules/config/lib/Drupal/config/Controller/ConfigController.php +++ b/core/modules/config/lib/Drupal/config/Controller/ConfigController.php @@ -9,6 +9,7 @@ use Drupal\Core\ControllerInterface; use Drupal\Core\Config\StorageInterface; +use Drupal\Component\Archiver\ArchiveTar; use Drupal\Core\Ajax\AjaxResponse; use Drupal\Core\Ajax\OpenModalDialogCommand; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -53,6 +54,20 @@ public function __construct(StorageInterface $target_storage, StorageInterface $ } /** + * Downloads a tarball of the site configuration. + */ + public function downloadExport() { + $archiver = new ArchiveTar(file_directory_temp() . '/config.tar.gz', 'gz'); + $config_dir = config_get_config_directory(); + $config_files = array(); + foreach (\Drupal::service('config.storage')->listAll() as $config_name) { + $config_files[] = $config_dir . '/' . $config_name . '.yml'; + } + $archiver->createModify($config_files, '', config_get_config_directory()); + return file_download('temporary', 'config.tar.gz'); + } + + /** * Shows diff of specificed configuration file. * * @param string $config_file diff --git a/core/modules/config/lib/Drupal/config/Form/ConfigExportForm.php b/core/modules/config/lib/Drupal/config/Form/ConfigExportForm.php new file mode 100644 index 0000000..4cf5bcd --- /dev/null +++ b/core/modules/config/lib/Drupal/config/Form/ConfigExportForm.php @@ -0,0 +1,31 @@ + '

' . t('Use the export button below to download your site configuration.') . '

', + ); + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('Export'), + ); + return $form; + } + + public function validateForm(array &$form, array &$form_state) { + } + + public function submitForm(array &$form, array &$form_state) { + } +} + diff --git a/core/modules/config/lib/Drupal/config/Form/ConfigImportForm.php b/core/modules/config/lib/Drupal/config/Form/ConfigImportForm.php new file mode 100644 index 0000000..30dc2d3 --- /dev/null +++ b/core/modules/config/lib/Drupal/config/Form/ConfigImportForm.php @@ -0,0 +1,54 @@ + '

' . t('Use the upload button below.') . '

', + ); + $form['import_tarball'] = array( + '#type' => 'file', + '#value' => t('Select your configuration export file'), + '#description' => t('This form will redirect you to the import configuration screen.'), + ); + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('Upload'), + ); + return $form; + } + + public function validateForm(array &$form, array &$form_state) { + if (!empty($_FILES['files']['error']['import_tarball'])) { + form_set_error('import_tarball', t('The import tarball could not be uploaded.')); + } + else { + $form_state['values']['import_tarball'] = $_FILES['files']['tmp_name']['import_tarball']; + } + } + + public function submitForm(array &$form, array &$form_state) { + if ($path = $form_state['values']['import_tarball']) { + \Drupal::service('config.storage.staging')->deleteAll(); + $archiver = new ArchiveTar($path, 'gz'); + $files = array(); + foreach ($archiver->listContent() as $file) { + $files[] = $file['filename']; + } + $archiver->extractList($files, config_get_config_directory(CONFIG_STAGING_DIRECTORY)); + drupal_unlink($path); + drupal_set_message('Your configuration files were successfully uploaded, ready for import.'); + $form_state['redirect'] = 'admin/config/development/sync'; + } + } +} + diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigCRUDTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigCRUDTest.php index 7322324..d4c170c 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigCRUDTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigCRUDTest.php @@ -193,23 +193,6 @@ function testNameValidation() { catch (ConfigNameException $e) { $this->pass($message); } - - // Write configuration with an invalid name (missing a namespace) to - // staging. - $staging = $this->container->get('config.storage.staging'); - $manifest_data = config('manifest.invalid_object_name')->get(); - $manifest_data['new']['name'] = 'invalid'; - $staging->write('manifest.invalid_object_name', $manifest_data); - - // Verify that an exception is thrown when importing. - $message = 'Expected ConfigNameException was thrown when attempting to sync invalid configuration.'; - try { - $this->configImporter()->import(); - $this->fail($message); - } - catch (ConfigNameException $e) { - $this->pass($message); - } } - } + diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigEntityTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigEntityTest.php index e2e910f..00e1f35 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigEntityTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigEntityTest.php @@ -35,7 +35,6 @@ public static function getInfo() { * Tests CRUD operations. */ function testCRUD() { - $manifest_name = 'manifest.config_test.dynamic'; $default_langcode = language_default()->langcode; // Verify default properties on a newly created empty entity. $empty = entity_create('config_test', array()); @@ -123,10 +122,6 @@ function testCRUD() { $this->fail('EntityMalformedException was not thrown.'); } - // Verify that the config manifest entry exists. - $manifest_data = config($manifest_name)->get(); - $this->assertTrue(isset($manifest_data[$config_test->id()]), 'Configuration manifest for config_test.dynamic entities updated after an entity save.'); - // Verify that the correct status is returned and properties did not change. $this->assertIdentical($status, SAVED_NEW); $this->assertIdentical($config_test->id(), $expected['id']); @@ -181,13 +176,6 @@ function testCRUD() { // Verify that originalID points to new ID directly after renaming. $this->assertIdentical($config_test->id(), $new_id); $this->assertIdentical($config_test->getOriginalID(), $new_id); - - // Verify that the config manifest entry exists. - $manifest_data = config($manifest_name)->get(); - // Check that the old id is not in the manifest. - $this->assertFalse(isset($manifest_data[$old_id]), 'Old id removed from configuration manifest after an entity save.'); - // Check that the new id is in the manifest. - $this->assertTrue(isset($manifest_data[$new_id]), 'New id added to configuration manifest after an entity save.'); } // Test config entity prepopulation. diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigImportUITest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigImportUITest.php index c2863f7..6296ed5 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigImportUITest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigImportUITest.php @@ -29,6 +29,7 @@ function setUp() { $this->web_user = $this->drupalCreateUser(array('synchronize configuration')); $this->drupalLogin($this->web_user); + $this->copyConfig($this->container->get('config.storage'), $this->container->get('config.storage.staging')); } /** @@ -40,13 +41,8 @@ function testImport() { $storage = $this->container->get('config.storage'); $staging = $this->container->get('config.storage.staging'); - // Verify the configuration to create and update does not exist yet. - $this->assertIdentical($staging->exists($name), FALSE, $name . ' not found.'); - $this->assertIdentical($staging->exists($dynamic_name), FALSE, $dynamic_name . ' not found.'); - - // Verify that the import UI recognises that the staging folder is empty. $this->drupalGet('admin/config/development/sync'); - $this->assertText('There is no configuration to import.'); + $this->assertText('There are no configuration changes.'); $this->assertNoFieldById('edit-submit', t('Import all')); // Create updated configuration object. @@ -66,15 +62,9 @@ function testImport() { 'protected_property' => '', ); $staging->write($dynamic_name, $original_dynamic_data); - - // Create manifest for new config entity. - $manifest_data = config('manifest.config_test.dynamic')->get(); - $manifest_data[$original_dynamic_data['id']]['name'] = 'config_test.dynamic.' . $original_dynamic_data['id']; - $staging->write('manifest.config_test.dynamic', $manifest_data); - $this->assertIdentical($staging->exists($dynamic_name), TRUE, $dynamic_name . ' found.'); - // Verify that both appear as new. + // Verify that both appear as ready to import. $this->drupalGet('admin/config/development/sync'); $this->assertText($name); $this->assertText($dynamic_name); @@ -82,13 +72,12 @@ function testImport() { // Import and verify that both do not appear anymore. $this->drupalPost(NULL, array(), t('Import all')); - $this->assertUrl('admin/config/development/sync'); $this->assertNoText($name); $this->assertNoText($dynamic_name); $this->assertNoFieldById('edit-submit', t('Import all')); // Verify that there are no further changes to import. - $this->assertText(t('There is no configuration to import.')); + $this->assertText(t('There are no configuration changes.')); // Verify site name has changed. $this->assertIdentical($new_site_name, config('system.site')->get('name')); @@ -118,7 +107,6 @@ function testImportLock() { // Attempt to import configuration and verify that an error message appears. $this->drupalPost(NULL, array(), t('Import all')); - $this->assertUrl('admin/config/development/sync'); $this->assertText(t('Another request may be synchronizing configuration already.')); // Release the lock, just to keep testing sane. diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigImporterTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigImporterTest.php index 0160ee3..28a63b7 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigImporterTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigImporterTest.php @@ -8,7 +8,8 @@ namespace Drupal\config\Tests; use Drupal\Core\Config\ConfigImporter; -use Drupal\Core\Config\StorageComparerManifest; +use Drupal\Core\Config\ConfigImporterException; +use Drupal\Core\Config\StorageComparer; use Drupal\simpletest\DrupalUnitTestBase; /** @@ -50,9 +51,10 @@ function setUp() { unset($GLOBALS['hook_config_test']); // Set up the ConfigImporter object for testing. - $config_comparer = new StorageComparerManifest( + $config_comparer = new StorageComparer( $this->container->get('config.storage.staging'), - $this->container->get('config.storage')); + $this->container->get('config.storage') + ); $this->configImporter = new ConfigImporter( $config_comparer->createChangelist(), $this->container->get('event_dispatcher'), @@ -60,6 +62,7 @@ function setUp() { $this->container->get('plugin.manager.entity'), $this->container->get('lock') ); + $this->copyConfig($this->container->get('config.storage'), $this->container->get('config.storage.staging')); } /** @@ -77,6 +80,20 @@ function testNoImport() { } /** + * Tests that trying to import from an empty staging configuration directory fails. + */ + function testEmptyImportFails() { + try { + $this->container->get('config.storage.staging')->deleteAll(); + $this->configImporter->reset()->import(); + $this->assertFalse(FALSE, "ConfigImporterException not thrown, we didn't stop an empty import."); + } + catch (ConfigImporterException $e) { + $this->assertTrue(TRUE, 'ConfigImporterException thrown, successfully stopping an empty import.'); + } + } + + /** * Tests deletion of configuration during import. */ function testDeleted() { @@ -88,12 +105,13 @@ function testDeleted() { $config = config($dynamic_name); $this->assertIdentical($config->get('id'), 'dotted.default'); - // Create an empty manifest to delete the configuration object. - $staging->write('manifest.config_test.dynamic', array()); + // Delete the file from the staging directory. + $staging->delete($dynamic_name); + // Import. $this->configImporter->reset()->import(); - // Verify the values have disappeared. + // Verify the file has been removed. $this->assertIdentical($storage->read($dynamic_name), FALSE); $config = config($dynamic_name); @@ -122,8 +140,6 @@ function testNew() { // Verify the configuration to create does not exist yet. $this->assertIdentical($storage->exists($dynamic_name), FALSE, $dynamic_name . ' not found.'); - $this->assertIdentical($staging->exists($dynamic_name), FALSE, $dynamic_name . ' not found.'); - // Create new config entity. $original_dynamic_data = array( 'id' => 'new', @@ -137,11 +153,6 @@ function testNew() { ); $staging->write($dynamic_name, $original_dynamic_data); - // Create manifest for new config entity. - $manifest_data = config('manifest.config_test.dynamic')->get(); - $manifest_data[$original_dynamic_data['id']]['name'] = 'config_test.dynamic.' . $original_dynamic_data['id']; - $staging->write('manifest.config_test.dynamic', $manifest_data); - $this->assertIdentical($staging->exists($dynamic_name), TRUE, $dynamic_name . ' found.'); // Import. @@ -185,9 +196,6 @@ function testUpdated() { $original_dynamic_data = $storage->read($dynamic_name); $original_dynamic_data['label'] = 'Updated'; $staging->write($dynamic_name, $original_dynamic_data); - // Create manifest for updated config entity. - $manifest_data = config('manifest.config_test.dynamic')->get(); - $staging->write('manifest.config_test.dynamic', $manifest_data); // Verify the active configuration still returns the default values. $config = config($name); @@ -219,5 +227,5 @@ function testUpdated() { // Verify that there is nothing more to import. $this->assertFalse($this->configImporter->hasUnprocessedChanges()); } - } + diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigInstallTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigInstallTest.php index 4cb9ea3..3d4093d 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigInstallTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigInstallTest.php @@ -35,13 +35,6 @@ function setUp() { function testModuleInstallation() { $default_config = 'config_test.system'; $default_configuration_entity = 'config_test.dynamic.dotted.default'; - $default_config_manifest = 'manifest.config_test.dynamic'; - $expected_manifest_data = array( - 'dotted.default' => array( - 'name' => 'config_test.dynamic.dotted.default', - ), - ); - $default_empty_config_manifest = 'manifest.config_test.empty_manifest'; // Verify that default module config does not exist before installation yet. $config = config($default_config); @@ -49,12 +42,6 @@ function testModuleInstallation() { $config = config($default_configuration_entity); $this->assertIdentical($config->isNew(), TRUE); - // Verify that configuration entity manifests do not exist. - $config = config($default_config_manifest); - $this->assertIdentical($config->isNew(), TRUE); - $config = config($default_empty_config_manifest); - $this->assertIdentical($config->isNew(), TRUE); - // Install the test module. $this->enableModules(array('config_test')); $this->installConfig(array('config_test')); @@ -65,13 +52,6 @@ function testModuleInstallation() { $config = config($default_configuration_entity); $this->assertIdentical($config->isNew(), FALSE); - // Verify that configuration entity manifests have been created with - // expected contents. - $config = config($default_config_manifest); - $this->assertIdentical($config->get(), $expected_manifest_data); - $config = config($default_empty_config_manifest); - $this->assertIdentical($config->get(), array()); - // Verify that configuration import callback was invoked for the dynamic // configuration entity. $this->assertTrue($GLOBALS['hook_config_import']); diff --git a/core/modules/config/tests/config_test/lib/Drupal/config_test/Plugin/Core/Entity/ConfigTestEmptyManifest.php b/core/modules/config/tests/config_test/lib/Drupal/config_test/Plugin/Core/Entity/ConfigTestEmptyManifest.php deleted file mode 100644 index a122204..0000000 --- a/core/modules/config/tests/config_test/lib/Drupal/config_test/Plugin/Core/Entity/ConfigTestEmptyManifest.php +++ /dev/null @@ -1,55 +0,0 @@ -id = $category->cid; - // Save the id to add to the manifest file. - $ids[] = $category->id; // Save default category setting. if ($category->selected) { config('contact.settings') @@ -79,8 +76,6 @@ function contact_update_8001() { ->set('langcode', Language::LANGCODE_NOT_SPECIFIED) ->save(); } - - update_config_manifest_add('contact.category', $ids); } /** diff --git a/core/modules/contact/lib/Drupal/contact/Tests/ContactUpgradePathTest.php b/core/modules/contact/lib/Drupal/contact/Tests/ContactUpgradePathTest.php index de5d002..4c61653 100644 --- a/core/modules/contact/lib/Drupal/contact/Tests/ContactUpgradePathTest.php +++ b/core/modules/contact/lib/Drupal/contact/Tests/ContactUpgradePathTest.php @@ -64,10 +64,6 @@ public function testContactUpgrade() { // Check that no default config imported on upgrade. $this->assertFalse(entity_load('contact_category', 'feedback')); - - // Assert that manifest has been created and contains the expected records. - $manifest = config('manifest.contact.category'); - $this->assertEqual($manifest->get('1.name'), 'contact.category.1'); - $this->assertEqual($manifest->get('2.name'), 'contact.category.2'); } } + diff --git a/core/modules/field/field.install b/core/modules/field/field.install index 24b2950..2f544e6 100644 --- a/core/modules/field/field.install +++ b/core/modules/field/field.install @@ -376,13 +376,11 @@ function field_update_8002() { foreach ($form_displays as $config) { $config->save(); } - update_config_manifest_add('entity.form_display', array_keys($form_displays)); // Save the displays to configuration. foreach ($displays as $config) { $config->save(); } - update_config_manifest_add('entity.display', array_keys($displays)); } /** @@ -390,7 +388,6 @@ function field_update_8002() { */ function field_update_8003() { $uuid = new Uuid(); - $manifest_ids = array('fields' => array(), 'instances' => array()); $state = Drupal::state(); $deleted_fields = $state->get('field.field.deleted') ?: array(); @@ -435,7 +432,6 @@ function field_update_8003() { Drupal::config('field.field.' . $config['id']) ->setData($config) ->save(); - $manifest_ids['fields'][] = $config['id']; } else { $config['deleted'] = TRUE; @@ -492,7 +488,6 @@ function field_update_8003() { Drupal::config('field.instance.' . $config['id']) ->setData($config) ->save(); - $manifest_ids['instances'][] = $config['id']; } else { $config['deleted'] = TRUE; @@ -511,10 +506,6 @@ function field_update_8003() { } } - // Create the manifest files. - update_config_manifest_add('field.field', $manifest_ids['fields']); - update_config_manifest_add('field.instance', $manifest_ids['instances']); - // Save the deleted fields and instances in state. $state->set('field.field.deleted', $deleted_fields); $state->set('field.instance.deleted', $deleted_instances); diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldImportChangeTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldImportChangeTest.php index 70e7286..523687b 100644 --- a/core/modules/field/lib/Drupal/field/Tests/FieldImportChangeTest.php +++ b/core/modules/field/lib/Drupal/field/Tests/FieldImportChangeTest.php @@ -37,20 +37,14 @@ function testImportChange() { // Import default config. $this->installConfig(array('field_test_config')); - - // Simulate config data to import: - // - the current manifest for field instances, - // - a modified version (modified label) of the instance config. - $manifest_name = 'manifest.field.instance'; $active = $this->container->get('config.storage'); - $manifest = $active->read($manifest_name); + $staging = $this->container->get('config.storage.staging'); + $this->copyConfig($active, $staging); + + // Save as files in the the staging directory. $instance = $active->read($instance_config_name); $new_label = 'Test update import field'; $instance['label'] = $new_label; - - // Save as files in the the staging directory. - $staging = $this->container->get('config.storage.staging'); - $staging->write($manifest_name, $manifest); $staging->write($instance_config_name, $instance); // Import the content of the staging directory. @@ -60,5 +54,5 @@ function testImportChange() { $instance = entity_load('field_instance', $instance_id); $this->assertEqual($instance['label'], $new_label, 'Instance label updated'); } - } + diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldImportCreateTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldImportCreateTest.php index 577de45..fe9f5c6 100644 --- a/core/modules/field/lib/Drupal/field/Tests/FieldImportCreateTest.php +++ b/core/modules/field/lib/Drupal/field/Tests/FieldImportCreateTest.php @@ -49,25 +49,15 @@ function testImportCreate() { $field_config_name = "field.field.$field_id"; $instance_config_name = "field.instance.$instance_id"; - // Simulate config data to import: + $active = $this->container->get('config.storage'); + $staging = $this->container->get('config.storage.staging'); + $this->copyConfig($active, $staging); + + // Add the new files to the staging directory. $src_dir = drupal_get_path('module', 'field_test_config') . '/staging'; $this->assertTrue(file_unmanaged_copy("$src_dir/$field_config_name.yml", "public://config_staging/$field_config_name.yml")); $this->assertTrue(file_unmanaged_copy("$src_dir/$instance_config_name.yml", "public://config_staging/$instance_config_name.yml")); - // Add the coresponding entries to the current manifest data. - $field_manifest_name = 'manifest.field.field'; - $instance_manifest_name = 'manifest.field.instance'; - $active = $this->container->get('config.storage'); - $field_manifest = $active->read($field_manifest_name); - $field_manifest[$field_id] = array('name' => $field_config_name); - $instance_manifest = $active->read($instance_manifest_name); - $instance_manifest[$instance_id] = array('name' => $instance_config_name); - - // Save the manifests as files in the the staging directory. - $staging = $this->container->get('config.storage.staging'); - $staging->write($field_manifest_name, $field_manifest); - $staging->write($instance_manifest_name, $instance_manifest); - // Import the content of the staging directory. $this->configImporter()->import(); @@ -77,5 +67,5 @@ function testImportCreate() { $instance = entity_load('field_instance', $instance_id); $this->assertTrue($instance, 'Test import field instance from staging exists'); } - } + diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldImportDeleteTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldImportDeleteTest.php index c1ac59a..d6bf26a 100644 --- a/core/modules/field/lib/Drupal/field/Tests/FieldImportDeleteTest.php +++ b/core/modules/field/lib/Drupal/field/Tests/FieldImportDeleteTest.php @@ -30,7 +30,7 @@ public static function getInfo() { /** * Tests deleting fields and instances as part of config import. */ - function testImportDelete() { + public function testImportDelete() { $field_id = 'field_test_import'; $instance_id = "test_entity.test_bundle.$field_id"; $field_config_name = "field.field.$field_id"; @@ -46,24 +46,11 @@ function testImportDelete() { $this->assertTrue($instance, 'The field instance was created.'); $field_uuid = $field->uuid; - - // Simulate config data to import: - // - the current manifest for fields, without the entry for the field we - // remove, - // - the current manifest for instances, without the entry for the instance - // we remove. - $field_manifest_name = 'manifest.field.field'; - $instance_manifest_name = 'manifest.field.instance'; $active = $this->container->get('config.storage'); - $field_manifest = $active->read($field_manifest_name); - unset($field_manifest[$field_id]); - $instance_manifest = $active->read($instance_manifest_name); - unset($instance_manifest[$instance_id]); - - // Save as files in the the staging directory. $staging = $this->container->get('config.storage.staging'); - $staging->write($field_manifest_name, $field_manifest); - $staging->write($instance_manifest_name, $instance_manifest); + $this->copyConfig($active, $staging); + $staging->delete($field_config_name); + $staging->delete($instance_config_name); // Import the content of the staging directory. $this->configImporter()->import(); @@ -89,5 +76,5 @@ function testImportDelete() { $deleted_fields = \Drupal::state()->get('field.field.deleted') ?: array(); $this->assertTrue(empty($deleted_fields), 'Fields are deleted'); } - } + diff --git a/core/modules/filter/filter.install b/core/modules/filter/filter.install index 45955ad..b450c36 100644 --- a/core/modules/filter/filter.install +++ b/core/modules/filter/filter.install @@ -52,7 +52,6 @@ function filter_update_8001() { $config = config('filter.format.' . $id); $config->setData($format); $config->save(); - update_config_manifest_add('filter.format', array($id)); } } diff --git a/core/modules/image/lib/Drupal/image/Tests/ImageAdminStylesTest.php b/core/modules/image/lib/Drupal/image/Tests/ImageAdminStylesTest.php index dc51c16..f7e5d35 100644 --- a/core/modules/image/lib/Drupal/image/Tests/ImageAdminStylesTest.php +++ b/core/modules/image/lib/Drupal/image/Tests/ImageAdminStylesTest.php @@ -364,11 +364,11 @@ function testConfigImport() { $this->drupalGet('node/' . $nid); $this->assertRaw(image_style_url($style_name, file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['fid'])->uri), format_string('Image displayed using style @style.', array('@style' => $style_name))); - // Write empty manifest to staging. - $manifest_data = config('manifest.image.style')->get(); - unset($manifest_data[$style_name]); + // Copy config to staging, and delete the image style. $staging = $this->container->get('config.storage.staging'); - $staging->write('manifest.image.style', $manifest_data); + $active = $this->container->get('config.storage'); + $this->copyConfig($active, $staging); + $staging->delete('image.style.' . $style_name); $this->configImporter()->import(); $this->assertFalse(entity_load('image_style', $style_name), 'Style deleted after config import.'); diff --git a/core/modules/menu/menu.install b/core/modules/menu/menu.install index a76207b..ae94f90 100644 --- a/core/modules/menu/menu.install +++ b/core/modules/menu/menu.install @@ -86,6 +86,6 @@ function menu_update_8004() { ->set('label', $menu->title) ->set('description', $menu->description) ->save(); - update_config_manifest_add('menu.menu', array($menu->menu_name)); } } + diff --git a/core/modules/shortcut/shortcut.install b/core/modules/shortcut/shortcut.install index 4a84150..d78fa3b 100644 --- a/core/modules/shortcut/shortcut.install +++ b/core/modules/shortcut/shortcut.install @@ -91,7 +91,6 @@ function shortcut_update_8000() { ->save(); $ids[] = $set->set_name; } - update_config_manifest_add('shortcut.set', $ids); } /** diff --git a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php index f07e249..c766a61 100644 --- a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php +++ b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php @@ -10,9 +10,10 @@ use Drupal\Core\Database\Database; use Drupal\Component\Utility\Settings; use Drupal\Core\Config\ConfigImporter; -use Drupal\Core\Config\StorageComparerManifest; +use Drupal\Core\Config\StorageComparer; use Drupal\Core\DependencyInjection\ContainerBuilder; use Drupal\Core\Database\ConnectionNotDefinedException; +use Drupal\Core\Config\StorageInterface; use Drupal\Core\DrupalKernel; use Drupal\Core\Language\Language; use ReflectionMethod; @@ -1292,9 +1293,10 @@ public static function filePreDeleteCallback($path) { public function configImporter() { if (!$this->configImporter) { // Set up the ConfigImporter object for testing. - $config_comparer = new StorageComparerManifest( + $config_comparer = new StorageComparer( $this->container->get('config.storage.staging'), - $this->container->get('config.storage')); + $this->container->get('config.storage') + ); $this->configImporter = new ConfigImporter( $config_comparer, $this->container->get('event_dispatcher'), @@ -1306,4 +1308,19 @@ public function configImporter() { // Always recalculate the changelist when called. return $this->configImporter->reset(); } + + /** + * Copies configuration objects from source storage to target storage. + * + * @param \Drupal\Core\Config\StorageInterface $source_storage + * The source config storage service. + * @param \Drupal\Core\Config\StorageInterface $target_storage + * The target config storage service. + */ + public function copyConfig(StorageInterface $source_storage, StorageInterface $target_storage) { + $target_storage->deleteAll(); + foreach ($source_storage->listAll() as $name) { + $target_storage->write($name, $source_storage->read($name)); + } + } } diff --git a/core/modules/system/lib/Drupal/system/SystemConfigSubscriber.php b/core/modules/system/lib/Drupal/system/SystemConfigSubscriber.php new file mode 100644 index 0000000..4f6cc82 --- /dev/null +++ b/core/modules/system/lib/Drupal/system/SystemConfigSubscriber.php @@ -0,0 +1,39 @@ +getConfigImporter(); + $importList = $importer->getStorageComparer()->getSourceStorage()->listAll(); + if (empty($importerList)) { + throw new ConfigImporterException("This import will delete all your active configuration, I'm bailing out now."); + } + } +} + diff --git a/core/modules/system/lib/Drupal/system/Tests/Upgrade/FieldUpgradePathTest.php b/core/modules/system/lib/Drupal/system/Tests/Upgrade/FieldUpgradePathTest.php index 3fb464e..ab3e56d 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Upgrade/FieldUpgradePathTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/FieldUpgradePathTest.php @@ -43,13 +43,6 @@ public function testEntityDisplayUpgrade() { $this->assertTrue(!empty($displays['default'])); $this->assertTrue(!empty($displays['teaser'])); - // Check that manifest entries for the 'article' node type were correctly - // created. - $manifest = config('manifest.entity.display'); - $data = $manifest->get(); - $this->assertEqual($data['node.article.default'], array('name' => 'entity.display.node.article.default')); - $this->assertEqual($data['node.article.teaser'], array('name' => 'entity.display.node.article.teaser')); - // Check that the 'body' field is configured as expected. $expected = array( 'default' => array( @@ -98,12 +91,6 @@ public function testEntityFormDisplayUpgrade() { $form_display = config('entity.form_display.node.article.default')->get(); $this->assertTrue(!empty($form_display)); - // Check that manifest entries for the 'article' node type were correctly - // created. - $manifest = config('manifest.entity.form_display'); - $data = $manifest->get(); - $this->assertEqual($data['node.article.default'], array('name' => 'entity.form_display.node.article.default')); - // Check that the 'body' field is configured as expected. $expected = array( 'type' => 'text_textarea_with_summary', @@ -133,9 +120,6 @@ public function testEntityFormDisplayUpgrade() { function testFieldUpgradeToConfig() { $this->assertTrue($this->performUpgrade(), t('The upgrade was completed successfully.')); - $field_manifest = config('manifest.field.field')->get(); - $instance_manifest = config('manifest.field.instance')->get(); - // Check that the configuration for the 'body' field is correct. $config = \Drupal::config('field.field.body')->get(); // We cannot predict the value of the UUID, we just check it's present. @@ -164,8 +148,6 @@ function testFieldUpgradeToConfig() { 'status' => 1, 'langcode' => 'und', )); - // Check that an entry is present in the manifest. - $this->assertEqual($field_manifest['body']['name'], 'field.field.body'); // Check that the configuration for the instance on article and page nodes // is correct. @@ -193,8 +175,6 @@ function testFieldUpgradeToConfig() { 'status' => 1, 'langcode' => 'und', )); - // Check that an entry is present in the manifest. - $this->assertEqual($instance_manifest["node.$node_type.body"]['name'], "field.instance.node.$node_type.body"); } // Check that field values in a pre-existing node are read correctly. diff --git a/core/modules/system/lib/Drupal/system/Tests/Upgrade/ShortcutUpgradePathTest.php b/core/modules/system/lib/Drupal/system/Tests/Upgrade/ShortcutUpgradePathTest.php index 36f6ca3..cc5b61d 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Upgrade/ShortcutUpgradePathTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/ShortcutUpgradePathTest.php @@ -47,11 +47,6 @@ public function testContactUpgrade() { $set = entity_load('shortcut', 'shortcut-set-2'); $this->assertTrue($set->uuid(), 'Converted set has a UUID'); $this->assertEqual($set->label(), 'Custom shortcut set'); - - // Assert that manifest has been created and contains the expected records. - $manifest = config('manifest.shortcut.set'); - $this->assertEqual($manifest->get('default.name'), 'shortcut.set.default'); - $this->assertEqual($manifest->get('shortcut-set-2.name'), 'shortcut.set.shortcut-set-2'); } - } + diff --git a/core/modules/system/system.install b/core/modules/system/system.install index 3824136..d276b10 100644 --- a/core/modules/system/system.install +++ b/core/modules/system/system.install @@ -390,7 +390,7 @@ function system_requirements($phase) { elseif ($phase == 'install') { // For the installer UI, we need different wording. 'value' will // be treated as version, so provide none there. - $description = $error . $t('An automated attempt to create this directory failed, possibly due to a permissions problem. To proceed with the installation, either create the directory and modify its permissions manually or ensure that the installer has the permissions to create it automatically. For more information, see INSTALL.txt or the online handbook.', array('@handbook_url' => 'http://drupal.org/server-permissions', '@install_txt' => base_path() . 'core/INSTALL.txt')); + $description = $error . $t('An automated attempt to create this directory failed, possibly due to a permissions problem. To proceed with the installation, either create the directory and modify its permissions manually or ensure that the installer has the permissions to create it automatically. For more information, see INSTALL.txt or the online handbook.', array('@handbook_url' => 'http://drupal.org/server-permissions')); $requirements['file system']['value'] = ''; } if (!empty($description)) { diff --git a/core/modules/user/user.install b/core/modules/user/user.install index ed56aed..27f1b19 100644 --- a/core/modules/user/user.install +++ b/core/modules/user/user.install @@ -758,7 +758,6 @@ function user_update_8011() { 'weight' => -1, )) ->save(); - update_config_manifest_add('entity.form_display', array($form_display->get('id'))); // Assign display settings for the 'default' and 'compact' view modes. $display = _update_8000_entity_get_display('user', 'user', 'default'); @@ -772,7 +771,6 @@ function user_update_8011() { 'weight' => 0, )) ->save(); - update_config_manifest_add('entity.display', array($display->get('id'))); $display = _update_8000_entity_get_display('user', 'user', 'compact'); $display->set('content.user_picture', array( @@ -785,7 +783,6 @@ function user_update_8011() { 'weight' => 0, )) ->save(); - update_config_manifest_add('entity.display', array($display->get('id'))); // Add file usage for the default field. if (!empty($default_image_fid)) { @@ -1051,10 +1048,6 @@ function user_update_8017() { ->set('langcode', Language::LANGCODE_NOT_SPECIFIED) ->save(); } - - update_config_manifest_add('user.role', array_map(function ($role) { - return $role->rid; - }, $roles)); } /**