Current File : /var/www/prestashop/modules/ps_metrics/vendor/friendsofphp/php-cs-fixer/src/Runner/Runner.php |
<?php
declare (strict_types=1);
/*
* This file is part of PHP CS Fixer.
*
* (c) Fabien Potencier <fabien@symfony.com>
* Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace ps_metrics_module_v4_0_6\PhpCsFixer\Runner;
use ps_metrics_module_v4_0_6\PhpCsFixer\AbstractFixer;
use ps_metrics_module_v4_0_6\PhpCsFixer\Cache\CacheManagerInterface;
use ps_metrics_module_v4_0_6\PhpCsFixer\Cache\Directory;
use ps_metrics_module_v4_0_6\PhpCsFixer\Cache\DirectoryInterface;
use ps_metrics_module_v4_0_6\PhpCsFixer\Differ\DifferInterface;
use ps_metrics_module_v4_0_6\PhpCsFixer\Error\Error;
use ps_metrics_module_v4_0_6\PhpCsFixer\Error\ErrorsManager;
use ps_metrics_module_v4_0_6\PhpCsFixer\FileReader;
use ps_metrics_module_v4_0_6\PhpCsFixer\Fixer\FixerInterface;
use ps_metrics_module_v4_0_6\PhpCsFixer\FixerFileProcessedEvent;
use ps_metrics_module_v4_0_6\PhpCsFixer\Linter\LinterInterface;
use ps_metrics_module_v4_0_6\PhpCsFixer\Linter\LintingException;
use ps_metrics_module_v4_0_6\PhpCsFixer\Linter\LintingResultInterface;
use ps_metrics_module_v4_0_6\PhpCsFixer\Tokenizer\Tokens;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Filesystem\Exception\IOException;
use Symfony\Contracts\EventDispatcher\Event;
/**
* @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
*/
final class Runner
{
/**
* @var DifferInterface
*/
private $differ;
/**
* @var DirectoryInterface
*/
private $directory;
/**
* @var null|EventDispatcherInterface
*/
private $eventDispatcher;
/**
* @var ErrorsManager
*/
private $errorsManager;
/**
* @var CacheManagerInterface
*/
private $cacheManager;
/**
* @var bool
*/
private $isDryRun;
/**
* @var LinterInterface
*/
private $linter;
/**
* @var \Traversable
*/
private $finder;
/**
* @var FixerInterface[]
*/
private $fixers;
/**
* @var bool
*/
private $stopOnViolation;
public function __construct($finder, array $fixers, DifferInterface $differ, ?EventDispatcherInterface $eventDispatcher, ErrorsManager $errorsManager, LinterInterface $linter, bool $isDryRun, CacheManagerInterface $cacheManager, ?DirectoryInterface $directory = null, bool $stopOnViolation = \false)
{
$this->finder = $finder;
$this->fixers = $fixers;
$this->differ = $differ;
$this->eventDispatcher = $eventDispatcher;
$this->errorsManager = $errorsManager;
$this->linter = $linter;
$this->isDryRun = $isDryRun;
$this->cacheManager = $cacheManager;
$this->directory = $directory ?: new Directory('');
$this->stopOnViolation = $stopOnViolation;
}
public function fix() : array
{
$changed = [];
$finder = $this->finder;
$finderIterator = $finder instanceof \IteratorAggregate ? $finder->getIterator() : $finder;
$fileFilteredFileIterator = new FileFilterIterator($finderIterator, $this->eventDispatcher, $this->cacheManager);
$collection = $this->linter->isAsync() ? new FileCachingLintingIterator($fileFilteredFileIterator, $this->linter) : new FileLintingIterator($fileFilteredFileIterator, $this->linter);
/** @var \SplFileInfo $file */
foreach ($collection as $file) {
$fixInfo = $this->fixFile($file, $collection->currentLintingResult());
// we do not need Tokens to still caching just fixed file - so clear the cache
Tokens::clearCache();
if (null !== $fixInfo) {
$name = $this->directory->getRelativePathTo($file->__toString());
$changed[$name] = $fixInfo;
if ($this->stopOnViolation) {
break;
}
}
}
return $changed;
}
private function fixFile(\SplFileInfo $file, LintingResultInterface $lintingResult) : ?array
{
$name = $file->getPathname();
try {
$lintingResult->check();
} catch (LintingException $e) {
$this->dispatchEvent(FixerFileProcessedEvent::NAME, new FixerFileProcessedEvent(FixerFileProcessedEvent::STATUS_INVALID));
$this->errorsManager->report(new Error(Error::TYPE_INVALID, $name, $e));
return null;
}
$old = FileReader::createSingleton()->read($file->getRealPath());
$tokens = Tokens::fromCode($old);
$oldHash = $tokens->getCodeHash();
$newHash = $oldHash;
$new = $old;
$appliedFixers = [];
try {
foreach ($this->fixers as $fixer) {
// for custom fixers we don't know is it safe to run `->fix()` without checking `->supports()` and `->isCandidate()`,
// thus we need to check it and conditionally skip fixing
if (!$fixer instanceof AbstractFixer && (!$fixer->supports($file) || !$fixer->isCandidate($tokens))) {
continue;
}
$fixer->fix($file, $tokens);
if ($tokens->isChanged()) {
$tokens->clearEmptyTokens();
$tokens->clearChanged();
$appliedFixers[] = $fixer->getName();
}
}
} catch (\ParseError $e) {
$this->dispatchEvent(FixerFileProcessedEvent::NAME, new FixerFileProcessedEvent(FixerFileProcessedEvent::STATUS_LINT));
$this->errorsManager->report(new Error(Error::TYPE_LINT, $name, $e));
return null;
} catch (\Throwable $e) {
$this->processException($name, $e);
return null;
}
$fixInfo = null;
if (!empty($appliedFixers)) {
$new = $tokens->generateCode();
$newHash = $tokens->getCodeHash();
}
// We need to check if content was changed and then applied changes.
// But we can't simply check $appliedFixers, because one fixer may revert
// work of other and both of them will mark collection as changed.
// Therefore we need to check if code hashes changed.
if ($oldHash !== $newHash) {
$fixInfo = ['appliedFixers' => $appliedFixers, 'diff' => $this->differ->diff($old, $new, $file)];
try {
$this->linter->lintSource($new)->check();
} catch (LintingException $e) {
$this->dispatchEvent(FixerFileProcessedEvent::NAME, new FixerFileProcessedEvent(FixerFileProcessedEvent::STATUS_LINT));
$this->errorsManager->report(new Error(Error::TYPE_LINT, $name, $e, $fixInfo['appliedFixers'], $fixInfo['diff']));
return null;
}
if (!$this->isDryRun) {
$fileName = $file->getRealPath();
if (!\file_exists($fileName)) {
throw new IOException(\sprintf('Failed to write file "%s" (no longer) exists.', $file->getPathname()), 0, null, $file->getPathname());
}
if (\is_dir($fileName)) {
throw new IOException(\sprintf('Cannot write file "%s" as the location exists as directory.', $fileName), 0, null, $fileName);
}
if (!\is_writable($fileName)) {
throw new IOException(\sprintf('Cannot write to file "%s" as it is not writable.', $fileName), 0, null, $fileName);
}
if (\false === @\file_put_contents($fileName, $new)) {
$error = \error_get_last();
throw new IOException(\sprintf('Failed to write file "%s", "%s".', $fileName, $error ? $error['message'] : 'no reason available'), 0, null, $fileName);
}
}
}
$this->cacheManager->setFile($name, $new);
$this->dispatchEvent(FixerFileProcessedEvent::NAME, new FixerFileProcessedEvent($fixInfo ? FixerFileProcessedEvent::STATUS_FIXED : FixerFileProcessedEvent::STATUS_NO_CHANGES));
return $fixInfo;
}
/**
* Process an exception that occurred.
*/
private function processException(string $name, \Throwable $e) : void
{
$this->dispatchEvent(FixerFileProcessedEvent::NAME, new FixerFileProcessedEvent(FixerFileProcessedEvent::STATUS_EXCEPTION));
$this->errorsManager->report(new Error(Error::TYPE_EXCEPTION, $name, $e));
}
private function dispatchEvent(string $name, Event $event) : void
{
if (null === $this->eventDispatcher) {
return;
}
$this->eventDispatcher->dispatch($event, $name);
}
}