Skip to content

Commit 9b95ed0

Browse files
committed
fix: fix logic error for file finder
1 parent de25967 commit 9b95ed0

File tree

2 files changed

+86
-45
lines changed

2 files changed

+86
-45
lines changed

src/FileFinder.php

+74-44
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
use RecursiveIteratorIterator;
2626
use RuntimeException;
2727
use SplFileInfo;
28+
use Toolkit\Stdlib\Str;
2829
use Traversable;
2930
use UnexpectedValueException;
3031
use function array_flip;
@@ -34,6 +35,7 @@
3435
use function fnmatch;
3536
use function get_object_vars;
3637
use function is_iterable;
38+
use function is_string;
3739
use function iterator_count;
3840
use function str_contains;
3941
use function stream_get_meta_data;
@@ -78,16 +80,14 @@ final class FileFinder implements IteratorAggregate, Countable
7880
/** @var bool */
7981
private bool $ignoreVcsAdded = false;
8082

81-
/**
82-
* @var bool
83-
*/
83+
/** @var bool */
8484
private bool $skipUnreadableDirs = true;
8585

8686
/** @var array */
8787
private array $dirs = [];
8888

8989
/**
90-
* File,dir name match.
90+
* add include file,dir name match.
9191
*
9292
* eg: '.php' '*.php' 'test.php'
9393
*
@@ -96,26 +96,28 @@ final class FileFinder implements IteratorAggregate, Countable
9696
private array $names = [];
9797

9898
/**
99-
* File,dir name exclude
99+
* add exclude file,dir name patterns
100100
*
101101
* eg: '.php' '*.php' 'test.php'
102102
*
103103
* @var array
104104
*/
105105
private array $notNames = [];
106106

107-
/** @var array */
107+
/** @var array<string> include paths pattern. */
108108
private array $paths = [];
109109

110-
/** @var array */
110+
/** @var array<string> exclude paths pattern */
111111
private array $notPaths = [];
112112

113-
/**
114-
* @var array exclude directories
115-
*/
113+
/** @var array<string> exclude directory names */
116114
private array $excludes = [];
117115

118-
/** @var array */
116+
/**
117+
* path filters. each filter like: `Closure(SplFileInfo):bool`, return FALSE to exclude.
118+
*
119+
* @var array
120+
*/
119121
private array $filters = [];
120122

121123
/** @var array */
@@ -213,6 +215,8 @@ public function onlyFiles(): self
213215
}
214216

215217
/**
218+
* add include file,dir name match pattern.
219+
*
216220
* $finder->name('*.php')
217221
* $finder->name('test.php')
218222
*
@@ -222,28 +226,29 @@ public function onlyFiles(): self
222226
*/
223227
public function name(string $pattern): self
224228
{
225-
if ($pattern) {
226-
$this->names[] = $pattern;
227-
}
228-
229-
return $this;
229+
return $this->addNames($pattern);
230230
}
231231

232232
/**
233+
* add include file,dir name match pattern.
234+
*
233235
* @param array|string $patterns
234236
*
235237
* @return FileFinder
236238
*/
237239
public function addNames(array|string $patterns): self
238240
{
239241
if ($patterns) {
240-
$this->names = array_merge($this->names, (array)$patterns);
242+
$patterns = is_string($patterns) ? Str::splitTrimmed($patterns) : $patterns;
243+
// append
244+
$this->names = array_merge($this->names, $patterns);
241245
}
242-
243246
return $this;
244247
}
245248

246249
/**
250+
* add exclude file,dir name patterns
251+
*
247252
* @param string $pattern
248253
*
249254
* @return FileFinder
@@ -255,20 +260,25 @@ public function notName(string $pattern): self
255260
}
256261

257262
/**
263+
* add exclude file,dir name patterns
264+
*
258265
* @param array|string $patterns
259266
*
260267
* @return FileFinder
261268
*/
262269
public function notNames(array|string $patterns): self
263270
{
264271
if ($patterns) {
265-
$this->notNames = array_merge($this->notNames, (array)$patterns);
272+
$patterns = is_string($patterns) ? Str::splitTrimmed($patterns) : $patterns;
273+
// append
274+
$this->notNames = array_merge($this->notNames, $patterns);
266275
}
267-
268276
return $this;
269277
}
270278

