-
-
Notifications
You must be signed in to change notification settings - Fork 344
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
Add support for cache results #1011
Merged
kylekatarnls
merged 59 commits into
phpmd:master
from
frankdekker:Add-support-for-cache-results
Jul 2, 2023
Merged
Changes from all commits
Commits
Show all changes
59 commits
Select commit
Hold shift + click to select a range
24d28fd
Merge pull request #6 from phpmd/master
frankdekker e5be40d
Add result cache config, state and engine
frankdekker f20700f
Add result cache config, state and engine
frankdekker e432cc6
Add result cache config, state and engine
frankdekker ee23400
Add result cache config, state and engine
frankdekker fde96e8
Extract AbstractNode from RuleViolation
frankdekker eb29a66
Added method to add RuleViolation to ResultCacheState
frankdekker 3659e71
Add ResultCacheIO to save and read the state
frankdekker 29f417f
Read state from result cache
frankdekker 799abbf
Read state from result cache
frankdekker e198a23
Create RuleViolations from result cache
frankdekker 5b7e504
Extract ResultCacheFileFilter
frankdekker ebe7df2
Reorganize classes
frankdekker 5367f2b
Fix codestyle
frankdekker a075f3b
Add commandline options for --cache and --cache-file
frankdekker 646da75
Update documentation
frankdekker ae964f1
Add commandline options to factory
frankdekker 62f3636
Improve ResultCacheEngineFactory
frankdekker b462802
Add cache strategy commandline argument
frankdekker 3ec1dcb
Reorganize namespace
frankdekker 9ba711e
Add basics for ResultCacheKey
frankdekker f0ada49
Add cache key factory
frankdekker 06641fd
Add cache key factory
frankdekker e4e026e
Add cache key factory
frankdekker ef03049
Cleanup ResultCacheConfig
frankdekker a2c02f0
Improve ResultCacheStateFactory
frankdekker 3996b93
Add composer to cache key
frankdekker 7f8c248
Run phpcbf
frankdekker 8b486d2
Change mb5_file to sha1_file
frankdekker 46559c0
Add coverage ResultCacheKey
frankdekker 0f8573d
Add coverage ResultCacheEngine
frankdekker 0ca1564
Add coverage ResultCacheFileFilter
frankdekker e6bef09
Add coverage ResultCacheFileFilter
frankdekker f59c603
Add coverage ResultCacheStateFactory
frankdekker 2840b51
Add coverage ResultCacheKeyFactory
frankdekker c5d35fa
Add coverage ResultCacheKeyFactory
frankdekker 0d67271
Add coverage ResultCacheWriter
frankdekker f99bfae
Add coverage ResultCacheUpdater
frankdekker fc122d6
Add coverage ResultCacheEngineFactory
frankdekker be344ef
Add coverage ResultCacheState
frankdekker 3acf3e2
Fix coverage RuleViolationTest
frankdekker 1c3eaa4
Fix PHPMDTest
frankdekker 7916220
Update gitignore
frankdekker 3e06735
Add coverage ResultCacheState
frankdekker 8210ac4
Add coverage ResultCacheState
frankdekker 77573ff
Add coverage ResultCacheState
frankdekker 7d25e91
Add commandline cli information
frankdekker 9156017
Add baseline file hash to cache key
frankdekker 8ab75f2
Add baseline file hash to cache key
frankdekker 12affac
Avoid reading or writing the cache when generating/updating the baseline
frankdekker b2e5fe5
Avoid reading or writing the cache when generating/updating the baseline
frankdekker f7303ff
Fix phpcs issues
frankdekker 2380fe6
Fix ResultCacheKeyFactoryTest
frankdekker bc91be2
Add coverage NodeInfo
frankdekker b92d8f5
Add coverage NodeInfoFactory
frankdekker 2010c2c
Add coverage Paths::concat
frankdekker 1c323df
Fix codestyle issue
frankdekker b00bda2
Merge branch 'phpmd:master' into master
frankdekker efab9d0
Merge branch 'master' into Add-support-for-cache-results
frankdekker File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,7 @@ | |
.project | ||
.buildpath | ||
.settings | ||
.phpmd.result-cache.php | ||
*.phar | ||
/*.xml | ||
composer.lock | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
<?php | ||
|
||
namespace PHPMD\Cache\Model; | ||
|
||
class ResultCacheKey | ||
{ | ||
/** @var bool */ | ||
private $strict; | ||
/** @var string|null */ | ||
private $baselineHash; | ||
/** @var array<string, string> */ | ||
private $rules; | ||
/** @var array<string, string> */ | ||
private $composer; | ||
/** @var int */ | ||
private $phpVersion; | ||
|
||
/** | ||
* @param bool $strict | ||
* @param string|null $baselineHash | ||
* @param array<string, string> $rules | ||
* @param array<string, string> $composer | ||
* @param int $phpVersion | ||
*/ | ||
public function __construct($strict, $baselineHash, $rules, $composer, $phpVersion) | ||
{ | ||
$this->strict = $strict; | ||
$this->baselineHash = $baselineHash; | ||
$this->rules = $rules; | ||
$this->composer = $composer; | ||
$this->phpVersion = $phpVersion; | ||
} | ||
|
||
/** | ||
* @return array | ||
*/ | ||
public function toArray() | ||
{ | ||
return array( | ||
'strict' => $this->strict, | ||
'baselineHash' => $this->baselineHash, | ||
'rules' => $this->rules, | ||
'composer' => $this->composer, | ||
'phpVersion' => $this->phpVersion, | ||
); | ||
} | ||
|
||
/** | ||
* @return bool | ||
*/ | ||
public function isEqualTo(ResultCacheKey $other) | ||
{ | ||
return $this->strict === $other->strict | ||
&& $this->baselineHash === $other->baselineHash | ||
&& $this->rules === $other->rules | ||
&& $this->composer === $other->composer | ||
&& $this->phpVersion === $other->phpVersion; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
<?php | ||
|
||
namespace PHPMD\Cache\Model; | ||
|
||
use PHPMD\Node\NodeInfo; | ||
use PHPMD\Rule; | ||
use PHPMD\RuleSet; | ||
use PHPMD\RuleViolation; | ||
use PHPMD\Utility\Paths; | ||
|
||
class ResultCacheState | ||
{ | ||
/** @var ResultCacheKey */ | ||
private $cacheKey; | ||
|
||
/** @var array{files: array<string, array{hash: string, violations: array}>} */ | ||
private $state; | ||
|
||
/** | ||
* @param array{files: array<string, array{hash: string, violations: array}>} $state | ||
*/ | ||
public function __construct(ResultCacheKey $cacheKey, $state = array()) | ||
{ | ||
$this->cacheKey = $cacheKey; | ||
$this->state = $state; | ||
} | ||
|
||
/** | ||
* @return ResultCacheKey | ||
*/ | ||
public function getCacheKey() | ||
{ | ||
return $this->cacheKey; | ||
} | ||
|
||
/** | ||
* @param string $filePath | ||
* @return array | ||
*/ | ||
public function getViolations($filePath) | ||
{ | ||
if (isset($this->state['files'][$filePath]['violations']) === false) { | ||
return array(); | ||
} | ||
|
||
return $this->state['files'][$filePath]['violations']; | ||
} | ||
|
||
/** | ||
* @param string $filePath | ||
*/ | ||
public function setViolations($filePath, array $violations) | ||
{ | ||
$this->state['files'][$filePath]['violations'] = $violations; | ||
} | ||
|
||
/** | ||
* @param string $filePath | ||
*/ | ||
public function addRuleViolation($filePath, RuleViolation $violation) | ||
{ | ||
$this->state['files'][$filePath]['violations'][] = array( | ||
'rule' => get_class($violation->getRule()), | ||
'namespaceName' => $violation->getNamespaceName(), | ||
'className' => $violation->getClassName(), | ||
'methodName' => $violation->getMethodName(), | ||
'functionName' => $violation->getFunctionName(), | ||
'beginLine' => $violation->getBeginLine(), | ||
'endLine' => $violation->getEndLine(), | ||
'description' => $violation->getDescription(), | ||
'args' => $violation->getArgs(), | ||
'metric' => $violation->getMetric() | ||
); | ||
} | ||
|
||
/** | ||
* @param string $basePath | ||
* @param RuleSet[] $ruleSetList | ||
*/ | ||
public function getRuleViolations($basePath, array $ruleSetList) | ||
{ | ||
if (isset($this->state['files']) === false) { | ||
return array(); | ||
} | ||
|
||
$ruleViolations = array(); | ||
|
||
foreach ($this->state['files'] as $filePath => $violations) { | ||
if (isset($violations['violations']) === false) { | ||
continue; | ||
} | ||
foreach ($violations['violations'] as $violation) { | ||
$rule = self::findRuleIn($violation['rule'], $ruleSetList); | ||
$nodeInfo = new NodeInfo( | ||
Paths::concat($basePath, $filePath), | ||
$violation['namespaceName'], | ||
$violation['className'], | ||
$violation['methodName'], | ||
$violation['functionName'], | ||
$violation['beginLine'], | ||
$violation['endLine'] | ||
); | ||
|
||
if ($violation['args'] === null) { | ||
$violationMessage = $violation['description']; | ||
} else { | ||
$violationMessage = array('args' => $violation['args'], 'message' => $violation['description']); | ||
} | ||
$ruleViolations[] = new RuleViolation($rule, $nodeInfo, $violationMessage, $violation['metric']); | ||
} | ||
} | ||
|
||
return $ruleViolations; | ||
} | ||
|
||
/** | ||
* @param string $filePath | ||
* @param string $hash | ||
* @return bool | ||
*/ | ||
public function isFileModified($filePath, $hash) | ||
{ | ||
if (isset($this->state['files'][$filePath]['hash']) === false) { | ||
return true; | ||
} | ||
|
||
return $this->state['files'][$filePath]['hash'] !== $hash; | ||
} | ||
|
||
/** | ||
* @param string $filePath | ||
* @param string $hash | ||
*/ | ||
public function setFileState($filePath, $hash) | ||
{ | ||
return $this->state['files'][$filePath]['hash'] = $hash; | ||
} | ||
|
||
/** | ||
* @return array | ||
*/ | ||
public function toArray() | ||
{ | ||
return array( | ||
'key' => $this->cacheKey->toArray(), | ||
'state' => $this->state | ||
); | ||
} | ||
|
||
/** | ||
* @param string $ruleClassName | ||
* @param RuleSet[] $ruleSetList | ||
* @return Rule|null | ||
*/ | ||
private static function findRuleIn($ruleClassName, array $ruleSetList) | ||
{ | ||
foreach ($ruleSetList as $ruleSet) { | ||
foreach ($ruleSet->getRules() as $rule) { | ||
if (get_class($rule) === $ruleClassName) { | ||
return $rule; | ||
} | ||
} | ||
} | ||
|
||
return null; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
<?php | ||
|
||
namespace PHPMD\Cache\Model; | ||
|
||
class ResultCacheStrategy | ||
{ | ||
/** | ||
* Determine the file cache freshness based on sha hash of the contents of the file | ||
*/ | ||
const CONTENT = 'content'; | ||
|
||
/** | ||
* Determine the file cache freshness based on the file modified timestamp | ||
*/ | ||
const TIMESTAMP = 'timestamp'; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
<?php | ||
|
||
namespace PHPMD\Cache; | ||
|
||
class ResultCacheEngine | ||
{ | ||
/** @var ResultCacheFileFilter */ | ||
private $fileFilter; | ||
|
||
/** @var ResultCacheUpdater */ | ||
private $updater; | ||
|
||
/** @var ResultCacheWriter */ | ||
private $writer; | ||
|
||
public function __construct( | ||
ResultCacheFileFilter $fileFilter, | ||
ResultCacheUpdater $updater, | ||
ResultCacheWriter $writer | ||
) { | ||
|
||
$this->fileFilter = $fileFilter; | ||
$this->updater = $updater; | ||
$this->writer = $writer; | ||
} | ||
|
||
/** | ||
* @return ResultCacheFileFilter | ||
*/ | ||
public function getFileFilter() | ||
{ | ||
return $this->fileFilter; | ||
} | ||
|
||
/** | ||
* @return ResultCacheUpdater | ||
*/ | ||
public function getUpdater() | ||
{ | ||
return $this->updater; | ||
} | ||
|
||
/** | ||
* @return ResultCacheWriter | ||
*/ | ||
public function getWriter() | ||
{ | ||
return $this->writer; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
<?php | ||
|
||
namespace PHPMD\Cache; | ||
|
||
use PHPMD\RuleSet; | ||
use PHPMD\TextUI\CommandLineOptions; | ||
|
||
class ResultCacheEngineFactory | ||
{ | ||
/** @var ResultCacheKeyFactory */ | ||
private $cacheKeyFactory; | ||
/** @var ResultCacheStateFactory */ | ||
private $cacheStateFactory; | ||
|
||
public function __construct(ResultCacheKeyFactory $cacheKeyFactory, ResultCacheStateFactory $cacheStateFactory) | ||
{ | ||
$this->cacheKeyFactory = $cacheKeyFactory; | ||
$this->cacheStateFactory = $cacheStateFactory; | ||
} | ||
|
||
/** | ||
* @param string $basePath | ||
* @param RuleSet[] $ruleSetList | ||
* @return ResultCacheEngine|null | ||
*/ | ||
public function create($basePath, CommandLineOptions $options, array $ruleSetList) | ||
{ | ||
if ($options->isCacheEnabled() === false) { | ||
return null; | ||
} | ||
|
||
// create cache key based on the current rules and environment | ||
$cacheKey = $this->cacheKeyFactory->create($options->hasStrict(), $ruleSetList); | ||
|
||
// load result cache from file | ||
$state = $this->cacheStateFactory->fromFile($options->cacheFile()); | ||
|
||
// the cache key doesn't match the stored cache key. Invalidate cache | ||
if ($state !== null && $state->getCacheKey()->isEqualTo($cacheKey) === false) { | ||
$state = null; | ||
} | ||
|
||
return new ResultCacheEngine( | ||
new ResultCacheFileFilter($basePath, $options->cacheStrategy(), $cacheKey, $state), | ||
new ResultCacheUpdater($basePath), | ||
new ResultCacheWriter($options->cacheFile()) | ||
); | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
To be able to create a RuleViolation without
Node
, changed signature to NodeInfo object that's serializable.