Repository navigation
Invalidate the cache when a local checker's code changes #211
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,6 +5,7 @@ | |
| namespace Symplify\EasyCodingStandard\Caching; | ||
|
|
||
| use Nette\Utils\Json; | ||
| use ReflectionClass; | ||
| use Symplify\EasyCodingStandard\Application\Version\StaticVersionResolver; | ||
| use Symplify\EasyCodingStandard\Config\ECSConfig; | ||
| use Symplify\EasyCodingStandard\DependencyInjection\SimpleParameterProvider; | ||
|
|
@@ -24,8 +25,11 @@ public function computeConfig(string $filePath): string | |
| $ecsConfig = new ECSConfig(); | ||
| $callable($ecsConfig); | ||
|
|
||
| // hash the registered checkers and their configuration | ||
| $fileHash = sha1(Json::encode($ecsConfig->getCheckerConfiguration())); | ||
| // hash the registered checkers, their configuration and the source of the local ones | ||
| $checkerConfiguration = $ecsConfig->getCheckerConfiguration(); | ||
| $fileHash = sha1( | ||
| Json::encode($checkerConfiguration) . $this->hashLocalCheckerFiles(array_keys($checkerConfiguration)) | ||
| ); | ||
|
|
||
| return sha1($fileHash . SimpleParameterProvider::hash() . StaticVersionResolver::PACKAGE_VERSION); | ||
| } | ||
|
|
@@ -39,4 +43,49 @@ public function compute(string $filePath): string | |
|
|
||
| return $fileHash; | ||
| } | ||
|
|
||
| /** | ||
| * A checker installed in vendor/ only changes with its package, but a project's own checker can change while its | ||
| * class name and configuration stay the same, so its code has to be part of the hash. | ||
| * | ||
| * @param array<class-string> $checkerClasses | ||
| */ | ||
| private function hashLocalCheckerFiles(array $checkerClasses): string | ||
| { | ||
| $fileHashes = []; | ||
| foreach ($checkerClasses as $checkerClass) { | ||
| foreach ($this->resolveClassFileNames(new ReflectionClass($checkerClass)) as $fileName) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At first glance, this seems quite costly to help with cache.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for looking. Cost is the right concern, so I measured it before answering. Hashing the checker list takes 0.27 ms per call (PHP 8.4, average of 200 runs). That's with all 301 classes from PHP-CS-Fixer's built-in set plus one local sniff. It runs once per container boot, for the main process and each parallel worker. The reflection is cheap because ECS has already loaded every checker class by then: A package version can't cover this case, unfortunately. The checkers it targets live in the project itself, so there is no version to read. That's exactly why their changes are invisible to the cache today. If you'd still rather avoid reflection, an explicit option would work too. For example,
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's quite hard for me to undestand, can you put it in simpler words? If it only concerns local rules, the native ones starting with |
||
| if (str_contains($fileName, DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR)) { | ||
| continue; | ||
| } | ||
|
|
||
| $fileHashes[$fileName] = $this->compute($fileName); | ||
| } | ||
| } | ||
|
|
||
| // contents only, so that the same project checked out elsewhere keeps its cache | ||
| $fileHashes = array_values($fileHashes); | ||
| sort($fileHashes); | ||
|
|
||
| return sha1(implode('', $fileHashes)); | ||
| } | ||
|
|
||
| /** | ||
| * @param ReflectionClass<object> $reflectionClass | ||
| * @return string[] | ||
| */ | ||
| private function resolveClassFileNames(ReflectionClass $reflectionClass): array | ||
| { | ||
| $fileNames = []; | ||
| do { | ||
| $fileNames[] = $reflectionClass->getFileName(); | ||
| foreach ($reflectionClass->getTraits() as $traitReflectionClass) { | ||
| $fileNames[] = $traitReflectionClass->getFileName(); | ||
| } | ||
|
|
||
| $reflectionClass = $reflectionClass->getParentClass(); | ||
| } while ($reflectionClass instanceof ReflectionClass); | ||
|
|
||
| return array_filter($fileNames, is_string(...)); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace Symplify\EasyCodingStandard\Tests\ChangedFilesDetector\FileHashComputer\Source; | ||
|
|
||
| use PHP_CodeSniffer\Files\File; | ||
| use PHP_CodeSniffer\Sniffs\Sniff; | ||
|
|
||
| final class LocalSniff implements Sniff | ||
| { | ||
| public function register() | ||
| { | ||
| return [T_WHILE]; | ||
| } | ||
|
|
||
| public function process(File $phpcsFile, $stackPtr) | ||
| { | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| use Symplify\EasyCodingStandard\Config\ECSConfig; | ||
| use Symplify\EasyCodingStandard\Tests\ChangedFilesDetector\FileHashComputer\Source\LocalSniff; | ||
|
|
||
| return ECSConfig::configure() | ||
| ->withRules([LocalSniff::class]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you split this onto more lines? Seems connecting 2 different cases here.