diff --git a/Neos.Fusion/Classes/Core/Cache/ParserCacheFlusher.php b/Neos.Fusion/Classes/Core/Cache/ParserCacheFlusher.php index 04a4b0c13ac..e263967f402 100644 --- a/Neos.Fusion/Classes/Core/Cache/ParserCacheFlusher.php +++ b/Neos.Fusion/Classes/Core/Cache/ParserCacheFlusher.php @@ -14,6 +14,7 @@ */ use Neos\Flow\Cache\CacheManager; +use Neos\Flow\Monitor\ChangeDetectionStrategy\ChangeDetectionStrategyInterface; /** * Helper around the ParsePartials Cache. @@ -50,10 +51,21 @@ public function flushPartialCacheOnFileChanges($fileMonitorIdentifier, array $ch $identifiersToFlush = []; foreach ($changedFiles as $changedFile => $status) { - // flow already returns absolute file paths from the file monitor, so we don't have to call realpath. - // attempting to use realpath can even result in an error as the file might be removed and thus no realpath can be resolved via file system. - // https://github.com/neos/neos-development-collection/pull/4509 - $identifiersToFlush[] = $this->getCacheIdentifierForAbsoluteUnixStyleFilePathWithoutDirectoryTraversal($changedFile); + // flow returns linux style file paths without directory traversal from the file monitor. + // As discovered via https://github.com/neos/neos-development-collection/issues/4915 the paths will point to symlinks instead of the actual file. + // Thus, we still need to invoke `realpath` as the cache invalidation otherwise would not work (due to a different hash) + // But attempting to use realpath on removed/moved files fails because it surely cannot be resolved via file system. + if ($status === ChangeDetectionStrategyInterface::STATUS_DELETED) { + // Ignoring removed files means we cannot flush removed files, but this is a compromise for now. + // See https://github.com/neos/neos-development-collection/issues/4415 as reminder that flushing is disabled for deleted files + continue; + } + $fusionFileRealPath = realpath($changedFile); + if ($fusionFileRealPath === false) { + // should not happen as we ignored deleted files beforehand. + throw new \RuntimeException("Couldn't resolve realpath for: '$changedFile'", 1709122619); + } + $identifiersToFlush[] = $this->getCacheIdentifierForAbsoluteUnixStyleFilePathWithoutDirectoryTraversal($fusionFileRealPath); } if ($identifiersToFlush !== []) { diff --git a/Neos.Fusion/Classes/Core/Cache/ParserCacheIdentifierTrait.php b/Neos.Fusion/Classes/Core/Cache/ParserCacheIdentifierTrait.php index 23fd8a76b36..241bbcb3ca8 100644 --- a/Neos.Fusion/Classes/Core/Cache/ParserCacheIdentifierTrait.php +++ b/Neos.Fusion/Classes/Core/Cache/ParserCacheIdentifierTrait.php @@ -33,9 +33,10 @@ private function getCacheIdentifierForDslCode(string $identifier, string $code): * - /Users/marc/Code/neos-project/Packages/Neos * * its crucial that the path - * - is absolute + * - is absolute (starting with /) * - the path separator is in unix style: forward-slash / * - doesn't contain directory traversal /../ or /./ + * - is not a symlink * * to be absolutely sure the path matches the criteria, {@see realpath} can be used. *