From bb7986e2213f7ea0c98dd46f09f3e4f39fb72b89 Mon Sep 17 00:00:00 2001 From: Francis Besset Date: Fri, 11 Mar 2011 23:35:48 +0100 Subject: [PATCH] [FrameworkBundle] Added cache:clear command with warmup option --- .../Command/CacheClearCommand.php | 84 +++++++++++++++++++ .../Command/CacheWarmupCommand.php | 82 +++++++++++++++++- .../HttpKernel/CacheWarmer/CacheWarmer.php | 9 ++ src/Symfony/Component/HttpKernel/Kernel.php | 29 ++++++- 4 files changed, 197 insertions(+), 7 deletions(-) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php new file mode 100644 index 0000000000000..7c7c17255207f --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php @@ -0,0 +1,84 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Command; + +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * Clear and Warmup the cache. + * + * @author Francis Besset + */ +class CacheClearCommand extends CacheWarmupCommand +{ + /** + * @see Command + */ + protected function configure() + { + $this + ->setName('cache:clear') + ->setDefinition(array( + new InputOption('warmup', '', InputOption::VALUE_NONE, 'Warms up the cache') + )) + ->setDescription('Clear the cache') + ->setHelp(<<cache:clear command clear the cache. + +./app/console cache:clear --warmup + +Warmup option, warms up the cache. +EOF + ) + ; + } + + protected function initialize(InputInterface $input, OutputInterface $output) + { + parent::initialize($input, $output); + + $this->cacheDir = $this->container->getParameter('kernel.environment').'_tmp'; + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $realCacheDir = $this->container->getParameter('kernel.cache_dir'); + $oldCacheDir = $realCacheDir.'_old'; + + if (!is_writable($realCacheDir)) { + throw new \RuntimeException(sprintf('Unable to write %s directory', $this->realCacheDir)); + } + + $this->clearDir($oldCacheDir); + + if (!$input->getOption('warmup')) { + $output->writeln('Clear cache'); + + rename($realCacheDir, $oldCacheDir); + $this->clearDir($oldCacheDir); + } else { + parent::execute($input, $output); + + $output->writeln('Move cache directories'); + rename($realCacheDir, $oldCacheDir); + rename($this->kernelTmp->getCacheDir(), $realCacheDir); + + $output->writeln('Clear the old cache'); + $this->clearDir($oldCacheDir); + } + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/CacheWarmupCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/CacheWarmupCommand.php index d997812e879e4..f4b657f2ed13f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/CacheWarmupCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/CacheWarmupCommand.php @@ -12,15 +12,22 @@ namespace Symfony\Bundle\FrameworkBundle\Command; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\Finder\Finder; /** * Warmup the cache. * * @author Fabien Potencier + * @author Francis Besset */ class CacheWarmupCommand extends Command { + protected $cacheDir; + protected $kernelTmp; + /** * @see Command */ @@ -29,15 +36,27 @@ protected function configure() $this ->setName('cache:warmup') ->setDescription('Warms up an empty cache') + ->setDefinition(array( + new InputOption('warmup-dir', '', InputOption::VALUE_OPTIONAL, 'Warms up the cache in a specific directory') + )) ->setHelp(<<cache:warmup command warms up the cache. +The cache:warmup --warmup-dir=new_cache command warms up the cache. -Before running this command, the cache must be empty. +Before running this command, the cache must be empty if not use warmup-dir option. EOF ) ; } + protected function initialize(InputInterface $input, OutputInterface $output) + { + parent::initialize($input, $output); + + if ($input->hasOption('warmup-dir')) { + $this->cacheDir = $input->getOption('warmup-dir'); + } + } + /** * {@inheritdoc} */ @@ -45,8 +64,63 @@ protected function execute(InputInterface $input, OutputInterface $output) { $output->writeln('Warming up the cache'); - $warmer = $this->container->get('cache_warmer'); + if (!$this->cacheDir) { + $this->warmUp($this->container); + } else { + $this->kernelTmp = new \AppKernel( + $this->container->getParameter('kernel.environment'), + $this->container->getParameter('kernel.debug'), + $this->cacheDir + ); + + $this->clearDir($this->kernelTmp->getCacheDir()); + + $this->kernelTmp->boot(); + unlink($this->kernelTmp->getCacheDir().DIRECTORY_SEPARATOR.$this->kernelTmp->getContainerClass().'.php'); + + $this->warmUp($this->kernelTmp->getContainer()); + } + } + + protected function warmUp(ContainerInterface $container) + { + $warmer = $container->get('cache_warmer'); $warmer->enableOptionalWarmers(); - $warmer->warmUp($this->container->getParameter('kernel.cache_dir')); + $warmer->warmUp($container->getParameter('kernel.cache_dir')); + } + + protected function clearDir($dir) + { + if (is_dir($dir)) { + $finder = new Finder(); + $files = $finder + ->in($dir) + ->getIterator() + ; + + $array = iterator_to_array($files); + + foreach (array_reverse($array) as $file) { + if ($file->isFile()) { + if (!is_writable($file->getPathname())) { + throw new \RuntimeException(sprintf('Unable to delete %s file', $file->getPathname())); + } + + unlink($file->getPathname()); + } else { + if (!is_writable($file->getPathname())) { + throw new \RuntimeException(sprintf('Unable to delete %s directory', $file->getPathname())); + } + + rmdir($file->getPathname()); + } + } + + if (!is_writable($dir)) { + throw new \RuntimeException(sprintf('Unable to delete %s directory', $dir)); + } + + rmdir($dir); + } } } diff --git a/src/Symfony/Component/HttpKernel/CacheWarmer/CacheWarmer.php b/src/Symfony/Component/HttpKernel/CacheWarmer/CacheWarmer.php index 70a4e11ba9d92..65b346283dfef 100644 --- a/src/Symfony/Component/HttpKernel/CacheWarmer/CacheWarmer.php +++ b/src/Symfony/Component/HttpKernel/CacheWarmer/CacheWarmer.php @@ -19,6 +19,15 @@ abstract class CacheWarmer implements CacheWarmerInterface { protected function writeCacheFile($file, $content) { + $dir = dirname($file); + if (!is_dir($dir)) { + if (false === @mkdir($dir, 0777, true)) { + throw new \RuntimeException(sprintf('Unable to create the %s directory', $dir)); + } + } elseif (!is_writable($dir)) { + throw new \RuntimeException(sprintf('Unable to write in the %s directory', $dir)); + } + $tmpFile = tempnam(dirname($file), basename($file)); if (false !== @file_put_contents($tmpFile, $content) && @rename($tmpFile, $file)) { chmod($file, 0644); diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index f72faa811e88a..f6506dbb28d88 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -44,6 +44,7 @@ abstract class Kernel implements KernelInterface protected $rootDir; protected $environment; protected $debug; + protected $cacheDir; protected $booted; protected $name; protected $startTime; @@ -56,10 +57,11 @@ abstract class Kernel implements KernelInterface * @param string $environment The environment * @param Boolean $debug Whether to enable debugging or not */ - public function __construct($environment, $debug) + public function __construct($environment, $debug, $cacheDir = null) { $this->environment = $environment; $this->debug = (Boolean) $debug; + $this->cacheDir = $cacheDir; $this->booted = false; $this->rootDir = realpath($this->registerRootDir()); $this->name = preg_replace('/[^a-zA-Z0-9_]+/', '', basename($this->rootDir)); @@ -308,6 +310,14 @@ public function getContainer() return $this->container; } + /** + * @return string The container classname + */ + public function getContainerClass() + { + return $this->name.ucfirst($this->environment).($this->debug ? 'Debug' : '').'ProjectContainer'.($this->cacheDir ? 'Tmp' : ''); + } + /** * Gets the request start time (not available if debug is disabled). * @@ -325,7 +335,7 @@ public function getStartTime() */ public function getCacheDir() { - return $this->rootDir.'/cache/'.$this->environment; + return $this->rootDir.'/cache/'.($this->cacheDir ?: $this->environment); } /** @@ -399,7 +409,7 @@ protected function initializeBundles() protected function initializeContainer() { - $class = $this->name.ucfirst($this->environment).($this->debug ? 'Debug' : '').'ProjectContainer'; + $class = $this->getContainerClass(); $cache = new ConfigCache($this->getCacheDir(), $class, $this->debug); $fresh = false; if (!$cache->isFresh()) { @@ -417,6 +427,19 @@ protected function initializeContainer() if ($fresh && 'cli' !== php_sapi_name()) { $this->container->get('cache_warmer')->warmUp($this->container->getParameter('kernel.cache_dir')); } + + if ($cacheDir = $this->cacheDir) { + $realCacheDir = $this->getCacheDir(); + $this->cacheDir = null; + + $class = $this->getContainerClass(); + $cache = new ConfigCache($realCacheDir, $class, $this->debug); + + $container = $this->buildContainer(); + $this->dumpContainer($cache, $container, $class); + + $this->cacheDir = $cacheDir; + } } protected function getKernelParameters()