Skip to content

Commit 8bd590f

Browse files
author
Nathaniel Catchpole
committed
Issue #3031740 by alexpott, tmanhollan, catch, collinhaines: Updating to 8.6.8 or 8.6.9 with Drush 8 causes data loss via update_fix_compatibility()
(cherry picked from commit 9340bf9)
1 parent 1feffcf commit 8bd590f

File tree

4 files changed

+108
-4
lines changed

4 files changed

+108
-4
lines changed

includes/update.inc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ use Drupal\Core\Utility\Error;
1616
* Disables any extensions that are incompatible with the current core version.
1717
*/
1818
function update_fix_compatibility() {
19+
// Fix extension objects if the update is being done via Drush 8. In non-Drush
20+
// environments this will already be fixed by the UpdateKernel this point.
21+
UpdateKernel::fixSerializedExtensionObjects(\Drupal::getContainer());
22+
1923
$extension_config = \Drupal::configFactory()->getEditable('core.extension');
2024
$save = FALSE;
2125
foreach (['module', 'theme'] as $type) {
@@ -30,10 +34,6 @@ function update_fix_compatibility() {
3034
$extension_config->set('module', module_config_sort($extension_config->get('module')));
3135
$extension_config->save();
3236
}
33-
34-
// Fix extension objects if the update is being done via Drush 8. In non-Drush
35-
// environments this will already be fixed by the UpdateKernel this point.
36-
UpdateKernel::fixSerializedExtensionObjects(\Drupal::getContainer());
3737
}
3838

3939
/**

lib/Drupal/Core/Update/UpdateKernel.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,9 @@ public static function fixSerializedExtensionObjects(ContainerInterface $contain
219219
// will be PHP warnings. This silently fixes Drupal so that the update can
220220
// continue.
221221
$callable = function () use ($container) {
222+
// Reset static caches in profile list so the module list is rebuilt
223+
// correctly.
224+
$container->get('extension.list.profile')->reset();
222225
foreach ($container->getParameter('cache_bins') as $service_id => $bin) {
223226
$container->get($service_id)->deleteAll();
224227
}

modules/system/system.install

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use Drupal\Core\Entity\ContentEntityTypeInterface;
1818
use Drupal\Core\Entity\EntityTypeInterface;
1919
use Drupal\Core\Entity\FieldableEntityInterface;
2020
use Drupal\Core\DrupalKernel;
21+
use Drupal\Core\Extension\Extension;
2122
use Drupal\Core\Field\BaseFieldDefinition;
2223
use Drupal\Core\Site\Settings;
2324
use Drupal\Core\StreamWrapper\PrivateStream;
@@ -2173,3 +2174,67 @@ function system_update_8501() {
21732174
}
21742175
}
21752176
}
2177+
2178+
/**
2179+
* Fix missing install profile after updating to Drupal 8.6.9 with Drush 8.
2180+
*/
2181+
function system_update_8601() {
2182+
$extension_config = \Drupal::configFactory()->getEditable('core.extension');
2183+
$install_profile = $extension_config->get('profile');
2184+
if (!$install_profile) {
2185+
// There's no install profile configured.
2186+
return;
2187+
}
2188+
$modules = $extension_config->get('module');
2189+
if (isset($modules[$install_profile])) {
2190+
// The install profile is already in the installed module list.
2191+
return;
2192+
}
2193+
2194+
// Ensure the install profile is available.
2195+
if (!\Drupal::service('extension.list.module')->exists($install_profile)) {
2196+
return t('The %install_profile install profile configured in core.extension is not available.', ['%install_profile' => $install_profile]);
2197+
}
2198+
2199+
// Add the install profile to the list of enabled modules.
2200+
$modules[$install_profile] = 1000;
2201+
$modules = module_config_sort($modules);
2202+
$extension_config
2203+
->set('module', $modules)
2204+
->save(TRUE);
2205+
2206+
// Build a module list from the updated extension configuration.
2207+
$current_module_filenames = \Drupal::moduleHandler()->getModuleList();
2208+
$current_modules = array_fill_keys(array_keys($current_module_filenames), 0);
2209+
$current_modules = module_config_sort(array_merge($current_modules, $extension_config->get('module')));
2210+
$module_filenames = [];
2211+
foreach ($current_modules as $name => $weight) {
2212+
if (isset($current_module_filenames[$name])) {
2213+
$module_filenames[$name] = $current_module_filenames[$name];
2214+
}
2215+
else {
2216+
$module_path = \Drupal::service('extension.list.module')->getPath($name);
2217+
$pathname = "$module_path/$name.info.yml";
2218+
$filename = file_exists($module_path . "/$name.module") ? "$name.module" : NULL;
2219+
$module_filenames[$name] = new Extension(\Drupal::root(), 'module', $pathname, $filename);
2220+
}
2221+
}
2222+
2223+
// Update the module handler list to contain the missing install profile.
2224+
\Drupal::moduleHandler()->setModuleList($module_filenames);
2225+
\Drupal::moduleHandler()->load($install_profile);
2226+
2227+
// Clear the static cache of the "extension.list.module" service to pick
2228+
// up the new install profile correctly.
2229+
\Drupal::service('extension.list.profile')->reset();
2230+
2231+
// Clear the static cache of the "extension.list.module" service to pick
2232+
// up the new module, since it merges the installation status of modules
2233+
// into its statically cached list.
2234+
\Drupal::service('extension.list.module')->reset();
2235+
2236+
// Update the kernel to include the missing profile.
2237+
\Drupal::service('kernel')->updateModules($module_filenames, $module_filenames);
2238+
2239+
return t('The %install_profile install profile has been added to the installed module list.', ['%install_profile' => $install_profile]);
2240+
}

modules/system/tests/src/Functional/Update/WarmCacheUpdateFrom8dot6Test.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Drupal\Tests\system\Functional\Update;
44

5+
use Drupal\Core\Database\Database;
56
use Drupal\FunctionalTests\Update\UpdatePathTestBase;
67
use Symfony\Component\DependencyInjection\ContainerInterface;
78

@@ -39,6 +40,41 @@ public function testUpdatedSite() {
3940
$this->assertSame('Australia/Sydney', $this->config('system.date')->get('timezone.default'));
4041
}
4142

43+
/**
44+
* Tests system_update_8601().
45+
*/
46+
public function testWithMissingProfile() {
47+
// Remove the install profile from the module list to simulate how Drush 8
48+
// and update_fix_compatibility() worked together to remove the install
49+
// profile. See https://www.drupal.org/project/drupal/issues/3031740.
50+
$connection = Database::getConnection();
51+
$config = $connection->select('config')
52+
->fields('config', ['data'])
53+
->condition('collection', '')
54+
->condition('name', 'core.extension')
55+
->execute()
56+
->fetchField();
57+
$config = unserialize($config);
58+
unset($config['module']['minimal']);
59+
$connection->update('config')
60+
->fields([
61+
'data' => serialize($config),
62+
'collection' => '',
63+
'name' => 'core.extension',
64+
])
65+
->condition('collection', '')
66+
->condition('name', 'core.extension')
67+
->execute();
68+
69+
$this->runUpdates();
70+
$this->assertSession()->pageTextContains('The minimal install profile has been added to the installed module list.');
71+
72+
// Login and check that the status report is working correctly.
73+
$this->drupalLogin($this->rootUser);
74+
$this->drupalGet('admin/reports/status');
75+
$this->assertSession()->pageTextContains("Installation Profile Minimal");
76+
}
77+
4278
/**
4379
* {@inheritdoc}
4480
*/

0 commit comments

Comments
 (0)