From 2dde842172039756b1fc28655044c70c688eeb43 Mon Sep 17 00:00:00 2001 From: kkmuffme <11071985+kkmuffme@users.noreply.github.com> Date: Thu, 21 Jul 2022 11:32:24 +0200 Subject: [PATCH] fix race conditions causing notices if directory does not exist --- src/Psalm/Config.php | 28 ++++++++++++++----- .../Internal/Provider/ParserCacheProvider.php | 7 +++++ 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/Psalm/Config.php b/src/Psalm/Config.php index 08bc9604f2e..28e4ecbc95c 100644 --- a/src/Psalm/Config.php +++ b/src/Psalm/Config.php @@ -52,6 +52,7 @@ use function basename; use function chdir; use function class_exists; +use function clearstatcache; use function count; use function dirname; use function error_log; @@ -2268,6 +2269,7 @@ public function getPotentialComposerFilePathForClassLike(string $class): ?string public static function removeCacheDirectory(string $dir): void { + clearstatcache(true, $dir); if (is_dir($dir)) { $objects = scandir($dir, SCANDIR_SORT_NONE); @@ -2276,17 +2278,29 @@ public static function removeCacheDirectory(string $dir): void } foreach ($objects as $object) { - if ($object !== '.' && $object !== '..') { - if (filetype($dir . '/' . $object) === 'dir') { - self::removeCacheDirectory($dir . '/' . $object); - } else { - unlink($dir . '/' . $object); - } + if ($object === '.' || $object === '..') { + continue; + } + + // if it was deleted in the meantime/race condition with other psalm process + if (!file_exists($dir . '/' . $object)) { + continue; + } + + if (filetype($dir . '/' . $object) === 'dir') { + self::removeCacheDirectory($dir . '/' . $object); + } else { + unlink($dir . '/' . $object); } } reset($objects); - rmdir($dir); + + // may have been removed in the meantime + clearstatcache(true, $dir); + if (is_dir($dir)) { + rmdir($dir); + } } } diff --git a/src/Psalm/Internal/Provider/ParserCacheProvider.php b/src/Psalm/Internal/Provider/ParserCacheProvider.php index 893844e2eee..af722c77e5a 100644 --- a/src/Psalm/Internal/Provider/ParserCacheProvider.php +++ b/src/Psalm/Internal/Provider/ParserCacheProvider.php @@ -7,6 +7,7 @@ use Psalm\Config; use RuntimeException; +use function clearstatcache; use function error_log; use function fclose; use function file_get_contents; @@ -302,6 +303,12 @@ public function saveFileContentHashes(): void return; } + // directory was removed, most likely due to a race condition with other psalm instances that were manually started at the same time + clearstatcache(true, $root_cache_directory); + if (!is_dir($root_cache_directory)) { + return; + } + $file_content_hashes = $this->new_file_content_hashes + $this->getExistingFileContentHashes(); $file_hashes_path = $root_cache_directory . DIRECTORY_SEPARATOR . self::FILE_HASHES;