diff --git a/core/lib/Drupal/Core/Extension/ExtensionDiscovery.php b/core/lib/Drupal/Core/Extension/ExtensionDiscovery.php index 3238ce6..e90cd0c 100644 --- a/core/lib/Drupal/Core/Extension/ExtensionDiscovery.php +++ b/core/lib/Drupal/Core/Extension/ExtensionDiscovery.php @@ -96,9 +96,10 @@ class ExtensionDiscovery { * @param string $root * The app root. */ - public function __construct($root) { + public function __construct($root, $use_file_cache = TRUE, $profile_directories = NULL) { $this->root = $root; - $this->fileCache = FileCacheFactory::get('extension_discovery'); + $this->fileCache = $use_file_cache ? FileCacheFactory::get('extension_discovery') : NULL; + $this->profileDirectories = $profile_directories; } /** @@ -427,7 +428,7 @@ protected function scanDirectory($dir, $include_tests) { continue; } - if ($cached_extension = $this->fileCache->get($fileinfo->getPathName())) { + if ($this->fileCache && $cached_extension = $this->fileCache->get($fileinfo->getPathName())) { $files[$cached_extension->getType()][$key] = $cached_extension; continue; } @@ -467,7 +468,10 @@ protected function scanDirectory($dir, $include_tests) { $extension->origin = $dir; $files[$type][$key] = $extension; - $this->fileCache->set($fileinfo->getPathName(), $extension); + + if ($this->fileCache) { + $this->fileCache->set($fileinfo->getPathName(), $extension); + } } return $files; } diff --git a/core/modules/system/system.routing.yml b/core/modules/system/system.routing.yml index a656ab3..3ec57c9 100644 --- a/core/modules/system/system.routing.yml +++ b/core/modules/system/system.routing.yml @@ -449,7 +449,7 @@ system.batch_page.json: _admin_route: TRUE system.db_update: - path: '/update.php/{op}' + path: '/admin/update/{op}' defaults: _title: 'Drupal database update' _controller: '\Drupal\system\Controller\DbUpdateController::handle' diff --git a/core/update.php b/core/update.php new file mode 100644 index 0000000..02ca5cc --- /dev/null +++ b/core/update.php @@ -0,0 +1,127 @@ +getPath() . '/' . $module->getName() . '.update_early.inc'; + if (file_exists($filename)) { + include_once $filename; + } +} + +/** + * Gets all available update_early functions. + * + * @return string[] + */ +function _update_get_available_update_early_functions() { + $regexp = '/^(?.+)_update_early_(?\d+)$/'; + $functions = get_defined_functions(); + + $updates = []; + foreach (preg_grep('/_\d+$/', $functions['user']) as $function) { + // If this function is a module update function, add it to the list of + // module updates. + if (preg_match($regexp, $function, $matches)) { + $updates[$matches['module']][] = $matches['version']; + } + } + + // Ensure that updates are applied in numerical order. + foreach ($updates as &$module_updates) { + sort($module_updates, SORT_NUMERIC); + } + + return $updates; +} + +// Change the directory to the Drupal root. +chdir('..'); + +$autoloader = require_once __DIR__ . '/vendor/autoload.php'; +require_once __DIR__ . '/includes/utility.inc'; + +$request = Request::createFromGlobals(); +// Manually resemble early bootstrap of DrupalKernel::boot(). +require_once __DIR__ . '/includes/bootstrap.inc'; +DrupalKernel::bootEnvironment(); + +try { + Settings::initialize(dirname(__DIR__), DrupalKernel::findSitePath($request), $autoloader); + + if (!Settings::get('update_free_access', FALSE)) { + throw new AccessDeniedHttpException(); + } + else { + $kernel = new DrupalKernel('prod', $autoloader); + $kernel->setSitePath(DrupalKernel::findSitePath($request)); + + // We need a) the list of active modules (we get that from the config + // bootstrap factory) and b) the path to the modules, we use the extension + // discovery for that. + + // Scan the module list. + // We don't support install profiles at that point? + $extension_discovery = new ExtensionDiscovery($kernel->getAppRoot(), FALSE, []); + $module_extensions = $extension_discovery->scan('module'); + + $config = BootstrapConfigStorageFactory::get(); + + // Load all the update_early.inc files. + foreach (array_keys($config->read('core.extension')['module']) as $module) { + if (isset($module_extensions[$module])) { + _update_load_update_early_file($module_extensions[$module]); + } + } + + // First figure out which hook_update_early got executed already. + $filename = PublicStream::basePath() . '/.ht.update_early'; + $existing_update_early_N = []; + if (file_exists($filename)) { + $existing_update_early_N = file_get_contents($filename); + $existing_update_early_N = explode("\n", $existing_update_early_N); + } + + $available_update_early_N = _update_get_available_update_early_functions(); + $not_executed_update_early_N = array_diff($available_update_early_N, $existing_update_early_N); + + // Execute all of the remainign ones. + foreach ($available_update_early_N as $function) { + $output = $function(); + $response->setContent($output)->prepare($request)->send(); + } + + // Redirect to the actual update controller. + $response = new RedirectResponse(str_replace('core/update.php', '', $request->getUriForPath('/admin/update'))); + $response->prepare($request)->send(); + } +} +catch (HttpExceptionInterface $e) { + $response = new Response('', $e->getStatusCode()); + $response->prepare($request)->send(); + exit; +}