From 36cf829fc28cc07461cdfb0c7ba8c244baf51738 Mon Sep 17 00:00:00 2001 From: Nick Wilde Date: Sat, 21 Oct 2017 16:33:36 -0700 Subject: [PATCH 1/9] Load Drush services for themes as well as modules. --- src/Drupal/DrupalKernel.php | 38 ++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/Drupal/DrupalKernel.php b/src/Drupal/DrupalKernel.php index 544f9a6e3c..da7ed3603f 100644 --- a/src/Drupal/DrupalKernel.php +++ b/src/Drupal/DrupalKernel.php @@ -106,7 +106,11 @@ public function discoverServiceProviders() // necessary that the class files in these commands are available // in the autoloader. - // Also add Drush services from all modules + // Also add Drush services from all modules & themes. + $extensions = $this->getConfigStorage()->read('core.extension'); + $this->moduleList += isset($extensions['theme']) ? $extensions['theme'] : []; + $this->themeData(); + $module_filenames = $this->getModuleFileNames(); // Load each module's serviceProvider class. foreach ($module_filenames as $module => $filename) { @@ -124,4 +128,36 @@ protected function addDrushServiceProvider($serviceProviderName, $filename) $this->serviceYamls['app'][$serviceProviderName] = $filename; } } + + /** + * populates theme data on the filesystem. + * + * @see Drupal\Core\DrupalKernel::moduleData(). + */ + protected function themeData() + { + // First, find profiles. + $listing = new ExtensionDiscovery($this->root); + $listing->setProfileDirectories([]); + $all_profiles = $listing->scan('profile'); + $profiles = array_intersect_key($all_profiles, $this->moduleList); + + // If a module is within a profile directory but specifies another + // profile for testing, it needs to be found in the parent profile. + $settings = $this->getConfigStorage()->read('simpletest.settings'); + $parent_profile = !empty($settings['parent_profile']) ? $settings['parent_profile'] : NULL; + if ($parent_profile && !isset($profiles[$parent_profile])) { + // In case both profile directories contain the same extension, the + // actual profile always has precedence. + $profiles = array($parent_profile => $all_profiles[$parent_profile]) + $profiles; + } + + $profile_directories = array_map(function ($profile) { + return $profile->getPath(); + }, $profiles); + $listing->setProfileDirectories($profile_directories); + + // Now find themes. + $this->moduleData += $listing->scan('theme'); + } } From 73cca09349873532cc5548bc1e603f752901573f Mon Sep 17 00:00:00 2001 From: Nick Wilde Date: Sun, 22 Oct 2017 11:26:10 -0700 Subject: [PATCH 2/9] Split theme & module lists to prevent possible other effects. To facilitat this, also have to add the theme namespaces to the autoloader. --- src/Drupal/DrupalKernel.php | 49 ++++++++++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/src/Drupal/DrupalKernel.php b/src/Drupal/DrupalKernel.php index da7ed3603f..1c1653d099 100644 --- a/src/Drupal/DrupalKernel.php +++ b/src/Drupal/DrupalKernel.php @@ -11,6 +11,9 @@ class DrupalKernel extends DrupalDrupalKernel /** @var ServiceModifierInterface[] */ protected $serviceModifiers = []; + /** @var array */ + protected $themeNames; + /** * @inheritdoc */ @@ -60,6 +63,7 @@ protected function initializeContainer() if ($this->shouldDrushInvalidateContainer()) { $this->invalidateContainer(); } + $this->classLoaderAddMultiplePsr4($this->getModuleNamespacesPsr4($this->getThemeFileNames())); return parent::initializeContainer(); } @@ -106,17 +110,21 @@ public function discoverServiceProviders() // necessary that the class files in these commands are available // in the autoloader. - // Also add Drush services from all modules & themes. - $extensions = $this->getConfigStorage()->read('core.extension'); - $this->moduleList += isset($extensions['theme']) ? $extensions['theme'] : []; - $this->themeData(); - + // Also add Drush services from all modules. $module_filenames = $this->getModuleFileNames(); // Load each module's serviceProvider class. foreach ($module_filenames as $module => $filename) { $filename = dirname($filename) . "/drush.services.yml"; $this->addDrushServiceProvider("_drush.$module", $filename); } + + // Also add Drush services from all themes. + $theme_filenames = $this->getThemeFileNames(); + // Load each theme's serviceProvider class. + foreach ($theme_filenames as $theme => $filename) { + $filename = dirname($filename) . "/drush.services.yml"; + $this->addDrushServiceProvider("_drush.$theme", $filename); + } } /** @@ -134,15 +142,15 @@ protected function addDrushServiceProvider($serviceProviderName, $filename) * * @see Drupal\Core\DrupalKernel::moduleData(). */ - protected function themeData() + protected function themeData($theme_list) { // First, find profiles. $listing = new ExtensionDiscovery($this->root); $listing->setProfileDirectories([]); $all_profiles = $listing->scan('profile'); - $profiles = array_intersect_key($all_profiles, $this->moduleList); + $profiles = array_intersect_key($all_profiles, $theme_list); - // If a module is within a profile directory but specifies another + // If a theme is within a profile directory but specifies another // profile for testing, it needs to be found in the parent profile. $settings = $this->getConfigStorage()->read('simpletest.settings'); $parent_profile = !empty($settings['parent_profile']) ? $settings['parent_profile'] : NULL; @@ -158,6 +166,29 @@ protected function themeData() $listing->setProfileDirectories($profile_directories); // Now find themes. - $this->moduleData += $listing->scan('theme'); + return $listing->scan('theme'); + } + + /** + * Gets the file name for each enabled module. + * + * @return array + * Array where each key is a module name, and each value is a path to the + * respective *.info.yml file. + */ + protected function getThemeFileNames() { + if ($this->themeNames) { + return $this->themeNames; + } + $extensions = $this->getConfigStorage()->read('core.extension'); + $theme_list = isset($extensions['theme']) ? $extensions['theme'] : []; + $theme = []; + $theme_data = $this->themeData($theme_list); + foreach ($theme_list as $theme => $weight) { + if (isset($theme_data[$theme])) { + $this->themeNames[$theme] = $theme_data[$theme]->getPathname(); + } + } + return $this->themeNames; } } From 4c50cf15b32bf9272d5270ef043caa701d5b43f0 Mon Sep 17 00:00:00 2001 From: Nick Wilde Date: Sun, 22 Oct 2017 11:35:33 -0700 Subject: [PATCH 3/9] fix mention of 'modules' in docstring for theme function. --- src/Drupal/DrupalKernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Drupal/DrupalKernel.php b/src/Drupal/DrupalKernel.php index 1c1653d099..9f5b2ce26c 100644 --- a/src/Drupal/DrupalKernel.php +++ b/src/Drupal/DrupalKernel.php @@ -170,10 +170,10 @@ protected function themeData($theme_list) } /** - * Gets the file name for each enabled module. + * Gets the file name for each enabled theme. * * @return array - * Array where each key is a module name, and each value is a path to the + * Array where each key is a theme name, and each value is a path to the * respective *.info.yml file. */ protected function getThemeFileNames() { From dd0898591e23894d8bf5509bf07582e34d6f692b Mon Sep 17 00:00:00 2001 From: Nick Wilde Date: Mon, 23 Oct 2017 12:15:38 -0700 Subject: [PATCH 4/9] Update DrupalKernel.php Few code standard fixes Drupal->Drush --- src/Drupal/DrupalKernel.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Drupal/DrupalKernel.php b/src/Drupal/DrupalKernel.php index 9f5b2ce26c..e6fd7b04f4 100644 --- a/src/Drupal/DrupalKernel.php +++ b/src/Drupal/DrupalKernel.php @@ -153,7 +153,7 @@ protected function themeData($theme_list) // If a theme is within a profile directory but specifies another // profile for testing, it needs to be found in the parent profile. $settings = $this->getConfigStorage()->read('simpletest.settings'); - $parent_profile = !empty($settings['parent_profile']) ? $settings['parent_profile'] : NULL; + $parent_profile = !empty($settings['parent_profile']) ? $settings['parent_profile'] : null; if ($parent_profile && !isset($profiles[$parent_profile])) { // In case both profile directories contain the same extension, the // actual profile always has precedence. @@ -176,9 +176,10 @@ protected function themeData($theme_list) * Array where each key is a theme name, and each value is a path to the * respective *.info.yml file. */ - protected function getThemeFileNames() { + protected function getThemeFileNames() + { if ($this->themeNames) { - return $this->themeNames; + return $this->themeNames; } $extensions = $this->getConfigStorage()->read('core.extension'); $theme_list = isset($extensions['theme']) ? $extensions['theme'] : []; From 10ba5e04fc013498fccff530b78f9cec3cc86659 Mon Sep 17 00:00:00 2001 From: Nick Wilde Date: Sun, 17 Dec 2017 00:07:10 -0800 Subject: [PATCH 5/9] Only load theme namespaces when there are Drush commands for the theme Further narrow the namespace to only Drupal/theme_name/Commands. --- src/Drupal/DrupalKernel.php | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/Drupal/DrupalKernel.php b/src/Drupal/DrupalKernel.php index 2647dc3a5a..670a502f6a 100644 --- a/src/Drupal/DrupalKernel.php +++ b/src/Drupal/DrupalKernel.php @@ -66,7 +66,7 @@ protected function initializeContainer() $this->invalidateContainer(); } - $this->classLoaderAddMultiplePsr4($this->getModuleNamespacesPsr4($this->getThemeFileNames())); + $this->classLoaderAddMultiplePsr4($this->getThemeCommandNamespaces()); return parent::initializeContainer(); } @@ -124,8 +124,7 @@ public function discoverServiceProviders() $theme_filenames = $this->getThemeFileNames(); // Load each theme's serviceProvider class. foreach ($theme_filenames as $theme => $filename) { - $filename = dirname($filename) . "/drush.services.yml"; - $this->addDrushServiceProvider("_drush.$theme", $filename); + $this->addModuleDrushServiceProvider($theme, $filename); } } @@ -266,9 +265,26 @@ protected function getThemeFileNames() $theme_data = $this->themeData($theme_list); foreach ($theme_list as $theme => $weight) { if (isset($theme_data[$theme])) { + // Skip themes that don't have a Drush service.yml. + if (!$this->findModuleDrushServiceProvider($theme, dirname($theme_data[$theme]->getPathname()))) { + continue; + } $this->themeNames[$theme] = $theme_data[$theme]->getPathname(); } } return $this->themeNames; } + + /** + * Get PSR4 namespaces for Drush Commands in themes. + */ + protected function getThemeCommandNamespaces() + { + $namespaces = []; + $themes = $this->getThemeFileNames(); + foreach ($themes as $theme => $path) { + $namespaces["Drupal\\$theme\Commands"] = dirname($path) . '/src/Commands'; + } + return $namespaces; + } } From 6369090d83e69744934d524b1604e0b3a7b4c515 Mon Sep 17 00:00:00 2001 From: Nick Wilde Date: Sun, 17 Dec 2017 07:46:38 -0800 Subject: [PATCH 6/9] Minor style fix --- src/Drupal/DrupalKernel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Drupal/DrupalKernel.php b/src/Drupal/DrupalKernel.php index 670a502f6a..1407728808 100644 --- a/src/Drupal/DrupalKernel.php +++ b/src/Drupal/DrupalKernel.php @@ -216,7 +216,7 @@ protected function addDrushServiceProvider($serviceProviderName, $serviceYmlPath } /** - * populates theme data on the filesystem. + * Populates theme filesystem information. * * @see Drupal\Core\DrupalKernel::moduleData(). */ From 153c10269df61821122085aab03f1539b2d64c8d Mon Sep 17 00:00:00 2001 From: Nick Wilde Date: Sun, 17 Dec 2017 07:47:16 -0800 Subject: [PATCH 7/9] Simply DrupalKernel::themeData() --- src/Drupal/DrupalKernel.php | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/src/Drupal/DrupalKernel.php b/src/Drupal/DrupalKernel.php index 1407728808..170428561d 100644 --- a/src/Drupal/DrupalKernel.php +++ b/src/Drupal/DrupalKernel.php @@ -228,23 +228,13 @@ protected function themeData($theme_list) $all_profiles = $listing->scan('profile'); $profiles = array_intersect_key($all_profiles, $theme_list); - // If a theme is within a profile directory but specifies another - // profile for testing, it needs to be found in the parent profile. - $settings = $this->getConfigStorage()->read('simpletest.settings'); - $parent_profile = !empty($settings['parent_profile']) ? $settings['parent_profile'] : null; - if ($parent_profile && !isset($profiles[$parent_profile])) { - // In case both profile directories contain the same extension, the - // actual profile always has precedence. - $profiles = array($parent_profile => $all_profiles[$parent_profile]) + $profiles; - } - $profile_directories = array_map(function ($profile) { return $profile->getPath(); }, $profiles); $listing->setProfileDirectories($profile_directories); // Now find themes. - return $listing->scan('theme'); + $listing->scan('theme'); } /** @@ -261,16 +251,15 @@ protected function getThemeFileNames() } $extensions = $this->getConfigStorage()->read('core.extension'); $theme_list = isset($extensions['theme']) ? $extensions['theme'] : []; - $theme = []; - $theme_data = $this->themeData($theme_list); + $this->themeData($theme_list); foreach ($theme_list as $theme => $weight) { - if (isset($theme_data[$theme])) { - // Skip themes that don't have a Drush service.yml. - if (!$this->findModuleDrushServiceProvider($theme, dirname($theme_data[$theme]->getPathname()))) { - continue; - } - $this->themeNames[$theme] = $theme_data[$theme]->getPathname(); + $dir = drupal_get_path('theme', $theme); + + // Skip themes that don't have a Drush service.yml. + if (!$this->findModuleDrushServiceProvider($theme, $dir)) { + continue; } + $this->themeNames[$theme] = $dir. "/$theme.info.yml"; } return $this->themeNames; } From 0f72f3d8565a2815a46ba27ff78349b9908bb8f9 Mon Sep 17 00:00:00 2001 From: Nick Wilde Date: Fri, 22 Dec 2017 18:36:32 -0800 Subject: [PATCH 8/9] Prevent cases where second invocations of Drush would fail --- src/Drupal/DrupalKernel.php | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/Drupal/DrupalKernel.php b/src/Drupal/DrupalKernel.php index 170428561d..19ed58e991 100644 --- a/src/Drupal/DrupalKernel.php +++ b/src/Drupal/DrupalKernel.php @@ -234,7 +234,7 @@ protected function themeData($theme_list) $listing->setProfileDirectories($profile_directories); // Now find themes. - $listing->scan('theme'); + return $listing->scan('theme'); } /** @@ -251,15 +251,18 @@ protected function getThemeFileNames() } $extensions = $this->getConfigStorage()->read('core.extension'); $theme_list = isset($extensions['theme']) ? $extensions['theme'] : []; - $this->themeData($theme_list); + $data = $this->themeData($theme_list); foreach ($theme_list as $theme => $weight) { - $dir = drupal_get_path('theme', $theme); + if (!isset($data[$theme])) { + continue; + } + $path = $data[$theme]->getPathname(); // Skip themes that don't have a Drush service.yml. - if (!$this->findModuleDrushServiceProvider($theme, $dir)) { + if (!$this->findModuleDrushServiceProvider($theme, dirname($path))) { continue; } - $this->themeNames[$theme] = $dir. "/$theme.info.yml"; + $this->themeNames[$theme] = $path; } return $this->themeNames; } From d22c9e5903c2326271a16ae30bdbca89c448e048 Mon Sep 17 00:00:00 2001 From: Nick Wilde Date: Fri, 22 Dec 2017 18:43:05 -0800 Subject: [PATCH 9/9] Standards - fix incorrect spacing --- src/Drupal/DrupalKernel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Drupal/DrupalKernel.php b/src/Drupal/DrupalKernel.php index 19ed58e991..bd7403b7e6 100644 --- a/src/Drupal/DrupalKernel.php +++ b/src/Drupal/DrupalKernel.php @@ -254,7 +254,7 @@ protected function getThemeFileNames() $data = $this->themeData($theme_list); foreach ($theme_list as $theme => $weight) { if (!isset($data[$theme])) { - continue; + continue; } $path = $data[$theme]->getPathname();