271279
/**
280+
* add exclude file,dir name patterns
281+
*
272282
* @param array|string $patterns
273283
*
274284
* @return FileFinder
@@ -279,6 +289,8 @@ public function addNotNames(array|string $patterns): self
279289
}
280290

281291
/**
292+
* add include paths pattern.
293+
* eg:
282294
* $finder->path('some/special/dir')
283295
*
284296
* @param string $pattern
@@ -292,33 +304,37 @@ public function path(string $pattern): self
292304
}
293305

294306
/**
307+
* add include paths pattern.
308+
*
295309
* @param array|string $patterns
296310
*
297311
* @return FileFinder
298312
*/
299313
public function addPaths(array|string $patterns): self
300314
{
301315
if ($patterns) {
302-
$this->paths = array_merge($this->paths, (array)$patterns);
316+
$patterns = is_string($patterns) ? Str::splitTrimmed($patterns) : $patterns;
317+
// append
318+
$this->paths = array_merge($this->paths, $patterns);
303319
}
304-
305320
return $this;
306321
}
307322

308323
/**
324+
* add exclude paths pattern
325+
*
309326
* @param string $pattern
310327
*
311328
* @return FileFinder
312329
*/
313330
public function notPath(string $pattern): self
314331
{
315-
if ($pattern) {
316-
$this->notPaths[] = $pattern;
317-
}
318-
return $this;
332+
return $this->addNotPaths($pattern);
319333
}
320334

321335
/**
336+
* add exclude paths pattern. alias of addNotPaths()
337+
*
322338
* @param array|string $patterns
323339
*
324340
* @return FileFinder
@@ -329,30 +345,37 @@ public function notPaths(array|string $patterns): self
329345
}
330346

331347
/**
348+
* add exclude paths pattern.
349+
* eg: $finder->addNotPaths(['vendor', 'node_modules', 'bin/'])
350+
*
332351
* @param array|string $patterns
333352
*
334353
* @return FileFinder
335354
*/
336355
public function addNotPaths(array|string $patterns): self
337356
{
338357
if ($patterns) {
339-
$this->notPaths = array_merge($this->notPaths, (array)$patterns);
358+
$patterns = is_string($patterns) ? Str::splitTrimmed($patterns) : $patterns;
359+
// append
360+
$this->notPaths = array_merge($this->notPaths, $patterns);
340361
}
341-
342362
return $this;
343363
}
344364

345365
/**
346-
* @param $dirs
366+
* exclude directory names
367+
*
368+
* @param array|string $dirNames
347369
*
348370
* @return FileFinder
349371
*/
350-
public function exclude($dirs): self
372+
public function exclude(array|string $dirNames): self
351373
{
352-
if ($dirs) {
353-
$this->excludes = array_merge($this->excludes, (array)$dirs);
374+
if ($dirNames) {
375+
$dirNames = is_string($dirNames) ? Str::splitTrimmed($dirNames) : $dirNames;
376+
// append
377+
$this->excludes = array_merge($this->excludes, $dirNames);
354378
}
355-
356379
return $this;
357380
}
358381

@@ -429,14 +452,13 @@ public function followLinks(mixed $followLinks = true): self
429452
}
430453

431454
/**
432-
* @param Closure $closure
455+
* @param Closure(SplFileInfo): bool $closure
433456
*
434457
* @return FileFinder
435458
*/
436459
public function filter(Closure $closure): self
437460
{
438461
$this->filters[] = $closure;
439-
440462
return $this;
441463
}
442464

@@ -460,9 +482,10 @@ public function in(array|string $dirs): self
460482
public function inDir(array|string $dirs): self
461483
{
462484
if ($dirs) {
463-
$this->dirs = array_merge($this->dirs, (array)$dirs);
485+
$dirs = is_string($dirs) ? Str::splitTrimmed($dirs) : $dirs;
486+
// append
487+
$this->dirs = array_merge($this->dirs, $dirs);
464488
}
465-
466489
return $this;
467490
}
468491

@@ -585,7 +608,7 @@ private function findInDirectory(string $dir): Iterator
585608
$flags |= RecursiveDirectoryIterator::FOLLOW_SYMLINKS;
586609
}
587610

