diff --git a/bin/ecs.php b/bin/ecs.php
index eb9e89d3486..e2fa0b3884a 100755
--- a/bin/ecs.php
+++ b/bin/ecs.php
@@ -3,11 +3,14 @@
declare(strict_types=1);
// decoupled in own "*.php" file, so ECS, Rector and PHPStan works out of the box here
+use Composer\InstalledVersions;
+use Composer\XdebugHandler\XdebugHandler;
+use Entropy\Console\ConsoleApplication;
+use Entropy\Console\Output\OutputColorizer;
+use Entropy\Console\Output\OutputPrinter;
use PHP_CodeSniffer\Util\Tokens;
-use Symfony\Component\Console\Command\Command;
-use Symfony\Component\Console\Input\ArgvInput;
-use Symplify\EasyCodingStandard\Console\EasyCodingStandardConsoleApplication;
-use Symplify\EasyCodingStandard\Console\Style\SymfonyStyleFactory;
+use Symplify\EasyCodingStandard\Application\Version\StaticVersionResolver;
+use Symplify\EasyCodingStandard\Console\ExitCode;
use Symplify\EasyCodingStandard\DependencyInjection\EasyCodingStandardContainerFactory;
use Symplify\EasyCodingStandard\DependencyInjection\ServiceContainerFactory;
@@ -142,21 +145,85 @@ public function loadIfNotLoadedYet(string $file): void
}
}
+$rawArgv = $_SERVER['argv'] ?? [];
+
+// @fixes https://github.com/rectorphp/rector/issues/2205
+$isXdebugAllowed = in_array('--xdebug', $rawArgv, true);
+if (! $isXdebugAllowed && ! defined('PHPUNIT_COMPOSER_INSTALL')) {
+ $xdebugHandler = new XdebugHandler('ecs');
+ $xdebugHandler->check();
+ unset($xdebugHandler);
+}
+
try {
- $input = new ArgvInput();
$ecsContainerFactory = new EasyCodingStandardContainerFactory();
- $container = $ecsContainerFactory->createFromFromInput($input);
+ $container = $ecsContainerFactory->createFromArgv($rawArgv);
} catch (Throwable $throwable) {
- $symfonyStyleFactory = new SymfonyStyleFactory();
- $symfonyStyle = $symfonyStyleFactory->create();
+ $outputPrinter = new OutputPrinter(new OutputColorizer());
+ $outputPrinter->error($throwable->getMessage());
+ $outputPrinter->writeln($throwable->getTraceAsString());
+ exit(ExitCode::FAILURE);
+}
- $symfonyStyle->error($throwable->getMessage());
- $symfonyStyle->writeln($throwable->getTraceAsString());
- exit(Command::FAILURE);
+// print version and exit
+if (in_array('--version', $rawArgv, true) || in_array('-V', $rawArgv, true)) {
+ echo sprintf('EasyCodingStandard %s', StaticVersionResolver::PACKAGE_VERSION) . PHP_EOL;
+ echo sprintf('+ PHP_CodeSniffer %s', InstalledVersions::getPrettyVersion('squizlabs/php_codesniffer')) . PHP_EOL;
+ echo sprintf('+ PHP-CS-Fixer %s', InstalledVersions::getPrettyVersion('friendsofphp/php-cs-fixer')) . PHP_EOL;
+ exit(ExitCode::SUCCESS);
}
-/** @var EasyCodingStandardConsoleApplication $application */
-$application = $container->make(EasyCodingStandardConsoleApplication::class);
+/** @var ConsoleApplication $application */
+$application = $container->make(ConsoleApplication::class);
-$statusCode = $application->run();
+$statusCode = $application->run(ecs_normalize_argv($rawArgv));
exit($statusCode);
+
+/**
+ * Strip global/decoration flags Symfony Console handled implicitly, and normalize
+ * the "-c" config shortcut to "--config", so the Entropy input parser does not
+ * treat them as unknown command options.
+ *
+ * @param string[] $argv
+ * @return string[]
+ */
+function ecs_normalize_argv(array $argv): array
+{
+ $decorationFlags = [
+ '--ansi',
+ '--no-ansi',
+ '--quiet',
+ '-q',
+ '--no-interaction',
+ '-n',
+ '-v',
+ '-vv',
+ '-vvv',
+ '--xdebug',
+ ];
+
+ if (in_array('--no-ansi', $argv, true)) {
+ putenv('NO_COLOR=1');
+ }
+
+ $normalized = [];
+ foreach ($argv as $arg) {
+ if (in_array($arg, $decorationFlags, true)) {
+ continue;
+ }
+
+ if ($arg === '-c') {
+ $normalized[] = '--config';
+ continue;
+ }
+
+ if (str_starts_with($arg, '-c=')) {
+ $normalized[] = '--config=' . substr($arg, 3);
+ continue;
+ }
+
+ $normalized[] = $arg;
+ }
+
+ return $normalized;
+}
diff --git a/composer.json b/composer.json
index e11839c850e..b65e9a9ce82 100644
--- a/composer.json
+++ b/composer.json
@@ -20,9 +20,8 @@
"nette/utils": "^4.1",
"sebastian/diff": "^9.0",
"squizlabs/php_codesniffer": "^4.0.1",
- "symfony/console": "^6.4.24",
"symfony/finder": "^7.4",
- "symplify/easy-parallel": "^12.0",
+ "symplify/easy-parallel": "dev-main",
"webmozart/assert": "^2.4"
},
"require-dev": {
@@ -82,6 +81,7 @@
"fix-cs": "bin/ecs check --fix --ansi"
},
"replace": {
+ "symfony/console": "*",
"symfony/event-dispatcher": "7.*",
"symfony/process": "7.*",
"symfony/stopwatch": "7.*"
diff --git a/src/Application/EasyCodingStandardApplication.php b/src/Application/EasyCodingStandardApplication.php
index 07fcdfa813a..fe76185ac83 100644
--- a/src/Application/EasyCodingStandardApplication.php
+++ b/src/Application/EasyCodingStandardApplication.php
@@ -5,8 +5,6 @@
namespace Symplify\EasyCodingStandard\Application;
use ParseError;
-use Symfony\Component\Console\Input\InputInterface;
-use Symfony\Component\Console\Style\SymfonyStyle;
use Symplify\EasyCodingStandard\Caching\ChangedFilesDetector;
use Symplify\EasyCodingStandard\Console\Style\EasyCodingStandardStyle;
use Symplify\EasyCodingStandard\DependencyInjection\SimpleParameterProvider;
@@ -38,7 +36,6 @@ public function __construct(
private ScheduleFactory $scheduleFactory,
private ParallelFileProcessor $parallelFileProcessor,
private CpuCoreCountProvider $cpuCoreCountProvider,
- private SymfonyStyle $symfonyStyle,
private ParametersMerger $parametersMerger
) {
}
@@ -46,7 +43,7 @@ public function __construct(
/**
* @return array{coding_standard_errors?: CodingStandardError[], file_diffs?: FileDiff[], system_errors?: SystemError[]|string[], system_errors_count?: int}
*/
- public function run(Configuration $configuration, InputInterface $input): array
+ public function run(Configuration $configuration): array
{
// 1. find files in sources
$filePaths = $this->sourceFinder->find($configuration->getSources());
@@ -87,11 +84,11 @@ public function run(Configuration $configuration, InputInterface $input): array
if (! $isProgressBarStarted) {
$fileCount = count($filePaths);
- $this->symfonyStyle->progressStart($fileCount);
+ $this->easyCodingStandardStyle->progressStart($fileCount);
$isProgressBarStarted = true;
}
- $this->symfonyStyle->progressAdvance($stepCount);
+ $this->easyCodingStandardStyle->progressAdvance($stepCount);
// running in parallel here → nothing else to do
};
@@ -106,7 +103,7 @@ public function run(Configuration $configuration, InputInterface $input): array
$mainScript,
$postFileCallback,
$configuration->getConfig(),
- $input
+ $configuration
);
}
diff --git a/src/Configuration/ConfigInitializer.php b/src/Configuration/ConfigInitializer.php
index 41a417d026b..2877adce46d 100644
--- a/src/Configuration/ConfigInitializer.php
+++ b/src/Configuration/ConfigInitializer.php
@@ -5,14 +5,14 @@
namespace Symplify\EasyCodingStandard\Configuration;
use Nette\Utils\FileSystem;
-use Symfony\Component\Console\Style\SymfonyStyle;
use Symplify\EasyCodingStandard\Application\FileProcessorCollector;
+use Symplify\EasyCodingStandard\Console\Style\EasyCodingStandardStyle;
final readonly class ConfigInitializer
{
public function __construct(
private FileProcessorCollector $fileProcessorCollector,
- private SymfonyStyle $symfonyStyle,
+ private EasyCodingStandardStyle $easyCodingStandardStyle,
private InitPathsResolver $initPathsResolver,
private \Symfony\Component\Filesystem\Filesystem $filesystem,
) {
@@ -30,13 +30,16 @@ public function createConfig(string $projectDirectory): void
// config already exists, nothing to add
if ($doesConfigExist) {
- $this->symfonyStyle->warning(
+ $this->easyCodingStandardStyle->warning(
'We found ecs.php config, but no rules in it. Register some rules or sets there first'
);
return;
}
- $response = $this->symfonyStyle->ask('No "ecs.php" config found. Should we generate it for you?', 'yes');
+ $response = $this->easyCodingStandardStyle->ask(
+ 'No "ecs.php" config found. Should we generate it for you?',
+ 'yes'
+ );
// be tolerant about input
if (! in_array($response, ['yes', 'YES', 'y', 'Y'], true)) {
@@ -52,7 +55,9 @@ public function createConfig(string $projectDirectory): void
// create the ecs.php file
FileSystem::write(getcwd() . '/ecs.php', $templateFileContents, null);
- $this->symfonyStyle->success('The ecs.php config was generated! Re-run the command to tidy your code');
+ $this->easyCodingStandardStyle->success(
+ 'The ecs.php config was generated! Re-run the command to tidy your code'
+ );
}
private function fillPaths(string $projectDirectory, string $templateFileContents): string
diff --git a/src/Configuration/ConfigurationFactory.php b/src/Configuration/ConfigurationFactory.php
index 69667113222..86580802195 100644
--- a/src/Configuration/ConfigurationFactory.php
+++ b/src/Configuration/ConfigurationFactory.php
@@ -4,7 +4,6 @@
namespace Symplify\EasyCodingStandard\Configuration;
-use Symfony\Component\Console\Input\InputInterface;
use Symplify\EasyCodingStandard\Console\Output\OutputFormatterCollector;
use Symplify\EasyCodingStandard\DependencyInjection\SimpleParameterProvider;
use Symplify\EasyCodingStandard\Exception\Configuration\SourceNotFoundException;
@@ -20,33 +19,32 @@ public function __construct(
/**
* Needs to run in the start of the life cycle, since the rest of workflow uses it.
+ *
+ * @param string[] $paths
*/
- public function createFromInput(InputInterface $input): Configuration
- {
- $paths = $this->resolvePaths($input);
-
- $isFixer = (bool) $input->getOption(Option::FIX);
- $shouldClearCache = (bool) $input->getOption(Option::CLEAR_CACHE);
- $showProgressBar = $this->canShowProgressBar($input);
- $showErrorTable = ! (bool) $input->getOption(Option::NO_ERROR_TABLE);
- $showDiffs = ! (bool) $input->getOption(Option::NO_DIFFS);
- $parallelPort = (string) $input->getOption(Option::PARALLEL_PORT);
- $parallelIdentifier = (string) $input->getOption(Option::PARALLEL_IDENTIFIER);
-
- $outputFormat = (string) $input->getOption(Option::OUTPUT_FORMAT);
-
- /** @var string|null $memoryLimit */
- $memoryLimit = $input->getOption(Option::MEMORY_LIMIT);
+ public function create(
+ array $paths,
+ bool $isFixer,
+ bool $shouldClearCache,
+ bool $noProgressBar,
+ bool $noErrorTable,
+ bool $noDiffs,
+ string $outputFormat,
+ ?string $config,
+ string $parallelPort,
+ string $parallelIdentifier,
+ ?string $memoryLimit,
+ bool $debug,
+ ): Configuration {
+ $paths = $this->resolvePaths($paths);
+
+ $showProgressBar = $this->canShowProgressBar($debug, $outputFormat, $noProgressBar);
+ $showErrorTable = ! $noErrorTable;
+ $showDiffs = ! $noDiffs;
$isParallel = SimpleParameterProvider::getBoolParameter(Option::PARALLEL);
-
$isReportingWithRealPath = SimpleParameterProvider::getBoolParameter(Option::REPORTING_REALPATH);
- $config = $input->getOption(Option::CONFIG);
- if ($config !== null) {
- $config = (string) $config;
- }
-
return new Configuration(
$isFixer,
$shouldClearCache,
@@ -64,22 +62,19 @@ public function createFromInput(InputInterface $input): Configuration
);
}
- private function canShowProgressBar(InputInterface $input): bool
+ private function canShowProgressBar(bool $debug, string $outputFormat, bool $noProgressBar): bool
{
// --debug option shows more
- $debug = (bool) $input->getOption(Option::DEBUG);
if ($debug) {
return false;
}
- $outputFormat = $input->getOption(Option::OUTPUT_FORMAT);
$outputFormatter = $this->outputFormatterCollector->getByName($outputFormat);
-
if (! $outputFormatter->hasSupportForProgressBars()) {
return false;
}
- return ! (bool) $input->getOption(Option::NO_PROGRESS_BAR);
+ return ! $noProgressBar;
}
/**
@@ -97,12 +92,11 @@ private function ensurePathsExists(array $paths): void
}
/**
+ * @param string[] $paths
* @return string[]
*/
- private function resolvePaths(InputInterface $input): array
+ private function resolvePaths(array $paths): array
{
- /** @var string[] $paths */
- $paths = (array) $input->getArgument(Option::PATHS);
if ($paths === []) {
// if not paths are provided from CLI, use the config ones
$paths = SimpleParameterProvider::getArrayParameter(Option::PATHS);
diff --git a/src/Console/Command/AbstractCheckCommand.php b/src/Console/Command/AbstractCheckCommand.php
deleted file mode 100644
index 2e2c13146d6..00000000000
--- a/src/Console/Command/AbstractCheckCommand.php
+++ /dev/null
@@ -1,64 +0,0 @@
-addArgument(
- Option::PATHS,
- // optional is on purpose here, since path from ecs.php can se used
- InputArgument::OPTIONAL | InputArgument::IS_ARRAY,
- 'The path(s) to be checked.'
- );
-
- $this->addOption(Option::FIX, null, null, 'Fix found violations.');
-
- $this->addOption(Option::CONFIG, 'c', InputOption::VALUE_REQUIRED, 'Path to config file');
-
- $this->addOption(Option::CLEAR_CACHE, null, null, 'Clear cache for already checked files.');
-
- $this->addOption(
- Option::NO_PROGRESS_BAR,
- null,
- InputOption::VALUE_NONE,
- 'Hide progress bar. Useful e.g. for nicer CI output.'
- );
-
- $this->addOption(
- Option::NO_ERROR_TABLE,
- null,
- InputOption::VALUE_NONE,
- 'Hide error table. Useful e.g. for fast check of error count.'
- );
- $this->addOption(
- Option::NO_DIFFS,
- null,
- InputOption::VALUE_NONE,
- 'Hide diffs of changed files. Useful e.g. for nicer CI output.'
- );
-
- $this->addOption(
- Option::OUTPUT_FORMAT,
- null,
- InputOption::VALUE_REQUIRED,
- 'Select output format',
- ConsoleOutputFormatter::getName()
- );
-
- $this->addOption(Option::MEMORY_LIMIT, null, InputOption::VALUE_REQUIRED, 'Memory limit for check');
-
- // for parallel run
- $this->addOption(Option::PARALLEL_PORT, null, InputOption::VALUE_REQUIRED);
- $this->addOption(Option::PARALLEL_IDENTIFIER, null, InputOption::VALUE_REQUIRED);
- }
-}
diff --git a/src/Console/Command/CheckCommand.php b/src/Console/Command/CheckCommand.php
index 6429fdc47df..3bea4a5dd12 100644
--- a/src/Console/Command/CheckCommand.php
+++ b/src/Console/Command/CheckCommand.php
@@ -4,48 +4,92 @@
namespace Symplify\EasyCodingStandard\Console\Command;
-use Override;
-use Symfony\Component\Console\Input\InputInterface;
-use Symfony\Component\Console\Output\OutputInterface;
+use Entropy\Console\Contract\CommandInterface;
+use Entropy\Console\Contract\DefaultCommandInterface;
use Symplify\EasyCodingStandard\Application\EasyCodingStandardApplication;
use Symplify\EasyCodingStandard\Configuration\ConfigInitializer;
use Symplify\EasyCodingStandard\Configuration\ConfigurationFactory;
+use Symplify\EasyCodingStandard\Console\ExitCode;
+use Symplify\EasyCodingStandard\Console\Output\ConsoleOutputFormatter;
use Symplify\EasyCodingStandard\MemoryLimitter;
use Symplify\EasyCodingStandard\Reporter\ProcessedFileReporter;
-final class CheckCommand extends AbstractCheckCommand
+final readonly class CheckCommand implements CommandInterface, DefaultCommandInterface
{
public function __construct(
- private readonly ProcessedFileReporter $processedFileReporter,
- private readonly MemoryLimitter $memoryLimitter,
- private readonly ConfigInitializer $configInitializer,
- private readonly EasyCodingStandardApplication $easyCodingStandardApplication,
- private readonly ConfigurationFactory $configurationFactory,
+ private ProcessedFileReporter $processedFileReporter,
+ private MemoryLimitter $memoryLimitter,
+ private ConfigInitializer $configInitializer,
+ private EasyCodingStandardApplication $easyCodingStandardApplication,
+ private ConfigurationFactory $configurationFactory,
) {
- parent::__construct();
}
- #[Override]
- protected function configure(): void
+ public function getName(): string
{
- $this->setName('check');
- $this->setDescription('Check coding standard in one or more directories');
-
- parent::configure();
+ return 'check';
}
- protected function execute(InputInterface $input, OutputInterface $output): int
+ public function getDescription(): string
{
+ return 'Check coding standard in one or more directories';
+ }
+
+ /**
+ * @param string $config Path to config file
+ * @param string $outputFormat Select output format
+ * @param string $memoryLimit Memory limit for check
+ * @param string $port [INTERNAL] parallel TCP port
+ * @param string $identifier [INTERNAL] parallel identifier
+ * @param string ...$paths The path(s) to be checked.
+ *
+ * @option $config
+ * @option $outputFormat
+ * @option $memoryLimit
+ * @option $port
+ * @option $identifier
+ *
+ * @api invoked via reflection by the Entropy console application
+ *
+ * @return ExitCode::*
+ */
+ public function run(
+ bool $fix = false,
+ bool $clearCache = false,
+ bool $noProgressBar = false,
+ bool $noErrorTable = false,
+ bool $noDiffs = false,
+ bool $debug = false,
+ string $config = '',
+ string $outputFormat = ConsoleOutputFormatter::NAME,
+ string $memoryLimit = '',
+ string $port = '',
+ string $identifier = '',
+ string ...$paths,
+ ): int {
// create ecs.php config file if does not exist yet
if (! $this->configInitializer->areSomeCheckersRegistered()) {
- $this->configInitializer->createConfig(getcwd());
- return self::SUCCESS;
+ $this->configInitializer->createConfig((string) getcwd());
+ return ExitCode::SUCCESS;
}
- $configuration = $this->configurationFactory->createFromInput($input);
+ $configuration = $this->configurationFactory->create(
+ array_values($paths),
+ $fix,
+ $clearCache,
+ $noProgressBar,
+ $noErrorTable,
+ $noDiffs,
+ $outputFormat,
+ $config !== '' ? $config : null,
+ $port,
+ $identifier,
+ $memoryLimit !== '' ? $memoryLimit : null,
+ $debug,
+ );
$this->memoryLimitter->adjust($configuration);
- $errorsAndDiffs = $this->easyCodingStandardApplication->run($configuration, $input);
+ $errorsAndDiffs = $this->easyCodingStandardApplication->run($configuration);
return $this->processedFileReporter->report($errorsAndDiffs, $configuration);
}
}
diff --git a/src/Console/Command/ListCheckersCommand.php b/src/Console/Command/ListCheckersCommand.php
index 0bbd7a1eb8f..0f02133de54 100644
--- a/src/Console/Command/ListCheckersCommand.php
+++ b/src/Console/Command/ListCheckersCommand.php
@@ -4,51 +4,50 @@
namespace Symplify\EasyCodingStandard\Console\Command;
+use Entropy\Console\Contract\CommandInterface;
use Nette\Utils\Json;
use PHP_CodeSniffer\Sniffs\Sniff;
use PhpCsFixer\Fixer\FixerInterface;
-use Symfony\Component\Console\Command\Command;
-use Symfony\Component\Console\Input\InputInterface;
-use Symfony\Component\Console\Input\InputOption;
-use Symfony\Component\Console\Output\OutputInterface;
+use Symplify\EasyCodingStandard\Console\ExitCode;
use Symplify\EasyCodingStandard\Console\Output\ConsoleOutputFormatter;
use Symplify\EasyCodingStandard\Console\Reporter\CheckerListReporter;
use Symplify\EasyCodingStandard\FixerRunner\Application\FixerFileProcessor;
use Symplify\EasyCodingStandard\Skipper\SkipCriteriaResolver\SkippedClassResolver;
use Symplify\EasyCodingStandard\SniffRunner\Application\SniffFileProcessor;
-use Symplify\EasyCodingStandard\ValueObject\Option;
-final class ListCheckersCommand extends Command
+final readonly class ListCheckersCommand implements CommandInterface
{
public function __construct(
- private readonly SniffFileProcessor $sniffFileProcessor,
- private readonly FixerFileProcessor $fixerFileProcessor,
- private readonly CheckerListReporter $checkerListReporter,
- private readonly SkippedClassResolver $skippedClassResolver
+ private SniffFileProcessor $sniffFileProcessor,
+ private FixerFileProcessor $fixerFileProcessor,
+ private CheckerListReporter $checkerListReporter,
+ private SkippedClassResolver $skippedClassResolver
) {
- parent::__construct();
}
- protected function configure(): void
+ public function getName(): string
{
- $this->setName('list-checkers');
- $this->setDescription('Shows loaded checkers');
-
- $this->addOption(
- Option::OUTPUT_FORMAT,
- null,
- InputOption::VALUE_REQUIRED,
- 'Select output format',
- ConsoleOutputFormatter::getName()
- );
-
- $this->addOption(Option::CONFIG, 'c', InputOption::VALUE_REQUIRED, 'Path to config file');
+ return 'list-checkers';
}
- protected function execute(InputInterface $input, OutputInterface $output): int
+ public function getDescription(): string
{
- $outputFormat = $input->getOption(Option::OUTPUT_FORMAT);
+ return 'Shows loaded checkers';
+ }
+ /**
+ * @param string $outputFormat Select output format
+ * @param string $config Path to config file
+ *
+ * @option $outputFormat
+ * @option $config
+ *
+ * @api invoked via reflection by the Entropy console application
+ *
+ * @return ExitCode::*
+ */
+ public function run(string $outputFormat = ConsoleOutputFormatter::NAME, string $config = ''): int
+ {
// include skipped rules to avoid adding those too
$skippedCheckers = $this->getSkippedCheckers();
@@ -61,14 +60,14 @@ protected function execute(InputInterface $input, OutputInterface $output): int
echo Json::encode($data, Json::PRETTY) . PHP_EOL;
- return Command::SUCCESS;
+ return ExitCode::SUCCESS;
}
$this->checkerListReporter->report($this->getSniffClasses(), 'from PHP_CodeSniffer');
$this->checkerListReporter->report($this->getFixerClasses(), 'from PHP-CS-Fixer');
$this->checkerListReporter->report($skippedCheckers, 'are skipped');
- return self::SUCCESS;
+ return ExitCode::SUCCESS;
}
/**
diff --git a/src/Console/Command/WorkerCommand.php b/src/Console/Command/WorkerCommand.php
index 31e7dd83872..cf311538443 100644
--- a/src/Console/Command/WorkerCommand.php
+++ b/src/Console/Command/WorkerCommand.php
@@ -6,13 +6,14 @@
use Clue\React\NDJson\Decoder;
use Clue\React\NDJson\Encoder;
-use Override;
+use Entropy\Console\Contract\CommandInterface;
+use Entropy\Console\Contract\HiddenCommandInterface;
use React\EventLoop\StreamSelectLoop;
use React\Socket\ConnectionInterface;
use React\Socket\TcpConnector;
-use Symfony\Component\Console\Input\InputInterface;
-use Symfony\Component\Console\Output\OutputInterface;
use Symplify\EasyCodingStandard\Configuration\ConfigurationFactory;
+use Symplify\EasyCodingStandard\Console\ExitCode;
+use Symplify\EasyCodingStandard\Console\Output\ConsoleOutputFormatter;
use Symplify\EasyCodingStandard\MemoryLimitter;
use Symplify\EasyCodingStandard\Parallel\WorkerRunner;
use Symplify\EasyParallel\Enum\Action;
@@ -25,28 +26,71 @@
* ↓↓↓
* https://github.com/phpstan/phpstan-src/commit/b84acd2e3eadf66189a64fdbc6dd18ff76323f67#diff-7f625777f1ce5384046df08abffd6c911cfbb1cfc8fcb2bdeaf78f337689e3e2
*/
-final class WorkerCommand extends AbstractCheckCommand
+final readonly class WorkerCommand implements CommandInterface, HiddenCommandInterface
{
public function __construct(
- private readonly WorkerRunner $workerRunner,
- private readonly MemoryLimitter $memoryLimitter,
- private readonly ConfigurationFactory $configurationFactory,
+ private WorkerRunner $workerRunner,
+ private MemoryLimitter $memoryLimitter,
+ private ConfigurationFactory $configurationFactory,
) {
- parent::__construct();
}
- #[Override]
- protected function configure(): void
+ public function getName(): string
{
- $this->setName('worker');
- $this->setDescription('[INTERNAL] Support for parallel process');
-
- parent::configure();
+ return 'worker';
}
- protected function execute(InputInterface $input, OutputInterface $output): int
+ public function getDescription(): string
{
- $configuration = $this->configurationFactory->createFromInput($input);
+ return '[INTERNAL] Support for parallel process';
+ }
+
+ /**
+ * @param string $config Path to config file
+ * @param string $outputFormat Select output format
+ * @param string $memoryLimit Memory limit for check
+ * @param string $port [INTERNAL] parallel TCP port
+ * @param string $identifier [INTERNAL] parallel identifier
+ * @param string ...$paths The path(s) to be checked.
+ *
+ * @option $config
+ * @option $outputFormat
+ * @option $memoryLimit
+ * @option $port
+ * @option $identifier
+ *
+ * @api invoked via reflection by the Entropy console application
+ *
+ * @return ExitCode::*
+ */
+ public function run(
+ bool $fix = false,
+ bool $clearCache = false,
+ bool $noProgressBar = false,
+ bool $noErrorTable = false,
+ bool $noDiffs = false,
+ bool $debug = false,
+ string $config = '',
+ string $outputFormat = ConsoleOutputFormatter::NAME,
+ string $memoryLimit = '',
+ string $port = '',
+ string $identifier = '',
+ string ...$paths,
+ ): int {
+ $configuration = $this->configurationFactory->create(
+ array_values($paths),
+ $fix,
+ $clearCache,
+ $noProgressBar,
+ $noErrorTable,
+ $noDiffs,
+ $outputFormat,
+ $config !== '' ? $config : null,
+ $port,
+ $identifier,
+ $memoryLimit !== '' ? $memoryLimit : null,
+ $debug,
+ );
$this->memoryLimitter->adjust($configuration);
$streamSelectLoop = new StreamSelectLoop();
@@ -70,6 +114,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$streamSelectLoop->run();
- return self::SUCCESS;
+ return ExitCode::SUCCESS;
}
}
diff --git a/src/Console/EasyCodingStandardConsoleApplication.php b/src/Console/EasyCodingStandardConsoleApplication.php
deleted file mode 100644
index c57e27c4aa9..00000000000
--- a/src/Console/EasyCodingStandardConsoleApplication.php
+++ /dev/null
@@ -1,114 +0,0 @@
-setHidden();
-
- $this->add($checkCommand);
- $this->add($workerCommand);
- $this->add($listCheckersCommand);
-
- $this->get('completion')
- ->setHidden();
- $this->get('help')
- ->setHidden();
- $this->get('list')
- ->setHidden();
-
- $this->setDefaultCommand('check');
- }
-
- #[Override]
- public function doRun(InputInterface $input, OutputInterface $output): int
- {
- // @fixes https://github.com/rectorphp/rector/issues/2205
- $isXdebugAllowed = $input->hasParameterOption('--xdebug');
- if (! $isXdebugAllowed && ! defined('PHPUNIT_COMPOSER_INSTALL')) {
- $xdebugHandler = new XdebugHandler('ecs');
- $xdebugHandler->check();
- unset($xdebugHandler);
- }
-
- // skip in this case, since generate content must be clear from meta-info
- if ($this->shouldPrintMetaInformation($input)) {
- $output->writeln($this->getLongVersion());
- }
-
- $exitCode = parent::doRun($input, $output);
-
- // Append to the output of --version
- if ($exitCode === 0 && $input->hasParameterOption(['--version', '-V'], true)) {
- $output->writeln(sprintf('+ %s %s', 'PHP_CodeSniffer', PHP_CodeSniffer::VERSION));
- $output->writeln(sprintf('+ %s %s', 'PHP-CS-Fixer', PhpCsFixer::VERSION));
- }
-
- return $exitCode;
- }
-
- #[Override]
- protected function getDefaultInputDefinition(): InputDefinition
- {
- $inputDefinition = parent::getDefaultInputDefinition();
- $this->addExtraOptions($inputDefinition);
-
- return $inputDefinition;
- }
-
- private function shouldPrintMetaInformation(InputInterface $input): bool
- {
- $hasNoArguments = $input->getFirstArgument() === null;
-
- if ($hasNoArguments) {
- return false;
- }
-
- $outputFormat = $input->getParameterOption('--' . Option::OUTPUT_FORMAT);
-
- return $outputFormat === ConsoleOutputFormatter::getName();
- }
-
- private function addExtraOptions(InputDefinition $inputDefinition): void
- {
- $inputDefinition->addOption(new InputOption(
- Option::XDEBUG,
- null,
- InputOption::VALUE_NONE,
- 'Allow running xdebug'
- ));
-
- $inputDefinition->addOption(new InputOption(
- Option::DEBUG,
- null,
- InputOption::VALUE_NONE,
- 'Run in debug mode (alias for "-vvv")'
- ));
- }
-}
diff --git a/src/Console/ExitCode.php b/src/Console/ExitCode.php
index da3e952b38e..e11f516a188 100644
--- a/src/Console/ExitCode.php
+++ b/src/Console/ExitCode.php
@@ -4,13 +4,11 @@
namespace Symplify\EasyCodingStandard\Console;
-use Symfony\Component\Console\Command\Command;
-
final class ExitCode
{
- public const int SUCCESS = Command::SUCCESS;
+ public const int SUCCESS = 0;
- public const int FAILURE = Command::FAILURE;
+ public const int FAILURE = 1;
public const int CHANGED_CODE_OR_FOUND_ERRORS = 2;
}
diff --git a/src/Console/Formatter/ColorConsoleDiffFormatter.php b/src/Console/Formatter/ColorConsoleDiffFormatter.php
index 41bbe1385ed..580ed8cc25c 100644
--- a/src/Console/Formatter/ColorConsoleDiffFormatter.php
+++ b/src/Console/Formatter/ColorConsoleDiffFormatter.php
@@ -5,7 +5,6 @@
namespace Symplify\EasyCodingStandard\Console\Formatter;
use Nette\Utils\Strings;
-use Symfony\Component\Console\Formatter\OutputFormatter;
/**
* Inspired by @see https://github.com/FriendsOfPHP/PHP-CS-Fixer/blob/master/src/Differ/DiffConsoleFormatter.php to be
@@ -53,7 +52,7 @@ public function format(string $diff): string
private function formatWithTemplate(string $diff, string $template): string
{
- $escapedDiff = OutputFormatter::escape(rtrim($diff));
+ $escapedDiff = rtrim($diff);
$escapedDiffLines = Strings::split($escapedDiff, self::NEWLINES_REGEX);
diff --git a/src/Console/Reporter/CheckerListReporter.php b/src/Console/Reporter/CheckerListReporter.php
index 1c1a288b4dd..cc3c629a50b 100644
--- a/src/Console/Reporter/CheckerListReporter.php
+++ b/src/Console/Reporter/CheckerListReporter.php
@@ -4,12 +4,12 @@
namespace Symplify\EasyCodingStandard\Console\Reporter;
-use Symfony\Component\Console\Style\SymfonyStyle;
+use Symplify\EasyCodingStandard\Console\Style\EasyCodingStandardStyle;
final readonly class CheckerListReporter
{
public function __construct(
- private SymfonyStyle $symfonyStyle
+ private EasyCodingStandardStyle $easyCodingStandardStyle
) {
}
@@ -28,7 +28,7 @@ public function report(array $checkerClasses, string $type): void
count($checkerClasses) === 1 ? '' : 's',
$type
);
- $this->symfonyStyle->section($sectionMessage);
- $this->symfonyStyle->listing($checkerClasses);
+ $this->easyCodingStandardStyle->section($sectionMessage);
+ $this->easyCodingStandardStyle->listing($checkerClasses);
}
}
diff --git a/src/Console/Style/EasyCodingStandardStyle.php b/src/Console/Style/EasyCodingStandardStyle.php
index b38a1a6a0a0..e3b1bc12892 100644
--- a/src/Console/Style/EasyCodingStandardStyle.php
+++ b/src/Console/Style/EasyCodingStandardStyle.php
@@ -4,25 +4,82 @@
namespace Symplify\EasyCodingStandard\Console\Style;
-use Symfony\Component\Console\Input\InputInterface;
-use Symfony\Component\Console\Output\OutputInterface;
-use Symfony\Component\Console\Style\SymfonyStyle;
-use Symfony\Component\Console\Terminal;
+use Entropy\Console\Output\OutputPrinter;
+use Entropy\Console\Output\ProgressBar;
use Symplify\EasyCodingStandard\SniffRunner\ValueObject\Error\CodingStandardError;
-final class EasyCodingStandardStyle extends SymfonyStyle
+final readonly class EasyCodingStandardStyle
{
/**
* To fit in Linux/Windows terminal windows to prevent overflow.
*/
private const int BULGARIAN_CONSTANT = 8;
+ private const int DEFAULT_TERMINAL_WIDTH = 120;
+
public function __construct(
- InputInterface $input,
- OutputInterface $output,
- private readonly Terminal $terminal
+ private OutputPrinter $outputPrinter,
+ private ProgressBar $progressBar,
+ private bool $isDebug = false,
) {
- parent::__construct($input, $output);
+ }
+
+ public function writeln(string $message): void
+ {
+ $this->outputPrinter->writeln($this->normalizeTags($message));
+ }
+
+ public function newLine(int $count = 1): void
+ {
+ $this->outputPrinter->newline($count);
+ }
+
+ public function success(string $message): void
+ {
+ $this->outputPrinter->success($message);
+ }
+
+ public function warning(string $message): void
+ {
+ $this->outputPrinter->warning($message);
+ }
+
+ public function error(string $message): void
+ {
+ $this->outputPrinter->error($message);
+ }
+
+ public function section(string $message): void
+ {
+ $this->outputPrinter->section($message);
+ }
+
+ /**
+ * @param string[] $items
+ */
+ public function listing(array $items): void
+ {
+ $this->outputPrinter->listing($items);
+ }
+
+ public function ask(string $question, ?string $default = null): ?string
+ {
+ return $this->outputPrinter->ask($question, $default);
+ }
+
+ public function isDebug(): bool
+ {
+ return $this->isDebug;
+ }
+
+ public function progressStart(int $max): void
+ {
+ $this->progressBar->start($max);
+ }
+
+ public function progressAdvance(int $step = 1): void
+ {
+ $this->progressBar->advance($step);
}
/**
@@ -30,7 +87,6 @@ public function __construct(
*/
public function printErrors(array $codingStandardErrors): void
{
- /** @var CodingStandardError $codingStandardError */
foreach ($codingStandardErrors as $codingStandardError) {
$this->separator();
@@ -47,6 +103,23 @@ public function printErrors(array $codingStandardErrors): void
}
}
+ /**
+ * Translate the Symfony-style console tags still emitted by the reporters into
+ * the smaller tag vocabulary understood by Entropy's OutputColorizer.
+ */
+ private function normalizeTags(string $text): string
+ {
+ // drop bold/underscore styling, keep the text
+ $text = (string) preg_replace('#]+>(.*?)>#su', '$1', $text);
+
+ // → yellow, → green
+ $text = (string) preg_replace('#(.*?)#su', '$1>', $text);
+ $text = (string) preg_replace('#(.*?)#su', '$1>', $text);
+
+ // normalize explicit closing tags (e.g. ) to the generic closing tag
+ return (string) preg_replace('##', '>', $text);
+ }
+
private function separator(): void
{
$separator = str_repeat('-', $this->getTerminalWidth());
@@ -68,7 +141,12 @@ private function createMessageFromFileError(CodingStandardError $codingStandardE
private function getTerminalWidth(): int
{
- return $this->terminal->getWidth() - self::BULGARIAN_CONSTANT;
+ $columns = getenv('COLUMNS');
+ if (is_numeric($columns)) {
+ return (int) $columns - self::BULGARIAN_CONSTANT;
+ }
+
+ return self::DEFAULT_TERMINAL_WIDTH - self::BULGARIAN_CONSTANT;
}
/**
diff --git a/src/Console/Style/EasyCodingStandardStyleFactory.php b/src/Console/Style/EasyCodingStandardStyleFactory.php
index 43c8d757ce3..a7f04cde25f 100644
--- a/src/Console/Style/EasyCodingStandardStyleFactory.php
+++ b/src/Console/Style/EasyCodingStandardStyleFactory.php
@@ -4,74 +4,25 @@
namespace Symplify\EasyCodingStandard\Console\Style;
-use Symfony\Component\Console\Input\ArgvInput;
-use Symfony\Component\Console\Input\InputInterface;
-use Symfony\Component\Console\Output\ConsoleOutput;
-use Symfony\Component\Console\Output\OutputInterface;
-use Symfony\Component\Console\Terminal;
+use Entropy\Console\Output\OutputColorizer;
+use Entropy\Console\Output\OutputPrinter;
+use Entropy\Console\Output\ProgressBar;
/**
* @api
*/
final readonly class EasyCodingStandardStyleFactory
{
- public function __construct(
- private Terminal $terminal
- ) {
- }
-
/**
* @api
*/
public function create(): EasyCodingStandardStyle
{
- $argvInput = new ArgvInput();
- $consoleOutput = new ConsoleOutput();
-
- $this->applySymfonyConsoleArgs($argvInput, $consoleOutput);
-
- // --debug is called
- if ($argvInput->hasParameterOption('--debug')) {
- $consoleOutput->setVerbosity(OutputInterface::VERBOSITY_DEBUG);
- }
-
- // disable output for tests
- if (defined('PHPUNIT_COMPOSER_INSTALL')) {
- $consoleOutput->setVerbosity(OutputInterface::VERBOSITY_QUIET);
- }
-
- return new EasyCodingStandardStyle($argvInput, $consoleOutput, $this->terminal);
- }
-
- /**
- * This method was derived from the `Application::configureIO` method of the Symfony Console
- * component, under the MIT license. See NOTICE for the full license.
- *
- * @see https://github.com/symfony/console/blob/0aa29ca177f432ab68533432db0de059f39c92ae/Application.php#L905
- */
- private function applySymfonyConsoleArgs(InputInterface $input, OutputInterface $output): void
- {
- $enableAnsi = $input->hasParameterOption(['--ansi'], true);
- $disableAnsi = $input->hasParameterOption(['--no-ansi'], true);
-
- match (true) {
- $enableAnsi => $output->setDecorated(true),
- $disableAnsi => $output->setDecorated(false),
- default => null,
- };
-
- $enableQuiet = $input->hasParameterOption(['--quiet', '-q'], true);
+ $outputPrinter = new OutputPrinter(new OutputColorizer());
+ $progressBar = new ProgressBar();
- $isVVV = $input->hasParameterOption('-vvv', true);
- $isVV = $input->hasParameterOption('-vv', true);
- $isV = $input->hasParameterOption('-v', true);
+ $isDebug = in_array('--debug', $_SERVER['argv'] ?? [], true);
- match (true) {
- $enableQuiet => $output->setVerbosity(OutputInterface::VERBOSITY_QUIET),
- $isVVV => $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG),
- $isVV => $output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE),
- $isV => $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE),
- default => null,
- };
+ return new EasyCodingStandardStyle($outputPrinter, $progressBar, $isDebug);
}
}
diff --git a/src/Console/Style/SymfonyStyleFactory.php b/src/Console/Style/SymfonyStyleFactory.php
deleted file mode 100644
index 60b5d26a065..00000000000
--- a/src/Console/Style/SymfonyStyleFactory.php
+++ /dev/null
@@ -1,82 +0,0 @@
-hasParameterOption('--debug')) {
- $consoleOutput->setVerbosity(OutputInterface::VERBOSITY_DEBUG);
- }
-
- // disable output for tests
- if (self::isPHPUnitRun()) {
- $consoleOutput->setVerbosity(OutputInterface::VERBOSITY_QUIET);
- }
-
- return new SymfonyStyle($argvInput, $consoleOutput);
- }
-
- /**
- * Never ever used static methods if not neccesary, this is just handy for tests + src to prevent duplication.
- */
- private static function isPHPUnitRun(): bool
- {
- return defined('PHPUNIT_COMPOSER_INSTALL') || defined('__PHPUNIT_PHAR__');
- }
-
- /**
- * This method was derived from the `Application::configureIO` method of the Symfony Console
- * component, under the MIT license. See NOTICE for the full license.
- *
- * @see https://github.com/symfony/console/blob/0aa29ca177f432ab68533432db0de059f39c92ae/Application.php#L905
- */
- private static function applySymfonyConsoleArgs(InputInterface $input, OutputInterface $output): void
- {
- $enableAnsi = $input->hasParameterOption(['--ansi'], true);
- $disableAnsi = $input->hasParameterOption(['--no-ansi'], true);
-
- match (true) {
- $enableAnsi => $output->setDecorated(true),
- $disableAnsi => $output->setDecorated(false),
- default => null,
- };
-
- $enableQuiet = $input->hasParameterOption(['--quiet', '-q'], true);
-
- $isVVV = $input->hasParameterOption('-vvv', true);
- $isVV = $input->hasParameterOption('-vv', true);
- $isV = $input->hasParameterOption('-v', true);
-
- match (true) {
- $enableQuiet => $output->setVerbosity(OutputInterface::VERBOSITY_QUIET),
- $isVVV => $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG),
- $isVV => $output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE),
- $isV => $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE),
- default => null,
- };
- }
-}
diff --git a/src/DependencyInjection/EasyCodingStandardContainerFactory.php b/src/DependencyInjection/EasyCodingStandardContainerFactory.php
index ed6b6f01e63..3dfd9526e1f 100644
--- a/src/DependencyInjection/EasyCodingStandardContainerFactory.php
+++ b/src/DependencyInjection/EasyCodingStandardContainerFactory.php
@@ -4,7 +4,6 @@
namespace Symplify\EasyCodingStandard\DependencyInjection;
-use Symfony\Component\Console\Input\ArgvInput;
use Symplify\EasyCodingStandard\Caching\ChangedFilesDetector;
use Symplify\EasyCodingStandard\Config\ECSConfig;
@@ -13,20 +12,20 @@
*/
final class EasyCodingStandardContainerFactory
{
- public function createFromFromInput(ArgvInput $argvInput): ECSConfig
+ /**
+ * @param string[] $argv
+ */
+ public function createFromArgv(array $argv): ECSConfig
{
- // $easyCodingStandardKernel = new EasyCodingStandardKernel();
$serviceContainerFactory = new ServiceContainerFactory();
$inputConfigFiles = [];
$rootECSConfig = getcwd() . DIRECTORY_SEPARATOR . 'ecs.php';
- if ($argvInput->hasParameterOption(['--config', '-c'])) {
- $commandLineConfigFile = $argvInput->getParameterOption(['--config', '-c']);
- if (is_string($commandLineConfigFile) && file_exists($commandLineConfigFile)) {
- // must be realpath, so container builder knows the location
- $inputConfigFiles[] = (string) realpath($commandLineConfigFile);
- }
+ $commandLineConfigFile = $this->resolveConfigFromArgv($argv);
+ if ($commandLineConfigFile !== null && file_exists($commandLineConfigFile)) {
+ // must be realpath, so container builder knows the location
+ $inputConfigFiles[] = (string) realpath($commandLineConfigFile);
} elseif (file_exists($rootECSConfig)) {
$inputConfigFiles[] = $rootECSConfig;
}
@@ -43,4 +42,28 @@ public function createFromFromInput(ArgvInput $argvInput): ECSConfig
return $ecsConfig;
}
+
+ /**
+ * Resolve "--config ", "--config=", "-c " or "-c=" from raw argv.
+ *
+ * @param string[] $argv
+ */
+ private function resolveConfigFromArgv(array $argv): ?string
+ {
+ foreach ($argv as $index => $arg) {
+ if ($arg === '--config' || $arg === '-c') {
+ return $argv[$index + 1] ?? null;
+ }
+
+ if (str_starts_with($arg, '--config=')) {
+ return substr($arg, strlen('--config='));
+ }
+
+ if (str_starts_with($arg, '-c=')) {
+ return substr($arg, strlen('-c='));
+ }
+ }
+
+ return null;
+ }
}
diff --git a/src/DependencyInjection/ServiceContainerFactory.php b/src/DependencyInjection/ServiceContainerFactory.php
index 606431bb8ea..97fbd4b3bc2 100644
--- a/src/DependencyInjection/ServiceContainerFactory.php
+++ b/src/DependencyInjection/ServiceContainerFactory.php
@@ -10,13 +10,11 @@
use PhpCsFixer\Differ\DifferInterface;
use PhpCsFixer\Differ\UnifiedDiffer;
use PhpCsFixer\WhitespacesFixerConfig;
-use Symfony\Component\Console\Style\SymfonyStyle;
use Symplify\EasyCodingStandard\Caching\Cache;
use Symplify\EasyCodingStandard\Caching\CacheFactory;
use Symplify\EasyCodingStandard\Config\ECSConfig;
use Symplify\EasyCodingStandard\Console\Style\EasyCodingStandardStyle;
use Symplify\EasyCodingStandard\Console\Style\EasyCodingStandardStyleFactory;
-use Symplify\EasyCodingStandard\Console\Style\SymfonyStyleFactory;
use Symplify\EasyCodingStandard\FixerRunner\WhitespacesFixerConfigFactory;
use Webmozart\Assert\Assert;
@@ -41,7 +39,8 @@ static function (Container $container): EasyCodingStandardStyle {
}
);
- $ecsConfig->service(SymfonyStyle::class, static fn (): SymfonyStyle => SymfonyStyleFactory::create());
+ // console commands - autodiscovered, then collected by the default CommandRegistry contract lookup
+ $ecsConfig->autodiscover(__DIR__ . '/../Console/Command');
// whitespace
$ecsConfig->service(WhitespacesFixerConfig::class, static function (): WhitespacesFixerConfig {
@@ -70,9 +69,9 @@ static function (Container $container): EasyCodingStandardStyle {
Assert::isCallable($configClosure);
if ($configClosure instanceof Closure && ! defined('PHPUNIT_COMPOSER_INSTALL')) {
- /** @var SymfonyStyle $symfonyStyle */
- $symfonyStyle = $ecsConfig->make(SymfonyStyle::class);
- $symfonyStyle->warning(sprintf(
+ /** @var EasyCodingStandardStyle $easyCodingStandardStyle */
+ $easyCodingStandardStyle = $ecsConfig->make(EasyCodingStandardStyle::class);
+ $easyCodingStandardStyle->warning(sprintf(
'The "return function (ECSConfig $ecsConfig): void {}" config format is deprecated. Use "return ECSConfig::configure()" fluent API instead in "%s".',
$configFile
));
diff --git a/src/Parallel/Application/ParallelFileProcessor.php b/src/Parallel/Application/ParallelFileProcessor.php
index f62eeb6f34a..1b4660fc515 100644
--- a/src/Parallel/Application/ParallelFileProcessor.php
+++ b/src/Parallel/Application/ParallelFileProcessor.php
@@ -10,12 +10,11 @@
use React\EventLoop\StreamSelectLoop;
use React\Socket\ConnectionInterface;
use React\Socket\TcpServer;
-use Symfony\Component\Console\Command\Command;
-use Symfony\Component\Console\Input\InputInterface;
-use Symplify\EasyCodingStandard\Console\Command\CheckCommand;
+use Symplify\EasyCodingStandard\Console\ExitCode;
use Symplify\EasyCodingStandard\DependencyInjection\SimpleParameterProvider;
use Symplify\EasyCodingStandard\Parallel\ValueObject\Bridge;
use Symplify\EasyCodingStandard\SniffRunner\ValueObject\Error\CodingStandardError;
+use Symplify\EasyCodingStandard\ValueObject\Configuration;
use Symplify\EasyCodingStandard\ValueObject\Error\FileDiff;
use Symplify\EasyCodingStandard\ValueObject\Error\SystemError;
use Symplify\EasyCodingStandard\ValueObject\Option;
@@ -57,7 +56,7 @@ public function check(
string $mainScript,
callable $postFileCallback,
?string $projectConfigFile,
- InputInterface $input
+ Configuration $configuration
): array {
$jobs = array_reverse($schedule->getJobs());
$streamSelectLoop = new StreamSelectLoop();
@@ -124,6 +123,15 @@ public function check(
$timeoutInSeconds = SimpleParameterProvider::getIntParameter(Option::PARALLEL_TIMEOUT_IN_SECONDS);
+ // options mirrored to each worker sub-process
+ $workerOptionValues = [
+ Option::FIX => $configuration->isFixer(),
+ Option::CLEAR_CACHE => $configuration->shouldClearCache(),
+ Option::NO_ERROR_TABLE => ! $configuration->shouldShowErrorTable(),
+ Option::NO_DIFFS => ! $configuration->shouldShowDiffs(),
+ Option::MEMORY_LIMIT => $configuration->getMemoryLimit(),
+ ];
+
for ($i = 0; $i < $numberOfProcesses; ++$i) {
// nothing else to process, stop now
if ($jobs === []) {
@@ -133,11 +141,10 @@ public function check(
$processIdentifier = Random::generate();
$workerCommandLine = $this->workerCommandLineFactory->create(
$mainScript,
- CheckCommand::class,
'worker',
- Option::PATHS,
$projectConfigFile,
- $input,
+ $workerOptionValues,
+ $configuration->getSources(),
$processIdentifier,
$serverPort,
);
@@ -200,7 +207,7 @@ function (array $json) use (
// 3. callable on exit
function ($exitCode, string $stdErr) use (&$systemErrors, $processIdentifier): void {
$this->processPool->tryQuitProcess($processIdentifier);
- if ($exitCode === Command::SUCCESS) {
+ if ($exitCode === ExitCode::SUCCESS) {
return;
}
diff --git a/src/ValueObject/Option.php b/src/ValueObject/Option.php
index bb28fb7a413..d7cfa9022db 100644
--- a/src/ValueObject/Option.php
+++ b/src/ValueObject/Option.php
@@ -10,12 +10,8 @@ final class Option
public const string CLEAR_CACHE = 'clear-cache';
- public const string NO_PROGRESS_BAR = 'no-progress-bar';
-
public const string NO_ERROR_TABLE = 'no-error-table';
- public const string OUTPUT_FORMAT = 'output-format';
-
public const string NO_DIFFS = 'no-diffs';
/**
@@ -73,24 +69,16 @@ final class Option
*/
public const string INDENTATION_TAB = 'tab';
- public const string XDEBUG = 'xdebug';
-
- public const string DEBUG = 'debug';
-
/**
* @see \Symplify\EasyCodingStandard\Config\ECSConfig::parallel()
*/
public const string PARALLEL = 'parallel';
- public const string CONFIG = 'config';
-
/**
* @see \Symplify\EasyCodingStandard\Config\ECSConfig::parallel()
*/
public const string PARALLEL_JOB_SIZE = 'parallel_job_size';
- public const string PARALLEL_PORT = 'port';
-
public const string PARALLEL_IDENTIFIER = 'identifier';
/**
diff --git a/tests/Console/Command/CommandRegistrationTest.php b/tests/Console/Command/CommandRegistrationTest.php
new file mode 100644
index 00000000000..5fafbd9ca15
--- /dev/null
+++ b/tests/Console/Command/CommandRegistrationTest.php
@@ -0,0 +1,48 @@
+commandRegistry = $this->make(CommandRegistry::class);
+ }
+
+ public function testCommandsAreRegistered(): void
+ {
+ $this->assertTrue($this->commandRegistry->has('check'));
+ $this->assertTrue($this->commandRegistry->has('worker'));
+ $this->assertTrue($this->commandRegistry->has('list-checkers'));
+ }
+
+ public function testCheckIsTheDefaultCommand(): void
+ {
+ $this->assertInstanceOf(CheckCommand::class, $this->commandRegistry->getDefault());
+ }
+
+ public function testWorkerCommandIsHidden(): void
+ {
+ $visibleCommandClasses = array_map(
+ static fn (object $command): string => $command::class,
+ $this->commandRegistry->getVisible()
+ );
+
+ $this->assertNotContains(WorkerCommand::class, $visibleCommandClasses);
+ }
+}
diff --git a/tests/Console/Style/EasyCodingStandardStyleTest.php b/tests/Console/Style/EasyCodingStandardStyleTest.php
new file mode 100644
index 00000000000..574a81d4573
--- /dev/null
+++ b/tests/Console/Style/EasyCodingStandardStyleTest.php
@@ -0,0 +1,57 @@
+easyCodingStandardStyle = new EasyCodingStandardStyle(
+ new OutputPrinter(new OutputColorizer()),
+ new ProgressBar()
+ );
+
+ $this->normalizeTagsReflectionMethod = new ReflectionMethod($this->easyCodingStandardStyle, 'normalizeTags');
+ }
+
+ #[DataProvider('provideData')]
+ public function testNormalizeTags(string $input, string $expected): void
+ {
+ $normalized = $this->normalizeTagsReflectionMethod->invoke($this->easyCodingStandardStyle, $input);
+
+ $this->assertSame($expected, $normalized);
+ }
+
+ public static function provideData(): Iterator
+ {
+ yield 'comment tag becomes yellow' => ['hello', 'hello>'];
+
+ yield 'info tag becomes green' => ['done', 'done>'];
+
+ yield 'bold options are stripped, text kept' => ['title>', 'title'];
+
+ yield 'explicit color closing tag is normalized' => ['err', 'err>'];
+
+ yield 'plain text is left untouched' => ['no tags here', 'no tags here'];
+ }
+}