[AsseticBundle] inotify support for --watch option in assetic:dump command #205

Closed
wants to merge 2 commits into
from
Jump to file or symbol
Failed to load files and symbols.
+93 −12
Split
@@ -33,7 +33,7 @@ protected function configure()
->setName('assetic:dump')
->setDescription('Dumps all assets to the filesystem')
->addArgument('write_to', InputArgument::OPTIONAL, 'Override the configured asset root')
- ->addOption('watch', null, InputOption::VALUE_NONE, 'Check for changes every second')
+ ->addOption('watch', null, InputOption::VALUE_NONE, 'Check for changes every second, debug mode only')
;
}
@@ -61,7 +61,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
* Watches a asset manager for changes.
*
* This method includes an infinite loop the continuously polls the asset
- * manager for changes.
+ * manager for changes. If available, inotify is used to wait for changes.
*
* @param LazyAssetManager $am The asset manager
* @param string $basePath The base directory to write to
@@ -70,6 +70,10 @@ protected function execute(InputInterface $input, OutputInterface $output)
*/
protected function watch(LazyAssetManager $am, $basePath, OutputInterface $output, $debug = false)
{
+ if (!$debug) {
+ throw new \RuntimeException('The --watch option is only available in debug mode.');
+ }
+
$refl = new \ReflectionClass('Assetic\\AssetManager');
$prop = $refl->getProperty('assets');
$prop->setAccessible(true);
@@ -81,32 +85,109 @@ protected function watch(LazyAssetManager $am, $basePath, OutputInterface $outpu
$previously = array();
}
+ if (function_exists('inotify_init')) {
+ $inotify = inotify_init();
+ } else {
+ $inotify = false;
+ }
+
$error = '';
while (true) {
try {
- foreach ($am->getNames() as $name) {
- if ($asset = $this->checkAsset($am, $name, $previously)) {
- $this->dumpAsset($asset, $basePath, $output);
- }
+ file_put_contents($cache, serialize($previously));
+
+ if (false !== $inotify) {
+ $reload = $this->inotifyWait($am, $output, $inotify);
+ } else {
+ sleep(1);
+ $reload = true;
}
- // reset the asset manager
- $prop->setValue($am, array());
- if ($debug) {
+ $checkAssets = array();
+ if (true === $reload) {
+ // reset the asset manager
+ $prop->setValue($am, array());
$am->load();
+
+ $checkAssets = $am->getNames();
+ } else if (is_array($reload)) {
+ $checkAssets = $reload;
}
- file_put_contents($cache, serialize($previously));
- $error = '';
+ foreach ($checkAssets as $name) {
+ if ($asset = $this->checkAsset($am, $name, $previously)) {
+ $this->dumpAsset($asset, $basePath, $output);
+ }
+ }
- sleep(1);
+ $error = '';
} catch (\Exception $e) {
if ($error != $msg = $e->getMessage()) {
$output->writeln('<error>[error]</error> '.$msg);
$error = $msg;
}
}
}
+
+ if (false !== $inotify) {
+ fclose($inotify);
+ }
+ }
+
+ /**
+ * Sets up watches for inotify to monitor all assetic resources and assets.
+ *
+ * After waiting on inotify to find file modifications it either returns an
+ * array of modified assets or true to indicate that a resource was modifed.
+ *
+ * @param LazyAssetManager $am The asset manager
+ * @param OutputInterface $output The command output
+ * @param resource $inotify File descriptor of the inotify handle
+ *
+ * @return Boolean|array True if a resource was modified or an array of
+ * modified assets.
+ */
+ protected function inotifyWait(LazyAssetManager $am, OutputInterface $output, $inotify)
+ {
+ $flags = IN_MODIFY | IN_ATTRIB | IN_MOVE | IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MOVE_SELF;
+
+ // add a watch for every resource (e.g. template file directory)
+ $resourceWatches = array();
+ foreach ($am->getResources() as $resource) {
+ $path = (string) $resource;
+ $watch = inotify_add_watch($inotify, $path, $flags);
+ $resourceWatches[$watch] = true;
+ }
+
+ // add watches for all files involved in any formulas
+ $assetsWatches = array();
+ foreach ($am->getNames() as $name) {
+ $asset = $am->get($name);
+ foreach ($asset->getPaths() as $path) {
+ $watch = inotify_add_watch($inotify, $path, $flags);
+ $assetWatches[$watch] = $name;
+ }
+ }
+
+ // blocks until an event occurs
+ $events = inotify_read($inotify);
+
+ $reloadAssets = array();
+ $reload = false;
+ foreach ($events as $event) {
+ if (isset($resourceWatches[$event['wd']])) {
+ $reload = true;
+ } else if (isset($assetWatches[$event['wd']])) {
+ $reloadAssets[$event['wd']] = $assetWatches[$event['wd']];
+ }
+ }
+
+ if ($reload) {
+ $output->writeln('<info>[reload]</info> all asset manager resources');
+ return true;
+ }
+
+ return $reloadAssets;
}
/**