588-
$iterator = new class($dir, $flags) extends RecursiveDirectoryIterator {
611+
$iterator = new class($dir, $flags, $this->skipUnreadableDirs) extends RecursiveDirectoryIterator {
589612
private string $rootPath;
590613
private string $subPath = '';
591614
private bool|null $rewindable = null;
@@ -610,8 +633,9 @@ public function __construct(string $path, int $flags, bool $skipUnreadableDirs =
610633

611634
public function current(): SplFileInfo
612635
{
636+
// vdump($this->getPathname(), $this);
613637
if (null === $subPathname = $this->subPath) {
614-
$subPathname = $this->subPath = (string)$this->getSubPath();
638+
$subPathname = $this->subPath = $this->getSubPath();
615639
}
616640

617641
if ('' !== $subPathname) {
@@ -620,8 +644,9 @@ public function current(): SplFileInfo
620644

621645
$subPathname .= $this->getFilename();
622646

623-
// $fileInfo = new \SplFileInfo($this->getPathname());
624-
$fileInfo = new SplFileInfo($this->rootPath . $this->directorySep . $subPathname);
647+
$fileInfo = new SplFileInfo($this->getPathname());
648+
// $fileInfo = new SplFileInfo($this->rootPath . $this->directorySep . $subPathname);
649+
// vdump($this->rootPath, $subPathname, $fileInfo);
625650
// add props
626651
$fileInfo->relativePath = $this->subPath;
627652
$fileInfo->relativePathname = $subPathname;
@@ -634,7 +659,7 @@ public function getChildren(): RecursiveDirectoryIterator
634659
try {
635660
$children = parent::getChildren();
636661
if ($children instanceof self) {
637-
$children->rootPath = $this->rootPath;
662+
$children->rootPath = $this->rootPath;
638663
$children->rewindable = &$this->rewindable;
639664
$children->skipUnreadableDirs = $this->skipUnreadableDirs;
640665
}
@@ -680,6 +705,7 @@ public function isRewindable(): ?bool
680705
// exclude directories
681706
if ($this->excludes) {
682707
$iterator = new class($iterator, $this->excludes) extends FilterIterator implements RecursiveIterator {
708+
/** @var array<string, int> */
683709
private array $excludes;
684710

685711
private RecursiveIterator $iterator;
@@ -734,6 +760,7 @@ public function __construct(Iterator $iterator, int $mode)
734760

735761
public function accept(): bool
736762
{
763+
/** @var SplFileInfo $info */
737764
$info = $this->current();
738765
if (FileFinder::ONLY_DIR === $this->mode && $info->isFile()) {
739766
return false;
@@ -796,6 +823,7 @@ public function __construct(Iterator $iterator, array $filters)
796823

797824
public function accept(): bool
798825
{
826+
/** @var SplFileInfo $fileInfo */
799827
$fileInfo = $this->current();
800828
foreach ($this->filters as $filter) {
801829
if (false === $filter($fileInfo)) {
@@ -810,8 +838,9 @@ public function accept(): bool
810838

811839
if ($this->paths || $this->notPaths) {
812840
$iterator = new class($iterator, $this->paths, $this->notPaths) extends FilterIterator {
841+
/** @var array<string> */
813842
private array $paths;
814-
843+
/** @var array<string> */
815844
private array $notPaths;
816845

817846
public function __construct(Iterator $iterator, array $paths, array $notPaths)
@@ -823,7 +852,8 @@ public function __construct(Iterator $iterator, array $paths, array $notPaths)
823852

824853
public function accept(): bool
825854
{
826-
$pathname = $this->current()->relativePathname;
855+
/** @var string $pathname {@see SplFileInfo::getPathname()} */
856+
$pathname = $this->current()->getPathname();
827857
if ('\\' === DIRECTORY_SEPARATOR) {
828858
$pathname = str_replace('\\', '/', $pathname);
829859
}

src/Traits/FileSystemFuncTrait.php

+12-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
use function str_replace;
3535
use function stream_get_meta_data;
3636
use function strlen;
37-
use function strpos;
3837
use const DIRECTORY_SEPARATOR;
3938

4039
/**
@@ -228,6 +227,18 @@ public static function chown(Traversable|array|string $files, string $user, bool
228227
}
229228
}
230229

230+
/**
231+
* clear invalid sep and will parse ~ as user home dir.
232+
*
233+
* @param string $path
234+
*
235+
* @return string
236+
*/
237+
public static function expandPath(string $path): string
238+
{
239+
$path = realpath($path);
240+
}
241+
231242
/**
232243
* clear invalid sep and will parse ~ as user home dir.
233244
*

0 commit comments

Comments
 (0)