Skip to content

Commit 175f443

Browse files
authored
Merge pull request #1208 from phpDocumentor/cleanup-run-command
Improved exclude file options
2 parents 8e7c01f + bd0e218 commit 175f443

File tree

22 files changed

+826
-154
lines changed

22 files changed

+826
-154
lines changed

packages/filesystem/composer.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@
2424
},
2525
"minimum-stability": "stable",
2626
"require": {
27-
"php": "^8.1"
27+
"php": "^8.1",
28+
"webmozart/assert": "^1.3"
2829
},
2930
"extra": {
3031
"branch-alias": {
+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of phpDocumentor.
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*
11+
* @link https://phpdoc.org
12+
*/
13+
14+
namespace phpDocumentor\FileSystem\Finder;
15+
16+
use phpDocumentor\FileSystem\Path;
17+
18+
use function array_map;
19+
use function array_values;
20+
use function str_starts_with;
21+
22+
final class Exclude
23+
{
24+
/** @var list<string> */
25+
private readonly array $paths;
26+
27+
/** @param list<string|Path> $paths */
28+
public function __construct(
29+
array $paths = [],
30+
private readonly bool $hidden = false,
31+
private readonly bool $symlinks = false,
32+
) {
33+
$this->paths = array_values(
34+
array_map(
35+
static function (string|Path $path): string {
36+
if (str_starts_with((string) $path, '/')) {
37+
return (string) $path;
38+
}
39+
40+
return '/' . $path;
41+
},
42+
$paths,
43+
),
44+
);
45+
}
46+
47+
/** @return list<string> */
48+
public function getPaths(): array
49+
{
50+
return $this->paths;
51+
}
52+
53+
public function excludeHidden(): bool
54+
{
55+
return $this->hidden;
56+
}
57+
58+
public function followSymlinks(): bool
59+
{
60+
return $this->symlinks;
61+
}
62+
63+
/** @param list<string|path> $excludePaths */
64+
public function withPaths(array $excludePaths): self
65+
{
66+
return new self(
67+
$excludePaths,
68+
$this->hidden,
69+
$this->symlinks,
70+
);
71+
}
72+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of phpDocumentor.
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*
11+
* @link https://phpdoc.org
12+
*/
13+
14+
namespace phpDocumentor\FileSystem\Finder;
15+
16+
use Flyfinder\Path as FlyFinderPath;
17+
use Flyfinder\Specification\Glob;
18+
use Flyfinder\Specification\HasExtension;
19+
use Flyfinder\Specification\InPath;
20+
use Flyfinder\Specification\IsHidden;
21+
use Flyfinder\Specification\NotSpecification;
22+
use Flyfinder\Specification\SpecificationInterface;
23+
use phpDocumentor\FileSystem\Path;
24+
25+
/**
26+
* Factory class to build Specification used by FlyFinder when reading files to process.
27+
*/
28+
final class SpecificationFactory implements SpecificationFactoryInterface
29+
{
30+
/**
31+
* Creates a SpecificationInterface object based on the ignore and extension parameters.
32+
*
33+
* @param list<string|Path> $paths
34+
* @param list<string> $extensions
35+
*/
36+
public function create(array $paths, Exclude $ignore, array $extensions): SpecificationInterface
37+
{
38+
/** @var ?Glob $pathSpec */
39+
$pathSpec = null;
40+
foreach ($paths as $path) {
41+
if ($path instanceof Path) {
42+
$condition = new InPath(new FlyFinderPath((string) $path));
43+
} else {
44+
$condition = new Glob($path);
45+
}
46+
47+
if ($pathSpec === null) {
48+
$pathSpec = $condition;
49+
continue;
50+
}
51+
52+
$pathSpec = $pathSpec->orSpecification($condition);
53+
}
54+
55+
/** @var ?Glob $ignoreSpec */
56+
$ignoreSpec = null;
57+
foreach ($ignore->getPaths() as $path) {
58+
if ($ignoreSpec === null) {
59+
$ignoreSpec = new Glob($path);
60+
continue;
61+
}
62+
63+
$ignoreSpec = $ignoreSpec->orSpecification(new Glob($path));
64+
}
65+
66+
if ($ignore->excludeHidden()) {
67+
$ignoreSpec = $ignoreSpec === null
68+
? new IsHidden()
69+
: $ignoreSpec->orSpecification(new IsHidden());
70+
}
71+
72+
$result = new HasExtension($extensions);
73+
if ($ignoreSpec !== null) {
74+
$result = $result->andSpecification(new NotSpecification($ignoreSpec));
75+
}
76+
77+
if ($pathSpec !== null) {
78+
$result = $result->andSpecification($pathSpec);
79+
}
80+
81+
return $result;
82+
}
83+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of phpDocumentor.
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*
11+
* @link https://phpdoc.org
12+
*/
13+
14+
namespace phpDocumentor\FileSystem\Finder;
15+
16+
use Flyfinder\Specification\SpecificationInterface;
17+
use phpDocumentor\FileSystem\Path;
18+
19+
/**
20+
* Interface for Specifications used to filter the FileSystem.
21+
*/
22+
interface SpecificationFactoryInterface
23+
{
24+
/**
25+
* Creates a SpecificationInterface object based on the ignore and extension parameters.
26+
*
27+
* @param list<string|Path> $paths
28+
* @param list<string> $extensions
29+
*/
30+
public function create(array $paths, Exclude $ignore, array $extensions): SpecificationInterface;
31+
}

packages/filesystem/src/Path.php

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of phpDocumentor.
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*
11+
* @link https://phpdoc.org
12+
*/
13+
14+
namespace phpDocumentor\FileSystem;
15+
16+
use Stringable;
17+
use Webmozart\Assert\Assert;
18+
19+
use function array_pop;
20+
use function ctype_alpha;
21+
use function explode;
22+
use function implode;
23+
use function parse_url;
24+
use function sprintf;
25+
use function strlen;
26+
use function strspn;
27+
28+
use const PHP_URL_SCHEME;
29+
30+
/**
31+
* Value Object for paths.
32+
* This can be absolute or relative.
33+
*/
34+
final class Path implements Stringable
35+
{
36+
/**
37+
* Initializes the path.
38+
*/
39+
public function __construct(private readonly string $path)
40+
{
41+
Assert::notEmpty(
42+
$path,
43+
sprintf('"%s" is not a valid path', $path),
44+
);
45+
}
46+
47+
/**
48+
* Verifies if another Path object has the same identity as this one.
49+
*/
50+
public function equals(self $otherPath): bool
51+
{
52+
return $this->path === (string) $otherPath;
53+
}
54+
55+
/**
56+
* returns a string representation of the path.
57+
*/
58+
public function __toString(): string
59+
{
60+
return $this->path;
61+
}
62+
63+
/**
64+
* Returns whether the file path is an absolute path.
65+
*
66+
* @param string $file A file path
67+
*/
68+
public static function isAbsolutePath(string $file): bool
69+
{
70+
return strspn($file, '/\\', 0, 1)
71+
|| (strlen($file) > 3 && ctype_alpha($file[0])
72+
&& $file[1] === ':'
73+
&& strspn($file, '/\\', 2, 1)
74+
)
75+
|| parse_url($file, PHP_URL_SCHEME) !== null;
76+
}
77+
78+
public static function dirname(Path $input): self
79+
{
80+
$parts = explode('/', (string) $input);
81+
array_pop($parts);
82+
83+
$path = implode('/', $parts);
84+
if ($path === '') {
85+
return new self('/');
86+
}
87+
88+
return new self($path);
89+
}
90+
}

0 commit comments

Comments
 (0)