Skip to content
Snippets Groups Projects
Commit e4fe8675 authored by Adam G-H's avatar Adam G-H
Browse files

Issue #3408560 by phenaproxima, tedbow: If paths are being excluded in the...

Issue #3408560 by phenaproxima, tedbow: If paths are being excluded in the project root, log an informational message about it
parent 3d1bd218
No related branches found
No related tags found
1 merge request!993Resolve #3408560 "Use logger"
...@@ -125,6 +125,8 @@ services: ...@@ -125,6 +125,8 @@ services:
Drupal\package_manager\PathExcluder\UnknownPathExcluder: Drupal\package_manager\PathExcluder\UnknownPathExcluder:
tags: tags:
- { name: event_subscriber } - { name: event_subscriber }
calls:
- [setLogger, ['@logger.channel.package_manager']]
Drupal\package_manager\PathExcluder\SiteConfigurationExcluder: Drupal\package_manager\PathExcluder\SiteConfigurationExcluder:
arguments: arguments:
$sitePath: '%site.path%' $sitePath: '%site.path%'
......
...@@ -6,9 +6,14 @@ namespace Drupal\package_manager\PathExcluder; ...@@ -6,9 +6,14 @@ namespace Drupal\package_manager\PathExcluder;
use Drupal\Component\Serialization\Json; use Drupal\Component\Serialization\Json;
use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\package_manager\ComposerInspector; use Drupal\package_manager\ComposerInspector;
use Drupal\package_manager\Event\CollectPathsToExcludeEvent; use Drupal\package_manager\Event\CollectPathsToExcludeEvent;
use Drupal\package_manager\Event\StatusCheckEvent;
use Drupal\package_manager\PathLocator; use Drupal\package_manager\PathLocator;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerAwareTrait;
use Psr\Log\NullLogger;
use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/** /**
...@@ -36,7 +41,10 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface; ...@@ -36,7 +41,10 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface;
* at any time without warning. External code should not interact with this * at any time without warning. External code should not interact with this
* class. * class.
*/ */
final class UnknownPathExcluder implements EventSubscriberInterface { final class UnknownPathExcluder implements EventSubscriberInterface, LoggerAwareInterface {
use LoggerAwareTrait;
use StringTranslationTrait;
/** /**
* Constructs a UnknownPathExcluder object. * Constructs a UnknownPathExcluder object.
...@@ -52,7 +60,9 @@ final class UnknownPathExcluder implements EventSubscriberInterface { ...@@ -52,7 +60,9 @@ final class UnknownPathExcluder implements EventSubscriberInterface {
private readonly ComposerInspector $composerInspector, private readonly ComposerInspector $composerInspector,
private readonly PathLocator $pathLocator, private readonly PathLocator $pathLocator,
private readonly ConfigFactoryInterface $configFactory, private readonly ConfigFactoryInterface $configFactory,
) {} ) {
$this->setLogger(new NullLogger());
}
/** /**
* {@inheritdoc} * {@inheritdoc}
...@@ -60,26 +70,28 @@ final class UnknownPathExcluder implements EventSubscriberInterface { ...@@ -60,26 +70,28 @@ final class UnknownPathExcluder implements EventSubscriberInterface {
public static function getSubscribedEvents(): array { public static function getSubscribedEvents(): array {
return [ return [
CollectPathsToExcludeEvent::class => 'excludeUnknownPaths', CollectPathsToExcludeEvent::class => 'excludeUnknownPaths',
StatusCheckEvent::class => 'logExcludedPaths',
]; ];
} }
/** /**
* Excludes unknown paths from stage operations. * Returns the paths to exclude from stage operations.
* *
* @param \Drupal\package_manager\Event\CollectPathsToExcludeEvent $event * @return string[]
* The event object. * The paths that should be excluded from stage operations, relative to the
* project root.
* *
* @throws \Exception * @throws \Exception
* See \Drupal\package_manager\ComposerInspector::validate(). * See \Drupal\package_manager\ComposerInspector::validate().
*/ */
public function excludeUnknownPaths(CollectPathsToExcludeEvent $event): void { private function getExcludedPaths(): array {
// If this excluder is disabled, or the project root and web root are the // If this excluder is disabled, or the project root and web root are the
// same, there's nothing to do. // same, we are not excluding any paths.
$is_disabled = $this->configFactory->get('package_manager.settings') $is_disabled = $this->configFactory->get('package_manager.settings')
->get('include_unknown_files_in_project_root'); ->get('include_unknown_files_in_project_root');
$web_root = $this->pathLocator->getWebRoot(); $web_root = $this->pathLocator->getWebRoot();
if ($is_disabled || empty($web_root)) { if ($is_disabled || empty($web_root)) {
return; return [];
} }
// To determine the files to include, the installed packages must be known, // To determine the files to include, the installed packages must be known,
...@@ -115,18 +127,45 @@ final class UnknownPathExcluder implements EventSubscriberInterface { ...@@ -115,18 +127,45 @@ final class UnknownPathExcluder implements EventSubscriberInterface {
// glob() flags aren't supported on all systems. We also can't use // glob() flags aren't supported on all systems. We also can't use
// \Drupal\Core\File\FileSystemInterface::scanDirectory(), because it // \Drupal\Core\File\FileSystemInterface::scanDirectory(), because it
// unconditionally ignores hidden files and directories. // unconditionally ignores hidden files and directories.
$files_in_project_root = [];
$handle = opendir($project_root); $handle = opendir($project_root);
if (empty($handle)) { if (empty($handle)) {
throw new \RuntimeException("Could not scan for files in the project root."); throw new \RuntimeException("Could not scan for files in the project root.");
} }
while ($entry = readdir($handle)) { while ($entry = readdir($handle)) {
if ($entry === '.' || $entry === '..' || in_array($entry, $always_include, TRUE)) { $files_in_project_root[] = $entry;
continue;
}
// We can add the path as-is; it's already relative to the project root.
$event->add($entry);
} }
closedir($handle); closedir($handle);
return array_diff($files_in_project_root, $always_include, ['.', '..']);
}
/**
* Excludes unknown paths from stage operations.
*
* @param \Drupal\package_manager\Event\CollectPathsToExcludeEvent $event
* The event object.
*/
public function excludeUnknownPaths(CollectPathsToExcludeEvent $event): void {
// We can exclude the paths as-is; they are already relative to the project
// root.
$event->add(...$this->getExcludedPaths());
}
/**
* Logs the paths that will be excluded from stage operations.
*/
public function logExcludedPaths(): void {
$excluded_paths = $this->getExcludedPaths();
if ($excluded_paths) {
sort($excluded_paths);
$message = $this->t("The following paths in @project_root aren't recognized as part of your Drupal site, so to be safe, Package Manager is excluding them from all stage operations. If these files are not needed for Composer to work properly in your site, no action is needed. Otherwise, you can disable this behavior by setting the <code>package_manager.settings:include_unknown_files_in_project_root</code> config setting to <code>TRUE</code>.\n\n@list", [
'@project_root' => $this->pathLocator->getProjectRoot(),
'@list' => implode("\n", $excluded_paths),
]);
$this->logger->info($message);
}
} }
/** /**
......
...@@ -4,7 +4,9 @@ declare(strict_types = 1); ...@@ -4,7 +4,9 @@ declare(strict_types = 1);
namespace Drupal\Tests\package_manager\Kernel\PathExcluder; namespace Drupal\Tests\package_manager\Kernel\PathExcluder;
use ColinODell\PsrTestLogger\TestLogger;
use Drupal\Component\FileSystem\FileSystem as DrupalFileSystem; use Drupal\Component\FileSystem\FileSystem as DrupalFileSystem;
use Drupal\Core\Logger\RfcLogLevel;
use Drupal\package_manager\PathLocator; use Drupal\package_manager\PathLocator;
use Drupal\Tests\package_manager\Kernel\PackageManagerKernelTestBase; use Drupal\Tests\package_manager\Kernel\PackageManagerKernelTestBase;
use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\Filesystem\Filesystem;
...@@ -153,6 +155,28 @@ class UnknownPathExcluderTest extends PackageManagerKernelTestBase { ...@@ -153,6 +155,28 @@ class UnknownPathExcluderTest extends PackageManagerKernelTestBase {
} }
$stage = $this->createStage(); $stage = $this->createStage();
// Files are only excluded if the web root and project root are different.
// If anything in the project root is excluded, those paths should be
// logged.
if ($use_nested_webroot) {
$logger = new TestLogger();
$this->container->get('logger.factory')
->get('package_manager')
->addLogger($logger);
$this->runStatusCheck($stage);
$this->assertTrue($logger->hasRecordThatContains("The following paths in $active_dir aren't recognized as part of your Drupal site, so to be safe, Package Manager is excluding them from all stage operations. If these files are not needed for Composer to work properly in your site, no action is needed. Otherwise, you can disable this behavior by setting the <code>package_manager.settings:include_unknown_files_in_project_root</code> config setting to <code>TRUE</code>.", RfcLogLevel::INFO));
foreach ($unknown_files as $unknown_file) {
// If $unknown_file is in a subdirectory, only the subdirectory is going
// to be logged as an excluded path. The excluder doesn't recurse into
// subdirectories.
if (str_contains($unknown_file, '/')) {
$unknown_file = dirname($unknown_file);
}
$this->assertTrue($logger->hasRecordThatContains($unknown_file, RfcLogLevel::INFO));
}
}
$stage->create(); $stage->create();
$stage->require(['ext-json:*']); $stage->require(['ext-json:*']);
$stage_dir = $stage->getStageDirectory(); $stage_dir = $stage->getStageDirectory();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment