Skip to content

Commit 7432e87

Browse files
committed
wip
1 parent e244ac8 commit 7432e87

3 files changed

Lines changed: 123 additions & 47 deletions

File tree

src/Analyser.php

Lines changed: 98 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use Closure;
88
use Pest\TypeCoverage\Support\Cache;
9+
use PHPStan\Analyser\Error;
910
use Pokio\Environment;
1011

1112
/**
@@ -22,22 +23,107 @@ final class Analyser
2223
public static function analyse(array $files, Closure $postProcessedFile, Closure $onProcessedFile, Cache $cache): void
2324
{
2425
$testCase = new TestCaseForTypeCoverage('dummy');
25-
$chunkOfFiles = Environment::supportsFork() ? array_chunk($files, Environment::maxProcesses()) : [$files];
26-
$promisses = [];
2726

28-
foreach ($chunkOfFiles as $files) {
29-
$promisses[] = async(function () use ($cache, $files, $testCase, $onProcessedFile) {
27+
if (count($files) === 0) {
28+
return;
29+
}
30+
31+
$filesTouched = [];
32+
$filesInCache = [];
33+
34+
foreach ($files as $file) {
35+
if ($cache->has($file)) {
36+
$filesInCache[] = $file;
37+
} else {
38+
$filesTouched[] = $file;
39+
}
40+
}
41+
42+
unset($files);
43+
44+
self::analyseChunks(
45+
[$filesInCache],
46+
$testCase,
47+
$postProcessedFile,
48+
$onProcessedFile,
49+
$cache,
50+
false,
51+
);
52+
53+
// next, if we don't have touched files, we can return early
54+
55+
if (count($filesTouched) === 0) {
56+
return;
57+
}
58+
59+
// if not, lets warm up the cache with the first file:
60+
61+
$firstFile = array_shift($filesTouched);
62+
self::analyseChunks(
63+
[[$firstFile]],
64+
$testCase,
65+
$postProcessedFile,
66+
$onProcessedFile,
67+
$cache,
68+
false,
69+
);
70+
71+
$maxProcesses = Environment::maxProcesses() / 3;
72+
$maxProcesses = max(1, $maxProcesses);
73+
74+
$chunkOfFiles = array_fill(0, $maxProcesses, []);
75+
foreach (array_values($filesTouched) as $i => $file) {
76+
$chunkOfFiles[$i % $maxProcesses][] = $file;
77+
}
78+
79+
$chunkOfFiles = array_values(
80+
array_filter($chunkOfFiles, static fn (array $chunk) => count($chunk) > 0),
81+
);
82+
83+
self::analyseChunks(
84+
$chunkOfFiles,
85+
$testCase,
86+
$postProcessedFile,
87+
$onProcessedFile,
88+
$cache
89+
);
90+
}
91+
92+
/**
93+
* Analyse the chunks of files.
94+
*/
95+
private static function analyseChunks(
96+
array $chunks,
97+
TestCaseForTypeCoverage $testCase,
98+
Closure $postProcessedFile,
99+
Closure $onProcessedFile,
100+
Cache $cache,
101+
bool $useAsync = true,
102+
): void {
103+
$promises = [];
104+
105+
if ($useAsync === false) {
106+
pokio()->useSync();
107+
} else {
108+
if (Environment::supportsFork()) {
109+
pokio()->useFork();
110+
}
111+
}
112+
113+
foreach ($chunks as $files) {
114+
$promises[] = async(function () use ($files, $testCase, $onProcessedFile) {
115+
$testCase->resetIgnoredErrors();
30116
$results = [];
31117

32-
foreach ($files as $file) {
33-
[$file, $errors, $ignored] = $cache->get($file, function () use ($file, $testCase) {
34-
$testCase->resetIgnoredErrors();
118+
$analyserErrors = $testCase->gatherAnalyserErrors($files);
119+
$analyserIgnored = $testCase->getIgnoredErrors();
35120

36-
$errors = $testCase->gatherAnalyserErrors([$file]);
37-
$ignored = $testCase->getIgnoredErrors();
121+
foreach ($files as $file) {
122+
$errors = array_filter($analyserErrors, static fn (Error $error) => $error->getFile() === $file);
123+
$ignored = array_filter($analyserIgnored, static fn (Error $error) => $error->getFile() === $file);
38124

39-
return [$file, $errors, $ignored];
40-
});
125+
$errors = array_values($errors);
126+
$ignored = array_values($ignored);
41127

42128
$result = Result::fromPHPStanErrors($file, $errors, $ignored);
43129

@@ -50,7 +136,7 @@ public static function analyse(array $files, Closure $postProcessedFile, Closure
50136
});
51137
}
52138

53-
foreach (await($promisses) as $results) {
139+
foreach (await($promises) as $results) {
54140
foreach ($results as $result) {
55141
$postProcessedFile($result);
56142
}

src/Result.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,18 +68,18 @@ public static function fromPHPStanErrors(string $file, array $phpstanErrors, arr
6868
$constantsCoverage = 100;
6969

7070
foreach ($phpstanErrors as $error) {
71-
if (str_contains($message = $error->getMessage(), 'property types')) {
72-
$propertyCoverage = (int) explode(' ', explode('only ', $message)[1])[2];
71+
if (str_contains($error->getMessage(), 'property types')) {
72+
$propertyCoverage = 0;
7373
}
7474
if (str_contains($error->getMessage(), 'param types')) {
75-
$paramCoverage = (int) explode(' ', explode('only ', $message)[1])[2];
75+
$paramCoverage = 0;
7676
}
7777
if (str_contains($error->getMessage(), 'return types')) {
78-
$returnTypeCoverage = (int) explode(' ', explode('only ', $message)[1])[2];
78+
$returnTypeCoverage = 0;
7979
}
8080

8181
if (str_contains($error->getMessage(), 'constant types')) {
82-
$constantsCoverage = (int) explode(' ', explode('only ', $message)[1])[2];
82+
$constantsCoverage = 0;
8383
}
8484
}
8585

src/Support/Cache.php

Lines changed: 20 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -25,39 +25,19 @@ public static function instance(): self
2525
}
2626

2727
/**
28-
* Gets the cache contents.
29-
*
30-
* @param callable(): array $callback
31-
* @return array<int, string>
28+
* Checks if the cache contains the given file.
3229
*/
33-
public function get(string $file, callable $callback): array
30+
public function has(string $file): bool
3431
{
3532
$fileHash = md5_file($file);
33+
3634
if ($fileHash === false) {
37-
return $callback();
35+
return false;
3836
}
3937

4038
$items = $this->all();
4139

42-
if (array_key_exists($fileHash, $items)) {
43-
return $items[$fileHash];
44-
}
45-
46-
$values = $callback();
47-
48-
foreach ($values as $value) {
49-
if (is_array($value)) {
50-
foreach ($value as $item) {
51-
if ($item instanceof Error) {
52-
(fn () => $this->canBeIgnored = null)->call($item);
53-
}
54-
}
55-
}
56-
}
57-
58-
$this->persist(md5_file($file), $values);
59-
60-
return $values;
40+
return array_key_exists($fileHash, $items);
6141
}
6242

6343
/**
@@ -102,14 +82,24 @@ private function all(): array
10282
/**
10383
* Persists the cache contents.
10484
*/
105-
private function persist(string $key, array $values): void
85+
public function persist(string $key, array $values): void
10686
{
87+
foreach ($values as $value) {
88+
if (is_array($value)) {
89+
foreach ($value as $item) {
90+
if ($item instanceof Error) {
91+
(fn () => $this->canBeIgnored = null)->call($item);
92+
}
93+
}
94+
}
95+
}
96+
10797
$dirPath = dirname($this->file());
10898
if (! is_dir($dirPath)) {
109-
if (! mkdir($dirPath, 0777, true)) {
99+
if (! mkdir($dirPath, 0755, true)) {
110100
return;
111101
}
112-
chmod($dirPath, 0777);
102+
chmod($dirPath, 0755);
113103
}
114104

115105
$this->withinLock(function () use ($key, $values) {
@@ -145,8 +135,8 @@ private function withinLock(callable $callback): mixed
145135
$dirPath = dirname($filePath);
146136

147137
if (! is_dir($dirPath)) {
148-
mkdir($dirPath, 0777, true);
149-
chmod($dirPath, 0777);
138+
mkdir($dirPath, 0755, true);
139+
chmod($dirPath, 0755);
150140
}
151141

152142
if (! is_file($lockPath)) {

0 commit comments

Comments
 (0)