Apply FinderSanitizer to make sure all files exists and have content [closes #655]

This commit is contained in:
Tomas Votruba 2018-10-12 10:24:07 +08:00
parent cb651ec8fb
commit a8ef98e2b5
15 changed files with 81 additions and 58 deletions

View File

@ -3,9 +3,9 @@
namespace Rector\FileSystemRector\Contract;
use Rector\Contract\Rector\RectorInterface;
use Symfony\Component\Finder\SplFileInfo;
use Symplify\PackageBuilder\FileSystem\SmartFileInfo;
interface FileSystemRectorInterface extends RectorInterface
{
public function refactor(SplFileInfo $fileInfo): void;
public function refactor(SmartFileInfo $smartFileInfo): void;
}

View File

@ -3,7 +3,7 @@
namespace Rector\FileSystemRector;
use Rector\FileSystemRector\Contract\FileSystemRectorInterface;
use Symfony\Component\Finder\SplFileInfo;
use Symplify\PackageBuilder\FileSystem\SmartFileInfo;
final class FileSystemFileProcessor
{
@ -28,10 +28,10 @@ final class FileSystemFileProcessor
return $this->fileSystemRectors;
}
public function processFileInfo(SplFileInfo $fileInfo): void
public function processFileInfo(SmartFileInfo $smartFileInfo): void
{
foreach ($this->fileSystemRectors as $fileSystemRector) {
$fileSystemRector->refactor($fileInfo);
$fileSystemRector->refactor($smartFileInfo);
}
}

View File

@ -3,7 +3,7 @@
namespace Rector\YamlRector;
use Rector\YamlRector\Contract\YamlRectorInterface;
use Symfony\Component\Finder\SplFileInfo;
use Symplify\PackageBuilder\FileSystem\SmartFileInfo;
final class YamlFileProcessor
{
@ -28,9 +28,9 @@ final class YamlFileProcessor
return $this->yamlRectors;
}
public function processFileInfo(SplFileInfo $splFileInfo): string
public function processFileInfo(SmartFileInfo $smartFileInfo): string
{
$content = $splFileInfo->getContents();
$content = $smartFileInfo->getContents();
foreach ($this->yamlRectors as $yamlRector) {
$content = $yamlRector->refactor($content);

View File

@ -2,12 +2,12 @@
namespace Rector\Application;
use Symfony\Component\Finder\SplFileInfo;
use Symplify\PackageBuilder\FileSystem\SmartFileInfo;
final class Error
{
/**
* @var SplFileInfo
* @var SmartFileInfo
*/
private $fileInfo;
@ -21,14 +21,14 @@ final class Error
*/
private $line;
public function __construct(SplFileInfo $fileInfo, string $message, ?int $line)
public function __construct(SmartFileInfo $smartFileInfo, string $message, ?int $line)
{
$this->fileInfo = $fileInfo;
$this->fileInfo = $smartFileInfo;
$this->message = $message;
$this->line = $line;
}
public function getFileInfo(): SplFileInfo
public function getFileInfo(): SmartFileInfo
{
return $this->fileInfo;
}

View File

@ -8,7 +8,7 @@ use Rector\NodeTraverser\RectorNodeTraverser;
use Rector\NodeTypeResolver\NodeScopeAndMetadataDecorator;
use Rector\Parser\Parser;
use Rector\Printer\FormatPerservingPrinter;
use Symfony\Component\Finder\SplFileInfo;
use Symplify\PackageBuilder\FileSystem\SmartFileInfo;
final class FileProcessor
{
@ -51,19 +51,19 @@ final class FileProcessor
$this->nodeScopeAndMetadataDecorator = $nodeScopeAndMetadataDecorator;
}
public function processFile(SplFileInfo $fileInfo): string
public function processFile(SmartFileInfo $smartFileInfo): string
{
[$newStmts, $oldStmts, $oldTokens] = $this->parseAndTraverseFileInfoToNodes($fileInfo);
[$newStmts, $oldStmts, $oldTokens] = $this->parseAndTraverseFileInfoToNodes($smartFileInfo);
return $this->formatPerservingPrinter->printToFile($fileInfo, $newStmts, $oldStmts, $oldTokens);
return $this->formatPerservingPrinter->printToFile($smartFileInfo, $newStmts, $oldStmts, $oldTokens);
}
/**
* See https://github.com/nikic/PHP-Parser/issues/344#issuecomment-298162516.
*/
public function processFileToString(SplFileInfo $fileInfo): string
public function processFileToString(SmartFileInfo $smartFileInfo): string
{
[$newStmts, $oldStmts, $oldTokens] = $this->parseAndTraverseFileInfoToNodes($fileInfo);
[$newStmts, $oldStmts, $oldTokens] = $this->parseAndTraverseFileInfoToNodes($smartFileInfo);
return $this->formatPerservingPrinter->printToString($newStmts, $oldStmts, $oldTokens);
}
@ -71,12 +71,15 @@ final class FileProcessor
/**
* @return Node[][]|mixed[]
*/
private function parseAndTraverseFileInfoToNodes(SplFileInfo $fileInfo): array
private function parseAndTraverseFileInfoToNodes(SmartFileInfo $smartFileInfo): array
{
$oldStmts = $this->parser->parseFile($fileInfo->getRealPath());
$oldStmts = $this->parser->parseFile($smartFileInfo->getRealPath());
$oldTokens = $this->lexer->getTokens();
$newStmts = $this->nodeScopeAndMetadataDecorator->decorateNodesFromFile($oldStmts, $fileInfo->getRealPath());
$newStmts = $this->nodeScopeAndMetadataDecorator->decorateNodesFromFile(
$oldStmts,
$smartFileInfo->getRealPath()
);
$newStmts = $this->rectorNodeTraverser->traverse($newStmts);
return [$newStmts, $oldStmts, $oldTokens];

View File

@ -22,9 +22,9 @@ use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Finder\SplFileInfo;
use Symfony\Component\Process\Process;
use Symplify\PackageBuilder\Console\Command\CommandNaming;
use Symplify\PackageBuilder\FileSystem\SmartFileInfo;
use Symplify\PackageBuilder\Parameter\ParameterProvider;
use Throwable;
use function Safe\sprintf;
@ -210,7 +210,7 @@ final class ProcessCommand extends Command
}
/**
* @param SplFileInfo[] $fileInfos
* @param SmartFileInfo[] $fileInfos
*/
private function processFileInfos(array $fileInfos, bool $shouldHideAutoloadErrors): void
{
@ -226,7 +226,7 @@ final class ProcessCommand extends Command
$this->consoleStyle->newLine(2);
}
private function processFileInfo(SplFileInfo $fileInfo, bool $shouldHideAutoloadErrors): void
private function processFileInfo(SmartFileInfo $fileInfo, bool $shouldHideAutoloadErrors): void
{
try {
if ($fileInfo->getExtension() === 'php') {
@ -253,7 +253,7 @@ final class ProcessCommand extends Command
}
}
private function processFile(SplFileInfo $fileInfo): void
private function processFile(SmartFileInfo $fileInfo): void
{
$oldContent = $fileInfo->getContents();
@ -273,7 +273,7 @@ final class ProcessCommand extends Command
}
}
private function processYamlFile(SplFileInfo $fileInfo): void
private function processYamlFile(SmartFileInfo $fileInfo): void
{
$oldContent = $fileInfo->getContents();
@ -295,7 +295,7 @@ final class ProcessCommand extends Command
}
}
private function processFileSystemFile(SplFileInfo $fileInfo): void
private function processFileSystemFile(SmartFileInfo $fileInfo): void
{
$this->fileSystemFileProcessor->processFileInfo($fileInfo);
}

View File

@ -3,17 +3,18 @@
namespace Rector\Exception\Application;
use Exception;
use Symfony\Component\Finder\SplFileInfo;
use Symplify\PackageBuilder\FileSystem\SmartFileInfo;
use Throwable;
use function Safe\sprintf;
final class FileProcessingException extends Exception
{
public function __construct(SplFileInfo $fileInfo, Throwable $throwable)
public function __construct(SmartFileInfo $smartFileInfo, Throwable $throwable)
{
$message = sprintf(
'Processing file "%s" failed. ' . PHP_EOL . PHP_EOL . '%s',
$fileInfo->getRealPath(),
'Processing file "%s" failed. %s%s',
$smartFileInfo->getRealPath(),
PHP_EOL . PHP_EOL,
$throwable
);

View File

@ -6,12 +6,13 @@ use Nette\Utils\Strings;
use Rector\Utils\FilesystemTweaker;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Finder\SplFileInfo;
use Symplify\PackageBuilder\FileSystem\FinderSanitizer;
use Symplify\PackageBuilder\FileSystem\SmartFileInfo;
final class FilesFinder
{
/**
* @var SplFileInfo[][]
* @var SmartFileInfo[][]
*/
private $fileInfosBySourceAndSuffixes = [];
@ -25,19 +26,28 @@ final class FilesFinder
*/
private $filesystemTweaker;
/**
* @var FinderSanitizer
*/
private $finderSanitizer;
/**
* @param string[] $excludePaths
*/
public function __construct(array $excludePaths, FilesystemTweaker $filesystemTweaker)
{
public function __construct(
array $excludePaths,
FilesystemTweaker $filesystemTweaker,
FinderSanitizer $finderSanitizer
) {
$this->excludePaths = $excludePaths;
$this->filesystemTweaker = $filesystemTweaker;
$this->finderSanitizer = $finderSanitizer;
}
/**
* @param string[] $source
* @param string[] $suffixes
* @return SplFileInfo[]
* @return SmartFileInfo[]
*/
public function findInDirectoriesAndFiles(array $source, array $suffixes): array
{
@ -48,20 +58,20 @@ final class FilesFinder
[$files, $directories] = $this->filesystemTweaker->splitSourceToDirectoriesAndFiles($source);
$splFileInfos = [];
$smartFileInfos = [];
foreach ($files as $file) {
$splFileInfos[] = new SmartFileInfo($file);
$smartFileInfos[] = new SmartFileInfo($file);
}
$splFileInfos = array_merge($splFileInfos, $this->findInDirectories($directories, $suffixes));
$smartFileInfos = array_merge($smartFileInfos, $this->findInDirectories($directories, $suffixes));
return $this->fileInfosBySourceAndSuffixes[$cacheKey] = $splFileInfos;
return $this->fileInfosBySourceAndSuffixes[$cacheKey] = $smartFileInfos;
}
/**
* @param string[] $directories
* @param string[] $suffixes
* @return SplFileInfo[]
* @return SmartFileInfo[]
*/
private function findInDirectories(array $directories, array $suffixes): array
{
@ -85,7 +95,7 @@ final class FilesFinder
$this->addFilterWithExcludedPaths($finder);
return iterator_to_array($finder->getIterator());
return $this->finderSanitizer->sanitize($finder);
}
/**

View File

@ -2,10 +2,10 @@
namespace Rector\Printer;
use Nette\Utils\FileSystem;
use PhpParser\Node;
use PhpParser\PrettyPrinter\Standard;
use Symfony\Component\Finder\SplFileInfo;
use function Safe\file_put_contents;
use Symplify\PackageBuilder\FileSystem\SmartFileInfo;
final class FormatPerservingPrinter
{
@ -24,11 +24,11 @@ final class FormatPerservingPrinter
* @param Node[] $oldStmts
* @param Node[] $oldTokens
*/
public function printToFile(SplFileInfo $fileInfo, array $newStmts, array $oldStmts, array $oldTokens): string
public function printToFile(SmartFileInfo $fileInfo, array $newStmts, array $oldStmts, array $oldTokens): string
{
$newContent = $this->printToString($newStmts, $oldStmts, $oldTokens);
file_put_contents($fileInfo->getRealPath(), $newContent);
FileSystem::write($fileInfo->getRealPath(), $newContent);
return $newContent;
}

View File

@ -14,7 +14,7 @@ use Rector\RectorDefinition\CodeSample;
use Rector\RectorDefinition\RectorDefinition;
use Rector\Utils\BetterNodeFinder;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Finder\SplFileInfo;
use Symplify\PackageBuilder\FileSystem\SmartFileInfo;
final class MultipleClassFileToPsr4ClassesRector implements FileSystemRectorInterface
{
@ -112,17 +112,20 @@ CODE_SAMPLE
);
}
public function refactor(SplFileInfo $fileInfo): void
public function refactor(SmartFileInfo $smartFileInfo): void
{
$oldStmts = $this->parser->parseFile($fileInfo->getRealPath());
$oldStmts = $this->parser->parseFile($smartFileInfo->getRealPath());
// needed for format preserving
$newStmts = $this->nodeScopeAndMetadataDecorator->decorateNodesFromFile($oldStmts, $fileInfo->getRealPath());
$newStmts = $this->nodeScopeAndMetadataDecorator->decorateNodesFromFile(
$oldStmts,
$smartFileInfo->getRealPath()
);
/** @var Namespace_[] $namespaceNodes */
$namespaceNodes = $this->betterNodeFinder->findInstanceOf($newStmts, Namespace_::class);
if ($this->shouldSkip($fileInfo, $newStmts, $namespaceNodes)) {
if ($this->shouldSkip($smartFileInfo, $newStmts, $namespaceNodes)) {
return;
}
@ -144,7 +147,7 @@ CODE_SAMPLE
// reindex from 0, for the printer
$newStmt->stmts = array_values($newStmt->stmts);
$fileDestination = $this->createClassFileDestination($classNode, $fileInfo);
$fileDestination = $this->createClassFileDestination($classNode, $smartFileInfo);
$fileContent = $this->formatPerservingPrinter->printToString(
$newStmtsSet,
@ -158,9 +161,9 @@ CODE_SAMPLE
}
}
private function createClassFileDestination(Class_ $classNode, SplFileInfo $fileInfo): string
private function createClassFileDestination(Class_ $classNode, SmartFileInfo $smartFileInfo): string
{
$currentDirectory = dirname($fileInfo->getRealPath());
$currentDirectory = dirname($smartFileInfo->getRealPath());
return $currentDirectory . DIRECTORY_SEPARATOR . (string) $classNode->name . '.php';
}
@ -194,7 +197,7 @@ CODE_SAMPLE
* @param Node[] $nodes
* @param Namespace_[] $namespaceNodes
*/
private function shouldSkip(SplFileInfo $fileInfo, array $nodes, array $namespaceNodes): bool
private function shouldSkip(SmartFileInfo $smartFileInfo, array $nodes, array $namespaceNodes): bool
{
// process only namespaced file
if (! $namespaceNodes) {
@ -215,7 +218,7 @@ CODE_SAMPLE
if (count($nonAnonymousClassNodes) === 1) {
$nonAnonymousClassNode = $nonAnonymousClassNodes[0];
if ((string) $nonAnonymousClassNode->name === $fileInfo->getFilename()) {
if ((string) $nonAnonymousClassNode->name === $smartFileInfo->getFilename()) {
return true;
}
}

View File

@ -27,6 +27,7 @@ services:
alias: Symfony\Component\Console\Output\ConsoleOutput
Symplify\PackageBuilder\FileSystem\FileSystem: ~
Symplify\PackageBuilder\FileSystem\FinderSanitizer: ~
# parameters
Symplify\PackageBuilder\Parameter\ParameterProvider: ~

View File

@ -0,0 +1,3 @@
<?php
echo 'Hi';

View File

@ -5,7 +5,7 @@ namespace Rector\Tests\FileSystem\FilesFinder;
use Iterator;
use Rector\FileSystem\FilesFinder;
use Rector\Tests\AbstractContainerAwareTestCase;
use Symfony\Component\Finder\SplFileInfo;
use Symplify\PackageBuilder\FileSystem\SmartFileInfo;
use function Safe\sort;
final class FilesFinderTest extends AbstractContainerAwareTestCase
@ -28,7 +28,7 @@ final class FilesFinderTest extends AbstractContainerAwareTestCase
$foundFiles = $this->filesFinder->findInDirectoriesAndFiles([__DIR__ . '/FilesFinderSource'], [$suffix]);
$this->assertCount($count, $foundFiles);
/** @var SplFileInfo $foundFile */
/** @var SmartFileInfo $foundFile */
$foundFile = array_pop($foundFiles);
$this->assertSame($expectedFileName, $foundFile->getBasename());
}