noitran /
cs-fixer-command
| 1 | <?php |
||
| 2 | |||
| 3 | namespace Noitran\CsFixer\Console; |
||
| 4 | |||
| 5 | use Illuminate\Console\Command; |
||
| 6 | |||
| 7 | use PhpCsFixer\Config; |
||
| 8 | use PhpCsFixer\Console\Command\FixCommandExitStatusCalculator; |
||
| 9 | use PhpCsFixer\Console\ConfigurationResolver; |
||
| 10 | use PhpCsFixer\Console\Output\ErrorOutput; |
||
| 11 | use PhpCsFixer\Console\Output\NullOutput; |
||
| 12 | use PhpCsFixer\Console\Output\ProcessOutput; |
||
| 13 | use PhpCsFixer\Error\ErrorsManager; |
||
| 14 | use PhpCsFixer\Finder; |
||
| 15 | use PhpCsFixer\Report\ReportSummary; |
||
| 16 | use PhpCsFixer\Runner\Runner; |
||
| 17 | use PhpCsFixer\ToolInfo; |
||
| 18 | use Symfony\Component\Console\Output\OutputInterface; |
||
| 19 | use Symfony\Component\Console\Terminal; |
||
| 20 | use Symfony\Component\EventDispatcher\EventDispatcher; |
||
| 21 | use Symfony\Component\Stopwatch\Stopwatch; |
||
| 22 | use RuntimeException; |
||
| 23 | use ArrayIterator; |
||
| 24 | |||
| 25 | /** |
||
| 26 | * Class PhpCsCommand |
||
| 27 | */ |
||
| 28 | class PhpCsCommand extends Command |
||
| 29 | { |
||
| 30 | /** |
||
| 31 | * The default verbosity of output commands. |
||
| 32 | * |
||
| 33 | * @var int |
||
| 34 | */ |
||
| 35 | protected $verbosity = OutputInterface::VERBOSITY_VERBOSE; |
||
| 36 | |||
| 37 | /** |
||
| 38 | * The console command name. |
||
| 39 | * |
||
| 40 | * @var string |
||
| 41 | */ |
||
| 42 | protected $name = 'phpcs:fix'; |
||
| 43 | |||
| 44 | /** |
||
| 45 | * The name and signature of the console command. |
||
| 46 | * |
||
| 47 | * @var string |
||
| 48 | */ |
||
| 49 | protected $signature = 'phpcs:fix |
||
| 50 | {--path=* : The path.} |
||
| 51 | {--path-mode=override : Specify path mode (can be override or intersection).} |
||
| 52 | {--allow-risky= : Are risky fixers allowed (can be yes or no).} |
||
| 53 | {--config= : The path to a .php_cs file.} |
||
| 54 | {--dry-run : Only shows which files would have been modified.} |
||
| 55 | {--rules= : The Rules} |
||
| 56 | {--using-cache=yes : Does cache should be used (can be yes or no).} |
||
| 57 | {--cache-file= : The path to the cache file.} |
||
| 58 | {--diff : Also produce diff for each file.} |
||
| 59 | {--diff-format= : Specify diff format.} |
||
| 60 | {--format= : To output results in other formats.} |
||
| 61 | {--stop-on-violation : Stop execution on first violation.} |
||
| 62 | {--show-progress= : Type of progress indicator (none, run-in, estimating or estimating-max).}'; |
||
| 63 | |||
| 64 | /** |
||
| 65 | * The console command description. |
||
| 66 | * |
||
| 67 | * @var string |
||
| 68 | */ |
||
| 69 | protected $description = 'Runs PHPCS-Fixer tool to fix code to follow coding standards.'; |
||
| 70 | |||
| 71 | /** |
||
| 72 | * @var ErrorsManager |
||
| 73 | */ |
||
| 74 | private $errorsManager; |
||
| 75 | |||
| 76 | /** |
||
| 77 | * @var EventDispatcher |
||
| 78 | */ |
||
| 79 | private $eventDispatcher; |
||
| 80 | |||
| 81 | /** |
||
| 82 | * @var Stopwatch |
||
| 83 | */ |
||
| 84 | private $stopwatch; |
||
| 85 | |||
| 86 | /** |
||
| 87 | * @var ToolInfo |
||
| 88 | */ |
||
| 89 | private $toolInfo; |
||
| 90 | |||
| 91 | /** |
||
| 92 | * PhpCsCommand constructor. |
||
| 93 | */ |
||
| 94 | 1 | public function __construct() |
|
| 95 | { |
||
| 96 | 1 | parent::__construct(); |
|
| 97 | |||
| 98 | 1 | $this->errorsManager = new ErrorsManager(); |
|
| 99 | 1 | $this->eventDispatcher = new EventDispatcher(); |
|
| 100 | 1 | $this->stopwatch = new Stopwatch(); |
|
| 101 | 1 | $this->toolInfo = new ToolInfo(); |
|
| 102 | 1 | } |
|
| 103 | |||
| 104 | /** |
||
| 105 | * Handles the Command |
||
| 106 | */ |
||
| 107 | 1 | public function handle(): int |
|
| 108 | { |
||
| 109 | 1 | $this->validateOptions(); |
|
| 110 | 1 | $resolver = $this->getResolver(); |
|
| 111 | 1 | [$finder, $progressOutput] = $this->manageProgress($resolver); |
|
| 112 | 1 | $runner = $this->getRunner($finder, $resolver); |
|
| 113 | |||
| 114 | 1 | $this->stopwatch->start('fixFiles'); |
|
| 115 | 1 | $changed = $runner->fix(); |
|
| 116 | 1 | $this->stopwatch->stop('fixFiles'); |
|
| 117 | 1 | $progressOutput->printLegend(); |
|
| 118 | 1 | $fixEvent = $this->stopwatch->getEvent('fixFiles'); |
|
| 119 | |||
| 120 | 1 | $reportSummary = $this->createReport($changed, $fixEvent, $resolver); |
|
| 121 | |||
| 122 | 1 | $this->getOutput()->isDecorated() ? |
|
| 123 | $this->getOutput()->write($resolver->getReporter()->generate($reportSummary)) : |
||
| 124 | 1 | $this->getOutput()->write( |
|
| 125 | 1 | $resolver->getReporter()->generate($reportSummary), |
|
| 126 | 1 | false, |
|
| 127 | 1 | OutputInterface::OUTPUT_RAW |
|
| 128 | ); |
||
| 129 | |||
| 130 | 1 | $invalidErrors = $this->errorsManager->getInvalidErrors(); |
|
| 131 | 1 | $exceptionErrors = $this->errorsManager->getExceptionErrors(); |
|
| 132 | 1 | $lintErrors = $this->errorsManager->getLintErrors(); |
|
| 133 | |||
| 134 | 1 | $errorOutput = new ErrorOutput($this->getOutput()); |
|
| 135 | |||
| 136 | 1 | if (\count($invalidErrors) > 0) { |
|
| 137 | $errorOutput->listErrors('linting before fixing', $invalidErrors); |
||
| 138 | } |
||
| 139 | |||
| 140 | 1 | if (\count($exceptionErrors) > 0) { |
|
| 141 | $errorOutput->listErrors('fixing', $exceptionErrors); |
||
| 142 | } |
||
| 143 | |||
| 144 | 1 | if (\count($lintErrors) > 0) { |
|
| 145 | $errorOutput->listErrors('linting after fixing', $lintErrors); |
||
| 146 | } |
||
| 147 | |||
| 148 | 1 | $exitStatusCalculator = new FixCommandExitStatusCalculator(); |
|
| 149 | |||
| 150 | 1 | return $exitStatusCalculator->calculate( |
|
| 151 | 1 | $resolver->isDryRun(), |
|
| 152 | 1 | \count($changed) > 0, |
|
| 153 | 1 | \count($invalidErrors) > 0, |
|
| 154 | 1 | \count($exceptionErrors) > 0 |
|
| 155 | ); |
||
| 156 | } |
||
| 157 | |||
| 158 | /** |
||
| 159 | * @param $changed |
||
| 160 | * @param $fixEvent |
||
| 161 | * @param ConfigurationResolver $resolver |
||
| 162 | * |
||
| 163 | * @return ReportSummary |
||
| 164 | */ |
||
| 165 | 1 | protected function createReport($changed, $fixEvent, ConfigurationResolver $resolver): ReportSummary |
|
| 166 | { |
||
| 167 | 1 | return new ReportSummary( |
|
| 168 | 1 | $changed, |
|
| 169 | 1 | $fixEvent->getDuration(), |
|
| 170 | 1 | $fixEvent->getMemory(), |
|
| 171 | 1 | OutputInterface::VERBOSITY_VERBOSE <= $this->verbosity, |
|
| 172 | 1 | $resolver->isDryRun(), |
|
| 173 | 1 | $this->getOutput()->isDecorated() |
|
| 174 | ); |
||
| 175 | } |
||
| 176 | |||
| 177 | /** |
||
| 178 | * @param $finder |
||
| 179 | * @param ConfigurationResolver $resolver |
||
| 180 | * |
||
| 181 | * @return Runner |
||
| 182 | */ |
||
| 183 | 1 | protected function getRunner($finder, ConfigurationResolver $resolver): Runner |
|
| 184 | { |
||
| 185 | 1 | return new Runner( |
|
| 186 | 1 | $finder, |
|
| 187 | 1 | $resolver->getFixers(), |
|
| 188 | 1 | $resolver->getDiffer(), |
|
| 189 | 1 | 'none' !== $resolver->getProgress() ? $this->eventDispatcher : null, |
|
| 190 | 1 | $this->errorsManager, |
|
| 191 | 1 | $resolver->getLinter(), |
|
| 192 | 1 | $resolver->isDryRun(), |
|
| 193 | 1 | $resolver->getCacheManager(), |
|
| 194 | 1 | $resolver->getDirectory(), |
|
| 195 | 1 | $resolver->shouldStopOnViolation() |
|
| 196 | ); |
||
| 197 | } |
||
| 198 | |||
| 199 | /** |
||
| 200 | * @return Config |
||
| 201 | */ |
||
| 202 | 1 | protected function getConfig(): Config |
|
| 203 | { |
||
| 204 | 1 | $config = new Config('artisan'); |
|
| 205 | |||
| 206 | 1 | $config->setRules(config('phpcs.rules')) |
|
| 207 | 1 | ->setFinder($this->getFinder()) |
|
| 208 | 1 | ->setCacheFile(storage_path('framework/cache/phpcs.json')); |
|
| 209 | |||
| 210 | 1 | return $config; |
|
| 211 | } |
||
| 212 | |||
| 213 | /** |
||
| 214 | * @return Finder |
||
| 215 | */ |
||
| 216 | 1 | protected function getFinder(): Finder |
|
| 217 | { |
||
| 218 | 1 | return Finder::create() |
|
| 219 | 1 | ->in(base_path()) |
|
| 220 | 1 | ->exclude(config('phpcs.excludes')) |
|
| 221 | 1 | ->notPath('_ide_helper_models.php') |
|
| 222 | 1 | ->notPath('_ide_helper.php') |
|
| 223 | 1 | ->notPath('.phpstorm.meta.php') |
|
| 224 | 1 | ->notName('*.blade.php') |
|
| 225 | 1 | ->ignoreDotFiles(true) |
|
| 226 | 1 | ->ignoreVCS(true); |
|
| 227 | } |
||
| 228 | |||
| 229 | /** |
||
| 230 | * @return ConfigurationResolver |
||
| 231 | */ |
||
| 232 | 1 | protected function getResolver(): ConfigurationResolver |
|
| 233 | { |
||
| 234 | 1 | $resolver = new ConfigurationResolver( |
|
| 235 | 1 | $this->getConfig(), |
|
| 236 | [ |
||
| 237 | 1 | 'allow-risky' => $this->option('allow-risky'), |
|
| 238 | 1 | 'config' => $this->option('config'), |
|
| 239 | 1 | 'dry-run' => $this->option('dry-run'), |
|
| 240 | 1 | 'rules' => $this->option('rules'), |
|
| 241 | 1 | 'path' => $this->option('path'), |
|
| 242 | 1 | 'path-mode' => $this->option('path-mode'), |
|
| 243 | 1 | 'using-cache' => $this->option('using-cache'), |
|
| 244 | 1 | 'cache-file' => $this->option('cache-file'), |
|
| 245 | 1 | 'format' => $this->option('format'), |
|
| 246 | 1 | 'diff' => $this->option('diff'), |
|
| 247 | 1 | 'diff-format' => $this->option('diff-format'), |
|
| 248 | 1 | 'stop-on-violation' => $this->option('stop-on-violation'), |
|
| 249 | 1 | 'verbosity' => $this->verbosity, |
|
| 250 | 1 | 'show-progress' => $this->option('show-progress'), |
|
| 251 | ], |
||
| 252 | 1 | getcwd(), |
|
| 253 | 1 | $this->toolInfo |
|
| 254 | ); |
||
| 255 | |||
| 256 | 1 | $this->info(sprintf( |
|
| 257 | 1 | 'Loaded config <comment>%s</comment>%s.', |
|
| 258 | 1 | $resolver->getConfig()->getName(), |
|
| 259 | 1 | null === $resolver->getConfigFile() ? '' : ' from "' . $resolver->getConfigFile() . '"' |
|
| 260 | )); |
||
| 261 | |||
| 262 | 1 | if ($resolver->getUsingCache()) { |
|
| 263 | 1 | $cacheFile = $resolver->getCacheFile(); |
|
| 264 | 1 | if (is_file($cacheFile)) { |
|
| 265 | 1 | $this->info(sprintf('Using cache file <comment>%s</comment>.', $cacheFile)); |
|
| 266 | } |
||
| 267 | } |
||
| 268 | |||
| 269 | 1 | if ($resolver->configFinderIsOverridden()) { |
|
| 270 | $this->info( |
||
| 271 | 'Paths from configuration file have been overridden by paths provided as command arguments.' |
||
| 272 | ); |
||
| 273 | } |
||
| 274 | |||
| 275 | 1 | return $resolver; |
|
| 276 | } |
||
| 277 | |||
| 278 | /** |
||
| 279 | * |
||
| 280 | */ |
||
| 281 | 1 | protected function validateOptions(): void |
|
| 282 | { |
||
| 283 | 1 | if (null !== $this->option('config') && null !== $this->option('rules')) { |
|
|
0 ignored issues
–
show
introduced
by
Loading history...
|
|||
| 284 | if (getenv('PHP_CS_FIXER_FUTURE_MODE')) { |
||
| 285 | throw new RuntimeException( |
||
| 286 | 'Passing both `config` and `rules` options is not possible. |
||
| 287 | This check was performed as `PHP_CS_FIXER_FUTURE_MODE` env var is set.' |
||
| 288 | ); |
||
| 289 | } |
||
| 290 | |||
| 291 | $this->warn('When passing both "--config" and "--rules" |
||
| 292 | the rules within the configuration file are not used.'); |
||
| 293 | $this->warn('Passing both options is deprecated; version |
||
| 294 | v3.0 PHP-CS-Fixer will exit with a configuration error code.'); |
||
| 295 | } |
||
| 296 | 1 | } |
|
| 297 | |||
| 298 | /** |
||
| 299 | * @param ConfigurationResolver $resolver |
||
| 300 | * |
||
| 301 | * @return array |
||
| 302 | */ |
||
| 303 | 1 | protected function manageProgress(ConfigurationResolver $resolver): array |
|
| 304 | { |
||
| 305 | 1 | $finder = $resolver->getFinder(); |
|
| 306 | 1 | if ('none' === $resolver->getProgress()) { |
|
| 307 | $progressOutput = new NullOutput(); |
||
| 308 | 1 | } elseif ('run-in' === $resolver->getProgress()) { |
|
| 309 | 1 | $progressOutput = new ProcessOutput($this->getOutput(), $this->eventDispatcher, null, null); |
|
| 310 | } else { |
||
| 311 | $finder = new ArrayIterator(iterator_to_array($finder)); |
||
| 312 | $progressOutput = new ProcessOutput( |
||
| 313 | $this->getOutput(), |
||
| 314 | $this->eventDispatcher, |
||
| 315 | 'estimating-max' === $resolver->getProgress() ? (new Terminal())->getWidth() : null, |
||
| 316 | \count($finder) |
||
| 317 | ); |
||
| 318 | } |
||
| 319 | |||
| 320 | 1 | return [$finder, $progressOutput]; |
|
| 321 | } |
||
| 322 | } |
||
| 323 |