resolved conflicts

This commit is contained in:
2025-03-31 03:46:05 +03:00
6454 changed files with 1520539 additions and 9 deletions
@@ -0,0 +1,134 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Iterator;
use Symfony\Component\Finder\Exception\AccessDeniedException;
use Symfony\Component\Finder\SplFileInfo;
/**
* Extends the \RecursiveDirectoryIterator to support relative paths.
*
* @author Victor Berchet <victor@suumit.com>
*
* @extends \RecursiveDirectoryIterator<string, SplFileInfo>
*/
class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
{
private bool $ignoreUnreadableDirs;
private bool $ignoreFirstRewind = true;
// these 3 properties take part of the performance optimization to avoid redoing the same work in all iterations
private string $rootPath;
private string $subPath;
private string $directorySeparator = '/';
/**
* @throws \RuntimeException
*/
public function __construct(string $path, int $flags, bool $ignoreUnreadableDirs = false)
{
if ($flags & (self::CURRENT_AS_PATHNAME | self::CURRENT_AS_SELF)) {
throw new \RuntimeException('This iterator only support returning current as fileinfo.');
}
parent::__construct($path, $flags);
$this->ignoreUnreadableDirs = $ignoreUnreadableDirs;
$this->rootPath = $path;
if ('/' !== \DIRECTORY_SEPARATOR && !($flags & self::UNIX_PATHS)) {
$this->directorySeparator = \DIRECTORY_SEPARATOR;
}
}
/**
* Return an instance of SplFileInfo with support for relative paths.
*/
public function current(): SplFileInfo
{
// the logic here avoids redoing the same work in all iterations
if (!isset($this->subPath)) {
$this->subPath = $this->getSubPath();
}
$subPathname = $this->subPath;
if ('' !== $subPathname) {
$subPathname .= $this->directorySeparator;
}
$subPathname .= $this->getFilename();
$basePath = $this->rootPath;
if ('/' !== $basePath && !str_ends_with($basePath, $this->directorySeparator) && !str_ends_with($basePath, '/')) {
$basePath .= $this->directorySeparator;
}
return new SplFileInfo($basePath.$subPathname, $this->subPath, $subPathname);
}
public function hasChildren(bool $allowLinks = false): bool
{
$hasChildren = parent::hasChildren($allowLinks);
if (!$hasChildren || !$this->ignoreUnreadableDirs) {
return $hasChildren;
}
try {
parent::getChildren();
return true;
} catch (\UnexpectedValueException) {
// If directory is unreadable and finder is set to ignore it, skip children
return false;
}
}
/**
* @throws AccessDeniedException
*/
public function getChildren(): \RecursiveDirectoryIterator
{
try {
$children = parent::getChildren();
if ($children instanceof self) {
// parent method will call the constructor with default arguments, so unreadable dirs won't be ignored anymore
$children->ignoreUnreadableDirs = $this->ignoreUnreadableDirs;
// performance optimization to avoid redoing the same work in all children
$children->rootPath = $this->rootPath;
}
return $children;
} catch (\UnexpectedValueException $e) {
throw new AccessDeniedException($e->getMessage(), $e->getCode(), $e);
}
}
public function next(): void
{
$this->ignoreFirstRewind = false;
parent::next();
}
public function rewind(): void
{
// some streams like FTP are not rewindable, ignore the first rewind after creation,
// as newly created DirectoryIterator does not need to be rewound
if ($this->ignoreFirstRewind) {
$this->ignoreFirstRewind = false;
return;
}
parent::rewind();
}
}
@@ -0,0 +1,173 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Iterator;
use Symfony\Component\Finder\Gitignore;
/**
* @extends \FilterIterator<string, \SplFileInfo>
*/
final class VcsIgnoredFilterIterator extends \FilterIterator
{
private string $baseDir;
/**
* @var array<string, array{0: string, 1: string}|null>
*/
private array $gitignoreFilesCache = [];
/**
* @var array<string, bool>
*/
private array $ignoredPathsCache = [];
/**
* @param \Iterator<string, \SplFileInfo> $iterator
*/
public function __construct(\Iterator $iterator, string $baseDir)
{
$this->baseDir = $this->normalizePath($baseDir);
foreach ([$this->baseDir, ...$this->parentDirectoriesUpwards($this->baseDir)] as $directory) {
if (@is_dir("{$directory}/.git")) {
$this->baseDir = $directory;
break;
}
}
parent::__construct($iterator);
}
public function accept(): bool
{
$file = $this->current();
$fileRealPath = $this->normalizePath($file->getRealPath());
return !$this->isIgnored($fileRealPath);
}
private function isIgnored(string $fileRealPath): bool
{
if (is_dir($fileRealPath) && !str_ends_with($fileRealPath, '/')) {
$fileRealPath .= '/';
}
if (isset($this->ignoredPathsCache[$fileRealPath])) {
return $this->ignoredPathsCache[$fileRealPath];
}
$ignored = false;
foreach ($this->parentDirectoriesDownwards($fileRealPath) as $parentDirectory) {
if ($this->isIgnored($parentDirectory)) {
// rules in ignored directories are ignored, no need to check further.
break;
}
$fileRelativePath = substr($fileRealPath, \strlen($parentDirectory) + 1);
if (null === $regexps = $this->readGitignoreFile("{$parentDirectory}/.gitignore")) {
continue;
}
[$exclusionRegex, $inclusionRegex] = $regexps;
if (preg_match($exclusionRegex, $fileRelativePath)) {
$ignored = true;
continue;
}
if (preg_match($inclusionRegex, $fileRelativePath)) {
$ignored = false;
}
}
return $this->ignoredPathsCache[$fileRealPath] = $ignored;
}
/**
* @return list<string>
*/
private function parentDirectoriesUpwards(string $from): array
{
$parentDirectories = [];
$parentDirectory = $from;
while (true) {
$newParentDirectory = \dirname($parentDirectory);
// dirname('/') = '/'
if ($newParentDirectory === $parentDirectory) {
break;
}
$parentDirectories[] = $parentDirectory = $newParentDirectory;
}
return $parentDirectories;
}
private function parentDirectoriesUpTo(string $from, string $upTo): array
{
return array_filter(
$this->parentDirectoriesUpwards($from),
static fn (string $directory): bool => str_starts_with($directory, $upTo)
);
}
/**
* @return list<string>
*/
private function parentDirectoriesDownwards(string $fileRealPath): array
{
return array_reverse(
$this->parentDirectoriesUpTo($fileRealPath, $this->baseDir)
);
}
/**
* @return array{0: string, 1: string}|null
*/
private function readGitignoreFile(string $path): ?array
{
if (\array_key_exists($path, $this->gitignoreFilesCache)) {
return $this->gitignoreFilesCache[$path];
}
if (!file_exists($path)) {
return $this->gitignoreFilesCache[$path] = null;
}
if (!is_file($path) || !is_readable($path)) {
throw new \RuntimeException("The \"ignoreVCSIgnored\" option cannot be used by the Finder as the \"{$path}\" file is not readable.");
}
$gitignoreFileContent = file_get_contents($path);
return $this->gitignoreFilesCache[$path] = [
Gitignore::toRegex($gitignoreFileContent),
Gitignore::toRegexMatchingNegatedPatterns($gitignoreFileContent),
];
}
private function normalizePath(string $path): string
{
if ('\\' === \DIRECTORY_SEPARATOR) {
return str_replace('\\', '/', $path);
}
return $path;
}
}