mirror of
https://github.com/rectorphp/rector.git
synced 2025-01-17 13:28:18 +01:00
allow loading --config and --level together [closes #613]
This commit is contained in:
parent
d114f0649c
commit
1c51f5d9bf
3
.gitignore
vendored
3
.gitignore
vendored
@ -6,4 +6,5 @@
|
||||
/build
|
||||
composer.lock
|
||||
|
||||
/demo
|
||||
/demo
|
||||
rector-symfony.yml
|
@ -5,19 +5,22 @@ use Symfony\Component\Console\Input\ArgvInput;
|
||||
use Symplify\PackageBuilder\Configuration\ConfigFileFinder;
|
||||
use Symplify\PackageBuilder\Configuration\LevelFileFinder;
|
||||
|
||||
// 1. Detect configuration from --level
|
||||
$configFile = (new LevelFileFinder())->detectFromInputAndDirectory(new ArgvInput(), __DIR__ . '/../config/level');
|
||||
$configFiles = [];
|
||||
|
||||
// 2. Or from --config
|
||||
if ($configFile === null) {
|
||||
ConfigFileFinder::detectFromInput('rector', new ArgvInput());
|
||||
$configFile = ConfigFileFinder::provide('rector', ['rector.yml', 'rector.yaml']);
|
||||
}
|
||||
// Detect configuration from --level
|
||||
$configFiles[] = (new LevelFileFinder())->detectFromInputAndDirectory(new ArgvInput(), __DIR__ . '/../config/level');
|
||||
|
||||
// And from --config or default one
|
||||
ConfigFileFinder::detectFromInput('rector', new ArgvInput());
|
||||
$configFiles[] = ConfigFileFinder::provide('rector', ['rector.yml', 'rector.yaml']);
|
||||
|
||||
// remove empty values
|
||||
$configFiles = array_filter($configFiles);
|
||||
|
||||
// 3. Build DI container
|
||||
$containerFactory = new ContainerFactory();
|
||||
if ($configFile) {
|
||||
return $containerFactory->createWithConfig($configFile);
|
||||
if ($configFiles) {
|
||||
return $containerFactory->createWithConfigFiles($configFiles);
|
||||
}
|
||||
|
||||
return $containerFactory->create();
|
||||
|
@ -25,7 +25,7 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"humbug/php-scoper": "^0.9.1",
|
||||
"phpunit/phpunit": "^7.1",
|
||||
"phpunit/phpunit": "^7.3",
|
||||
"slam/php-cs-fixer-extensions": "^1.15",
|
||||
"symplify/easy-coding-standard": "^4.6.1",
|
||||
"tracy/tracy": "^2.5"
|
||||
|
@ -6,6 +6,7 @@ use Nette\Utils\Strings;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Expr\StaticCall;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Name\FullyQualified;
|
||||
use PhpParser\Node\Scalar\String_;
|
||||
use Rector\Rector\AbstractRector;
|
||||
@ -38,6 +39,14 @@ final class DefineConstantToStaticCallRector extends AbstractRector
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $node->name instanceof Name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($node->name->toString() !== 'defined') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$argumentValue = $node->args[0]->value;
|
||||
if (! $argumentValue instanceof String_) {
|
||||
return null;
|
||||
|
@ -82,6 +82,7 @@ CODE_SAMPLE
|
||||
if ($parentClassName !== $this->controllerClass) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $this->chainMethodCallAnalyzer->isTypeAndChainCalls(
|
||||
$node,
|
||||
'Symfony\Component\HttpFoundation\Request',
|
||||
|
@ -32,7 +32,7 @@ abstract class AbstractYamlRectorTest extends TestCase
|
||||
$this->fileGuard = new FileGuard();
|
||||
$this->fileGuard->ensureFileExists($config, get_called_class());
|
||||
|
||||
$this->container = (new ContainerFactory())->createWithConfig($config);
|
||||
$this->container = (new ContainerFactory())->createWithConfigFiles([$config]);
|
||||
|
||||
$this->yamlFileProcessor = $this->container->get(YamlFileProcessor::class);
|
||||
}
|
||||
|
@ -47,10 +47,6 @@ parameters:
|
||||
- '#Parameter \#1 \$pattern of function fnmatch expects string, string\|false given#'
|
||||
- '#Parameter \#1 \$file of function file_put_contents expects string, string\|false given#'
|
||||
- '#Parameter \#1 \$filePath of method Rector\\Parser\\Parser::parseFile\(\) expects string, string\|false given#'
|
||||
- '#Parameter \#2 \$filename of function fnmatch expects string, string\|false given#'
|
||||
|
||||
# getcwd false postive
|
||||
- '#Parameter \#1 \$dirs of method Symfony\\Component\\Finder\\Finder::in\(\) expects array\|string, string\|false given#'
|
||||
|
||||
# false positive, has annotation type above (@todo recheck for possible ignored positives)
|
||||
- '#Access to an undefined property PhpParser\\Node::\$name#' # 11
|
||||
|
@ -3,10 +3,14 @@
|
||||
namespace Rector\Autoloading;
|
||||
|
||||
use Nette\Loaders\RobotLoader;
|
||||
use Nette\Utils\Strings;
|
||||
use Rector\Configuration\Option;
|
||||
use Rector\FileSystem\FileGuard;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
|
||||
/**
|
||||
* Should it pass autoload files/directories to PHPStan analyzer?
|
||||
*/
|
||||
final class AdditionalAutoloader
|
||||
{
|
||||
/**
|
||||
@ -28,10 +32,11 @@ final class AdditionalAutoloader
|
||||
* @param string[] $autoloadFiles
|
||||
* @param string[] $autoloadDirectories
|
||||
*/
|
||||
public function __construct(array $autoloadFiles, array $autoloadDirectories)
|
||||
public function __construct(array $autoloadFiles, array $autoloadDirectories, FileGuard $fileGuard)
|
||||
{
|
||||
$this->autoloadFiles = $autoloadFiles;
|
||||
$this->autoloadDirectories = $autoloadDirectories;
|
||||
$this->fileGuard = $fileGuard;
|
||||
}
|
||||
|
||||
public function autoloadWithInput(InputInterface $input): void
|
||||
@ -41,6 +46,32 @@ final class AdditionalAutoloader
|
||||
$this->autoloadFiles($this->autoloadFiles);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $source
|
||||
*/
|
||||
public function autoloadWithInputAndSource(InputInterface $input, array $source): void
|
||||
{
|
||||
$this->autoloadWithInput($input);
|
||||
|
||||
[$files, $directories] = $this->splitSourceToDirectoriesAndFiles($source);
|
||||
|
||||
// @todo include the files so people don't have to do it manually?
|
||||
|
||||
$absoluteDirectories = [];
|
||||
|
||||
foreach ($directories as $directory) {
|
||||
if (Strings::contains($directory, '*')) { // is fnmatch for directories
|
||||
$absoluteDirectories = array_merge($absoluteDirectories, glob($directory, GLOB_ONLYDIR));
|
||||
} else { // is classic directory
|
||||
$absoluteDirectories[] = $directory;
|
||||
}
|
||||
}
|
||||
|
||||
if (count($absoluteDirectories)) {
|
||||
$this->autoloadDirectories($absoluteDirectories);
|
||||
}
|
||||
}
|
||||
|
||||
private function autoloadFileFromInput(InputInterface $input): void
|
||||
{
|
||||
/** @var string|null $autoloadFile */
|
||||
@ -52,6 +83,27 @@ final class AdditionalAutoloader
|
||||
$this->autoloadFiles([$autoloadFile]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo decouple to standalone Finder/File something
|
||||
* @param string[] $source
|
||||
* @return string[][]|string[]
|
||||
*/
|
||||
private function splitSourceToDirectoriesAndFiles(array $source): array
|
||||
{
|
||||
$files = [];
|
||||
$directories = [];
|
||||
|
||||
foreach ($source as $singleSource) {
|
||||
if (is_file($singleSource)) {
|
||||
$files[] = $singleSource;
|
||||
} else {
|
||||
$directories[] = $singleSource;
|
||||
}
|
||||
}
|
||||
|
||||
return [$files, $directories];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $directories
|
||||
*/
|
||||
|
@ -138,8 +138,6 @@ final class ProcessCommand extends Command
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$this->additionalAutoloader->autoloadWithInput($input);
|
||||
|
||||
$this->rectorGuard->ensureSomeRectorsAreRegistered();
|
||||
|
||||
$source = $input->getArgument(Option::SOURCE);
|
||||
@ -150,6 +148,8 @@ final class ProcessCommand extends Command
|
||||
$yamlFileInfos = $this->filesFinder->findInDirectoriesAndFiles($source, ['yml', 'yaml']);
|
||||
$allFileInfos = $phpFileInfos + $yamlFileInfos;
|
||||
|
||||
$this->additionalAutoloader->autoloadWithInputAndSource($input, $source);
|
||||
|
||||
$this->processCommandReporter->reportLoadedRectors();
|
||||
|
||||
$this->processFileInfos($allFileInfos);
|
||||
|
@ -16,9 +16,12 @@ final class ContainerFactory
|
||||
return $appKernel->getContainer();
|
||||
}
|
||||
|
||||
public function createWithConfig(string $config): ContainerInterface
|
||||
/**
|
||||
* @param string[] $configFiles
|
||||
*/
|
||||
public function createWithConfigFiles(array $configFiles): ContainerInterface
|
||||
{
|
||||
$appKernel = new RectorKernel($config);
|
||||
$appKernel = new RectorKernel($configFiles);
|
||||
$appKernel->boot();
|
||||
// this is require to keep CLI verbosity independent on AppKernel dev/prod mode
|
||||
putenv('SHELL_VERBOSITY=0');
|
||||
|
@ -24,26 +24,29 @@ use Symplify\PackageBuilder\Yaml\FileLoader\ParameterImportsYamlFileLoader;
|
||||
final class RectorKernel extends Kernel
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
* @var string[]
|
||||
*/
|
||||
private $configFile;
|
||||
private $extraConfigFiles = [];
|
||||
|
||||
public function __construct(?string $configFile = '')
|
||||
/**
|
||||
* @param string[] $configFiles
|
||||
*/
|
||||
public function __construct(array $configFiles = [])
|
||||
{
|
||||
if ($configFile) {
|
||||
$this->configFile = $configFile;
|
||||
}
|
||||
$this->extraConfigFiles = $configFiles;
|
||||
|
||||
// debug: true is require to invalidate container on service files change
|
||||
parent::__construct('cli' . sha1((string) $configFile), true);
|
||||
$configFilesHash = md5(serialize($configFiles));
|
||||
|
||||
// debug: require to invalidate container on service files change
|
||||
parent::__construct('cli_' . $configFilesHash, true);
|
||||
}
|
||||
|
||||
public function registerContainerConfiguration(LoaderInterface $loader): void
|
||||
{
|
||||
$loader->load(__DIR__ . '/../config/config.yml');
|
||||
|
||||
if ($this->configFile) {
|
||||
$loader->load($this->configFile);
|
||||
foreach ($this->extraConfigFiles as $extraConfigFile) {
|
||||
$loader->load($extraConfigFile);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,6 +56,10 @@ final class FilesFinder
|
||||
private function findInDirectories(array $directories, array $suffixes): array
|
||||
{
|
||||
$absoluteDirectories = $this->resolveAbsoluteDirectories($directories);
|
||||
if (! $absoluteDirectories) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$suffixesPattern = $this->normalizeSuffixesToPattern($suffixes);
|
||||
|
||||
$finder = Finder::create()
|
||||
@ -65,17 +69,7 @@ final class FilesFinder
|
||||
->exclude(['examples', 'Examples', 'stubs', 'Stubs', 'fixtures', 'Fixtures', 'polyfill', 'Polyfill'])
|
||||
->notName('*polyfill*');
|
||||
|
||||
if ($this->excludePaths) {
|
||||
$finder->filter(function (NativeSplFileInfo $splFileInfo) {
|
||||
foreach ($this->excludePaths as $excludePath) {
|
||||
if (Strings::match($splFileInfo->getRealPath(), $excludePath)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return fnmatch($splFileInfo->getRealPath(), $excludePath);
|
||||
}
|
||||
});
|
||||
}
|
||||
$this->addFilterWithExcludedPaths($finder);
|
||||
|
||||
return iterator_to_array($finder->getIterator());
|
||||
}
|
||||
@ -140,18 +134,7 @@ final class FilesFinder
|
||||
|
||||
foreach ($directories as $directory) {
|
||||
if (Strings::contains($directory, '*')) { // is fnmatch for directories
|
||||
$directoriesFinder = Finder::create()
|
||||
->in(getcwd())
|
||||
->directories()
|
||||
->filter(function (NativeSplFileInfo $splFileInfo) use ($directory) {
|
||||
// keep only file that match specific pattern
|
||||
return fnmatch('*' . $directory . '*', $splFileInfo->getRealPath());
|
||||
});
|
||||
|
||||
$absoluteDirectories = array_merge(
|
||||
$absoluteDirectories,
|
||||
iterator_to_array($directoriesFinder->getIterator())
|
||||
);
|
||||
$absoluteDirectories = array_merge($absoluteDirectories, glob($directory, GLOB_ONLYDIR));
|
||||
} else { // is classic directory
|
||||
$this->ensureDirectoryExists($directory);
|
||||
$absoluteDirectories[] = $directory;
|
||||
@ -160,4 +143,23 @@ final class FilesFinder
|
||||
|
||||
return $absoluteDirectories;
|
||||
}
|
||||
|
||||
private function addFilterWithExcludedPaths(Finder $finder): void
|
||||
{
|
||||
if (! $this->excludePaths) {
|
||||
return;
|
||||
}
|
||||
|
||||
$finder->filter(function (NativeSplFileInfo $splFileInfo) {
|
||||
foreach ($this->excludePaths as $excludePath) {
|
||||
if (Strings::match($splFileInfo->getRealPath(), $excludePath)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return fnmatch($splFileInfo->getRealPath(), $excludePath);
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -44,16 +44,18 @@ abstract class AbstractRectorTestCase extends TestCase
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$config = $this->provideConfig();
|
||||
$configFile = $this->provideConfig();
|
||||
$this->fileGuard = new FileGuard();
|
||||
$this->fileGuard->ensureFileExists($config, get_called_class());
|
||||
$this->fileGuard->ensureFileExists($configFile, get_called_class());
|
||||
|
||||
$key = md5_file($config);
|
||||
$key = md5_file($configFile);
|
||||
|
||||
if (isset(self::$containersPerConfig[$key]) && $this->rebuildFreshContainer === false) {
|
||||
$this->container = self::$containersPerConfig[$key];
|
||||
} else {
|
||||
self::$containersPerConfig[$key] = $this->container = (new ContainerFactory())->createWithConfig($config);
|
||||
self::$containersPerConfig[$key] = $this->container = (new ContainerFactory())->createWithConfigFiles(
|
||||
[$configFile]
|
||||
);
|
||||
}
|
||||
|
||||
$this->fileProcessor = $this->container->get(FileProcessor::class);
|
||||
|
@ -20,7 +20,7 @@ abstract class AbstractConfigurableContainerAwareTestCase extends TestCase
|
||||
*/
|
||||
public function __construct(?string $name = null, array $data = [], string $dataName = '')
|
||||
{
|
||||
$this->container = (new ContainerFactory())->createWithConfig($this->provideConfig());
|
||||
$this->container = (new ContainerFactory())->createWithConfigFiles([$this->provideConfig()]);
|
||||
|
||||
parent::__construct($name, $data, $dataName);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user