diff --git a/core/includes/update.inc b/core/includes/update.inc index e1f35be..a294490 100644 --- a/core/includes/update.inc +++ b/core/includes/update.inc @@ -15,6 +15,7 @@ use Drupal\Core\DrupalKernel; use Drupal\Component\Uuid\Uuid; use Drupal\Component\Utility\NestedArray; +use Symfony\Component\HttpFoundation\Request; /** * Minimum schema version of Drupal 7 required for upgrade to Drupal 8. @@ -102,8 +103,10 @@ function update_prepare_d8_bootstrap() { $settings['cache']['default'] = 'cache.backend.memory'; new Settings($settings); - // Enable UpdateBundle service overrides. - $GLOBALS['conf']['container_bundles'][] = 'Drupal\Core\DependencyInjection\UpdateBundle'; + // Enable UpdateBundle service overrides. While the container_bundles array + // does not need a key, let's use so it can be removed once the upgrade are + // finished. @see update_flush_all_caches() + $GLOBALS['conf']['container_bundles']['UpdateBundle'] = 'Drupal\Core\DependencyInjection\UpdateBundle'; // Check whether settings.php needs to be rewritten. $settings_exist = !empty($GLOBALS['config_directories']); @@ -351,10 +354,6 @@ function update_prepare_d8_bootstrap() { ':schema_uninstalled' => SCHEMA_UNINSTALLED, )); - // Populate a fixed module list (again, why did it get lost?) to avoid - // errors due to the drupal_alter() in _system_rebuild_module_data(). - $module_list['system'] = 'core/modules/system/system.module'; - drupal_container()->get('module_handler')->setModuleList($module_list); $module_data = _system_rebuild_module_data(); // Migrate each extension into configuration, varying by the extension's @@ -452,6 +451,9 @@ function update_prepare_stored_includes() { */ function update_prepare_d8_language() { if (db_table_exists('languages')) { + + module_enable(array('language')); + $languages = db_select('languages', 'l') ->fields('l') ->execute(); @@ -490,12 +492,6 @@ function update_prepare_d8_language() { // Rename the languages table to language. db_rename_table('languages', 'language'); - // Install/enable the language module. We need to use the update specific - // version of this function to ensure schema conflicts don't happen due to - // our updated data. - $modules = array('language'); - update_module_enable($modules); - // Rename language column to langcode and set it again as the primary key. if (db_field_exists('language', 'language')) { db_drop_primary_key('language'); @@ -631,7 +627,7 @@ function update_fix_d8_requirements() { // Make sure that file.module is enabled as it is required for the user // picture upgrade path. - update_module_enable(array('file')); + module_enable(array('file')); $schema = array( 'description' => 'Generic key/value storage table with an expiration.', @@ -671,73 +667,33 @@ function update_fix_d8_requirements() { ); db_create_table('key_value_expire', $schema); + // Views module is required to convert all previously existing listings into + // views configurations. + // Like any other module APIs and services, Views' services are not available + // in update.php. Existing listings are migrated into configuration, using + // the limited standard tools of raw database queries and config(). + module_enable(array('views')); + update_variable_set('update_d8_requirements', TRUE); } } /** - * Installs a new module in Drupal 8 via hook_update_N(). + * Forces a module to a given schema version. * - * @param array $modules - * List of modules to enable. Dependencies are not checked and must be - * ensured by the caller. - * @param bool $update_schema_version - * (optional) The schema version the module should be set to. Defaults to 0 - * which works well for completely new modules. + * This function is rarely necessary. * - * @return array - * List of the old schema versions keyed by the module names, - * SCHEMA_UNINSTALLED if it was not installed before. Additional manual - * installation steps like installing default configuration might be necessary - * if the module was not installed before. + * @param string $module + * Name of the module. + * @param string $schema_version + * The schema version the module should be set to. */ -function update_module_enable(array $modules, $schema_version = 0) { - $schema_store = Drupal::keyValue('system.schema'); - $old_schema = array(); - foreach ($modules as $module) { - // Check for initial schema and install it. The schema version of a newly - // installed module is always 0. Using 8000 here would be inconsistent - // since $module_update_8000() may involve a schema change, and we want - // to install the schema as it was before any updates were added. - module_load_install($module); - $function = $module . '_schema_0'; - if (function_exists($function)) { - $schema = $function(); - foreach ($schema as $table => $spec) { - db_create_table($table, $spec); - } - } - // Enable the module with a weight of 0. - $module_config = config('system.module'); - $module_config - ->set("enabled.$module", 0) - ->set('enabled', module_config_sort($module_config->get('enabled'))) - ->save(); - // Ensure the module is not contained in disabled modules. - config('system.module.disabled') - ->clear($module) - ->save(); - - $current_schema = $schema_store->get($module); - // Set the schema version if the module was not just disabled before. - if ($current_schema === NULL || $current_schema === SCHEMA_UNINSTALLED) { - // Change the schema version to the given value (defaults to 0), so any - // module updates since the module's inception are executed in a core - // upgrade. - $schema_store->set($module, $schema_version); - $old_schema[$module] = SCHEMA_UNINSTALLED; - } - else { - $old_schema[$module] = $current_schema; - } - - // system_list_reset() is in module.inc but that would only be available - // once the variable bootstrap is done. - require_once __DIR__ . '/module.inc'; - system_list_reset(); - // @todo: figure out what to do about hook_install() and hook_enable(). - } - return $old_schema; +function update_set_schema($module, $schema_version) { + Drupal::keyValue('system.schema')->set($module, $schema_version); + // system_list_reset() is in module.inc but that would only be available + // once the variable bootstrap is done. + require_once __DIR__ . '/module.inc'; + system_list_reset(); } /** @@ -935,7 +891,7 @@ function update_batch($start, $redirect = NULL, $url = NULL, $batch = array(), $ */ function update_finished($success, $results, $operations) { // Clear the caches in case the data has been updated. - drupal_flush_all_caches(); + update_flush_all_caches(); $_SESSION['update_results'] = $results; $_SESSION['update_success'] = $success; @@ -1271,7 +1227,7 @@ function update_retrieve_dependencies() { // Nothing to upgrade. continue; } - $function = $module . '_update_dependencies'; + $function = $module . '_update_dependencies'; // Ensure install file is loaded. module_load_install($module); if (function_exists($function)) { diff --git a/core/lib/Drupal/Core/Cache/DatabaseBackend.php b/core/lib/Drupal/Core/Cache/DatabaseBackend.php index 913a43b..a45d338 100644 --- a/core/lib/Drupal/Core/Cache/DatabaseBackend.php +++ b/core/lib/Drupal/Core/Cache/DatabaseBackend.php @@ -218,7 +218,7 @@ public function deleteMultiple(array $cids) { * Implements Drupal\Core\Cache\CacheBackendInterface::deleteTags(). */ public function deleteTags(array $tags) { - $tag_cache = &drupal_static('Drupal\Core\Cache\CacheBackendInterface::tagCache'); + $tag_cache = &drupal_static('Drupal\Core\Cache\CacheBackendInterface::tagCache', array()); foreach ($this->flattenTags($tags) as $tag) { unset($tag_cache[$tag]); try { @@ -277,7 +277,7 @@ public function invalidateMultiple(array $cids) { */ public function invalidateTags(array $tags) { try { - $tag_cache = &drupal_static('Drupal\Core\Cache\CacheBackendInterface::tagCache'); + $tag_cache = &drupal_static('Drupal\Core\Cache\CacheBackendInterface::tagCache', array()); foreach ($this->flattenTags($tags) as $tag) { unset($tag_cache[$tag]); $this->connection->merge('cache_tags') diff --git a/core/lib/Drupal/Core/DependencyInjection/UpdateBundle.php b/core/lib/Drupal/Core/DependencyInjection/UpdateBundle.php index 06a9522..91528e5 100644 --- a/core/lib/Drupal/Core/DependencyInjection/UpdateBundle.php +++ b/core/lib/Drupal/Core/DependencyInjection/UpdateBundle.php @@ -32,6 +32,12 @@ public function build(SymfonyContainerBuilder $container) { $container ->register('config.storage', 'Drupal\Core\Config\FileStorage') ->addArgument(config_get_config_directory(CONFIG_ACTIVE_DIRECTORY)); + $container->register('module_handler', 'Drupal\Core\Extension\UpdateModuleHandler') + ->addArgument('%container.modules%'); + $container + ->register("cache_factory", 'Drupal\Core\Cache\MemoryBackendFactory'); + $container + ->register('router.builder', 'Drupal\Core\Routing\RouteBuilderStatic'); } } diff --git a/core/lib/Drupal/Core/Extension/UpdateModuleHandler.php b/core/lib/Drupal/Core/Extension/UpdateModuleHandler.php new file mode 100644 index 0000000..a391680 --- /dev/null +++ b/core/lib/Drupal/Core/Extension/UpdateModuleHandler.php @@ -0,0 +1,136 @@ + $spec) { + db_create_table($table, $spec); + } + } + // Enable the module with a weight of 0. + $module_config = config('system.module'); + $module_config + ->set("enabled.$module", 0) + ->set('enabled', module_config_sort($module_config->get('enabled'))) + ->save(); + // Ensure the module is not contained in disabled modules. + config('system.module.disabled') + ->clear($module) + ->save(); + + $current_schema = $schema_store->get($module); + // Set the schema version if the module was not just disabled before. + if ($current_schema === NULL || $current_schema === SCHEMA_UNINSTALLED) { + // Change the schema version to the given value (defaults to 0), so any + // module updates since the module's inception are executed in a core + // upgrade. + $schema_store->set($module, 0); + $old_schema[$module] = SCHEMA_UNINSTALLED; + } + else { + $old_schema[$module] = $current_schema; + } + + // Copy the default configuration of the module into the active storage. + // The default configuration is not altered in any way, and since the module + // is just being installed, none of its configuration can exist already, so + // this is a plain copy operation from one storage to another. + $module_config_path = drupal_get_path('module', $module) . '/config'; + if (is_dir($module_config_path)) { + $module_filestorage = new FileStorage($module_config_path); + $config_storage = drupal_container()->get('config.storage'); + foreach ($module_filestorage->listAll() as $config_name) { + // If this file already exists, something in the upgrade path went + // completely wrong and we want to know. + if ($config_storage->exists($config_name)) { + throw new ConfigException(format_string('Default configuration file @name of @module module unexpectedly exists already before the module was installed.', array( + '@module' => $module, + '@name' => $config_name, + ))); + } + $config_storage->write($config_name, $module_filestorage->read($config_name)); + } + } + + // system_list_reset() is in module.inc but that would only be available + // once the variable bootstrap is done. + require_once DRUPAL_ROOT . '/core/includes/module.inc'; + system_list_reset(); + $this->moduleList[$module] = drupal_get_filename('module', $module); + $this->load($module); + drupal_classloader_register($module, dirname($this->moduleList[$module])); + // @todo Figure out what to do about hook_install() and hook_enable(). + } + return $old_schema; + } + + /** + * {@inheritdoc} + */ + public function disable($module_list, $disable_dependents = TRUE) { + throw new \LogicException('Disabling modules is not supported during updates'); + } + + /** + * {@inheritdoc} + */ + public function uninstall($module_list = array(), $uninstall_dependents = TRUE) { + throw new \LogicException('Uninstalling modules is not supported during updates'); + } + +} diff --git a/core/lib/Drupal/Core/Routing/RouteBuilderStatic.php b/core/lib/Drupal/Core/Routing/RouteBuilderStatic.php new file mode 100644 index 0000000..d6161f6 --- /dev/null +++ b/core/lib/Drupal/Core/Routing/RouteBuilderStatic.php @@ -0,0 +1,23 @@ +condition('aid', 'system_block_ip_action') ->execute(); // Enable the new Ban module. - update_module_enable(array('ban')); + module_enable(array('ban')); } else { // Drop old table. @@ -1552,7 +1552,7 @@ function system_update_8020() { */ function system_update_8021() { // Enable the module without re-installing the schema. - update_module_enable(array('action')); + module_enable(array('action')); // Rename former System module actions. $map = array( 'system_message_action' => 'action_message_action', @@ -1857,7 +1857,7 @@ function system_update_8041() { * Enable the new Entity module. */ function system_update_8042() { - update_module_enable(array('entity')); + module_enable(array('entity')); } /** @@ -1922,18 +1922,21 @@ function system_update_8045() { function system_update_8046() { $front_page = config('system.site')->get('page.front'); if (!isset($front_page) || $front_page == 'node') { - update_module_enable(array('views')); - - // Register views to the container, so views can use it's services. - $module_list = drupal_container()->getParameter('container.modules'); - drupal_load('module', 'views'); - - drupal_container()->get('kernel')->updateModules($module_list, array('views' => 'core/modules/views/views.module')); - - // This does not fire a hook just calls views. - config_install_default_config('module', 'views'); // This imports the node frontpage view. - config_install_default_config('module', 'node'); + $module = 'node'; + $config_name = 'views.view.frontpage'; + $module_config_path = drupal_get_path('module', $module) . '/config'; + $module_filestorage = new FileStorage($module_config_path); + $config_storage = drupal_container()->get('config.storage'); + // If this file already exists, something in the upgrade path went + // completely wrong and we want to know. + if ($config_storage->exists($config_name)) { + throw new ConfigException(format_string('Default configuration file @name of @module module unexpectedly exists already before the module was installed.', array( + '@module' => $module, + '@name' => $config_name, + ))); + } + $config_storage->write($config_name, $module_filestorage->read($config_name)); } } @@ -1960,7 +1963,7 @@ function system_update_8047() { */ function system_update_8048() { // Enable the module without re-installing the schema. - update_module_enable(array('menu_link')); + module_enable(array('menu_link')); // Add the langcode column if it doesn't exist. if (!db_field_exists('menu_inks', 'langcode')) { diff --git a/core/modules/toolbar/toolbar.install b/core/modules/toolbar/toolbar.install index 6732bb9..3d4f517 100644 --- a/core/modules/toolbar/toolbar.install +++ b/core/modules/toolbar/toolbar.install @@ -18,7 +18,7 @@ */ function toolbar_update_8000() { // Enable the modules without re-installing the schema. - update_module_enable(array('breakpoint')); + module_enable(array('breakpoint')); } /** diff --git a/core/modules/user/user.install b/core/modules/user/user.install index 9819cde..683957a 100644 --- a/core/modules/user/user.install +++ b/core/modules/user/user.install @@ -657,10 +657,11 @@ function user_update_8011() { // User pictures can only be migrated to the new user picture image field // if Image module is installed. if (!module_exists('image')) { - // Install image.module with schema version 8002 as a previous version - // would have to create tables that would be removed again. - $old_schema = update_module_enable(array('image'), 8002); + $old_schema = module_enable(array('image')); if ($old_schema['image'] == SCHEMA_UNINSTALLED) { + // Install image.module with schema version 8002 as a previous version + // would have to create tables that would be removed again. + update_set_schema('image', 8002); // If image.module was not installed before, install default // configuration and run the install hook. config_install_default_config('module', 'image'); diff --git a/core/modules/views/views.install b/core/modules/views/views.install index aea8d0c..d3c0dee 100644 --- a/core/modules/views/views.install +++ b/core/modules/views/views.install @@ -17,7 +17,7 @@ function views_install() { /** * Provide an initial schema. * - * @see update_module_enable(). + * @see UpdateModuleHandler::enable(). */ function views_schema_0() { module_load_install('system'); diff --git a/core/update.php b/core/update.php index cee23c4..deb3f52 100644 --- a/core/update.php +++ b/core/update.php @@ -14,6 +14,7 @@ * back to its original state! */ +use Drupal\Core\DrupalKernel; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\DependencyInjection\Reference; @@ -134,7 +135,7 @@ function update_script_selection_form($form, &$form_state) { ); // No updates to run, so caches won't get flushed later. Clear them now. - drupal_flush_all_caches(); + update_flush_all_caches(); } else { $form['help'] = array( @@ -179,6 +180,20 @@ function update_helpful_links() { } /** + * Remove update overrides and flush all caches. + * + * This will need to be run once all (if any) updates are run. Do not call this + * while updates are running. + */ +function update_flush_all_caches() { + unset($GLOBALS['conf']['container_bundles']['UpdateBundle']); + Drupal::service('kernel')->updateModules(Drupal::moduleHandler()->getModuleList()); + + // No updates to run, so caches won't get flushed later. Clear them now. + drupal_flush_all_caches(); +} + +/** * Displays results of the update script with any accompanying errors. */ function update_results_page() { @@ -435,13 +450,6 @@ function update_check_requirements($skip_warnings = FALSE) { require_once __DIR__ . '/includes/install.inc'; require_once DRUPAL_ROOT . '/core/modules/system/system.install'; - // Load module basics. - include_once __DIR__ . '/includes/module.inc'; - $module_list['system'] = 'core/modules/system/system.module'; - $module_handler = drupal_container()->get('module_handler'); - $module_handler->setModuleList($module_list); - $module_handler->load('system'); - // Set up $language, since the installer components require it. drupal_language_initialize();