diff --git a/src/Symfony/Bundle/AsseticBundle/Command/DumpCommand.php b/src/Symfony/Bundle/AsseticBundle/Command/DumpCommand.php index 1d948ec5e8673..55cacb4a7a463 100644 --- a/src/Symfony/Bundle/AsseticBundle/Command/DumpCommand.php +++ b/src/Symfony/Bundle/AsseticBundle/Command/DumpCommand.php @@ -11,9 +11,12 @@ namespace Symfony\Bundle\AsseticBundle\Command; +use Assetic\Asset\AssetInterface; +use Assetic\Factory\LazyAssetManager; use Symfony\Bundle\FrameworkBundle\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; /** @@ -29,6 +32,7 @@ protected function configure() ->setName('assetic:dump') ->setDescription('Dumps all assets to the filesystem') ->addArgument('base_dir', InputArgument::OPTIONAL, 'The base directory') + ->addOption('watch', null, InputOption::VALUE_NONE, 'Check for changes every second') ; } @@ -39,18 +43,116 @@ protected function execute(InputInterface $input, OutputInterface $output) } $am = $this->container->get('assetic.asset_manager'); - foreach ($am->all() as $name => $asset) { - $output->writeln('[asset] '.$name); - $asset->load(); - - $target = $baseDir . '/' . $asset->getTargetUrl(); - if (!is_dir($dir = dirname($target))) { - $output->writeln('[dir+] '.$dir); - mkdir($dir); + + if ($input->getOption('watch')) { + return $this->watch($am, $baseDir, $output, $this->container->getParameter('kernel.debug')); + } + + foreach ($am->getNames() as $name) { + $this->dumpAsset($am->get($name), $baseDir, $output); + } + } + + /** + * Watches a asset manager for changes. + * + * This method includes an infinite loop the continuously polls the asset + * manager for changes. + * + * @param LazyAssetManager $am The asset manager + * @param string $baseDir The base directory to write to + * @param OutputInterface $output The command output + * @param Boolean $debug Debug mode + */ + protected function watch(LazyAssetManager $am, $baseDir, OutputInterface $output, $debug = false) + { + $refl = new \ReflectionClass('Assetic\\AssetManager'); + $prop = $refl->getProperty('assets'); + $prop->setAccessible(true); + + $cache = sys_get_temp_dir().'/assetic_watch_'.substr(sha1($baseDir), 0, 7); + if (file_exists($cache)) { + $previously = unserialize(file_get_contents($cache)); + } else { + $previously = array(); + } + + $error = ''; + while (true) { + try { + foreach ($am->getNames() as $name) { + if ($asset = $this->checkAsset($am, $name, $previously)) { + $this->dumpAsset($asset, $baseDir, $output); + } + } + + // reset the asset manager + $prop->setValue($am, array()); + if ($debug) { + $am->load(); + } + + file_put_contents($cache, serialize($previously)); + $error = ''; + + sleep(1); + } catch (\Exception $e) { + if ($error != $msg = $e->getMessage()) { + $output->writeln('[error] '.$msg); + $error = $msg; + } } + } + } + + /** + * Checks if an asset should be dumped. + * + * @param LazyAssetManager $am The asset manager + * @param string $name The asset name + * @param array $previously An array of previous visits + * + * @return AssetInterface|Boolean The asset if it should be dumped + */ + protected function checkAsset(LazyAssetManager $am, $name, array &$previously) + { + $formula = $am->hasFormula($name) ? serialize($am->getFormula($name)) : null; + $asset = $am->get($name); + $mtime = $asset->getLastModified(); + + if (isset($previously[$name])) { + $changed = $previously[$name]['mtime'] != $mtime || $previously[$name]['formula'] != $formula; + } else { + $changed = true; + } + + $previously[$name] = array('mtime' => $mtime, 'formula' => $formula); + + return $changed ? $asset : false; + } + + /** + * Writes an asset. + * + * @param AssetInterface $asset An asset + * @param string $baseDir The base directory to write to + * @param OutputInterface $output The command output + * + * @throws RuntimeException If there is a problem writing the asset + */ + protected function dumpAsset(AssetInterface $asset, $baseDir, OutputInterface $output) + { + $target = rtrim($baseDir, '/') . '/' . $asset->getTargetUrl(); + if (!is_dir($dir = dirname($target))) { + $output->writeln('[dir+] '.$dir); + if (false === @mkdir($dir)) { + throw new \RuntimeException('Unable to create directory '.$dir); + } + } - $output->writeln('[file+] '.$asset->getTargetUrl()); - file_put_contents($target, $asset->dump()); + $output->writeln('[file+] '.$target); + if (false === @file_put_contents($target, $asset->dump())) { + throw new \RuntimeException('Unable to write file '.$target); } } }