diff --git a/src/Bootstrap/AddServicesCompilerPass.php b/src/Bootstrap/AddServicesCompilerPass.php index c10813262..5b74c9a9f 100644 --- a/src/Bootstrap/AddServicesCompilerPass.php +++ b/src/Bootstrap/AddServicesCompilerPass.php @@ -12,6 +12,8 @@ use Drupal\Console\Utils\TranslatorManager; use Drupal\Console\Extension\Extension; use Drupal\Console\Extension\Manager; +use Drupal\Core\Cache\ListCacheBinsPass; +use GuzzleHttp\Client; /** * FindCommandsCompilerPass @@ -77,15 +79,35 @@ public function process(ContainerBuilder $container) * @var Site $site */ $site = $container->get('console.site'); - \Drupal::getContainer()->set( + $container->set( 'console.root', $this->root ); + // The AddServicesCompilerPass cache pass is executed before the + // ListCacheBinsPass causing exception: ParameterNotFoundException: You + // have requested a non-existent parameter "cache_default_bin_backends" + $cache_pass = new ListCacheBinsPass(); + $cache_pass->process($container); + + // Fix ContainerNotInitializedException: \Drupal::$container is not initialized yet. + // \Drupal::setContainer() must be called with a real container. The use of stream_wrapper.temporary + // service at cachedServicesFileExists method uses the container that in compiler pass + // is not ready to use: https://github.com/symfony/symfony/issues/22125#issuecomment-288734689 + // This is workaroud works but seems that we cannot depend on services at this stage. + \Drupal::setContainer($container); + + // Avoid Error: Call to undefined function + // Drupal\Core\StreamWrapper\file_directory_temp() in TemporaryStream + // that seems to be needed to the cache services and when no other + // stream wrapper is available defaults ont TemporaryStream. + $site->loadLegacyFile('/core/includes/file.inc'); + if (!$this->rebuild && $site->cachedServicesFileExists()) { $loader->load($site->getCachedServicesFile()); } else { $site->removeCachedServicesFile(); + $finder = new Finder(); $finder->files() ->name('*.yml') @@ -105,10 +127,18 @@ public function process(ContainerBuilder $container) ); } + // Avoid to use the container to get the console.extension_manager due + // container is not ready and cause exceptions. + + /** + * @var GuzzleHttp\Client $httpClient + */ + $httpClient = new Client; /** * @var Manager $extensionManager */ - $extensionManager = $container->get('console.extension_manager'); + $extensionManager = new Manager($site, $httpClient, $this->appRoot); + /** * @var Extension[] $modules */ diff --git a/src/Bootstrap/Drupal.php b/src/Bootstrap/Drupal.php index 3056eed6e..de08f7610 100644 --- a/src/Bootstrap/Drupal.php +++ b/src/Bootstrap/Drupal.php @@ -10,6 +10,8 @@ use Drupal\Console\Core\Utils\ArgvInputReader; use Drupal\Console\Core\Bootstrap\DrupalConsoleCore; use Drupal\Console\Core\Utils\DrupalFinder; +use Drupal\Component\FileCache\FileCacheFactory; +use Drupal\Core\Site\Settings; class Drupal { @@ -143,9 +145,26 @@ public function boot() $io->writeln("\r\033[K\033[1A\r"); $io->writeln('➤ Rebuilding container'); } + + // Fix an exception of FileCacheFactory not prefix not set when + // container is build and looks that as we depend on cache for + // AddServicesCompilerPass but container is not ready this prefix + // needs to be set manually to allow use of the cache files. + FileCacheFactory::setPrefix($this->drupalFinder->getDrupalRoot()); + + // Invalidate container to ensure rebuild of any cached state + // when boot is processed. $drupalKernel->invalidateContainer(); - $drupalKernel->rebuildContainer(); + + // Looks that the boot process is handling an initializeContainer + // so looks that rebuildContainer repeats what we finally do in boot(). + //$drupalKernel->rebuildContainer(); + + // Load legacy libraries, modules, register stream wrapper, and push + // request to request stack but without trigger processing of '/' + // request that invokes hooks like hook_page_attachments(). $drupalKernel->boot(); + $drupalKernel->preHandle($request); if ($debug) { $io->writeln("\r\033[K\033[1A\r"); diff --git a/src/Bootstrap/DrupalKernel.php b/src/Bootstrap/DrupalKernel.php index 0bf201230..ff616edfb 100644 --- a/src/Bootstrap/DrupalKernel.php +++ b/src/Bootstrap/DrupalKernel.php @@ -26,7 +26,17 @@ public static function createFromRequest(Request $request, $class_loader, $envir $kernel = new static($environment, $class_loader, $allow_dumping, $app_root); static::bootEnvironment($app_root); $kernel->initializeSettings($request); - $kernel->handle($request); + // Calling the request handle causes that a page request "/" is + // processed for any console execution even: help or --version and + // with sites that have globally displayed blocks contexts are not + // ready for blocks plugins so this causes lot of problems like: + // https://github.com/hechoendrupal/drupal-console/issues/3091 and + // https://github.com/hechoendrupal/drupal-console/issues/3553 Also + // handle does a initializeContainer which originally was invalidated + // and rebuild at Console Drupal Bootstrap. By disabling handle + // and processing the boot() at Bootstrap commands that do not + // depend on requests works well. + //$kernel->handle($request); return $kernel; } diff --git a/src/Extension/Manager.php b/src/Extension/Manager.php index 3c82b78c8..e97cd9e0c 100644 --- a/src/Extension/Manager.php +++ b/src/Extension/Manager.php @@ -211,7 +211,6 @@ private function getExtensions( $extensions[$name] = $extension; } - return $nameOnly?array_keys($extensions):$extensions; } @@ -221,11 +220,6 @@ private function getExtensions( */ private function discoverExtensions($type) { - if ($type === 'module') { - $this->site->loadLegacyFile('/core/modules/system/system.module'); - system_rebuild_module_data(); - } - if ($type === 'theme') { $themeHandler = \Drupal::service('theme_handler'); $themeHandler->rebuildThemeData(); @@ -237,8 +231,29 @@ private function discoverExtensions($type) */ $discovery = new Discovery($this->appRoot); $discovery->reset(); + $extensions = $discovery->scan($type); + + if ($type === 'module') { + // Using system_rebuild_module_data causes an error: + // Constructing service "logger.factory" from a parent definition is not supported at build time. + //$this->site->loadLegacyFile('/core/modules/system/system.module'); + //system_rebuild_module_data(); + + // Looks that dependency on rebuild module data is just to determine + // the installed status so alternatively we can just look on installed + // modules config and apply to discovered extensions. + $installed_modules = \Drupal::config('core.extension')->get('module') ?: []; + + /** + * @var \Drupal\Core\Extension\Extension $extension + */ + foreach ($extensions as $name => $extension) { + $extensions[$name]->weight = isset($installed_modules[$name]) ? $installed_modules[$name] : 0; + $extensions[$name]->status = (int) isset($installed_modules[$name]); + } + } - return $discovery->scan($type); + return $extensions; } /**