From 0a5efeaf844b63d477529bd15a3bd50b270c702a Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Tue, 22 Oct 2019 14:38:49 +0200 Subject: [PATCH 1/3] add Standalone --- bin/bootstrap.php | 12 +- composer.json | 1 + src/Console/Option/SetOptionResolver.php | 41 ++--- .../RectorContainerFactory.php | 71 ++++++++ src/Set/Set.php | 13 ++ src/Set/SetProvider.php | 2 +- src/Standalone/RectorStandaloneRunner.php | 165 ++++++++++++++++++ .../RectorContainerFactoryTest.php | 29 +++ 8 files changed, 305 insertions(+), 29 deletions(-) create mode 100644 src/DependencyInjection/RectorContainerFactory.php create mode 100644 src/Set/Set.php create mode 100644 src/Standalone/RectorStandaloneRunner.php create mode 100644 tests/DependencyInjection/RectorContainerFactoryTest.php diff --git a/bin/bootstrap.php b/bin/bootstrap.php index e2dcbfc7413f..b920accfdd2a 100644 --- a/bin/bootstrap.php +++ b/bin/bootstrap.php @@ -8,17 +8,14 @@ function includeProjectsAutoload(string $composerJsonPath, string $cwd): void $composerSettings = json_decode($contents, true); if (! is_array($composerSettings)) { - fwrite(STDERR, "Failed to load '${composerJsonPath}'\n"); - exit(1); + die(sprintf('Failed to load "%s"', $composerJsonPath)); } $vendorPath = $composerSettings['config']['vendor-dir'] ?? $cwd . '/vendor'; if (! is_dir($vendorPath)) { - fwrite(STDERR, "Please check if 'composer.phar install' was run already (expected to find '${vendorPath}')\n"); - exit(1); + die(sprintf('Please check if "composer install" was run already (expected to find "%s")', $vendorPath)); } - /** @noinspection PhpIncludeInspection */ require $vendorPath . '/autoload.php'; } @@ -29,6 +26,7 @@ function includeProjectsAutoload(string $composerJsonPath, string $cwd): void require $projectAutoload; } +// is autolaod successful? if (class_exists('Rector\HttpKernel\RectorKernel')) { return; } @@ -53,11 +51,9 @@ function includeProjectsAutoload(string $composerJsonPath, string $cwd): void return; } -fwrite( - STDERR, +die( sprintf( 'Composer autoload.php was not found in paths "%s". Have you ran "composer update"?', implode('", "', $possibleAutoloadPaths) ) ); -exit(1); diff --git a/composer.json b/composer.json index c40f1d93dc77..220379eb4e2e 100644 --- a/composer.json +++ b/composer.json @@ -11,6 +11,7 @@ "bin": ["bin/rector"], "require": { "php": "^7.1", + "ext-json": "*", "composer/xdebug-handler": "^1.3", "doctrine/annotations": "^1.6", "doctrine/inflector": "^1.3", diff --git a/src/Console/Option/SetOptionResolver.php b/src/Console/Option/SetOptionResolver.php index 94e146c5504c..6021134ccaa2 100644 --- a/src/Console/Option/SetOptionResolver.php +++ b/src/Console/Option/SetOptionResolver.php @@ -40,6 +40,11 @@ public function detectFromInputAndDirectory(InputInterface $input, string $confi return null; } + return $this->detectFromNameAndDirectory($setName, $configDirectory); + } + + public function detectFromNameAndDirectory(string $setName, string $configDirectory): ?string + { $nearestMatches = $this->findNearestMatchingFiles($configDirectory, $setName); if (count($nearestMatches) === 0) { $this->reportSetNotFound($configDirectory, $setName); @@ -57,18 +62,16 @@ private function reportSetNotFound(string $configDirectory, string $setName): vo $suggestedSet = ObjectHelpers::getSuggestion($allSets, $setName); - $hasSetVersion = (bool) Strings::match($setName, '#[\d]#'); - [$versionedSets, $unversionedSets] = $this->separateVersionedAndUnversionedSets($allSets); - $setsListInString = $this->createSetListInString($hasSetVersion, $unversionedSets, $versionedSets); + $setsListInString = $this->createSetListInString($unversionedSets, $versionedSets); $setNotFoundMessage = sprintf( '%s "%s" was not found.%s%s', ucfirst($this->keyName), $setName, PHP_EOL, - $suggestedSet ? sprintf('Did you mean "%s"?', $suggestedSet) . PHP_EOL : 'Pick one of above.' + $suggestedSet ? sprintf('Did you mean "%s"?', $suggestedSet) . PHP_EOL : '' ); $pickOneOfMessage = sprintf('Pick "--%s" of:%s%s', $this->keyName, PHP_EOL . PHP_EOL, $setsListInString); @@ -152,24 +155,18 @@ private function matchVersionInTheEnd(string $setName): ?string * @param string[] $unversionedSets * @param string[] $versionedSets */ - private function createSetListInString( - bool $hasSetVersion, - array $unversionedSets, - array $versionedSets - ): string { + private function createSetListInString(array $unversionedSets, array $versionedSets): string + { $setsListInString = ''; - if ($hasSetVersion === false) { - foreach ($unversionedSets as $unversionedSet) { - $setsListInString .= ' * ' . $unversionedSet . PHP_EOL; - } + foreach ($unversionedSets as $unversionedSet) { + $setsListInString .= ' * ' . $unversionedSet . PHP_EOL; } - if ($hasSetVersion) { - foreach ($versionedSets as $groupName => $configName) { - $setsListInString .= ' * ' . $groupName . ': ' . implode(', ', $configName) . PHP_EOL; - } + foreach ($versionedSets as $groupName => $configName) { + $setsListInString .= ' * ' . $groupName . ': ' . implode(', ', $configName) . PHP_EOL; } + return $setsListInString; } @@ -183,12 +180,16 @@ private function separateVersionedAndUnversionedSets(array $allSets): array $unversionedSets = []; foreach ($allSets as $set) { - $match = Strings::match($set, '#^[A-Za-z\-]+#'); - if ($match === null) { + $hasVersion = (bool) Strings::match($set, '#\d#'); + + if ($hasVersion === false) { $unversionedSets[] = $set; + continue; } - $setWithoutVersion = rtrim($match[0], '-'); + $match = Strings::match($set, '#^(?[A-Za-z\-]+)#'); + $setWithoutVersion = $match['set']; + if ($setWithoutVersion !== $set) { $versionedSets[$setWithoutVersion][] = $set; } diff --git a/src/DependencyInjection/RectorContainerFactory.php b/src/DependencyInjection/RectorContainerFactory.php new file mode 100644 index 000000000000..92f146afec87 --- /dev/null +++ b/src/DependencyInjection/RectorContainerFactory.php @@ -0,0 +1,71 @@ +setOptionResolver = new SetOptionResolver(); + } + + public function createFromSet(string $set): ContainerInterface + { + $configFiles = $this->resolveConfigs($set); + + return $this->createFromConfigs($configFiles); + } + + /** + * @return string[] + */ + private function resolveConfigs(string $set): array + { + $config = $this->setOptionResolver->detectFromNameAndDirectory($set, Set::SET_DIRECTORY); + if ($config === null) { + throw new ShouldNotHappenException(sprintf('Config file for "%s" set was not found', $set)); + } + + // copied mostly from https://github.com/rectorphp/rector/blob/master/bin/container.php + $configFiles = []; + $configFiles[] = $config; + // local config has priority + $configFiles[] = ConfigFileFinder::provide('rector', ['rector.yml', 'rector.yaml']); + + // remove empty values + return array_filter($configFiles); + } + + /** + * @param string[] $configFiles + */ + private function createFromConfigs(array $configFiles): ContainerInterface + { + // to override the configs without clearing cache + $environment = 'prod' . random_int(1, 10000000); + $isDebug = true; + + $rectorKernel = new RectorKernel($environment, $isDebug); + if ($configFiles) { + $rectorKernel->setConfigs($configFiles); + } + + $rectorKernel->boot(); + + return $rectorKernel->getContainer(); + } +} diff --git a/src/Set/Set.php b/src/Set/Set.php new file mode 100644 index 000000000000..ca5c5db7de4b --- /dev/null +++ b/src/Set/Set.php @@ -0,0 +1,13 @@ +files() - ->in(__DIR__ . '/../../config/set'); + ->in(Set::SET_DIRECTORY); $sets = []; foreach ($finder->getIterator() as $fileInfo) { diff --git a/src/Standalone/RectorStandaloneRunner.php b/src/Standalone/RectorStandaloneRunner.php new file mode 100644 index 000000000000..d2f7fefc3aad --- /dev/null +++ b/src/Standalone/RectorStandaloneRunner.php @@ -0,0 +1,165 @@ +rectorContainerFactory = $rectorContainerFactory; + $this->nativeSymfonyStyle = $symfonyStyle; + } + + /** + * @param string[] $source + */ + public function processSourceWithSet(array $source, string $set, bool $isDryRun): void + { + $source = $this->absolutizeSource($source); + + $container = $this->rectorContainerFactory->createFromSet($set); + $this->prepare($container, $source, $isDryRun); + + /** @var FilesFinder $filesFinder */ + $filesFinder = $container->get(FilesFinder::class); + $phpFileInfos = $filesFinder->findInDirectoriesAndFiles($source, ['php']); + + /** @var RectorApplication $rectorApplication */ + $rectorApplication = $container->get(RectorApplication::class); + $rectorApplication->runOnFileInfos($phpFileInfos); + + $this->reportErrors($container); + + $this->finish($container); + } + + /** + * Mostly copied from: https://github.com/rectorphp/rector/blob/master/src/Console/Command/ProcessCommand.php. + * @param string[] $source + */ + private function prepare(ContainerInterface $container, array $source, bool $isDryRun): void + { + ini_set('memory_limit', '4096M'); + + /** @var RectorNodeTraverser $rectorNodeTraverser */ + $rectorNodeTraverser = $container->get(RectorNodeTraverser::class); + $this->prepareConfiguration($container, $rectorNodeTraverser, $isDryRun); + + /** @var RectorGuard $rectorGuard */ + $rectorGuard = $container->get(RectorGuard::class); + $rectorGuard->ensureSomeRectorsAreRegistered(); + + // setup verbosity from the current run + /** @var SymfonyStyle $symfonyStyle */ + $symfonyStyle = $container->get(SymfonyStyle::class); + $symfonyStyle->setVerbosity($this->nativeSymfonyStyle->getVerbosity()); + + /** @var AdditionalAutoloader $additionalAutoloader */ + $additionalAutoloader = $container->get(AdditionalAutoloader::class); + $additionalAutoloader->autoloadWithInputAndSource(new ArrayInput([]), $source); + + /** @var StubLoader $stubLoader */ + $stubLoader = $container->get(StubLoader::class); + $stubLoader->loadStubs(); + } + + private function reportErrors(ContainerInterface $container): void + { + /** @var ErrorAndDiffCollector $errorAndDiffCollector */ + $errorAndDiffCollector = $container->get(ErrorAndDiffCollector::class); + + /** @var ConsoleOutputFormatter $consoleOutputFormatter */ + $consoleOutputFormatter = $container->get(ConsoleOutputFormatter::class); + $consoleOutputFormatter->report($errorAndDiffCollector); + } + + /** + * @param string[] $source + * @return string[] + */ + private function absolutizeSource(array $source): array + { + foreach ($source as $key => $singleSource) { + /** @var string $singleSource */ + if (! file_exists($singleSource)) { + throw new FileNotFoundException($singleSource); + } + + /** @var string $realpath */ + $realpath = realpath($singleSource); + $source[$key] = $realpath; + } + + return $source; + } + + private function finish(ContainerInterface $container): void + { + /** @var FinishingExtensionRunner $finishingExtensionRunner */ + $finishingExtensionRunner = $container->get(FinishingExtensionRunner::class); + $finishingExtensionRunner->run(); + + /** @var ReportingExtensionRunner $reportingExtensionRunner */ + $reportingExtensionRunner = $container->get(ReportingExtensionRunner::class); + $reportingExtensionRunner->run(); + } + + private function prepareConfiguration( + ContainerInterface $container, + RectorNodeTraverser $rectorNodeTraverser, + bool $isDryRun + ): void { + /** @var Configuration $configuration */ + $configuration = $container->get(Configuration::class); + + $configuration->setAreAnyPhpRectorsLoaded((bool) $rectorNodeTraverser->getPhpRectorCount()); + + // definition mimics @see ProcessCommand definition + /** @var ProcessCommand $processCommand */ + $processCommand = $container->get(ProcessCommand::class); + $definition = clone $processCommand->getDefinition(); + + // reset arguments to prevent "source is missing" + $definition->setArguments([]); + + $configuration->resolveFromInput(new ArrayInput([ + '--' . Option::OPTION_DRY_RUN => $isDryRun, + '--' . Option::OPTION_OUTPUT_FORMAT => 'console', + ], $definition)); + } +} diff --git a/tests/DependencyInjection/RectorContainerFactoryTest.php b/tests/DependencyInjection/RectorContainerFactoryTest.php new file mode 100644 index 000000000000..53f70146e8cb --- /dev/null +++ b/tests/DependencyInjection/RectorContainerFactoryTest.php @@ -0,0 +1,29 @@ +createFromSet('doctrine'); + $this->assertInstanceOf(ContainerInterface::class, $rectorContainer); + } + + public function testMissingSet(): void + { + $rectorContainerFactory = new RectorContainerFactory(); + + $this->expectException(SetNotFoundException::class); + $rectorContainerFactory->createFromSet('bla'); + } +} From beaf6a837844e6876c8692d0e949217bb1739db6 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Tue, 22 Oct 2019 15:11:39 +0200 Subject: [PATCH 2/3] make use of Set and ContainerFactory --- bin/container.php | 31 ++++++--------- .../RectorContainerFactory.php | 39 ++++++++++--------- .../Configuration/ConfigurationFactory.php | 11 ++---- 3 files changed, 34 insertions(+), 47 deletions(-) diff --git a/bin/container.php b/bin/container.php index 2e6689f3452f..f56fee5df3d0 100644 --- a/bin/container.php +++ b/bin/container.php @@ -3,22 +3,21 @@ declare(strict_types=1); use Rector\Console\Option\SetOptionResolver; +use Rector\DependencyInjection\RectorContainerFactory; use Rector\Exception\Configuration\SetNotFoundException; -use Rector\HttpKernel\RectorKernel; +use Rector\Set\Set; use Symfony\Component\Console\Input\ArgvInput; use Symplify\PackageBuilder\Configuration\ConfigFileFinder; -use Symplify\PackageBuilder\Console\Input\InputDetector; use Symplify\PackageBuilder\Console\ShellCode; use Symplify\PackageBuilder\Console\Style\SymfonyStyleFactory; -$configFiles = []; +$configs = []; // Detect configuration from --set try { - $configFiles[] = (new SetOptionResolver())->detectFromInputAndDirectory( - new ArgvInput(), - __DIR__ . '/../config/set' - ); + $input = new ArgvInput(); + $setOptionResolver = new SetOptionResolver(); + $configs[] = $setOptionResolver->detectFromInputAndDirectory($input, Set::SET_DIRECTORY); } catch (SetNotFoundException $setNotFoundException) { $symfonyStyle = (new SymfonyStyleFactory())->create(); $symfonyStyle->error($setNotFoundException->getMessage()); @@ -27,19 +26,11 @@ // And from --config or default one ConfigFileFinder::detectFromInput('rector', new ArgvInput()); -$configFiles[] = ConfigFileFinder::provide('rector', ['rector.yml', 'rector.yaml']); +$configs[] = ConfigFileFinder::provide('rector', ['rector.yml', 'rector.yaml']); // remove empty values -$configFiles = array_filter($configFiles); +$configs = array_filter($configs); -// 3. Build DI container - -// to override the configs without clearing cache -$environment = 'prod' . random_int(1, 10000000); -$rectorKernel = new RectorKernel($environment, InputDetector::isDebug()); -if ($configFiles) { - $rectorKernel->setConfigs($configFiles); -} -$rectorKernel->boot(); - -return $rectorKernel->getContainer(); +// Build DI container +$rectorContainerFactory = new RectorContainerFactory(); +return $rectorContainerFactory->createFromConfigs($configs); diff --git a/src/DependencyInjection/RectorContainerFactory.php b/src/DependencyInjection/RectorContainerFactory.php index 92f146afec87..588dafcf8c9b 100644 --- a/src/DependencyInjection/RectorContainerFactory.php +++ b/src/DependencyInjection/RectorContainerFactory.php @@ -10,6 +10,7 @@ use Rector\HttpKernel\RectorKernel; use Rector\Set\Set; use Symplify\PackageBuilder\Configuration\ConfigFileFinder; +use Symplify\PackageBuilder\Console\Input\InputDetector; final class RectorContainerFactory { @@ -30,6 +31,25 @@ public function createFromSet(string $set): ContainerInterface return $this->createFromConfigs($configFiles); } + /** + * @param string[] $configFiles + */ + public function createFromConfigs(array $configFiles): ContainerInterface + { + // to override the configs without clearing cache + $environment = 'prod' . random_int(1, 10000000); + $isDebug = InputDetector::isDebug(); + + $rectorKernel = new RectorKernel($environment, $isDebug); + if ($configFiles) { + $rectorKernel->setConfigs($configFiles); + } + + $rectorKernel->boot(); + + return $rectorKernel->getContainer(); + } + /** * @return string[] */ @@ -49,23 +69,4 @@ private function resolveConfigs(string $set): array // remove empty values return array_filter($configFiles); } - - /** - * @param string[] $configFiles - */ - private function createFromConfigs(array $configFiles): ContainerInterface - { - // to override the configs without clearing cache - $environment = 'prod' . random_int(1, 10000000); - $isDebug = true; - - $rectorKernel = new RectorKernel($environment, $isDebug); - if ($configFiles) { - $rectorKernel->setConfigs($configFiles); - } - - $rectorKernel->boot(); - - return $rectorKernel->getContainer(); - } } diff --git a/utils/RectorGenerator/src/Configuration/ConfigurationFactory.php b/utils/RectorGenerator/src/Configuration/ConfigurationFactory.php index a63266ad1f98..a3fdcc9293bd 100644 --- a/utils/RectorGenerator/src/Configuration/ConfigurationFactory.php +++ b/utils/RectorGenerator/src/Configuration/ConfigurationFactory.php @@ -7,6 +7,7 @@ use Nette\Utils\Strings; use PhpParser\Node; use Rector\Exception\FileSystem\FileNotFoundException; +use Rector\Set\Set; use Rector\Utils\RectorGenerator\Exception\ConfigurationException; use Rector\Utils\RectorGenerator\Node\NodeClassProvider; use Rector\Utils\RectorGenerator\ValueObject\Configuration; @@ -16,11 +17,6 @@ final class ConfigurationFactory { - /** - * @var string - */ - private $setsDirectory; - /** * @var NodeClassProvider */ @@ -28,7 +24,6 @@ final class ConfigurationFactory public function __construct(NodeClassProvider $nodeClassProvider) { - $this->setsDirectory = __DIR__ . '/../../../../config/set'; $this->nodeClassProvider = $nodeClassProvider; } @@ -140,7 +135,7 @@ private function resolveSetConfig(string $set): ?string $fileSet = sprintf('#^%s(\.yaml)?$#', $set); $finder = Finder::create()->files() - ->in($this->setsDirectory) + ->in(Set::SET_DIRECTORY) ->name($fileSet); /** @var SplFileInfo[] $fileInfos */ @@ -149,7 +144,7 @@ private function resolveSetConfig(string $set): ?string // assume new one is created $match = Strings::match($set, '#\/(?[a-zA-Z_-]+])#'); if (isset($match['name'])) { - return $this->setsDirectory . '/' . $match['name'] . '/' . $set; + return Set::SET_DIRECTORY . '/' . $match['name'] . '/' . $set; } return null; From c64b9a08bcc1c6af5904bd95708c152205f5da75 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Tue, 22 Oct 2019 15:44:36 +0200 Subject: [PATCH 3/3] add test --- ecs.yaml | 2 +- src/Standalone/RectorStandaloneRunner.php | 99 +++++++++++++------ .../RectorStandaloneRunnerStaticFactory.php | 20 ++++ .../Standalone/RectorStandaloneRunnerTest.php | 35 +++++++ tests/Standalone/Source/LowQualityFile.php | 14 +++ 5 files changed, 137 insertions(+), 33 deletions(-) create mode 100644 src/Standalone/RectorStandaloneRunnerStaticFactory.php create mode 100644 tests/Standalone/RectorStandaloneRunnerTest.php create mode 100644 tests/Standalone/Source/LowQualityFile.php diff --git a/ecs.yaml b/ecs.yaml index 141d0d783b8b..6870625c4f45 100644 --- a/ecs.yaml +++ b/ecs.yaml @@ -109,7 +109,7 @@ parameters: - 'packages/BetterPhpDocParser/src/Annotation/AnnotationNaming.php' - 'src/Testing/PHPUnit/PHPUnitEnvironment.php' # honesty first - - 'src/*StaticHelper.php' + - 'src/*Static*.php' Symplify\CodingStandard\Fixer\Naming\PropertyNameMatchingTypeFixer: - 'packages/NodeTypeResolver/src/PHPStan/Scope/NodeScopeResolver.php' diff --git a/src/Standalone/RectorStandaloneRunner.php b/src/Standalone/RectorStandaloneRunner.php index d2f7fefc3aad..af0d34c7800a 100644 --- a/src/Standalone/RectorStandaloneRunner.php +++ b/src/Standalone/RectorStandaloneRunner.php @@ -21,7 +21,9 @@ use Rector\PhpParser\NodeTraverser\RectorNodeTraverser; use Rector\Stubs\StubLoader; use Symfony\Component\Console\Input\ArrayInput; +use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; +use Symplify\PackageBuilder\FileSystem\SmartFileInfo; /** * This class is needed over process/cli run to get console output in sane way; @@ -39,6 +41,11 @@ final class RectorStandaloneRunner */ private $nativeSymfonyStyle; + /** + * @var ContainerInterface + */ + private $container; + public function __construct(RectorContainerFactory $rectorContainerFactory, SymfonyStyle $symfonyStyle) { $this->rectorContainerFactory = $rectorContainerFactory; @@ -48,63 +55,72 @@ public function __construct(RectorContainerFactory $rectorContainerFactory, Symf /** * @param string[] $source */ - public function processSourceWithSet(array $source, string $set, bool $isDryRun): void - { + public function processSourceWithSet( + array $source, + string $set, + bool $isDryRun, + bool $isQuietMode = false + ): ErrorAndDiffCollector { $source = $this->absolutizeSource($source); - $container = $this->rectorContainerFactory->createFromSet($set); - $this->prepare($container, $source, $isDryRun); + $this->container = $this->rectorContainerFactory->createFromSet($set); - /** @var FilesFinder $filesFinder */ - $filesFinder = $container->get(FilesFinder::class); - $phpFileInfos = $filesFinder->findInDirectoriesAndFiles($source, ['php']); + // silent Symfony style + if ($isQuietMode) { + $this->nativeSymfonyStyle->setVerbosity(OutputInterface::VERBOSITY_QUIET); + } - /** @var RectorApplication $rectorApplication */ - $rectorApplication = $container->get(RectorApplication::class); - $rectorApplication->runOnFileInfos($phpFileInfos); + $this->prepare($source, $isDryRun); + + $phpFileInfos = $this->findFilesInSource($source); + $this->runRectorOnFileInfos($phpFileInfos); + + if ($isQuietMode === false) { + $this->reportErrors(); + } - $this->reportErrors($container); + $this->finish(); - $this->finish($container); + return $this->container->get(ErrorAndDiffCollector::class); } /** * Mostly copied from: https://github.com/rectorphp/rector/blob/master/src/Console/Command/ProcessCommand.php. * @param string[] $source */ - private function prepare(ContainerInterface $container, array $source, bool $isDryRun): void + private function prepare(array $source, bool $isDryRun): void { ini_set('memory_limit', '4096M'); /** @var RectorNodeTraverser $rectorNodeTraverser */ - $rectorNodeTraverser = $container->get(RectorNodeTraverser::class); - $this->prepareConfiguration($container, $rectorNodeTraverser, $isDryRun); + $rectorNodeTraverser = $this->container->get(RectorNodeTraverser::class); + $this->prepareConfiguration($rectorNodeTraverser, $isDryRun); /** @var RectorGuard $rectorGuard */ - $rectorGuard = $container->get(RectorGuard::class); + $rectorGuard = $this->container->get(RectorGuard::class); $rectorGuard->ensureSomeRectorsAreRegistered(); // setup verbosity from the current run /** @var SymfonyStyle $symfonyStyle */ - $symfonyStyle = $container->get(SymfonyStyle::class); + $symfonyStyle = $this->container->get(SymfonyStyle::class); $symfonyStyle->setVerbosity($this->nativeSymfonyStyle->getVerbosity()); /** @var AdditionalAutoloader $additionalAutoloader */ - $additionalAutoloader = $container->get(AdditionalAutoloader::class); + $additionalAutoloader = $this->container->get(AdditionalAutoloader::class); $additionalAutoloader->autoloadWithInputAndSource(new ArrayInput([]), $source); /** @var StubLoader $stubLoader */ - $stubLoader = $container->get(StubLoader::class); + $stubLoader = $this->container->get(StubLoader::class); $stubLoader->loadStubs(); } - private function reportErrors(ContainerInterface $container): void + private function reportErrors(): void { /** @var ErrorAndDiffCollector $errorAndDiffCollector */ - $errorAndDiffCollector = $container->get(ErrorAndDiffCollector::class); + $errorAndDiffCollector = $this->container->get(ErrorAndDiffCollector::class); /** @var ConsoleOutputFormatter $consoleOutputFormatter */ - $consoleOutputFormatter = $container->get(ConsoleOutputFormatter::class); + $consoleOutputFormatter = $this->container->get(ConsoleOutputFormatter::class); $consoleOutputFormatter->report($errorAndDiffCollector); } @@ -128,30 +144,27 @@ private function absolutizeSource(array $source): array return $source; } - private function finish(ContainerInterface $container): void + private function finish(): void { /** @var FinishingExtensionRunner $finishingExtensionRunner */ - $finishingExtensionRunner = $container->get(FinishingExtensionRunner::class); + $finishingExtensionRunner = $this->container->get(FinishingExtensionRunner::class); $finishingExtensionRunner->run(); /** @var ReportingExtensionRunner $reportingExtensionRunner */ - $reportingExtensionRunner = $container->get(ReportingExtensionRunner::class); + $reportingExtensionRunner = $this->container->get(ReportingExtensionRunner::class); $reportingExtensionRunner->run(); } - private function prepareConfiguration( - ContainerInterface $container, - RectorNodeTraverser $rectorNodeTraverser, - bool $isDryRun - ): void { + private function prepareConfiguration(RectorNodeTraverser $rectorNodeTraverser, bool $isDryRun): void + { /** @var Configuration $configuration */ - $configuration = $container->get(Configuration::class); + $configuration = $this->container->get(Configuration::class); $configuration->setAreAnyPhpRectorsLoaded((bool) $rectorNodeTraverser->getPhpRectorCount()); // definition mimics @see ProcessCommand definition /** @var ProcessCommand $processCommand */ - $processCommand = $container->get(ProcessCommand::class); + $processCommand = $this->container->get(ProcessCommand::class); $definition = clone $processCommand->getDefinition(); // reset arguments to prevent "source is missing" @@ -162,4 +175,26 @@ private function prepareConfiguration( '--' . Option::OPTION_OUTPUT_FORMAT => 'console', ], $definition)); } + + /** + * @param string[] $source + * @return SmartFileInfo[] + */ + private function findFilesInSource(array $source): array + { + /** @var FilesFinder $filesFinder */ + $filesFinder = $this->container->get(FilesFinder::class); + + return $filesFinder->findInDirectoriesAndFiles($source, ['php']); + } + + /** + * @param SmartFileInfo[] $phpFileInfos + */ + private function runRectorOnFileInfos(array $phpFileInfos): void + { + /** @var RectorApplication $rectorApplication */ + $rectorApplication = $this->container->get(RectorApplication::class); + $rectorApplication->runOnFileInfos($phpFileInfos); + } } diff --git a/src/Standalone/RectorStandaloneRunnerStaticFactory.php b/src/Standalone/RectorStandaloneRunnerStaticFactory.php new file mode 100644 index 000000000000..5699b1e8112d --- /dev/null +++ b/src/Standalone/RectorStandaloneRunnerStaticFactory.php @@ -0,0 +1,20 @@ +create(); + + return new RectorStandaloneRunner(new RectorContainerFactory(), $symfonyStyle); + } +} diff --git a/tests/Standalone/RectorStandaloneRunnerTest.php b/tests/Standalone/RectorStandaloneRunnerTest.php new file mode 100644 index 000000000000..f56f66194fba --- /dev/null +++ b/tests/Standalone/RectorStandaloneRunnerTest.php @@ -0,0 +1,35 @@ +rectorStandaloneRunner = RectorStandaloneRunnerStaticFactory::create(); + } + + public function test(): void + { + $errorAndDiffCollector = $this->rectorStandaloneRunner->processSourceWithSet( + [__DIR__ . '/Source/LowQualityFile.php'], + 'code-quality', + true, + true + ); + + $fileDiffs = $errorAndDiffCollector->getFileDiffs(); + $this->assertCount(1, $fileDiffs); + } +} diff --git a/tests/Standalone/Source/LowQualityFile.php b/tests/Standalone/Source/LowQualityFile.php new file mode 100644 index 000000000000..d9cf7cddff09 --- /dev/null +++ b/tests/Standalone/Source/LowQualityFile.php @@ -0,0 +1,14 @@ +