diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php index 5affec0ad8159..4ba713b2b37d4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php @@ -91,13 +91,20 @@ protected function execute(InputInterface $input, OutputInterface $output): int } $useBuildDir = $realBuildDir !== $realCacheDir; + $oldBuildDir = substr($realBuildDir, 0, -1).('~' === substr($realBuildDir, -1) ? '+' : '~'); if ($useBuildDir) { - $oldBuildDir = substr($realBuildDir, 0, -1).('~' === substr($realBuildDir, -1) ? '+' : '~'); $fs->remove($oldBuildDir); if (!is_writable($realBuildDir)) { throw new RuntimeException(sprintf('Unable to write in the "%s" directory.', $realBuildDir)); } + + if ($this->isNfs($realCacheDir)) { + $fs->remove($realCacheDir); + } else { + $fs->rename($realCacheDir, $oldCacheDir); + } + $fs->mkdir($realCacheDir); } $io->comment(sprintf('Clearing the cache for the %s environment with debug %s', $kernel->getEnvironment(), var_export($kernel->isDebug(), true))); @@ -114,7 +121,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int // the warmup cache dir name must have the same length as the real one // to avoid the many problems in serialized resources files - $warmupDir = substr($realCacheDir, 0, -1).('_' === substr($realCacheDir, -1) ? '-' : '_'); + $warmupDir = substr($realBuildDir, 0, -1).('_' === substr($realBuildDir, -1) ? '-' : '_'); if ($output->isVerbose() && $fs->exists($warmupDir)) { $io->comment('Clearing outdated warmup directory...'); @@ -153,35 +160,15 @@ protected function execute(InputInterface $input, OutputInterface $output): int touch($warmupDir.'/'.$containerDir.'.legacy'); } - if ('/' === \DIRECTORY_SEPARATOR && $mounts = @file('/proc/mounts')) { - foreach ($mounts as $mount) { - $mount = \array_slice(explode(' ', $mount), 1, -3); - if (!\in_array(array_pop($mount), ['vboxsf', 'nfs'])) { - continue; - } - $mount = implode(' ', $mount).'/'; - - if (0 === strpos($realCacheDir, $mount)) { - $io->note('For better performances, you should move the cache and log directories to a non-shared folder of the VM.'); - $oldCacheDir = false; - break; - } - } - } - - if ($oldCacheDir) { - $fs->rename($realCacheDir, $oldCacheDir); + if ($this->isNfs($realBuildDir)) { + $io->note('For better performances, you should move the cache and log directories to a non-shared folder of the VM.'); + $fs->remove($realBuildDir); } else { - $fs->remove($realCacheDir); - } - $fs->rename($warmupDir, $realCacheDir); - - if ($useBuildDir) { $fs->rename($realBuildDir, $oldBuildDir); - // Copy the content of the warmed cache in the build dir - $fs->mirror($realCacheDir, $realBuildDir); } + $fs->rename($warmupDir, $realBuildDir); + if ($output->isVerbose()) { $io->comment('Removing old build and cache directory...'); } @@ -214,6 +201,31 @@ protected function execute(InputInterface $input, OutputInterface $output): int return 0; } + private function isNfs(string $dir): bool + { + static $mounts = null; + + if (null === $mounts) { + $mounts = []; + if ('/' === \DIRECTORY_SEPARATOR && $mounts = @file('/proc/mounts')) { + foreach ($mounts as $mount) { + $mount = \array_slice(explode(' ', $mount), 1, -3); + if (!\in_array(array_pop($mount), ['vboxsf', 'nfs'])) { + continue; + } + $mounts[] = implode(' ', $mount).'/'; + } + } + } + foreach ($mounts as $mount) { + if (0 === strpos($dir, $mount)) { + return true; + } + } + + return false; + } + private function warmup(string $warmupDir, string $realBuildDir, bool $enableOptionalWarmers = true) { // create a temporary kernel diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php index 3eb98fc921d68..25d1957ac1977 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php @@ -157,7 +157,7 @@ protected function describeContainerEnvVars(array $envs, array $options = []) protected function describeContainerDeprecations(ContainerBuilder $builder, array $options = []): void { - $containerDeprecationFilePath = sprintf('%s/%sDeprecations.log', $builder->getParameter('kernel.cache_dir'), $builder->getParameter('kernel.container_class')); + $containerDeprecationFilePath = sprintf('%s/%sDeprecations.log', $builder->getParameter('kernel.build_dir'), $builder->getParameter('kernel.container_class')); if (!file_exists($containerDeprecationFilePath)) { throw new RuntimeException('The deprecation file does not exist, please try warming the cache first.'); } diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php index 7bbdf48e17d45..96170d32ad1b6 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php @@ -107,7 +107,7 @@ protected function describeContainerService($service, array $options = [], Conta protected function describeContainerDeprecations(ContainerBuilder $builder, array $options = []): void { - $containerDeprecationFilePath = sprintf('%s/%sDeprecations.log', $builder->getParameter('kernel.cache_dir'), $builder->getParameter('kernel.container_class')); + $containerDeprecationFilePath = sprintf('%s/%sDeprecations.log', $builder->getParameter('kernel.build_dir'), $builder->getParameter('kernel.container_class')); if (!file_exists($containerDeprecationFilePath)) { throw new RuntimeException('The deprecation file does not exist, please try warming the cache first.'); } diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php index c43a7a6e60deb..0e64b8b8ad121 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php @@ -360,7 +360,7 @@ protected function describeContainerDefinition(Definition $definition, array $op protected function describeContainerDeprecations(ContainerBuilder $builder, array $options = []): void { - $containerDeprecationFilePath = sprintf('%s/%sDeprecations.log', $builder->getParameter('kernel.cache_dir'), $builder->getParameter('kernel.container_class')); + $containerDeprecationFilePath = sprintf('%s/%sDeprecations.log', $builder->getParameter('kernel.build_dir'), $builder->getParameter('kernel.container_class')); if (!file_exists($containerDeprecationFilePath)) { $options['output']->warning('The deprecation file does not exist, please try warming the cache first.'); diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php index 279c52c4eb278..caa5913b21087 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php @@ -109,7 +109,7 @@ protected function describeContainerEnvVars(array $envs, array $options = []) protected function describeContainerDeprecations(ContainerBuilder $builder, array $options = []): void { - $containerDeprecationFilePath = sprintf('%s/%sDeprecations.log', $builder->getParameter('kernel.cache_dir'), $builder->getParameter('kernel.container_class')); + $containerDeprecationFilePath = sprintf('%s/%sDeprecations.log', $builder->getParameter('kernel.build_dir'), $builder->getParameter('kernel.container_class')); if (!file_exists($containerDeprecationFilePath)) { throw new RuntimeException('The deprecation file does not exist, please try warming the cache first.'); } diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 415ecdace70fd..0e85b5af70875 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -899,7 +899,7 @@ private function registerDebugConfiguration(array $config, ContainerBuilder $con $debug = $container->getParameter('kernel.debug'); if ($debug) { - $container->setParameter('debug.container.dump', '%kernel.cache_dir%/%kernel.container_class%.xml'); + $container->setParameter('debug.container.dump', '%kernel.build_dir%/%kernel.container_class%.xml'); } if ($debug && class_exists(Stopwatch::class)) { diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/collectors.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/collectors.php index 010b5bf8fccc6..abf9ded5e5949 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/collectors.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/collectors.php @@ -55,7 +55,7 @@ ->set('data_collector.logger', LoggerDataCollector::class) ->args([ service('logger')->ignoreOnInvalid(), - sprintf('%s/%s', param('kernel.cache_dir'), param('kernel.container_class')), + sprintf('%s/%s', param('kernel.build_dir'), param('kernel.container_class')), service('request_stack')->ignoreOnInvalid(), ]) ->tag('monolog.logger', ['channel' => 'profiler']) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.php index 4df97ed19c531..5f02a3e4a2f4f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.php @@ -109,7 +109,7 @@ class_exists(WorkflowEvents::class) ? WorkflowEvents::ALIASES : [] ->args([ tagged_iterator('kernel.cache_warmer'), param('kernel.debug'), - sprintf('%s/%sDeprecations.log', param('kernel.cache_dir'), param('kernel.container_class')), + sprintf('%s/%sDeprecations.log', param('kernel.build_dir'), param('kernel.container_class')), ]) ->tag('container.no_preload') diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/CacheClearCommand/CacheClearCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/CacheClearCommand/CacheClearCommandTest.php index 48dcb3626c40e..5f74f1f889a92 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/CacheClearCommand/CacheClearCommandTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/CacheClearCommand/CacheClearCommandTest.php @@ -18,9 +18,9 @@ use Symfony\Component\Config\Resource\ResourceInterface; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Output\NullOutput; +use Symfony\Component\DependencyInjection\Container; use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\Finder\Finder; -use Symfony\Component\HttpKernel\KernelInterface; class CacheClearCommandTest extends TestCase { @@ -41,40 +41,44 @@ protected function tearDown(): void $this->fs->remove($this->kernel->getProjectDir()); } - /** @dataProvider getKernel */ - public function testCacheIsFreshAfterCacheClearedWithWarmup(KernelInterface $kernel) + public function testCacheIsFreshAfterCacheClearedWithWarmup() { + $this->fs->mkdir($this->kernel->getProjectDir()); + $input = new ArrayInput(['cache:clear']); - $application = new Application($kernel); + $application = new Application($this->kernel); $application->setCatchExceptions(false); $application->doRun($input, new NullOutput()); // Ensure that all *.meta files are fresh $finder = new Finder(); - $metaFiles = $finder->files()->in($kernel->getCacheDir())->name('*.php.meta'); + $metaFiles = $finder->files()->in($this->kernel->getCacheDir())->name('*.php.meta'); // check that cache is warmed up $this->assertNotEmpty($metaFiles); $configCacheFactory = new ConfigCacheFactory(true); foreach ($metaFiles as $file) { - $configCacheFactory->cache(substr($file, 0, -5), function () use ($file) { - $this->fail(sprintf('Meta file "%s" is not fresh', (string) $file)); - }); + $configCacheFactory->cache( + substr($file, 0, -5), + function () use ($file) { + $this->fail(sprintf('Meta file "%s" is not fresh', (string) $file)); + } + ); } // check that app kernel file present in meta file of container's cache - $containerClass = $kernel->getContainer()->getParameter('kernel.container_class'); + $containerClass = $this->kernel->getContainer()->getParameter('kernel.container_class'); $containerRef = new \ReflectionClass($containerClass); $containerFile = \dirname($containerRef->getFileName(), 2).'/'.$containerClass.'.php'; $containerMetaFile = $containerFile.'.meta'; - $kernelRef = new \ReflectionObject($kernel); - $kernelFile = $kernelRef->getFileName(); + $this->kernelRef = new \ReflectionObject($this->kernel); + $this->kernelFile = $this->kernelRef->getFileName(); /** @var ResourceInterface[] $meta */ $meta = unserialize(file_get_contents($containerMetaFile)); $found = false; foreach ($meta as $resource) { - if ((string) $resource === $kernelFile) { + if ((string) $resource === $this->kernelFile) { $found = true; break; } @@ -82,24 +86,51 @@ public function testCacheIsFreshAfterCacheClearedWithWarmup(KernelInterface $ker $this->assertTrue($found, 'Kernel file should present as resource'); $containerRef = new \ReflectionClass(require $containerFile); - $containerFile = str_replace('tes_'.\DIRECTORY_SEPARATOR, 'test'.\DIRECTORY_SEPARATOR, $containerRef->getFileName()); - $this->assertMatchesRegularExpression(sprintf('/\'kernel.container_class\'\s*=>\s*\'%s\'/', $containerClass), file_get_contents($containerFile), 'kernel.container_class is properly set on the dumped container'); + $containerFile = str_replace( + 'tes_'.\DIRECTORY_SEPARATOR, + 'test'.\DIRECTORY_SEPARATOR, + $containerRef->getFileName() + ); + $this->assertMatchesRegularExpression( + sprintf('/\'kernel.container_class\'\s*=>\s*\'%s\'/', $containerClass), + file_get_contents($containerFile), + 'kernel.container_class is properly set on the dumped container' + ); } - public function getKernel() + public function testCacheIsWarmedWhenCalledTwice() { - yield [new TestAppKernel('test', true)]; - yield [new NoBuildDirKernel('test', true)]; + $input = new ArrayInput(['cache:clear']); + $application = new Application(clone $this->kernel); + $application->setCatchExceptions(false); + $application->doRun($input, new NullOutput()); + + $_SERVER['REQUEST_TIME'] = time() + 1; + $application = new Application(clone $this->kernel); + $application->setCatchExceptions(false); + $application->doRun($input, new NullOutput()); + + $this->assertTrue(is_file($this->kernel->getCacheDir().'/annotations.php')); } -} -class NoBuildDirKernel extends TestAppKernel -{ - protected function getKernelParameters() + public function testCacheIsWarmedWithOldContainer() { - $parameters = parent::getKernelParameters(); - unset($parameters['kernel.build_dir']); + $kernel = clone $this->kernel; + + // Hack to get a dumped working container, + // BUT without "kernel.build_dir" parameter (like an old dumped container) + $kernel->boot(); + $container = $kernel->getContainer(); + \Closure::bind(function (Container $class) { + unset($class->loadedDynamicParameters['kernel.build_dir']); + unset($class->parameters['kernel.build_dir']); + }, null, \get_class($container))($container); + + $input = new ArrayInput(['cache:clear']); + $application = new Application($kernel); + $application->setCatchExceptions(false); + $application->doRun($input, new NullOutput()); - return $parameters; + $this->expectNotToPerformAssertions(); } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/ObjectsProvider.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/ObjectsProvider.php index 528630a7a04f5..1da970371a04d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/ObjectsProvider.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/ObjectsProvider.php @@ -92,10 +92,12 @@ public static function getContainerDeprecations() { $builderWithDeprecations = new ContainerBuilder(); $builderWithDeprecations->setParameter('kernel.cache_dir', __DIR__.'/../../Fixtures/Descriptor/cache'); + $builderWithDeprecations->setParameter('kernel.build_dir', __DIR__.'/../../Fixtures/Descriptor/cache'); $builderWithDeprecations->setParameter('kernel.container_class', 'KernelContainerWith'); $builderWithoutDeprecations = new ContainerBuilder(); $builderWithoutDeprecations->setParameter('kernel.cache_dir', __DIR__.'/../../Fixtures/Descriptor/cache'); + $builderWithoutDeprecations->setParameter('kernel.build_dir', __DIR__.'/../../Fixtures/Descriptor/cache'); $builderWithoutDeprecations->setParameter('kernel.container_class', 'KernelContainerWithout'); return [ diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ContainerDebugCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ContainerDebugCommandTest.php index a08ec0942394f..020deec34b963 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ContainerDebugCommandTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ContainerDebugCommandTest.php @@ -139,7 +139,7 @@ public function testDescribeEnvVar() public function testGetDeprecation() { static::bootKernel(['test_case' => 'ContainerDebug', 'root_config' => 'config.yml', 'debug' => true]); - $path = sprintf('%s/%sDeprecations.log', static::$kernel->getContainer()->getParameter('kernel.cache_dir'), static::$kernel->getContainer()->getParameter('kernel.container_class')); + $path = sprintf('%s/%sDeprecations.log', static::$kernel->getContainer()->getParameter('kernel.build_dir'), static::$kernel->getContainer()->getParameter('kernel.container_class')); touch($path); file_put_contents($path, serialize([[ 'type' => 16384, @@ -169,7 +169,7 @@ public function testGetDeprecation() public function testGetDeprecationNone() { static::bootKernel(['test_case' => 'ContainerDebug', 'root_config' => 'config.yml', 'debug' => true]); - $path = sprintf('%s/%sDeprecations.log', static::$kernel->getContainer()->getParameter('kernel.cache_dir'), static::$kernel->getContainer()->getParameter('kernel.container_class')); + $path = sprintf('%s/%sDeprecations.log', static::$kernel->getContainer()->getParameter('kernel.build_dir'), static::$kernel->getContainer()->getParameter('kernel.container_class')); touch($path); file_put_contents($path, serialize([])); @@ -188,7 +188,7 @@ public function testGetDeprecationNone() public function testGetDeprecationNoFile() { static::bootKernel(['test_case' => 'ContainerDebug', 'root_config' => 'config.yml', 'debug' => true]); - $path = sprintf('%s/%sDeprecations.log', static::$kernel->getContainer()->getParameter('kernel.cache_dir'), static::$kernel->getContainer()->getParameter('kernel.container_class')); + $path = sprintf('%s/%sDeprecations.log', static::$kernel->getContainer()->getParameter('kernel.build_dir'), static::$kernel->getContainer()->getParameter('kernel.container_class')); @unlink($path); $application = new Application(static::$kernel); diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index 8f8dae611f45e..b1ac327002628 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -24,7 +24,7 @@ "symfony/event-dispatcher": "^5.1", "symfony/error-handler": "^4.4.1|^5.0.1", "symfony/http-foundation": "^5.2.1", - "symfony/http-kernel": "^5.2", + "symfony/http-kernel": "^5.2.1", "symfony/polyfill-mbstring": "~1.0", "symfony/polyfill-php80": "^1.15", "symfony/filesystem": "^4.4|^5.0", diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 55b59bc9b2066..5fd4c05115c63 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -609,7 +609,7 @@ protected function getKernelParameters() 'kernel.runtime_environment' => '%env(default:kernel.environment:APP_RUNTIME_ENV)%', 'kernel.debug' => $this->debug, 'kernel.build_dir' => realpath($buildDir = $this->warmupDir ?: $this->getBuildDir()) ?: $buildDir, - 'kernel.cache_dir' => realpath($this->getCacheDir()) ?: $this->getCacheDir(), + 'kernel.cache_dir' => realpath($cacheDir = ($this->getCacheDir() === $this->getBuildDir() ? ($this->warmupDir ?: $this->getCacheDir()) : $this->getCacheDir())) ?: $cacheDir, 'kernel.logs_dir' => realpath($this->getLogDir()) ?: $this->getLogDir(), 'kernel.bundles' => $bundles, 'kernel.bundles_metadata' => $bundlesMetadata,