Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 107 additions & 15 deletions bin/rector.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@
declare(strict_types=1);

use Composer\XdebugHandler\XdebugHandler;
use Entropy\Console\ConsoleApplication;
use Nette\Utils\Json;
use Rector\Application\VersionResolver;
use Rector\Bootstrap\AutoloadFileParameterResolver;
use Rector\Bootstrap\CliOptionValueResolver;
use Rector\Bootstrap\RectorConfigsResolver;
use Rector\ChangesReporting\Output\JsonOutputFormatter;
use Rector\Configuration\Option;
use Rector\Console\Style\SymfonyStyleFactory;
use Rector\Console\ExitCode;
use Rector\Console\Style\RectorStyleFactory;
use Rector\DependencyInjection\LazyContainerFactory;
use Rector\DependencyInjection\RectorContainerFactory;
use Rector\Util\Reflection\PrivatesAccessor;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\ArgvInput;

// @ intentionally: continue anyway
@ini_set('memory_limit', '-1');
Expand Down Expand Up @@ -125,7 +125,7 @@ public function loadIfExistsAndNotLoadedYet(string $filePath): void
$autoloadIncluder->autoloadFromCommandLine();

// restart without Xdebug before the container is built, so the restarted process does not repeat that work
if (! new ArgvInput()->hasParameterOption('--xdebug')) {
if (! in_array('--xdebug', $_SERVER['argv'] ?? [], true)) {
$xdebugHandler = new XdebugHandler('rector');
$xdebugHandler->setPersistent();
$xdebugHandler->check();
Expand All @@ -142,8 +142,7 @@ public function loadIfExistsAndNotLoadedYet(string $filePath): void
$container = $rectorContainerFactory->createFromBootstrapConfigs($bootstrapConfigs);
} catch (Throwable $throwable) {
// for json output
$argvInput = new ArgvInput();
$outputFormat = $argvInput->getParameterOption('--' . Option::OUTPUT_FORMAT);
$outputFormat = CliOptionValueResolver::resolve($_SERVER['argv'] ?? [], ['--' . Option::OUTPUT_FORMAT]);

// report fatal error in json format
if ($outputFormat === JsonOutputFormatter::NAME) {
Expand All @@ -157,16 +156,109 @@ public function loadIfExistsAndNotLoadedYet(string $filePath): void
]);
} else {
// report fatal errors in console format
$symfonyStyleFactory = new SymfonyStyleFactory(new PrivatesAccessor());
$symfonyStyle = $symfonyStyleFactory->create();
$rectorStyleFactory = new RectorStyleFactory();
$rectorStyle = $rectorStyleFactory->create();
do {
$symfonyStyle->error(str_replace("\r\n", "\n", $throwable->getMessage()));
$rectorStyle->error(str_replace("\r\n", "\n", $throwable->getMessage()));
} while ($throwable = $throwable->getPrevious());
}

exit(Command::FAILURE);
exit(ExitCode::FAILURE);
}

/** @var Application $application */
$application = $container->get(Application::class);
exit($application->run());
// print version and exit
$rawArgv = $_SERVER['argv'] ?? [];
if (in_array('--version', $rawArgv, true) || in_array('-V', $rawArgv, true)) {
echo sprintf('Rector %s', VersionResolver::PACKAGE_VERSION) . PHP_EOL;
exit(ExitCode::SUCCESS);
}

$application = $container->make(ConsoleApplication::class);
exit($application->run(rector_normalize_argv($rawArgv)));

/**
* Strip global decoration flags the former symfony/console handled implicitly, and normalize the
* short "-c"/"-n"/"-a" options to their long forms, so the Entropy input parser does not treat them
* as unknown options. Inject the default "process" command when the first argument is an option or a
* path, and expand the "p" alias.
*
* @param array<int, string> $argv
* @return array<int, string>
*/
function rector_normalize_argv(array $argv): array
{
$decorationFlags = ['--ansi', '--no-ansi', '--quiet', '-q', '--no-interaction', '-v', '-vv', '-vvv', '--xdebug'];

if (in_array('--no-ansi', $argv, true)) {
putenv('NO_COLOR=1');
}

$shortToLong = [
'-c' => '--' . Option::CONFIG,
'-n' => '--' . Option::DRY_RUN,
'-a' => '--' . Option::AUTOLOAD_FILE,
];

$normalized = [];
foreach ($argv as $arg) {
if (in_array($arg, $decorationFlags, true)) {
continue;
}

if (isset($shortToLong[$arg])) {
$normalized[] = $shortToLong[$arg];
continue;
}

$matched = false;
foreach ($shortToLong as $short => $long) {
if (str_starts_with($arg, $short . '=')) {
$normalized[] = $long . '=' . substr($arg, strlen($short) + 1);
$matched = true;
break;
}
}

if ($matched) {
continue;
}

$normalized[] = $arg;
}

// expand the "p" alias to the "process" command name
if (isset($normalized[1]) && $normalized[1] === 'p') {
$normalized[1] = 'process';
}

// leading "help" or "list" tokens show the application help, matching the former symfony/console behavior
if (isset($normalized[1]) && ($normalized[1] === 'help' || $normalized[1] === 'list')) {
return [$normalized[0], '--help'];
}

// first real argument is an option or a path - inject the default "process" command, so the parser
// does not mistake a leading "--option" or a path for an unknown command
$helpFlags = ['-h', '--help'];
if (
isset($normalized[1])
&& $normalized[1] !== 'process'
&& ! in_array($normalized[1], $helpFlags, true)
&& (str_starts_with($normalized[1], '-') || ! rector_is_known_command($normalized[1]))
) {
array_splice($normalized, 1, 0, 'process');
}

return $normalized;
}

