2021-11-23 13:20:36 +00:00
< ? php
declare ( strict_types = 1 );
2022-06-06 17:12:56 +00:00
namespace Rector\Parallel ;
2021-11-23 13:20:36 +00:00
2022-12-01 14:10:32 +00:00
use RectorPrefix202212\Clue\React\NDJson\Decoder ;
use RectorPrefix202212\Clue\React\NDJson\Encoder ;
use RectorPrefix202212\Nette\Utils\FileSystem ;
2022-06-06 17:12:56 +00:00
use PHPStan\Analyser\NodeScopeResolver ;
use Rector\Core\Application\FileProcessor\PhpFileProcessor ;
2022-06-25 06:53:01 +00:00
use Rector\Core\Console\Style\RectorConsoleOutputStyle ;
2022-06-06 17:12:56 +00:00
use Rector\Core\Provider\CurrentFileProvider ;
use Rector\Core\StaticReflection\DynamicSourceLocatorDecorator ;
2022-09-01 20:10:11 +00:00
use Rector\Core\Util\ArrayParametersMerger ;
2022-06-06 17:12:56 +00:00
use Rector\Core\ValueObject\Application\File ;
use Rector\Core\ValueObject\Configuration ;
use Rector\Core\ValueObject\Error\SystemError ;
use Rector\Parallel\ValueObject\Bridge ;
2022-12-01 14:10:32 +00:00
use RectorPrefix202212\Symplify\EasyParallel\Enum\Action ;
use RectorPrefix202212\Symplify\EasyParallel\Enum\ReactCommand ;
use RectorPrefix202212\Symplify\EasyParallel\Enum\ReactEvent ;
2021-11-23 13:20:36 +00:00
use Throwable ;
final class WorkerRunner
{
/**
* @ var string
*/
private const RESULT = 'result' ;
/**
2021-12-04 12:47:17 +00:00
* @ readonly
2022-09-01 20:10:11 +00:00
* @ var \Rector\Core\Util\ArrayParametersMerger
2021-11-23 13:20:36 +00:00
*/
2022-09-01 20:10:11 +00:00
private $arrayParametersMerger ;
2021-11-23 13:20:36 +00:00
/**
2021-12-04 12:47:17 +00:00
* @ readonly
2021-12-28 12:08:43 +00:00
* @ var \Rector\Core\Provider\CurrentFileProvider
2021-11-23 13:20:36 +00:00
*/
2021-12-28 12:08:43 +00:00
private $currentFileProvider ;
/**
* @ readonly
* @ var \Rector\Core\Application\FileProcessor\PhpFileProcessor
*/
private $phpFileProcessor ;
2022-01-04 16:58:25 +00:00
/**
* @ readonly
* @ var \PHPStan\Analyser\NodeScopeResolver
*/
private $nodeScopeResolver ;
/**
* @ readonly
* @ var \Rector\Core\StaticReflection\DynamicSourceLocatorDecorator
*/
private $dynamicSourceLocatorDecorator ;
2022-06-25 06:53:01 +00:00
/**
* @ readonly
* @ var \Rector\Core\Console\Style\RectorConsoleOutputStyle
*/
private $rectorConsoleOutputStyle ;
2022-09-01 20:10:11 +00:00
public function __construct ( ArrayParametersMerger $arrayParametersMerger , CurrentFileProvider $currentFileProvider , PhpFileProcessor $phpFileProcessor , NodeScopeResolver $nodeScopeResolver , DynamicSourceLocatorDecorator $dynamicSourceLocatorDecorator , RectorConsoleOutputStyle $rectorConsoleOutputStyle )
2021-11-23 13:20:36 +00:00
{
2022-09-01 20:10:11 +00:00
$this -> arrayParametersMerger = $arrayParametersMerger ;
2021-12-28 12:08:43 +00:00
$this -> currentFileProvider = $currentFileProvider ;
$this -> phpFileProcessor = $phpFileProcessor ;
2022-01-04 16:58:25 +00:00
$this -> nodeScopeResolver = $nodeScopeResolver ;
$this -> dynamicSourceLocatorDecorator = $dynamicSourceLocatorDecorator ;
2022-06-25 06:53:01 +00:00
$this -> rectorConsoleOutputStyle = $rectorConsoleOutputStyle ;
2021-11-23 13:20:36 +00:00
}
2022-06-07 08:22:29 +00:00
public function run ( Encoder $encoder , Decoder $decoder , Configuration $configuration ) : void
2021-11-23 13:20:36 +00:00
{
2022-01-04 16:58:25 +00:00
$this -> dynamicSourceLocatorDecorator -> addPaths ( $configuration -> getPaths ());
2021-11-23 13:20:36 +00:00
// 1. handle system error
2022-06-07 08:22:29 +00:00
$handleErrorCallback = static function ( Throwable $throwable ) use ( $encoder ) : void {
$systemErrors = new SystemError ( $throwable -> getMessage (), $throwable -> getFile (), $throwable -> getLine ());
$encoder -> write ([ ReactCommand :: ACTION => Action :: RESULT , self :: RESULT => [ Bridge :: SYSTEM_ERRORS => [ $systemErrors ], Bridge :: FILES_COUNT => 0 , Bridge :: SYSTEM_ERRORS_COUNT => 1 ]]);
2021-11-23 13:20:36 +00:00
$encoder -> end ();
};
2022-06-07 08:22:29 +00:00
$encoder -> on ( ReactEvent :: ERROR , $handleErrorCallback );
2021-11-23 13:20:36 +00:00
// 2. collect diffs + errors from file processor
2022-06-07 08:22:29 +00:00
$decoder -> on ( ReactEvent :: DATA , function ( array $json ) use ( $encoder , $configuration ) : void {
$action = $json [ ReactCommand :: ACTION ];
if ( $action !== Action :: MAIN ) {
2021-11-23 13:20:36 +00:00
return ;
}
$systemErrorsCount = 0 ;
/** @var string[] $filePaths */
2022-06-07 08:22:29 +00:00
$filePaths = $json [ Bridge :: FILES ] ? ? [];
2021-11-23 13:20:36 +00:00
$errorAndFileDiffs = [];
$systemErrors = [];
2022-01-04 16:58:25 +00:00
// 1. allow PHPStan to work with static reflection on provided files
$this -> nodeScopeResolver -> setAnalysedFiles ( $filePaths );
2021-11-23 13:20:36 +00:00
foreach ( $filePaths as $filePath ) {
try {
2022-09-01 09:30:44 +00:00
$file = new File ( $filePath , FileSystem :: read ( $filePath ));
2021-12-28 12:08:43 +00:00
$this -> currentFileProvider -> setFile ( $file );
2022-01-05 11:30:27 +00:00
if ( ! $this -> phpFileProcessor -> supports ( $file , $configuration )) {
continue ;
}
2021-12-28 12:08:43 +00:00
$currentErrorsAndFileDiffs = $this -> phpFileProcessor -> process ( $file , $configuration );
2022-09-01 20:10:11 +00:00
$errorAndFileDiffs = $this -> arrayParametersMerger -> merge ( $errorAndFileDiffs , $currentErrorsAndFileDiffs );
2022-12-04 13:15:14 +00:00
// warn about deprecated @noRector annotation
if ( \substr_compare ( $file -> getFilePath (), 'WorkerRunner.php' , - \strlen ( 'WorkerRunner.php' )) !== 0 && ( \strpos ( $file -> getFileContent (), ' @noRector ' ) !== \false || \strpos ( $file -> getFileContent (), ' @norector ' ) !== \false )) {
$systemErrors [] = new SystemError ( 'The @noRector annotation was deprecated and removed due to hiding fixed errors. Use more precise $rectorConfig->skip() method in the rector.php config.' , $file -> getFilePath ());
continue ;
}
2022-06-07 08:22:29 +00:00
} catch ( Throwable $throwable ) {
2021-11-23 13:20:36 +00:00
++ $systemErrorsCount ;
2022-06-25 06:53:01 +00:00
$systemErrors = $this -> collectSystemErrors ( $systemErrors , $throwable , $filePath );
2021-11-23 13:20:36 +00:00
}
}
/**
* this invokes all listeners listening $decoder -> on ( ... ) @ see \Symplify\EasyParallel\Enum\ReactEvent :: DATA
*/
2022-06-07 08:22:29 +00:00
$encoder -> write ([ ReactCommand :: ACTION => Action :: RESULT , self :: RESULT => [ Bridge :: FILE_DIFFS => $errorAndFileDiffs [ Bridge :: FILE_DIFFS ] ? ? [], Bridge :: FILES_COUNT => \count ( $filePaths ), Bridge :: SYSTEM_ERRORS => $systemErrors , Bridge :: SYSTEM_ERRORS_COUNT => $systemErrorsCount ]]);
2021-11-23 13:20:36 +00:00
});
2022-06-07 08:22:29 +00:00
$decoder -> on ( ReactEvent :: ERROR , $handleErrorCallback );
2021-11-23 13:20:36 +00:00
}
2022-06-25 06:53:01 +00:00
/**
* @ param SystemError [] $systemErrors
* @ return SystemError []
*/
private function collectSystemErrors ( array $systemErrors , Throwable $throwable , string $filePath ) : array
{
$errorMessage = \sprintf ( 'System error: "%s"' , $throwable -> getMessage ()) . \PHP_EOL ;
if ( $this -> rectorConsoleOutputStyle -> isDebug ()) {
$systemErrors [] = new SystemError ( $errorMessage . \PHP_EOL . 'Stack trace:' . \PHP_EOL . $throwable -> getTraceAsString (), $filePath , $throwable -> getLine ());
return $systemErrors ;
}
$errorMessage .= 'Run Rector with "--debug" option and post the report here: https://github.com/rectorphp/rector/issues/new' ;
$systemErrors [] = new SystemError ( $errorMessage , $filePath , $throwable -> getLine ());
return $systemErrors ;
}
2021-11-23 13:20:36 +00:00
}