diff -u b/core/includes/bootstrap.inc b/core/includes/bootstrap.inc --- b/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -212,14 +212,6 @@ // drupal_static(). static $files = array(); - // We use drupal_static() for the missing records so we can test it. - // drupal_static_fast() is used as this function may be called often. - static $drupal_static_fast; - if (!isset($drupal_static_fast)) { - $drupal_static_fast['missing'] = &drupal_static(__FUNCTION__ . ':missing'); - } - $missing = &$drupal_static_fast['missing']; - // Type 'core' only exists to simplify application-level logic; it always maps // to the /core directory, whereas $name is ignored. It is only requested via // drupal_get_path(). /core/core.info.yml does not exist, but is required @@ -257,43 +249,15 @@ if (!isset($files[$type][$name]) && \Drupal::hasService('state')) { $files[$type] += \Drupal::state()->get('system.' . $type . '.files', array()); } - // If still unknown, perform a filesystem scan. + // If still unknown, create a user-level error message. if (!isset($files[$type][$name])) { - if (!isset($missing)) { - $missing = array(); - if (\Drupal::hasService('cache.bootstrap')) { - $cache = \Drupal::cache('bootstrap')->get('drupal_get_filename:missing'); - if ($cache && $cache->data) { - $missing = $cache->data; - } - } - } - if (!isset($missing[$type][$name])) { - $listing = new ExtensionDiscovery(DRUPAL_ROOT); - // Prevent an infinite recursion by this legacy function. - if ($original_type == 'profile') { - $listing->setProfileDirectories(array()); - } - foreach ($listing->scan($original_type) as $extension_name => $file) { - $files[$type][$extension_name] = $file->getPathname(); - } - } + trigger_error(SafeMarkup::format('The following @type is missing from the file system: @name', array('@type' => $type, '@name' => $name)), E_USER_WARNING); } } if (isset($files[$type][$name])) { return $files[$type][$name]; } - elseif (!isset($missing[$type][$name])) { - // Add the missing file to a temporary cache and throw an alert. This cache - // will be cleared on cron runs as well as when visiting the module and - // theme list pages. - $missing[$type][$name] = TRUE; - if (\Drupal::hasService('cache.bootstrap')) { - \Drupal::cache('bootstrap')->set('drupal_get_filename:missing', $missing, REQUEST_TIME + 24 * 60 * 60); - } - trigger_error(SafeMarkup::format('The following @type is missing from the file system: @name', array('@type' => $type, '@name' => $name)), E_USER_WARNING); - } } /** 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,33 @@ 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'); + // @todo Remove as part of https://www.drupal.org/node/2186491 + $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) { + if (isset($module_list_scan[$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) { + if (isset($theme_list_scan[$theme])) { + $theme_list[$theme] = $theme_list_scan[$theme]; + } + } + $this->folders += $this->getComponentNames($theme_list); } if ($this->includeProfile) { @@ -100,8 +116,11 @@ // install profile version if there are any duplicates. $profile = drupal_get_profile(); if (isset($profile)) { - $profile_folders = $this->getComponentNames('profile', array($profile)); - $this->folders = $profile_folders + $this->folders; + $profile_list = $listing->scan('profile'); + if (isset($profile_list[$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 b/core/modules/system/src/Tests/Bootstrap/GetFilenameUnitTest.php --- b/core/modules/system/src/Tests/Bootstrap/GetFilenameUnitTest.php +++ b/core/modules/system/src/Tests/Bootstrap/GetFilenameUnitTest.php @@ -17,34 +17,6 @@ class GetFilenameUnitTest extends KernelTestBase { /** - * The container used by the test, moved out of the way. - * - * @var \Symfony\Component\DependencyInjection\ContainerInterface - */ - protected $previousContainer; - - /** - * {@inheritdoc} - */ - protected function setUp() { - parent::setUp(); - // Store the previous container. - $this->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() { @@ -53,22 +25,25 @@ global $install_state; $install_state['parameters']['profile'] = 'testing'; - // Assert that this test is meaningful. - $this->assertNull($this->container); - $this->assertFalse(\Drupal::hasContainer()); + // Rebuild system.module.files state data. + // @todo Remove as part of https://www.drupal.org/node/2186491 + drupal_static_reset('system_rebuild_module_data'); + system_rebuild_module_data(); // 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. + \Drupal::service('theme_handler')->install(array('stark')); $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'); + $this->assertIdentical(drupal_get_filename('theme_engine', 'twig'), 'core/themes/engines/twig/twig.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'); + $this->assertIdentical(drupal_get_filename('profile', 'testing'), 'core/profiles/testing/testing.info.yml'); + // Generate a non-existing module name. $non_existing_module = uniqid("", TRUE); @@ -77,20 +52,14 @@ 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:')) { + if (strstr($message, 'is missing from the file system:')) { + \Drupal::state()->set('get_filename_test_triggered_error', TRUE); return; } - throw new ErrorException($message, 0, $severity, $file, $line); + 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.'); + $this->assertTrue(\Drupal::state()->get('get_filename_test_triggered_error'), 'Searching for an item that does not exist triggers an error.'); // 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,12 @@ function install_begin_request($class_loader, &$install_state) { // Allow command line scripts to override server variables used by Drupal. require_once __DIR__ . '/bootstrap.inc'; + // Before having installed the system module and being able to do a module + // rebuild, prime the drupal_get_filename() static cache with the module's + // exact location. + // @todo Remove as part of https://www.drupal.org/node/2186491 + 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 @@ -1029,6 +1035,10 @@ function install_base_system(&$install_state) { // system.module in order to work. file_ensure_htaccess(); + // Before installing the user module, perform a module rebuild so we know + // where the user module is located. + // @todo Remove as part of https://www.drupal.org/node/2186491 + system_rebuild_module_data(); // Enable the user module so that sessions can be recorded during the // upcoming bootstrap step. \Drupal::service('module_installer')->install(array('user'), FALSE); only in patch2: unchanged: --- a/core/includes/install.inc +++ b/core/includes/install.inc @@ -556,7 +556,7 @@ function drupal_verify_profile($install_state) { $info = $install_state['profile_info']; // Get the list of available modules for the selected installation profile. - $listing = new ExtensionDiscovery(DRUPAL_ROOT); + $listing = new ExtensionDiscovery(\Drupal::root()); $present_modules = array(); foreach ($listing->scan('module') as $present_module) { $present_modules[] = $present_module->getName(); @@ -922,11 +922,20 @@ function drupal_check_profile($profile, array $install_state) { // Collect requirement testing results. $requirements = array(); + + // Performs an ExtensionDiscovery scan as the system module is unavailable and + // we don't yet know where all the modules are located. + // @todo Remove as part of https://www.drupal.org/node/2186491 + $listing = new ExtensionDiscovery(\Drupal::root()); + $module_list = $listing->scan('module'); 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,20 @@ 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(); + // Perform an ExtensionDiscovery scan as we cannot use drupal_get_path() + // yet because the system module may not yet be enabled during install. + // @todo Remove as part of https://www.drupal.org/node/2186491 + $listing = new ExtensionDiscovery(\Drupal::root()); if ($profile = drupal_get_profile()) { - $this->folders += $this->getComponentNames('profile', array($profile)); + $profile_list = $listing->scan('profile'); + if (isset($profile_list[$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'))); + // @todo Remove as part of https://www.drupal.org/node/2186491 + $this->folders += $this->getComponentNames($listing->scan('module')); + $this->folders += $this->getComponentNames($listing->scan('theme')); } return $this->folders; } @@ -172,21 +179,21 @@ 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) { + // We don't have to use ExtensionDiscovery here because our list of + // extensions was already obtained through an ExtensionDiscovery scan. + $directory = $this->getComponentFolder($extension_object); if (file_exists($directory)) { - $files = new \GlobIterator(DRUPAL_ROOT . '/' . $directory . '/*' . $extension); + $files = new \GlobIterator(\Drupal::root() . '/' . $directory . '/*' . $extension); foreach ($files as $file) { $folders[$file->getBasename($extension)] = $directory; } @@ -196,18 +203,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/ExtensionDiscovery.php +++ b/core/lib/Drupal/Core/Extension/ExtensionDiscovery.php @@ -134,8 +134,9 @@ public function __construct($root) { */ public function scan($type, $include_tests = NULL) { // Determine the installation profile directories to scan for extensions, - // unless explicit profile directories have been set. - if (!isset($this->profileDirectories)) { + // unless explicit profile directories have been set. Exclude profiles + // as we can't have profiles within profiles. + if (!isset($this->profileDirectories) && $type != 'profile') { $this->setProfileDirectoriesFromSettings(); } 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/lib/Drupal/Core/Extension/ThemeHandler.php +++ b/core/lib/Drupal/Core/Extension/ThemeHandler.php @@ -469,7 +469,8 @@ public function rebuildThemeData() { ); $sub_themes = array(); - $files = array(); + $files_theme = array(); + $files_theme_engine = array(); // Read info files for each theme. foreach ($themes as $key => $theme) { // @todo Remove all code that relies on the $status property. @@ -498,6 +499,7 @@ public function rebuildThemeData() { if (isset($engines[$engine])) { $theme->owner = $engines[$engine]->getExtensionPathname(); $theme->prefix = $engines[$engine]->getName(); + $files_theme_engine[$engine] = $engines[$engine]->getPathname(); } // Prefix screenshot with theme path. @@ -505,7 +507,7 @@ public function rebuildThemeData() { $theme->info['screenshot'] = $theme->getPath() . '/' . $theme->info['screenshot']; } - $files[$key] = $theme->getPathname(); + $files_theme[$key] = $theme->getPathname(); } // Build dependencies. // @todo Move into a generic ExtensionHandler base class. @@ -513,8 +515,10 @@ public function rebuildThemeData() { $themes = $this->moduleHandler->buildModuleDependencies($themes); // Store filenames to allow system_list() and drupal_get_filename() to - // retrieve them without having to scan the filesystem. - $this->state->set('system.theme.files', $files); + // retrieve them for themes and theme engines without having to scan the + // filesystem. + $this->state->set('system.theme.files', $files_theme); + $this->state->set('system.theme_engine.files', $files_theme_engine); // After establishing the full list of available themes, fill in data for // sub-themes. only in patch2: unchanged: --- a/core/modules/config/src/Tests/ConfigDependencyTest.php +++ b/core/modules/config/src/Tests/ConfigDependencyTest.php @@ -184,6 +184,10 @@ public function testConfigEntityUninstall() { ) ); $entity2->save(); + // Perform a module rebuild so we can know where the node module is located. + // and uninstall it. + // @todo Remove as part of https://www.drupal.org/node/2186491 + system_rebuild_module_data(); // 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. $config_manager->uninstall('module', 'node'); 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,14 @@ protected function installEntitySchema($entity_type_id) { * The new modules are only added to the active module list and loaded. */ protected function enableModules(array $modules) { + // Perform an ExtensionDiscovery scan as this function may receive a + // profile that is not the current profile, and we don't yet have a cached + // way to receive inactive profile information. + // @todo Remove as part of https://www.drupal.org/node/2186491 + $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'); @@ -492,7 +501,7 @@ protected function enableModules(array $modules) { $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,14 @@ 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(). + // @todo Remove as part of https://www.drupal.org/node/2186491 + system_rebuild_module_data(); + } + /** * {@inheritdoc} */ @@ -37,6 +45,11 @@ public function containerBuild(ContainerBuilder $container) { * The basic functionality of retrieving enabled modules. */ function testModuleList() { + // Prime the drupal_get_filename() static cache with the location of the + // testing profile as it is not the currently active profile and we don't + // yet have any cached way to retrieve its location. + // @todo Remove as part of https://www.drupal.org/node/2186491 + drupal_get_filename('profile', 'testing', 'core/profiles/testing/testing.info.yml'); // Build a list of modules, sorted alphabetically. $profile_info = install_profile_info('testing', 'en'); $module_list = $profile_info['dependencies']; @@ -184,6 +197,11 @@ function testUninstallProfileDependency() { $profile = 'minimal'; $dependency = 'dblog'; $this->settingsSet('install_profile', $profile); + // Prime the drupal_get_filename() static cache with the location of the + // minimal profile as it is not the currently active profile and we don't + // yet have any cached way to retrieve its location. + // @todo Remove as part of https://www.drupal.org/node/2186491 + drupal_get_filename('profile', 'minimal', 'core/profiles/' . $profile . '/' . $profile . '.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,9 @@ function testThemeInfoAlter() { $themes = $this->themeHandler()->listInfo(); $this->assertFalse(isset($themes[$name]->info['regions']['test_region'])); + // Rebuild module data so we know where module_test is located. + // @todo Remove as part of https://www.drupal.org/node/2186491 + 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,11 @@ class ScanDirectoryTest extends FileTestBase { protected function setUp() { parent::setUp(); - $this->path = drupal_get_path('module', 'simpletest') . '/files'; + // Hardcode the location of the simpletest files as it is already known + // and shouldn't change, and we don't yet have a way to retreive their + // location from drupal_get_filename() in a cached way. + // @todo Remove as part of https://www.drupal.org/node/2186491 + $this->path = 'core/modules/simpletest/files'; } /** @@ -123,10 +127,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,9 @@ function testInstallerTranslationFiles() { 'it' => array(), ); - $file_translation = new FileTranslation(drupal_get_path('module', 'simpletest') . '/files/translations'); + // Hardcode the simpletest module location as we don't yet know where it is. + // @todo Remove as part of https://www.drupal.org/node/2186491 + $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,10 @@ public function sampleUrlAliases() { public function tableDefinition() { $tables = array(); + // Prime the drupal_get_filename() cache with the location of the system + // module as its location is known and shouldn't change. + // @todo Remove as part of https://www.drupal.org/node/2186491 + drupal_get_filename('module', 'system', 'core/modules/system/system.info.yml'); module_load_install('system'); $schema = system_schema(); only in patch2: unchanged: --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -883,14 +883,24 @@ function system_get_info($type, $name = NULL) { */ function _system_rebuild_module_data() { $listing = new ExtensionDiscovery(\Drupal::root()); - // Find modules - $modules = $listing->scan('module'); - // Find installation profiles. - $profiles = $listing->scan('profile'); + // Find installation profiles. This needs to happen before performing a + // module scan as the module scan requires knowing what the active profile is. + // @todo Remove as part of https://www.drupal.org/node/2186491 + $profiles = $liseing->scan('profile'); + $profile = drupal_get_profile(); + if ($profile && isset($profiles[$profile])) { + // Prime the drupal_get_filename() static cache with the profile info file + // location so we can use drupal_get_path() on the active profile during + // the module scan. + // @todo Remove as part of https://www.drupal.org/node/2186491 + drupal_get_filename('profile', $profile, $profiles[$profile]->getPathname()); + } + // Find modules. + $modules = $listing->scan('module'); // Include the installation profile in modules that are loaded. - if ($profile = drupal_get_profile()) { + if ($profile) { $modules[$profile] = $profiles[$profile]; // Installation profile hooks are always executed last. $modules[$profile]->weight = 1000;