Add 'exclude_paths' option to exclude files or directories [closes #609]

This commit is contained in:
Tomas Votruba 2018-08-29 22:45:09 +02:00
parent 8efe81b6fd
commit 5817e17234
9 changed files with 134 additions and 2 deletions

View File

@ -64,6 +64,15 @@ parameters:
- '%kernel.project_dir%/vendor/project-without-composer'
```
You can also exclude files or directories - use regex or [fnmatch](http://php.net/manual/en/function.fnmatch.php):
```yaml
# rector.yml
parameters:
exclude_paths:
- '*/src/*/Tests/*'
```
## How to Reconstruct your Code
### A. Prepared Sets

View File

@ -41,6 +41,7 @@ parameters:
- '#Access to an undefined property PhpParser\\Node\\Expr\\Error\|PhpParser\\Node\\Expr\\Variable::\$name#'
# SplFileInfo::getRealPath() false positive
- '#Parameter \#1 \$pattern of function fnmatch expects string, string\|false given#'
- '#Parameter \#1 \$file of function file_put_contents expects string, string\|false given#'
- '#Parameter \#1 \$filePath of method Rector\\Parser\\Parser::parseFile\(\) expects string, string\|false given#'

View File

@ -2,6 +2,7 @@
namespace Rector\FileSystem;
use Nette\Utils\Strings;
use Rector\Exception\FileSystem\DirectoryNotFoundException;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Finder\SplFileInfo;
@ -13,6 +14,19 @@ final class FilesFinder
*/
private $fileInfosBySourceAndSuffixes = [];
/**
* @var string[]
*/
private $excludePaths = [];
/**
* @param string[] $excludePaths
*/
public function __construct(array $excludePaths)
{
$this->excludePaths = $excludePaths;
}
/**
* @param string[] $source
* @param string[] $suffixes
@ -61,7 +75,14 @@ final class FilesFinder
->exclude(['examples', 'Examples', 'stubs', 'Stubs', 'fixtures', 'Fixtures', 'polyfill', 'Polyfill'])
->notName('*polyfill*');
return iterator_to_array($finder->getIterator());
$splFileInfos = iterator_to_array($finder->getIterator());
if (! $this->excludePaths) {
return $splFileInfos;
}
// to overcome magic behavior: https://github.com/symfony/symfony/pull/26396/files
/** @var SplFileInfo[] $splFileInfos */
return $this->filterOutFilesByPatterns($splFileInfos, $this->excludePaths);
}
/**
@ -87,4 +108,30 @@ final class FilesFinder
return '#\.(' . $suffixesPattern . ')$#';
}
/**
* @param SplFileInfo[] $splFileInfos
* @param string[] $patternsToExclude
* @return SplFileInfo[]
*/
private function filterOutFilesByPatterns(array $splFileInfos, array $patternsToExclude): array
{
$filteredFiles = [];
foreach ($splFileInfos as $relativePath => $splFileInfo) {
foreach ($patternsToExclude as $patternToExclude) {
if (Strings::match($splFileInfo->getRealPath(), $patternToExclude)) {
continue;
}
if (fnmatch($splFileInfo->getRealPath(), $patternToExclude)) {
continue;
}
$filteredFiles[$relativePath] = $splFileInfo;
}
}
return $filteredFiles;
}
}

View File

@ -4,6 +4,6 @@ imports:
- { resource: 'external-services.yml' }
parameters:
excluded_paths: []
exclude_paths: []
autoload_directories: []
autoload_files: []

View File

@ -0,0 +1,29 @@
<?php declare(strict_types=1);
namespace Rector\Tests;
use PHPUnit\Framework\TestCase;
use Psr\Container\ContainerInterface;
use Rector\DependencyInjection\ContainerFactory;
abstract class AbstractConfigurableContainerAwareTestCase extends TestCase
{
/**
* @var ContainerInterface
*/
protected $container;
/**
* Constructs a test case with the given name.
*
* @param mixed[] $data
*/
public function __construct(?string $name = null, array $data = [], string $dataName = '')
{
$this->container = (new ContainerFactory())->createWithConfig($this->provideConfig());
parent::__construct($name, $data, $dataName);
}
abstract protected function provideConfig(): string;
}

View File

@ -0,0 +1,27 @@
<?php declare(strict_types=1);
namespace Rector\Tests\FileSystem\FilesFinder\ExcludePaths;
use Rector\FileSystem\FilesFinder;
use Rector\Tests\AbstractConfigurableContainerAwareTestCase;
final class ExcludePathsTest extends AbstractConfigurableContainerAwareTestCase
{
/**
* @var FilesFinder
*/
private $filesFinder;
public function testShouldFail(): void
{
$this->filesFinder = $this->container->get(FilesFinder::class);
$splFileInfos = $this->filesFinder->findInDirectoriesAndFiles([__DIR__ . '/Source'], ['php']);
$this->assertCount(1, $splFileInfos);
}
protected function provideConfig(): string
{
return __DIR__ . '/config/config-with-excluded-paths.yml';
}
}

View File

@ -0,0 +1,8 @@
<?php declare(strict_types=1);
namespace Rector\Tests\Configuration\ExcludePaths\ShouldBeExcludedSource;
final class FileWithMissingClass extends ThisClassIsNotHere
{
}

View File

@ -0,0 +1,8 @@
<?php declare(strict_types=1);
namespace Rector\Tests\Configuration\ExcludePaths\Source;
final class ThisShouldBeHere
{
}

View File

@ -0,0 +1,3 @@
parameters:
excluded_paths:
- '*/ShouldBeExcluded/*'