rector/src/Console/Output/ConsoleOutputFormatter.php

195 lines
6.1 KiB
PHP
Raw Normal View History

2019-10-13 05:59:52 +00:00
<?php
declare(strict_types=1);
2017-10-22 14:31:29 +00:00
namespace Rector\Core\Console\Output;
2017-10-22 14:31:29 +00:00
2019-08-10 07:28:27 +00:00
use Nette\Utils\Strings;
use Rector\Core\Application\ErrorAndDiffCollector;
use Rector\Core\Configuration\Configuration;
use Rector\Core\Configuration\Option;
use Rector\Core\Contract\Console\Output\OutputFormatterInterface;
use Rector\Core\PhpParser\Printer\BetterStandardPrinter;
use Rector\Core\ValueObject\Application\Error;
use Rector\Core\ValueObject\Reporting\FileDiff;
2019-08-10 07:28:27 +00:00
use Rector\NodeTypeResolver\Node\AttributeKey;
use Symfony\Component\Console\Style\SymfonyStyle;
2019-11-23 17:27:18 +00:00
use Symplify\SmartFileSystem\SmartFileInfo;
2017-10-22 14:31:29 +00:00
final class ConsoleOutputFormatter implements OutputFormatterInterface
2017-10-22 14:31:29 +00:00
{
/**
* @var string
*/
public const NAME = 'console';
2017-10-22 14:31:29 +00:00
/**
* @var SymfonyStyle
2017-10-22 14:31:29 +00:00
*/
private $symfonyStyle;
2017-10-22 14:31:29 +00:00
2019-08-10 07:28:27 +00:00
/**
* @var BetterStandardPrinter
*/
private $betterStandardPrinter;
/**
* @var Configuration
*/
private $configuration;
public function __construct(
SymfonyStyle $symfonyStyle,
BetterStandardPrinter $betterStandardPrinter,
Configuration $configuration
) {
$this->symfonyStyle = $symfonyStyle;
2019-08-10 07:28:27 +00:00
$this->betterStandardPrinter = $betterStandardPrinter;
$this->configuration = $configuration;
2017-10-22 14:31:29 +00:00
}
public function report(ErrorAndDiffCollector $errorAndDiffCollector): void
{
2020-01-17 13:54:37 +00:00
if ($this->configuration->getOutputFile()) {
2020-01-17 09:02:46 +00:00
$this->symfonyStyle->error(sprintf(
'Option "--%s" can be used only with "--%s %s"',
Option::OPTION_OUTPUT_FILE,
Option::OPTION_OUTPUT_FORMAT,
'json'
));
}
$this->reportFileDiffs($errorAndDiffCollector->getFileDiffs());
$this->reportErrors($errorAndDiffCollector->getErrors());
2019-08-06 07:37:31 +00:00
$this->reportRemovedFilesAndNodes($errorAndDiffCollector);
if ($errorAndDiffCollector->getErrors() !== []) {
return;
}
$changeCount = $errorAndDiffCollector->getFileDiffsCount()
+ $errorAndDiffCollector->getRemovedAndAddedFilesCount();
2020-01-08 14:55:19 +00:00
$message = 'Rector is done!';
if ($changeCount > 0) {
2020-01-08 14:55:19 +00:00
$message .= sprintf(
' %d file%s %s.',
$changeCount,
$changeCount > 1 ? 's' : '',
$this->configuration->isDryRun() ? 'would have changed (dry-run)' : 'have been changed'
2020-01-08 14:55:19 +00:00
);
}
$this->symfonyStyle->success($message);
}
public function getName(): string
{
return self::NAME;
}
/**
2018-02-08 15:51:16 +00:00
* @param FileDiff[] $fileDiffs
*/
private function reportFileDiffs(array $fileDiffs): void
{
2018-02-08 15:51:16 +00:00
if (count($fileDiffs) <= 0) {
return;
}
// normalize
ksort($fileDiffs);
$this->symfonyStyle->title(
2018-09-21 05:12:24 +00:00
sprintf('%d file%s with changes', count($fileDiffs), count($fileDiffs) === 1 ? '' : 's')
);
$i = 0;
2018-02-08 15:51:16 +00:00
foreach ($fileDiffs as $fileDiff) {
2019-05-28 20:38:21 +00:00
$relativeFilePath = $fileDiff->getRelativeFilePath();
2019-05-28 16:28:20 +00:00
$this->symfonyStyle->writeln(sprintf('<options=bold>%d) %s</>', ++$i, $relativeFilePath));
$this->symfonyStyle->newLine();
2019-05-28 14:18:05 +00:00
$this->symfonyStyle->writeln($fileDiff->getDiffConsoleFormatted());
$this->symfonyStyle->newLine();
2018-11-05 01:27:48 +00:00
2019-02-17 14:12:47 +00:00
if ($fileDiff->getAppliedRectorClasses() !== []) {
2019-11-05 15:15:51 +00:00
$this->symfonyStyle->writeln('Applied rules:');
2018-11-05 01:27:48 +00:00
$this->symfonyStyle->newLine();
$this->symfonyStyle->listing($fileDiff->getAppliedRectorClasses());
$this->symfonyStyle->newLine();
}
}
}
2018-09-17 10:38:11 +00:00
/**
* @param Error[] $errors
*/
private function reportErrors(array $errors): void
2018-09-17 10:38:11 +00:00
{
foreach ($errors as $error) {
$message = sprintf(
2018-11-04 23:36:12 +00:00
'Could not process "%s" file%s, due to: %s"%s".',
2018-09-17 10:38:11 +00:00
$error->getFileInfo()->getPathname(),
2018-11-04 23:36:12 +00:00
$error->getRectorClass() ? ' by "' . $error->getRectorClass() . '"' : '',
2018-09-17 10:38:11 +00:00
PHP_EOL,
$error->getMessage()
);
if ($error->getLine()) {
$message .= ' On line: ' . $error->getLine();
}
$this->symfonyStyle->error($message);
2018-09-17 10:38:11 +00:00
}
}
2019-08-06 07:37:31 +00:00
private function reportRemovedFilesAndNodes(ErrorAndDiffCollector $errorAndDiffCollector): void
{
2019-10-30 14:38:30 +00:00
if ($errorAndDiffCollector->getRemovedAndAddedFilesCount() !== 0) {
2019-08-06 07:37:31 +00:00
$this->symfonyStyle->note(
sprintf('%d files were added/removed', $errorAndDiffCollector->getRemovedAndAddedFilesCount())
);
}
2019-08-10 07:28:27 +00:00
$this->reportRemovedNodes($errorAndDiffCollector);
}
private function reportRemovedNodes(ErrorAndDiffCollector $errorAndDiffCollector): void
{
if ($errorAndDiffCollector->getRemovedNodeCount() === 0) {
return;
}
$this->symfonyStyle->warning(sprintf('%d nodes were removed', $errorAndDiffCollector->getRemovedNodeCount()));
if ($this->symfonyStyle->isVeryVerbose()) {
$i = 0;
foreach ($errorAndDiffCollector->getRemovedNodes() as $removedNode) {
/** @var SmartFileInfo $fileInfo */
$fileInfo = $removedNode->getAttribute(AttributeKey::FILE_INFO);
$this->symfonyStyle->writeln(sprintf(
'<options=bold>%d) %s:%d</>',
++$i,
$fileInfo->getRelativeFilePath(),
$removedNode->getStartLine()
));
$printedNode = $this->betterStandardPrinter->print($removedNode);
// color red + prefix with "-" to visually demonstrate removal
$printedNode = '-' . Strings::replace($printedNode, '#\n#', "\n-");
$printedNode = $this->colorTextToRed($printedNode);
$this->symfonyStyle->writeln($printedNode);
$this->symfonyStyle->newLine(1);
}
2019-08-06 07:37:31 +00:00
}
}
2019-08-10 07:28:27 +00:00
private function colorTextToRed(string $text): string
{
return '<fg=red>' . $text . '</fg=red>';
}
2017-10-22 14:31:29 +00:00
}