diff --git a/lib/Filesystem/Domain/FileList.php b/lib/Filesystem/Domain/FileList.php index 41d556becd..9221213c46 100644 --- a/lib/Filesystem/Domain/FileList.php +++ b/lib/Filesystem/Domain/FileList.php @@ -86,19 +86,49 @@ public function byExtensions(array $extensions): self } /** - * @param string[] $globPatterns + * @param string[] $includePatterns + * @param string[] $excludePatterns */ - public function excludePatterns(array $globPatterns): self - { - return $this->filter(function (SplFileInfo $info) use ($globPatterns) { - foreach ($globPatterns as $pattern) { - if (Glob::match($info->getPathname(), $pattern)) { - return false; + public function includeAndExclude(array $includePatterns, array $excludePatterns): self + { + // Building map of include paths that are sub paths of excludes so that we can include them again + $includedExcludes = []; + foreach($excludePatterns as $excludePattern) { + foreach($includePatterns as $includePattern) { + if (Glob::match($includePattern, $excludePattern)) { + $includedExcludes[$excludePattern][] = $includePattern; } } + } + + $this->includePatterns($includePatterns); + + return $this->filter(function (SplFileInfo $info) use ($excludePatterns, $includedExcludes) { + foreach ($excludePatterns as $pattern) { + if (!Glob::match($info->getPathname(), $pattern)) { + continue; + } + + $includePatterns = $includedExcludes[$pattern] ?? []; + foreach($includePatterns as $includePattern) { + if (Glob::match($info->getPathname(), $includePattern)) { + return true; + } + } + return false; + } return true; }); + + } + + /** + * @param string[] $globPatterns + */ + public function excludePatterns(array $globPatterns): self + { + return $this->includeAndExclude([], $globPatterns); } /** diff --git a/lib/Filesystem/Tests/Unit/Domain/FileListTest.php b/lib/Filesystem/Tests/Unit/Domain/FileListTest.php index 14dba9aab6..2aa6cf09ee 100644 --- a/lib/Filesystem/Tests/Unit/Domain/FileListTest.php +++ b/lib/Filesystem/Tests/Unit/Domain/FileListTest.php @@ -140,6 +140,22 @@ public function testIncldesFilesMatchingPatterns(): void ])); } + public function testIncludesExcludePatterns(): void + { + + $list = FileList::fromFilePaths([ + FilePath::fromString('/vendor/cache/important/bartest.php'), + FilePath::fromString('/vendor/cache/important/footest.php'), + FilePath::fromString('/vendor/cache/bar.php'), + FilePath::fromString('/vendor/cache/foo.php'), + ])->includeAndExclude( + includePatterns: [ '/src/**/*', '/vendor/cache/important/**/*'], + excludePatterns: [ '/vendor/**/*' ], + ); + + self::assertCount(2, $list); + } + public function testContainingString(): void { $this->workspace()->put('one', 'one two three'); diff --git a/lib/Indexer/Adapter/Filesystem/FilesystemFileListProvider.php b/lib/Indexer/Adapter/Filesystem/FilesystemFileListProvider.php index 7140e61993..40fe59c094 100644 --- a/lib/Indexer/Adapter/Filesystem/FilesystemFileListProvider.php +++ b/lib/Indexer/Adapter/Filesystem/FilesystemFileListProvider.php @@ -30,15 +30,10 @@ public function provideFileList(Index $index, ?string $subPath = null): FileList return FileList::fromSingleFilePath($subPath); } - $files = $this->filesystem->fileList()->byExtensions($this->supportedExtensions); - - if ($this->includePatterns) { - $files = $files->includePatterns($this->includePatterns); - } - - if ($this->excludePatterns) { - $files = $files->excludePatterns($this->excludePatterns); - } + $files = $this->filesystem->fileList() + ->byExtensions($this->supportedExtensions) + ->includeAndExclude($this->includePatterns, $this->excludePatterns) + ; if ($subPath) { $files = $files->within(FilePath::fromString($subPath)); diff --git a/lib/Indexer/Extension/IndexerExtension.php b/lib/Indexer/Extension/IndexerExtension.php index 703a63237e..18571d4de6 100644 --- a/lib/Indexer/Extension/IndexerExtension.php +++ b/lib/Indexer/Extension/IndexerExtension.php @@ -224,9 +224,7 @@ private function registerModel(ContainerBuilder $container): void ->setIncludePatterns($container->get(self::SERVICE_INDEXER_INCLUDE_PATTERNS)) /** @phpstan-ignore-next-line */ ->setSupportedExtensions($container->parameter(self::PARAM_SUPPORTED_EXTENSIONS)->value()) - ->setFollowSymlinks( - (bool) $container->getParameter(self::PARAM_INDEXER_FOLLOW_SYMLINKS), - ) + ->setFollowSymlinks($container->parameter(self::PARAM_INDEXER_FOLLOW_SYMLINKS)->bool()) ->setStubPaths($container->getParameter(self::PARAM_STUB_PATHS)); });