diff -u b/core/lib/Drupal/Core/Config/ExtensionInstallStorage.php b/core/lib/Drupal/Core/Config/ExtensionInstallStorage.php --- b/core/lib/Drupal/Core/Config/ExtensionInstallStorage.php +++ b/core/lib/Drupal/Core/Config/ExtensionInstallStorage.php @@ -8,6 +8,7 @@ namespace Drupal\Core\Config; use Drupal\Core\Site\Settings; +use Drupal\Core\Extension\ExtensionDiscovery; /** * Storage to access configuration and schema in enabled extensions. @@ -80,18 +81,28 @@ protected function getAllFolders() { if (!isset($this->folders)) { $this->folders = array(); - $this->folders += $this->getComponentNames('core', array('core')); + $this->folders += $this->getCoreNames(); $install_profile = Settings::get('install_profile'); $extensions = $this->configStorage->read('core.extension'); + $listing = new ExtensionDiscovery(DRUPAL_ROOT); if (!empty($extensions['module'])) { $modules = $extensions['module']; // Remove the install profile as this is handled later. unset($modules[$install_profile]); - $this->folders += $this->getComponentNames('module', array_keys($modules)); + $module_list_scan = $listing->scan('module'); + $module_list = array(); + foreach (array_keys($modules) as $module) { + $module_list[$module] = $module_list_scan[$module]; + } + $this->folders += $this->getComponentNames($module_list); } if (!empty($extensions['theme'])) { - $this->folders += $this->getComponentNames('theme', array_keys($extensions['theme'])); + $theme_list_scan = $listing->scan('theme'); + foreach (array_keys($extensions['theme']) as $theme) { + $theme_list[$theme] = $theme_list_scan[$theme]; + } + $this->folders += $this->getComponentNames($theme_list); } if ($this->includeProfile) { @@ -100,7 +111,8 @@ // install profile version if there are any duplicates. $profile = drupal_get_profile(); if (isset($profile)) { - $profile_folders = $this->getComponentNames('profile', array($profile)); + $profile_list = $listing->scan('profile'); + $profile_folders = $this->getComponentNames(array($profile_list[$profile])); $this->folders = $profile_folders + $this->folders; } } reverted: --- b/core/modules/system/src/Controller/SystemController.php +++ a/core/modules/system/src/Controller/SystemController.php @@ -15,7 +15,6 @@ use Drupal\Core\Menu\MenuLinkTreeInterface; use Drupal\Core\Menu\MenuTreeParameters; use Drupal\Core\Theme\ThemeAccessCheck; -use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Url; use Drupal\system\SystemManager; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -68,13 +67,6 @@ protected $menuLinkTree; /** - * The bootstrap cache service. - * - * @var \Drupal\Core\Cache\CacheBackendInterface - */ - protected $bootstrapCache; - - /** * Constructs a new SystemController. * * @param \Drupal\system\SystemManager $systemManager @@ -89,17 +81,14 @@ * The theme handler. * @param \Drupal\Core\Menu\MenuLinkTreeInterface * The menu link tree service. - * @parm \Drupal\Core\Cache\CacheBackendInterface - * The bootstrap cache service. */ + public function __construct(SystemManager $systemManager, QueryFactory $queryFactory, ThemeAccessCheck $theme_access, FormBuilderInterface $form_builder, ThemeHandlerInterface $theme_handler, MenuLinkTreeInterface $menu_link_tree) { - public function __construct(SystemManager $systemManager, QueryFactory $queryFactory, ThemeAccessCheck $theme_access, FormBuilderInterface $form_builder, ThemeHandlerInterface $theme_handler, MenuLinkTreeInterface $menu_link_tree, CacheBackendInterface $bootstrap_cache) { $this->systemManager = $systemManager; $this->queryFactory = $queryFactory; $this->themeAccess = $theme_access; $this->formBuilder = $form_builder; $this->themeHandler = $theme_handler; $this->menuLinkTree = $menu_link_tree; - $this->bootstrapCache = $bootstrap_cache; } /** @@ -112,8 +101,7 @@ $container->get('access_check.theme'), $container->get('form_builder'), $container->get('theme_handler'), + $container->get('menu.link_tree') - $container->get('menu.link_tree'), - $container->get('cache.bootstrap') ); } @@ -198,10 +186,6 @@ * @todo Move into ThemeController. */ public function themesPage() { - // Clean up the bootstrap "missing files" cache when listing themes. - $this->bootstrapCache->delete('drupal_get_filename:missing'); - drupal_static_reset('drupal_get_filename:missing'); - $config = $this->config('system.theme'); // Get all available themes. $themes = $this->themeHandler->rebuildThemeData(); reverted: --- b/core/modules/system/src/Form/ModulesListForm.php +++ a/core/modules/system/src/Form/ModulesListForm.php @@ -174,10 +174,6 @@ // Include system.admin.inc so we can use the sort callbacks. $this->moduleHandler->loadInclude('system', 'inc', 'system.admin'); - // Clean up the "missing files" cache when listing modules. - \Drupal::cache('bootstrap')->delete('drupal_get_filename:missing'); - drupal_static_reset('drupal_get_filename:missing'); - $form['filters'] = array( '#type' => 'container', '#attributes' => array( diff -u b/core/modules/system/src/Tests/Bootstrap/GetFilenameUnitTest.php /dev/null --- b/core/modules/system/src/Tests/Bootstrap/GetFilenameUnitTest.php +++ /dev/null @@ -1,96 +0,0 @@ -previousContainer = $this->container; - $this->container = NULL; - \Drupal::unsetContainer(); - } - - /** - * {@inheritdoc} - */ - protected function tearDown() { - parent::tearDown(); - // Restore the previous container. - $this->container = $this->previousContainer; - \Drupal::setContainer($this->previousContainer); - } - - /** - * Tests that drupal_get_filename() works when the file is not in database. - */ - function testDrupalGetFilename() { - // drupal_get_profile() is using obtaining the profile from state if the - // install_state global is not set. - global $install_state; - $install_state['parameters']['profile'] = 'testing'; - - // Assert that this test is meaningful. - $this->assertNull($this->container); - $this->assertFalse(\Drupal::hasContainer()); - - // Retrieving the location of a module. - $this->assertIdentical(drupal_get_filename('module', 'system'), 'core/modules/system/system.info.yml'); - - // Retrieving the location of a theme. - $this->assertIdentical(drupal_get_filename('theme', 'stark'), 'core/themes/stark/stark.info.yml'); - - // Retrieving the location of a theme engine. - $this->assertIdentical(drupal_get_filename('theme_engine', 'phptemplate'), 'core/themes/engines/phptemplate/phptemplate.info.yml'); - - // Retrieving the location of a profile. Profiles are a special case with - // a fixed location and naming. - $this->assertIdentical(drupal_get_filename('profile', 'standard'), 'core/profiles/standard/standard.info.yml'); - - // Generate a non-existing module name. - $non_existing_module = uniqid("", TRUE); - - // Set a custom error handler so we can ignore the file not found error. - set_error_handler(function($severity, $message, $file, $line) { - // Skip error handling if this is a "file not found" error. - if (!(error_reporting() & $severity) || strstr($message, 'is missing from the file system:')) { - return; - } - throw new ErrorException($message, 0, $severity, $file, $line); - }); - // Searching for an item that does not exist returns NULL. - $this->assertNull(drupal_get_filename('module', $non_existing_module), 'Searching for an item that does not exist returns NULL.'); - // Restore the original error handler. - restore_error_handler(); - - // Get the missing records static from drupal_get_filename. - $missing = &drupal_static('drupal_get_filename:missing'); - - // Searching for an item that does not exist creates a static record in - // drupal_get_filename(). - $this->assertTrue($missing['module'][$non_existing_module], 'Searching for an item that does not exist creates a static record in drupal_get_filename().'); - } -} only in patch2: unchanged: --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -302,6 +302,10 @@ function install_begin_request($class_loader, &$install_state) { // Allow command line scripts to override server variables used by Drupal. require_once __DIR__ . '/bootstrap.inc'; + // Prime the drupal_get_filename() cache with the location of the system + // module. + drupal_get_filename('module', 'system', 'core/modules/system/system.info.yml'); + // If the hash salt leaks, it becomes possible to forge a valid testing user // agent, install a new copy of Drupal, and take over the original site. // The user agent header is used to pass a database prefix in the request when @@ -1031,6 +1035,7 @@ function install_base_system(&$install_state) { // Enable the user module so that sessions can be recorded during the // upcoming bootstrap step. + system_rebuild_module_data(); \Drupal::service('module_installer')->install(array('user'), FALSE); // Save the list of other modules to install for the upcoming tasks. only in patch2: unchanged: --- a/core/includes/install.inc +++ b/core/includes/install.inc @@ -922,11 +922,19 @@ function drupal_check_profile($profile, array $install_state) { // Collect requirement testing results. $requirements = array(); + + $listing = new ExtensionDiscovery(DRUPAL_ROOT); + $module_list = $listing->scan('module'); + // Make sure the installation API is available + include_once __DIR__ . '/install.inc'; foreach ($info['dependencies'] as $module) { - module_load_install($module); + $file = DRUPAL_ROOT . '/' . $module_list[$module]->getPath() . "/$module.install"; + if (is_file($file)) { + require_once $file; + } $function = $module . '_requirements'; - drupal_classloader_register($module, drupal_get_path('module', $module)); + drupal_classloader_register($module, $module_list[$module]->getPath()); if (function_exists($function)) { $requirements = array_merge($requirements, $function('install')); } only in patch2: unchanged: --- a/core/lib/Drupal/Core/Config/InstallStorage.php +++ b/core/lib/Drupal/Core/Config/InstallStorage.php @@ -8,6 +8,7 @@ namespace Drupal\Core\Config; use Drupal\Core\Extension\ExtensionDiscovery; +use Drupal\Core\Extension\Extension; /** * Storage used by the Drupal installer. @@ -157,14 +158,14 @@ public function listAll($prefix = '') { protected function getAllFolders() { if (!isset($this->folders)) { $this->folders = array(); - $this->folders += $this->getComponentNames('core', array('core')); - // @todo Refactor getComponentNames() to use the extension list directly. + $this->folders += $this->getCoreNames(); + $listing = new ExtensionDiscovery(DRUPAL_ROOT); if ($profile = drupal_get_profile()) { - $this->folders += $this->getComponentNames('profile', array($profile)); + $profile_list = $listing->scan('profile'); + $this->folders += $this->getComponentNames(array($profile_list[$profile])); } - $listing = new ExtensionDiscovery(DRUPAL_ROOT); - $this->folders += $this->getComponentNames('module', array_keys($listing->scan('module'))); - $this->folders += $this->getComponentNames('theme', array_keys($listing->scan('theme'))); + $this->folders += $this->getComponentNames($listing->scan('module')); + $this->folders += $this->getComponentNames($listing->scan('theme')); } return $this->folders; } @@ -172,19 +173,17 @@ protected function getAllFolders() { /** * Get all configuration names and folders for a list of modules or themes. * - * @param string $type - * Type of components: 'module' | 'theme' | 'profile' - * @param array $list - * Array of theme or module names. + * @param \Drupal\Core\Extension\Extension[] $list + * An associative array of Extension objects, keyed by extension name. * * @return array * Folders indexed by configuration name. */ - public function getComponentNames($type, array $list) { + public function getComponentNames(array $list) { $extension = '.' . $this->getFileExtension(); $folders = array(); - foreach ($list as $name) { - $directory = $this->getComponentFolder($type, $name); + foreach ($list as $extension_object) { + $directory = $this->getComponentFolder($extension_object); if (file_exists($directory)) { $files = new \GlobIterator(DRUPAL_ROOT . '/' . $directory . '/*' . $extension); foreach ($files as $file) { @@ -196,18 +195,45 @@ public function getComponentNames($type, array $list) { } /** + * Get all configuration names and folders for Drupal core. + * + * @return array + * Folders indexed by configuration name. + */ + public function getCoreNames() { + $extension = '.' . $this->getFileExtension(); + $folders = array(); + $directory = $this->getCoreFolder(); + if (file_exists($directory)) { + $files = new \GlobIterator(DRUPAL_ROOT . '/' . $directory . '/*' . $extension); + foreach ($files as $file) { + $folders[$file->getBasename($extension)] = $directory; + } + } + return $folders; + } + + /** * Get folder inside each component that contains the files. * - * @param string $type - * Component type: 'module' | 'theme' | 'profile' - * @param string $name - * Component name. + * @param \Drupal\Core\Extension\Extension $extension + * The Extension object for the component. * * @return string * The configuration folder name for this component. */ - protected function getComponentFolder($type, $name) { - return drupal_get_path($type, $name) . '/' . $this->getCollectionDirectory(); + protected function getComponentFolder(Extension $extension) { + return $extension->getPath() . '/' . $this->getCollectionDirectory(); + } + + /** + * Get folder inside Drupal core that contains the files. + * + * @return string + * The configuration folder name for core. + */ + protected function getCoreFolder() { + return drupal_get_path('core', 'core') . '/' . $this->getCollectionDirectory(); } /** only in patch2: unchanged: --- a/core/lib/Drupal/Core/Extension/ModuleInstaller.php +++ b/core/lib/Drupal/Core/Extension/ModuleInstaller.php @@ -18,7 +18,7 @@ /** * Default implementation of the module installer. * - * It registers the module in config, install its own configuration, + * It registers the module in config, installs its own configuration, * installs the schema, updates the Drupal kernel and more. */ class ModuleInstaller implements ModuleInstallerInterface { only in patch2: unchanged: --- a/core/modules/config/src/Tests/ConfigDependencyTest.php +++ b/core/modules/config/src/Tests/ConfigDependencyTest.php @@ -186,6 +186,7 @@ public function testConfigEntityUninstall() { $entity2->save(); // Test that doing a config uninstall of the node module deletes entity2 // since it is dependent on entity1 which is dependent on the node module. + system_rebuild_module_data(); $config_manager->uninstall('module', 'node'); $this->assertFalse($storage->load('entity1'), 'Entity 1 deleted'); $this->assertFalse($storage->load('entity2'), 'Entity 2 deleted'); only in patch2: unchanged: --- a/core/modules/config/tests/config_test/src/TestInstallStorage.php +++ b/core/modules/config/tests/config_test/src/TestInstallStorage.php @@ -23,13 +23,12 @@ class TestInstallStorage extends InstallStorage { */ protected function getAllFolders() { if (!isset($this->folders)) { - $this->folders = $this->getComponentNames('core', array('core')); - // @todo Refactor getComponentNames() to use the extension list directly. + $this->folders = $this->getCoreNames(); $listing = new ExtensionDiscovery(\Drupal::root()); $listing->setProfileDirectories(array()); - $this->folders += $this->getComponentNames('profile', array_keys($listing->scan('profile'))); - $this->folders += $this->getComponentNames('module', array_keys($listing->scan('module'))); - $this->folders += $this->getComponentNames('theme', array_keys($listing->scan('theme'))); + $this->folders += $this->getComponentNames($listing->scan('profile')); + $this->folders += $this->getComponentNames($listing->scan('module')); + $this->folders += $this->getComponentNames($listing->scan('theme')); } return $this->folders; } only in patch2: unchanged: --- a/core/modules/simpletest/src/KernelTestBase.php +++ b/core/modules/simpletest/src/KernelTestBase.php @@ -13,6 +13,7 @@ use Drupal\Core\DependencyInjection\ContainerBuilder; use Drupal\Core\DrupalKernel; use Drupal\Core\Entity\Sql\SqlEntityStorageInterface; +use Drupal\Core\Extension\ExtensionDiscovery; use Drupal\Core\KeyValueStore\KeyValueMemoryFactory; use Drupal\Core\Language\Language; use Drupal\Core\Site\Settings; @@ -483,6 +484,10 @@ protected function installEntitySchema($entity_type_id) { * The new modules are only added to the active module list and loaded. */ protected function enableModules(array $modules) { + $listing = new ExtensionDiscovery(DRUPAL_ROOT); + $module_list = $listing->scan('module'); + // In ModuleHandlerTest we pass in a profile as if it were a module. + $module_list += $listing->scan('profile'); // Set the list of modules in the extension handler. $module_handler = $this->container->get('module_handler'); @@ -490,9 +495,8 @@ protected function enableModules(array $modules) { // the event dispatcher which can prevent modules from registering events. $active_storage = \Drupal::service('config.storage'); $extensions = $active_storage->read('core.extension'); - foreach ($modules as $module) { - $module_handler->addModule($module, drupal_get_path('module', $module)); + $module_handler->addModule($module, $module_list[$module]->getPath()); // Maintain the list of enabled modules in configuration. $extensions['module'][$module] = 0; } only in patch2: unchanged: --- a/core/modules/system/src/Tests/Extension/ModuleHandlerTest.php +++ b/core/modules/system/src/Tests/Extension/ModuleHandlerTest.php @@ -23,6 +23,13 @@ class ModuleHandlerTest extends KernelTestBase { */ public static $modules = array('system'); + public function setUp() { + parent::setUp(); + // Set up the state values so we know where to find the files when + // running drupal_get_filename(). + system_rebuild_module_data(); + } + /** * {@inheritdoc} */ @@ -38,6 +45,7 @@ public function containerBuild(ContainerBuilder $container) { */ function testModuleList() { // Build a list of modules, sorted alphabetically. + drupal_get_filename('profile', 'testing', 'core/profiles/testing/testing.info.yml'); $profile_info = install_profile_info('testing', 'en'); $module_list = $profile_info['dependencies']; @@ -184,6 +192,7 @@ function testUninstallProfileDependency() { $profile = 'minimal'; $dependency = 'dblog'; $this->settingsSet('install_profile', $profile); + drupal_get_filename('profile', 'minimal', 'core/profiles/minimal/minimal.info.yml'); $this->enableModules(array('module_test', $profile)); drupal_static_reset('system_rebuild_module_data'); only in patch2: unchanged: --- a/core/modules/system/src/Tests/Extension/ThemeHandlerTest.php +++ b/core/modules/system/src/Tests/Extension/ThemeHandlerTest.php @@ -316,6 +316,7 @@ function testThemeInfoAlter() { $themes = $this->themeHandler()->listInfo(); $this->assertFalse(isset($themes[$name]->info['regions']['test_region'])); + system_rebuild_module_data(); $this->moduleInstaller()->install(array('module_test'), FALSE); $this->assertTrue($this->moduleHandler()->moduleExists('module_test')); only in patch2: unchanged: --- a/core/modules/system/src/Tests/File/ScanDirectoryTest.php +++ b/core/modules/system/src/Tests/File/ScanDirectoryTest.php @@ -28,7 +28,7 @@ class ScanDirectoryTest extends FileTestBase { protected function setUp() { parent::setUp(); - $this->path = drupal_get_path('module', 'simpletest') . '/files'; + $this->path = 'core/modules/simpletest/files'; } /** @@ -123,10 +123,10 @@ function testOptionKey() { * Check that the recurse option descends into subdirectories. */ function testOptionRecurse() { - $files = file_scan_directory(drupal_get_path('module', 'simpletest'), '/^javascript-/', array('recurse' => FALSE)); + $files = file_scan_directory($this->path . '/..', '/^javascript-/', array('recurse' => FALSE)); $this->assertTrue(empty($files), "Without recursion couldn't find javascript files."); - $files = file_scan_directory(drupal_get_path('module', 'simpletest'), '/^javascript-/', array('recurse' => TRUE)); + $files = file_scan_directory($this->path . '/..', '/^javascript-/', array('recurse' => TRUE)); $this->assertEqual(2, count($files), 'With recursion we found the expected javascript files.'); } only in patch2: unchanged: --- a/core/modules/system/src/Tests/Installer/InstallerLanguageTest.php +++ b/core/modules/system/src/Tests/Installer/InstallerLanguageTest.php @@ -30,7 +30,7 @@ function testInstallerTranslationFiles() { 'it' => array(), ); - $file_translation = new FileTranslation(drupal_get_path('module', 'simpletest') . '/files/translations'); + $file_translation = new FileTranslation('core/modules/simpletest/files/translations'); foreach ($expected_translation_files as $langcode => $files_expected) { $files_found = $file_translation->findTranslationFiles($langcode); $this->assertTrue(count($files_found) == count($files_expected), format_string('@count installer languages found.', array('@count' => count($files_expected)))); only in patch2: unchanged: --- a/core/modules/system/src/Tests/Path/UrlAliasFixtures.php +++ b/core/modules/system/src/Tests/Path/UrlAliasFixtures.php @@ -80,6 +80,9 @@ public function sampleUrlAliases() { public function tableDefinition() { $tables = array(); + // Prime the drupal_get_filename() cache with the location of the system + // module. + drupal_get_filename('module', 'system', 'core/modules/system/system.info.yml'); module_load_install('system'); $schema = system_schema();