Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 744392d

Browse files
julienfalquefabpot
authored andcommitted
[Finder] Look for gitignore patterns up to git root
1 parent 8075e1d commit 744392d

File tree

8 files changed

+130
-21
lines changed

8 files changed

+130
-21
lines changed

src/Symfony/Component/Finder/Iterator/VcsIgnoredFilterIterator.php

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@ public function __construct(\Iterator $iterator, string $baseDir)
4040
{
4141
$this->baseDir = $this->normalizePath($baseDir);
4242

43+
foreach ($this->parentDirectoriesUpwards($this->baseDir) as $parentDirectory) {
44+
if (@is_dir("{$parentDirectory}/.git")) {
45+
$this->baseDir = $parentDirectory;
46+
break;
47+
}
48+
}
49+
4350
parent::__construct($iterator);
4451
}
4552

@@ -64,7 +71,7 @@ private function isIgnored(string $fileRealPath): bool
6471

6572
$ignored = false;
6673

67-
foreach ($this->parentsDirectoryDownward($fileRealPath) as $parentDirectory) {
74+
foreach ($this->parentDirectoriesDownwards($fileRealPath) as $parentDirectory) {
6875
if ($this->isIgnored($parentDirectory)) {
6976
// rules in ignored directories are ignored, no need to check further.
7077
break;
@@ -95,11 +102,11 @@ private function isIgnored(string $fileRealPath): bool
95102
/**
96103
* @return list<string>
97104
*/
98-
private function parentsDirectoryDownward(string $fileRealPath): array
105+
private function parentDirectoriesUpwards(string $from): array
99106
{
100107
$parentDirectories = [];
101108

102-
$parentDirectory = $fileRealPath;
109+
$parentDirectory = $from;
103110

104111
while (true) {
105112
$newParentDirectory = \dirname($parentDirectory);
@@ -109,16 +116,30 @@ private function parentsDirectoryDownward(string $fileRealPath): array
109116
break;
110117
}
111118

112-
$parentDirectory = $newParentDirectory;
119+
$parentDirectories[] = $parentDirectory = $newParentDirectory;
120+
}
113121

114-
if (!str_starts_with($parentDirectory, $this->baseDir)) {
115-
break;
116-
}
122+
return $parentDirectories;
123+
}
117124

118-
$parentDirectories[] = $parentDirectory;
119-
}
125+
private function parentDirectoriesUpTo(string $from, string $upTo): array
126+
{
127+
return array_filter(
128+
$this->parentDirectoriesUpwards($from),
129+
static function (string $directory) use ($upTo): bool {
130+
return str_starts_with($directory, $upTo);
131+
}
132+
);
133+
}
120134

121-
return array_reverse($parentDirectories);
135+
/**
136+
* @return list<string>
137+
*/
138+
private function parentDirectoriesDownwards(string $fileRealPath): array
139+
{
140+
return array_reverse(
141+
$this->parentDirectoriesUpTo($fileRealPath, $this->baseDir)
142+
);
122143
}
123144

124145
/**

src/Symfony/Component/Finder/Tests/FinderTest.php

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -433,18 +433,60 @@ public function testIgnoreVCSIgnored()
433433
->ignoreVCSIgnored(true)
434434
);
435435

436-
copy(__DIR__.'/Fixtures/gitignore/search_root/b.txt', __DIR__.'/Fixtures/gitignore/search_root/a.txt');
437-
copy(__DIR__.'/Fixtures/gitignore/search_root/b.txt', __DIR__.'/Fixtures/gitignore/search_root/c.txt');
438-
copy(__DIR__.'/Fixtures/gitignore/search_root/dir/a.txt', __DIR__.'/Fixtures/gitignore/search_root/dir/b.txt');
439-
copy(__DIR__.'/Fixtures/gitignore/search_root/dir/a.txt', __DIR__.'/Fixtures/gitignore/search_root/dir/c.txt');
436+
$this->assertIterator(self::toAbsolute([
437+
'gitignore/search_root/b.txt',
438+
'gitignore/search_root/dir',
439+
'gitignore/search_root/dir/a.txt',
440+
]), $finder->in(self::toAbsolute('gitignore/search_root'))->getIterator());
441+
}
442+
443+
public function testIgnoreVCSIgnoredUpToFirstGitRepositoryRoot()
444+
{
445+
$finder = $this->buildFinder();
446+
$this->assertSame(
447+
$finder,
448+
$finder
449+
->ignoreVCS(true)
450+
->ignoreDotFiles(true)
451+
->ignoreVCSIgnored(true)
452+
);
453+
454+
$this->assertIterator(self::toAbsolute([
455+
'gitignore/git_root/search_root/b.txt',
456+
'gitignore/git_root/search_root/c.txt',
457+
'gitignore/git_root/search_root/dir',
458+
'gitignore/git_root/search_root/dir/a.txt',
459+
'gitignore/git_root/search_root/dir/c.txt',
460+
]), $finder->in(self::toAbsolute('gitignore/git_root/search_root'))->getIterator());
461+
}
462+
463+
/**
464+
* @runInSeparateProcess
465+
*/
466+
public function testIgnoreVCSIgnoredWithOpenBasedir()
467+
{
468+
if (ini_get('open_basedir')) {
469+
$this->markTestSkipped('Cannot test when open_basedir is set');
470+
}
471+
472+
$finder = $this->buildFinder();
473+
$this->assertSame(
474+
$finder,
475+
$finder
476+
->ignoreVCS(true)
477+
->ignoreDotFiles(true)
478+
->ignoreVCSIgnored(true)
479+
);
440480

441-
$this->assertIterator($this->toAbsoluteFixtures([
481+
$this->iniSet('open_basedir', \dirname(__DIR__, 5).\PATH_SEPARATOR.self::toAbsolute('gitignore/search_root'));
482+
483+
$this->assertIterator(self::toAbsolute([
442484
'gitignore/search_root/b.txt',
443485
'gitignore/search_root/c.txt',
444486
'gitignore/search_root/dir',
445487
'gitignore/search_root/dir/a.txt',
446488
'gitignore/search_root/dir/c.txt',
447-
]), $finder->in(__DIR__.'/Fixtures/gitignore/search_root')->getIterator());
489+
]), $finder->in(self::toAbsolute('gitignore/search_root'))->getIterator());
448490
}
449491

450492
public function testIgnoreVCSCanBeDisabledAfterFirstIteration()
@@ -1462,6 +1504,15 @@ public function testIgnoredAccessDeniedException()
14621504

14631505
protected function buildFinder()
14641506
{
1465-
return Finder::create();
1507+
return Finder::create()->exclude('gitignore');
1508+
}
1509+
1510+
protected function iniSet(string $varName, string $newValue): void
1511+
{
1512+
if ('open_basedir' === $varName && $deprecationsFile = getenv('SYMFONY_DEPRECATIONS_SERIALIZE')) {
1513+
$newValue .= \PATH_SEPARATOR.$deprecationsFile;
1514+
}
1515+
1516+
parent::iniSet('open_basedir', $newValue);
14661517
}
14671518
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/a.txt

src/Symfony/Component/Finder/Tests/Fixtures/gitignore/git_root/search_root/b.txt

Whitespace-only changes.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/b.txt

src/Symfony/Component/Finder/Tests/Fixtures/gitignore/git_root/search_root/dir/a.txt

Whitespace-only changes.

src/Symfony/Component/Finder/Tests/Iterator/RealIteratorTestCase.php

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111

1212
namespace Symfony\Component\Finder\Tests\Iterator;
1313

14+
use Symfony\Component\Filesystem\Filesystem;
15+
use Symfony\Component\Finder\Tests\FinderTest;
16+
1417
abstract class RealIteratorTestCase extends IteratorTestCase
1518
{
1619
protected static $tmpDir;
@@ -44,6 +47,10 @@ public static function setUpBeforeClass(): void
4447
'qux/baz_100_1.py',
4548
];
4649

50+
if (FinderTest::class === static::class) {
51+
self::$files[] = 'gitignore/';
52+
}
53+
4754
self::$files = self::toAbsolute(self::$files);
4855

4956
if (is_dir(self::$tmpDir)) {
@@ -65,14 +72,39 @@ public static function setUpBeforeClass(): void
6572

6673
touch(self::toAbsolute('foo/bar.tmp'), strtotime('2005-10-15'));
6774
touch(self::toAbsolute('test.php'), strtotime('2005-10-15'));
75+
76+
if (FinderTest::class === static::class) {
77+
$fs = new Filesystem();
78+
$fs->mirror(__DIR__.'/../Fixtures/gitignore', self::toAbsolute('gitignore'));
79+
80+
foreach ([
81+
'gitignore/search_root/a.txt',
82+
'gitignore/search_root/c.txt',
83+
'gitignore/search_root/dir/b.txt',
84+
'gitignore/search_root/dir/c.txt',
85+
'gitignore/git_root/search_root/a.txt',
86+
'gitignore/git_root/search_root/c.txt',
87+
'gitignore/git_root/search_root/dir/b.txt',
88+
'gitignore/git_root/search_root/dir/c.txt',
89+
] as $file) {
90+
$fs->touch(self::toAbsolute($file));
91+
}
92+
93+
$fs->mkdir(self::toAbsolute('gitignore/git_root/.git'));
94+
}
6895
}
6996

7097
public static function tearDownAfterClass(): void
7198
{
72-
$paths = new \RecursiveIteratorIterator(
73-
new \RecursiveDirectoryIterator(self::$tmpDir, \RecursiveDirectoryIterator::SKIP_DOTS),
74-
\RecursiveIteratorIterator::CHILD_FIRST
75-
);
99+
try {
100+
$paths = new \RecursiveIteratorIterator(
101+
new \RecursiveDirectoryIterator(self::$tmpDir, \RecursiveDirectoryIterator::SKIP_DOTS),
102+
\RecursiveIteratorIterator::CHILD_FIRST
103+
);
104+
} catch (\UnexpectedValueException $exception) {
105+
// open_basedir restriction in effect
106+
return;
107+
}
76108

77109
foreach ($paths as $path) {
78110
if ($path->isDir()) {

src/Symfony/Component/Finder/composer.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
"require": {
1919
"php": ">=8.1"
2020
},
21+
"require-dev": {
22+
"symfony/filesystem": "^6.0"
23+
},
2124
"autoload": {
2225
"psr-4": { "Symfony\\Component\\Finder\\": "" },
2326
"exclude-from-classmap": [

0 commit comments

Comments
 (0)