66
77use FilesystemIterator ;
88use Nette \Utils \FileSystem ;
9- use Nette \Utils \Random ;
109use Rector \Caching \Contract \ValueObject \Storage \CacheStorageInterface ;
1110use Rector \Caching \ValueObject \CacheFilePaths ;
1211use Rector \Caching \ValueObject \CacheItem ;
@@ -55,7 +54,6 @@ public function save(string $key, string $variableKey, mixed $data): void
5554
5655 $ filePath = $ cacheFilePaths ->getFilePath ();
5756
58- $ tmpPath = \sprintf ('%s/%s.tmp ' , $ this ->directory , Random::generate ());
5957 $ errorBefore = \error_get_last ();
6058 $ exported = @\var_export (new CacheItem ($ variableKey , $ data ), true );
6159 $ errorAfter = \error_get_last ();
@@ -68,18 +66,9 @@ public function save(string $key, string $variableKey, mixed $data): void
6866 ));
6967 }
7068
71- // for performance reasons we don't use SmartFileSystem
72- FileSystem::write ($ tmpPath , \sprintf ("<?php declare(strict_types = 1); \n\nreturn %s; " , $ exported ), null );
73- $ copySuccess = @\copy ($ tmpPath , $ filePath );
74- @\unlink ($ tmpPath );
75-
76- if ($ copySuccess ) {
77- return ;
78- }
79-
80- if (\DIRECTORY_SEPARATOR === '/ ' || ! \file_exists ($ filePath )) {
81- throw new CachingException (\sprintf ('Could not write data to cache file %s. ' , $ filePath ));
82- }
69+ // atomic write via temp file + rename(), so a parallel reader never sees a partially written cache file
70+ // handles the Windows rename() edge case too, see https://github.com/rectorphp/rector/issues/9876
71+ FileSystem::writeAtomic ($ filePath , \sprintf ("<?php declare(strict_types = 1); \n\nreturn %s; " , $ exported ), null );
8372 }
8473
8574 public function clean (string $ key ): void
0 commit comments