From 0f35babffcebe912a62d46704a0386a188bdbd52 Mon Sep 17 00:00:00 2001 From: Tim Otten Date: Thu, 28 Jul 2016 15:49:36 -0700 Subject: [PATCH] CRM_Core_CodeGen_Reflection::needsUpdate() - Imitate DAO's check The old check was prone to false-positives if you make unrelated changes in `CRM/Core/CodeGen/*` and false-negatives when some hacks the underlying file. It's now more diligent. --- CRM/Core/CodeGen/BaseTask.php | 26 ++++++++++++++++++++++++ CRM/Core/CodeGen/DAO.php | 14 +++---------- CRM/Core/CodeGen/Reflection.php | 36 +++++++++++++++++++++++++++++---- 3 files changed, 61 insertions(+), 15 deletions(-) diff --git a/CRM/Core/CodeGen/BaseTask.php b/CRM/Core/CodeGen/BaseTask.php index 73bf72a5d7..83fcf1a410 100644 --- a/CRM/Core/CodeGen/BaseTask.php +++ b/CRM/Core/CodeGen/BaseTask.php @@ -57,4 +57,30 @@ abstract class CRM_Core_CodeGen_BaseTask implements CRM_Core_CodeGen_ITask { } } + /** + * Determine if two snippets of PHP code are approximately equivalent. + * + * This includes exceptions to equivalence for (a) whitespace and (b) + * the token "GenCodeChecksum". + * + * This is useful for determining if someone has manually mucked with + * one the files. However, it's not perfect -- because whitespace changes + * are not detected. Hence, it's good to use in combination with another + * heuristic. + * + * @param $actual + * @param $expected + * @return bool + */ + protected function isApproxPhpMatch($actual, $expected) { + $actual = preg_replace(';\(GenCodeChecksum:([a-zA-Z0-9]+)\);', '', $actual); + $actual = preg_replace(';[ \r\n\t];', '', $actual); + + $expected = preg_replace(';\(GenCodeChecksum:([a-zA-Z0-9]+)\);', '', + $expected); + $expected = preg_replace(';[ \r\n\t];', '', $expected); + + return $actual === $expected; + } + } diff --git a/CRM/Core/CodeGen/DAO.php b/CRM/Core/CodeGen/DAO.php index 632f3479c7..503ba3eb24 100644 --- a/CRM/Core/CodeGen/DAO.php +++ b/CRM/Core/CodeGen/DAO.php @@ -34,21 +34,13 @@ class CRM_Core_CodeGen_DAO extends CRM_Core_CodeGen_BaseTask { return TRUE; } - // Has the table metadata changed since the DAO was generated? if ($this->getTableChecksum() !== self::extractRegex($this->getAbsFileName(), ';\(GenCodeChecksum:([a-zA-Z0-9]+)\);')) { return TRUE; } - // Has someone messed with the logic of the DAO? - // Compare suggested+actual code (modulo whitespace). - $stripped['actual'] = file_get_contents($this->getAbsFileName()); - $stripped['expect'] = $this->getRaw(); - - foreach (array('actual', 'expect') as $key) { - $stripped[$key] = preg_replace(';\(GenCodeChecksum:([a-zA-Z0-9]+)\);', '', $stripped[$key]); - $stripped[$key] = preg_replace(';[ \r\n\t];', '', $stripped[$key]); - } - return $stripped['actual'] !== $stripped['expect']; + return !$this->isApproxPhpMatch( + file_get_contents($this->getAbsFileName()), + $this->getRaw()); } public function run() { diff --git a/CRM/Core/CodeGen/Reflection.php b/CRM/Core/CodeGen/Reflection.php index f47c8a0741..8741e2a0cd 100644 --- a/CRM/Core/CodeGen/Reflection.php +++ b/CRM/Core/CodeGen/Reflection.php @@ -7,6 +7,11 @@ class CRM_Core_CodeGen_Reflection extends CRM_Core_CodeGen_BaseTask { protected $checksum; + /** + * @var string + */ + private $raw; + /** * @return bool * TRUE if an update is needed. @@ -15,17 +20,40 @@ class CRM_Core_CodeGen_Reflection extends CRM_Core_CodeGen_BaseTask { if (!file_exists($this->getAbsFileName())) { return TRUE; } - return $this->getChecksum() !== self::extractRegex($this->getAbsFileName(), ';\(GenCodeChecksum:([a-z0-9]+)\);'); + + if ($this->getSchemaChecksum() !== self::extractRegex($this->getAbsFileName(), ';\(GenCodeChecksum:([a-zA-Z0-9]+)\);')) { + return TRUE; + } + + return !$this->isApproxPhpMatch( + file_get_contents($this->getAbsFileName()), + $this->getRaw()); } + public function run() { echo "Generating table list\n"; $template = new CRM_Core_CodeGen_Util_Template('php'); $template->assign('tables', $this->tables); - $template->assign('genCodeChecksum', $this->getChecksum()); + $template->assign('genCodeChecksum', $this->getSchemaChecksum()); $template->run('listAll.tpl', $this->getAbsFileName()); } + /** + * Generate the raw PHP code for the data file. + * + * @return string + */ + public function getRaw() { + if (!$this->raw) { + $template = new CRM_Core_CodeGen_Util_Template('php'); + $template->assign('tables', $this->tables); + $template->assign('genCodeChecksum', 'NEW'); + $this->raw = $template->fetch('listAll.tpl'); + } + return $this->raw; + } + /** * @return string */ @@ -33,11 +61,11 @@ class CRM_Core_CodeGen_Reflection extends CRM_Core_CodeGen_BaseTask { return $this->config->CoreDAOCodePath . "AllCoreTables.data.php"; } - protected function getChecksum() { + protected function getSchemaChecksum() { if (!$this->checksum) { CRM_Utils_Array::flatten($this->tables, $flat); ksort($flat); - $this->checksum = md5($this->config->getSourceDigest() . json_encode($flat)); + $this->checksum = md5(json_encode($flat)); } return $this->checksum; } -- 2.25.1