Skip to content

Commit 466ad51

Browse files
committed
Clean file cache from unused items
1 parent 19cd999 commit 466ad51

File tree

2 files changed

+115
-0
lines changed

2 files changed

+115
-0
lines changed

src/Cache/FileCacheStorage.php

+110
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,41 @@
44

55
use InvalidArgumentException;
66
use Nette\Utils\Random;
7+
use PHPStan\File\CouldNotReadFileException;
8+
use PHPStan\File\CouldNotWriteFileException;
9+
use PHPStan\File\FileReader;
710
use PHPStan\File\FileWriter;
811
use PHPStan\Internal\DirectoryCreator;
912
use PHPStan\Internal\DirectoryCreatorException;
1013
use PHPStan\ShouldNotHappenException;
14+
use RecursiveDirectoryIterator;
15+
use RecursiveIteratorIterator;
16+
use function array_keys;
17+
use function closedir;
18+
use function dirname;
1119
use function error_get_last;
20+
use function is_dir;
1221
use function is_file;
22+
use function opendir;
23+
use function readdir;
1324
use function rename;
25+
use function rmdir;
1426
use function sha1;
1527
use function sprintf;
28+
use function str_contains;
29+
use function str_starts_with;
30+
use function strlen;
1631
use function substr;
32+
use function uksort;
1733
use function unlink;
1834
use function var_export;
1935
use const DIRECTORY_SEPARATOR;
2036

2137
final class FileCacheStorage implements CacheStorage
2238
{
2339

40+
private const CACHED_CLEARED_VERSION = 'v1-variadic';
41+
2442
public function __construct(private string $directory)
2543
{
2644
}
@@ -100,4 +118,96 @@ private function getFilePaths(string $key): array
100118
];
101119
}
102120

121+
public function clearUnusedFiles(): void
122+
{
123+
if (!is_dir($this->directory)) {
124+
return;
125+
}
126+
127+
$cachedClearedFile = $this->directory . '/cache-cleared';
128+
if (is_file($cachedClearedFile)) {
129+
try {
130+
$cachedClearedContents = FileReader::read($cachedClearedFile);
131+
if ($cachedClearedContents === self::CACHED_CLEARED_VERSION) {
132+
return;
133+
}
134+
} catch (CouldNotReadFileException) {
135+
return;
136+
}
137+
}
138+
139+
$iterator = new RecursiveDirectoryIterator($this->directory);
140+
$iterator->setFlags(RecursiveDirectoryIterator::SKIP_DOTS);
141+
$files = new RecursiveIteratorIterator($iterator);
142+
$beginFunction = sprintf(
143+
"<?php declare(strict_types = 1);\n\n%s",
144+
sprintf('// %s', 'variadic-function-'),
145+
);
146+
$beginMethod = sprintf(
147+
"<?php declare(strict_types = 1);\n\n%s",
148+
sprintf('// %s', 'variadic-method-'),
149+
);
150+
$beginOld = sprintf(
151+
"<?php declare(strict_types = 1);\n\n%s",
152+
'return PHPStan\\Cache\\CacheItem::',
153+
);
154+
$emptyDirectoriesToCheck = [];
155+
foreach ($files as $file) {
156+
try {
157+
$path = $file->getPathname();
158+
$contents = FileReader::read($path);
159+
if (str_contains($contents, 'odsl-')) {
160+
continue;
161+
}
162+
if (
163+
!str_starts_with($contents, $beginFunction)
164+
&& !str_starts_with($contents, $beginMethod)
165+
&& !str_starts_with($contents, $beginOld)
166+
) {
167+
continue;
168+
}
169+
170+
$emptyDirectoriesToCheck[dirname($path)] = true;
171+
$emptyDirectoriesToCheck[dirname($path, 2)] = true;
172+
173+
@unlink($path);
174+
} catch (CouldNotReadFileException) {
175+
continue;
176+
}
177+
}
178+
179+
uksort($emptyDirectoriesToCheck, static fn ($a, $b) => strlen($b) - strlen($a));
180+
181+
foreach (array_keys($emptyDirectoriesToCheck) as $directory) {
182+
if (!$this->isDirectoryEmpty($directory)) {
183+
continue;
184+
}
185+
186+
@rmdir($directory);
187+
}
188+
189+
try {
190+
FileWriter::write($cachedClearedFile, self::CACHED_CLEARED_VERSION);
191+
} catch (CouldNotWriteFileException) {
192+
// pass
193+
}
194+
}
195+
196+
private function isDirectoryEmpty(string $directory): bool
197+
{
198+
$handle = opendir($directory);
199+
if ($handle === false) {
200+
return false;
201+
}
202+
while (($entry = readdir($handle)) !== false) {
203+
if ($entry !== '.' && $entry !== '..') {
204+
closedir($handle);
205+
return false;
206+
}
207+
}
208+
209+
closedir($handle);
210+
return true;
211+
}
212+
103213
}

src/Command/CommandHelper.php

+5
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use Nette\Schema\ValidationException;
1313
use Nette\Utils\AssertionException;
1414
use Nette\Utils\Strings;
15+
use PHPStan\Cache\FileCacheStorage;
1516
use PHPStan\Command\Symfony\SymfonyOutput;
1617
use PHPStan\Command\Symfony\SymfonyStyle;
1718
use PHPStan\DependencyInjection\Container;
@@ -434,6 +435,10 @@ public static function begin(
434435

435436
if ($cleanupContainerCache) {
436437
$containerFactory->clearOldContainers($tmpDir);
438+
$cacheStorage = $container->getService('cacheStorage');
439+
if ($cacheStorage instanceof FileCacheStorage) {
440+
$cacheStorage->clearUnusedFiles();
441+
}
437442
}
438443

439444
/** @var bool|null $customRulesetUsed */

0 commit comments

Comments
 (0)