From c95425811dfa0fd55e67cbbb75b6d684c6d2b5cb Mon Sep 17 00:00:00 2001 From: mhsdesign <85400359+mhsdesign@users.noreply.github.com> Date: Sun, 4 Feb 2024 15:43:31 +0100 Subject: [PATCH 1/2] BUGFIX: Introduce `flushDeletedOnPath` if ($this->identifier === 'Flow_ClassFiles' && str_ends_with($path, '/Packages/Neos/Neos.Neos/Classes/')) { // previously considered files for deletion var_dump($this->directoriesAndFiles[$path]); // more relivable? var_dump($deletedFiles); } --- .../ModificationTimeStrategy.php | 26 +++++++++++++++++++ Neos.Flow/Classes/Monitor/FileMonitor.php | 8 ++++++ 2 files changed, 34 insertions(+) diff --git a/Neos.Flow/Classes/Monitor/ChangeDetectionStrategy/ModificationTimeStrategy.php b/Neos.Flow/Classes/Monitor/ChangeDetectionStrategy/ModificationTimeStrategy.php index 39a239c735..c442fdff4d 100644 --- a/Neos.Flow/Classes/Monitor/ChangeDetectionStrategy/ModificationTimeStrategy.php +++ b/Neos.Flow/Classes/Monitor/ChangeDetectionStrategy/ModificationTimeStrategy.php @@ -64,6 +64,32 @@ public function setFileMonitor(FileMonitor $fileMonitor) $this->filesAndModificationTimes = json_decode($this->cache->get($this->fileMonitor->getIdentifier() . '_filesAndModificationTimes'), true); } + /** + * @param string $onPath + * @param array $filesIgnoreMask files to ignore as we are sure they exist + * @return array + */ + public function flushDeletedOnPath(string $onPath, array $filesIgnoreMask): array + { + $deletedFiles = []; + foreach ($this->filesAndModificationTimes as $pathAndFilename => $modificationTime) { + if (!str_starts_with($pathAndFilename, $onPath)) { + continue; + } + if (isset($filesIgnoreMask[$pathAndFilename])) { + continue; + } + if (file_exists($pathAndFilename)) { + // should not happen? + continue; + } + $this->modificationTimesChanged = true; + unset($this->filesAndModificationTimes[$pathAndFilename]); + $deletedFiles[$pathAndFilename] = ChangeDetectionStrategyInterface::STATUS_DELETED; + } + return $deletedFiles; + } + /** * Checks if the specified file has changed * diff --git a/Neos.Flow/Classes/Monitor/FileMonitor.php b/Neos.Flow/Classes/Monitor/FileMonitor.php index d2b5be6ffe..b0b48a82a5 100644 --- a/Neos.Flow/Classes/Monitor/FileMonitor.php +++ b/Neos.Flow/Classes/Monitor/FileMonitor.php @@ -303,7 +303,9 @@ protected function detectChangesOnPath($path, $filenamePattern) $this->changedPaths[$path] = ChangeDetectionStrategyInterface::STATUS_CREATED; } + $currentSubDirectoriesAndFilesMask = []; foreach ($currentSubDirectoriesAndFiles as $pathAndFilename) { + $currentSubDirectoriesAndFilesMask[$pathAndFilename] = 1; $status = $this->changeDetectionStrategy->getFileStatus($pathAndFilename); if ($status !== ChangeDetectionStrategyInterface::STATUS_UNCHANGED) { $this->changedFiles[$pathAndFilename] = $status; @@ -316,6 +318,12 @@ protected function detectChangesOnPath($path, $filenamePattern) $nowDetectedFilesAndDirectories[$pathAndFilename] = 1; } + $deletedFiles = $this->changeDetectionStrategy->flushDeletedOnPath($path, $currentSubDirectoriesAndFilesMask); + if ($deletedFiles) { + $this->changedFiles = [...$this->changedFiles, ...$deletedFiles]; + $currentDirectoryChanged = true; + } + if ($this->directoriesAndFiles[$path] !== []) { foreach (array_keys($this->directoriesAndFiles[$path]) as $pathAndFilename) { $this->changedFiles[$pathAndFilename] = ChangeDetectionStrategyInterface::STATUS_DELETED; From 5e34f233995f333578dcd9d20cf7a361fd8338d3 Mon Sep 17 00:00:00 2001 From: mhsdesign <85400359+mhsdesign@users.noreply.github.com> Date: Sun, 4 Feb 2024 15:50:36 +0100 Subject: [PATCH 2/2] WIP: BUGFIX: Introduce `flushDeletedOnPath` --- .../ModificationTimeStrategy.php | 2 +- ...trategyWithFlushDeletedOnPathInterface.php | 27 ++++++++++++++ .../StrategyWithMarkDeletedInterface.php | 1 + Neos.Flow/Classes/Monitor/FileMonitor.php | 37 +++++++++++-------- 4 files changed, 50 insertions(+), 17 deletions(-) create mode 100644 Neos.Flow/Classes/Monitor/ChangeDetectionStrategy/StrategyWithFlushDeletedOnPathInterface.php diff --git a/Neos.Flow/Classes/Monitor/ChangeDetectionStrategy/ModificationTimeStrategy.php b/Neos.Flow/Classes/Monitor/ChangeDetectionStrategy/ModificationTimeStrategy.php index c442fdff4d..b4c161ac45 100644 --- a/Neos.Flow/Classes/Monitor/ChangeDetectionStrategy/ModificationTimeStrategy.php +++ b/Neos.Flow/Classes/Monitor/ChangeDetectionStrategy/ModificationTimeStrategy.php @@ -18,7 +18,7 @@ /** * A change detection strategy based on modification times */ -class ModificationTimeStrategy implements ChangeDetectionStrategyInterface, StrategyWithMarkDeletedInterface +class ModificationTimeStrategy implements ChangeDetectionStrategyInterface, StrategyWithMarkDeletedInterface, StrategyWithFlushDeletedOnPathInterface { /** * @var \Neos\Flow\Monitor\FileMonitor diff --git a/Neos.Flow/Classes/Monitor/ChangeDetectionStrategy/StrategyWithFlushDeletedOnPathInterface.php b/Neos.Flow/Classes/Monitor/ChangeDetectionStrategy/StrategyWithFlushDeletedOnPathInterface.php new file mode 100644 index 0000000000..a1383130f3 --- /dev/null +++ b/Neos.Flow/Classes/Monitor/ChangeDetectionStrategy/StrategyWithFlushDeletedOnPathInterface.php @@ -0,0 +1,27 @@ + $filesIgnoreMask files to ignore as we are sure they exist + * @return array + */ + public function flushDeletedOnPath(string $onPath, array $filesIgnoreMask): array; +} diff --git a/Neos.Flow/Classes/Monitor/ChangeDetectionStrategy/StrategyWithMarkDeletedInterface.php b/Neos.Flow/Classes/Monitor/ChangeDetectionStrategy/StrategyWithMarkDeletedInterface.php index 30017d49b8..0538614cef 100644 --- a/Neos.Flow/Classes/Monitor/ChangeDetectionStrategy/StrategyWithMarkDeletedInterface.php +++ b/Neos.Flow/Classes/Monitor/ChangeDetectionStrategy/StrategyWithMarkDeletedInterface.php @@ -14,6 +14,7 @@ /** * Contract for a change detection strategy that allows the FileMonitor to mark a file deleted directly. * + * @deprecated in favour of more reliable {@see StrategyWithFlushDeletedOnPathInterface} * @api */ interface StrategyWithMarkDeletedInterface diff --git a/Neos.Flow/Classes/Monitor/FileMonitor.php b/Neos.Flow/Classes/Monitor/FileMonitor.php index b0b48a82a5..1dd723e3c1 100644 --- a/Neos.Flow/Classes/Monitor/FileMonitor.php +++ b/Neos.Flow/Classes/Monitor/FileMonitor.php @@ -17,6 +17,7 @@ use Neos\Flow\Log\PsrLoggerFactoryInterface; use Neos\Flow\Log\Utility\LogEnvironment; use Neos\Flow\Monitor\ChangeDetectionStrategy\ChangeDetectionStrategyInterface; +use Neos\Flow\Monitor\ChangeDetectionStrategy\StrategyWithFlushDeletedOnPathInterface; use Neos\Flow\Monitor\ChangeDetectionStrategy\StrategyWithMarkDeletedInterface; use Neos\Flow\SignalSlot\Dispatcher; use Neos\Utility\Files; @@ -81,6 +82,7 @@ class FileMonitor /** * Array of directories and files that were cached on the last run. * + * @deprecated to be replaced by only supporting {@see StrategyWithFlushDeletedOnPathInterface} * @var array */ protected $directoriesAndFiles = null; @@ -318,24 +320,27 @@ protected function detectChangesOnPath($path, $filenamePattern) $nowDetectedFilesAndDirectories[$pathAndFilename] = 1; } - $deletedFiles = $this->changeDetectionStrategy->flushDeletedOnPath($path, $currentSubDirectoriesAndFilesMask); - if ($deletedFiles) { - $this->changedFiles = [...$this->changedFiles, ...$deletedFiles]; - $currentDirectoryChanged = true; - } - - if ($this->directoriesAndFiles[$path] !== []) { - foreach (array_keys($this->directoriesAndFiles[$path]) as $pathAndFilename) { - $this->changedFiles[$pathAndFilename] = ChangeDetectionStrategyInterface::STATUS_DELETED; - if ($this->changeDetectionStrategy instanceof StrategyWithMarkDeletedInterface) { - $this->changeDetectionStrategy->setFileDeleted($pathAndFilename); - } else { - // This call is needed to mark the file deleted in any possibly existing caches of the strategy. - // The return value is not important as we know this file doesn't exist so we set the status to DELETED anyway. - $this->changeDetectionStrategy->getFileStatus($pathAndFilename); + if ($this->changeDetectionStrategy instanceof StrategyWithFlushDeletedOnPathInterface) { + $deletedFiles = $this->changeDetectionStrategy->flushDeletedOnPath($path, $currentSubDirectoriesAndFilesMask); + if ($deletedFiles) { + $this->changedFiles = [...$this->changedFiles, ...$deletedFiles]; + $currentDirectoryChanged = true; + } + } else { + // legacy deletion detection + if ($this->directoriesAndFiles[$path] !== []) { + foreach (array_keys($this->directoriesAndFiles[$path]) as $pathAndFilename) { + $this->changedFiles[$pathAndFilename] = ChangeDetectionStrategyInterface::STATUS_DELETED; + if ($this->changeDetectionStrategy instanceof StrategyWithMarkDeletedInterface) { + $this->changeDetectionStrategy->setFileDeleted($pathAndFilename); + } else { + // This call is needed to mark the file deleted in any possibly existing caches of the strategy. + // The return value is not important as we know this file doesn't exist so we set the status to DELETED anyway. + $this->changeDetectionStrategy->getFileStatus($pathAndFilename); + } } + $currentDirectoryChanged = true; } - $currentDirectoryChanged = true; } if ($currentDirectoryChanged) {