/**
* The commands a leading token may name; anything else is a path for the default "process" command.
*/
function rector_is_known_command(string $token): bool
{
return in_array(
$token,
['process', 'worker', 'list-rules', 'validate-config', 'custom-rule', 'setup-ci', 'composer-based'],
true
);
}
13 changes: 6 additions & 7 deletions build/build-preload.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@
declare(strict_types=1);

use Nette\Utils\Strings;
use Rector\Console\Style\SymfonyStyleFactory;
use Rector\Util\Reflection\PrivatesAccessor;
use Symfony\Component\Console\Command\Command;
use Rector\Console\ExitCode;
use Rector\Console\Style\RectorStyleFactory;
use Symfony\Component\Finder\Finder;

$possiblePaths = [
Expand All @@ -28,13 +27,13 @@

$buildDirectory = $argv[1];

$symfonyStyleFactory = new SymfonyStyleFactory(new PrivatesAccessor());
$symfonyStyle = $symfonyStyleFactory->create();
$rectorStyleFactory = new RectorStyleFactory();
$rectorStyle = $rectorStyleFactory->create();

if (! is_string($buildDirectory)) {
$errorMessage = 'Provide build directory path as an argument, e.g. "php build-preload.php rector-build-directory"';
$symfonyStyle->error($errorMessage);
exit(Command::FAILURE);
$rectorStyle->error($errorMessage);
exit(ExitCode::FAILURE);
}

$preloadBuilder = new PreloadBuilder();
Expand Down
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"composer/semver": "^3.4",
"composer/xdebug-handler": "^3.0.5",
"doctrine/inflector": "^2.1",
"entropy/entropy": "^0.4.12",
"entropy/entropy": "^0.4.35",
"fidry/cpu-core-counter": "^1.1",
"nette/utils": "^4.1.5",
"nikic/php-parser": "^5.9",
Expand All @@ -34,7 +34,6 @@
"rector/rector-phpunit": "dev-main",
"rector/rector-symfony": "dev-main",
"sebastian/diff": "^9.0",
"symfony/console": "^6.4.24",
"symfony/filesystem": "^8.1",
"symfony/finder": "^8.1",
"webmozart/assert": "^2.4"
Expand All @@ -60,6 +59,7 @@
},
"replace": {
"rector/rector": "self.version",
"symfony/console": "*",
"symplify/rule-doc-generator-contracts": "*"
},
"autoload": {
Expand Down
17 changes: 8 additions & 9 deletions e2e/e2eTestRunner.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@

use Rector\Console\Formatter\ColorConsoleDiffFormatter;
use Rector\Console\Formatter\ConsoleDiffer;
use Rector\Console\Style\SymfonyStyleFactory;
use Rector\Console\ExitCode;
use Rector\Console\Style\RectorStyleFactory;
use Rector\Differ\DefaultDiffer;
use Rector\Util\Reflection\PrivatesAccessor;
use Symfony\Component\Console\Command\Command;

$projectRoot = __DIR__ .'/..';
$rectorBin = $projectRoot . '/bin/rector';
Expand Down Expand Up @@ -59,20 +58,20 @@
exit($exitCode);
}

$symfonyStyleFactory = new SymfonyStyleFactory(new PrivatesAccessor());
$symfonyStyle = $symfonyStyleFactory->create();
$rectorStyleFactory = new RectorStyleFactory();
$rectorStyle = $rectorStyleFactory->create();

$matchedExpectedOutput = false;
$expectedOutput = trim((string) file_get_contents($expectedDiff));
if ($output === $expectedOutput) {
$symfonyStyle->success('End-to-end test successfully completed');
exit(Command::SUCCESS);
$rectorStyle->success('End-to-end test successfully completed');
exit(ExitCode::SUCCESS);
}

// print color diff, to make easy find the differences
$defaultDiffer = new DefaultDiffer();
$colorConsoleDiffFormatter = new ColorConsoleDiffFormatter();
$diff = $colorConsoleDiffFormatter->format($defaultDiffer->diff($output, $expectedOutput));
$symfonyStyle->writeln($diff);
$rectorStyle->writeln($diff);

exit(Command::FAILURE);
exit(ExitCode::FAILURE);
1 change: 0 additions & 1 deletion e2e/parallel-reflection-resolver/expected-output.diff
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
Applied rules:
* RemoveUnusedPrivatePropertyRector


2) src/SomeClassNotFound.php:4

---------- begin diff ----------
Expand Down
Loading
Loading