var $tplCodePath;
var $schemaPath; // ex: schema/Schema.xml
- function __construct($CoreDAOCodePath, $sqlCodePath, $phpCodePath, $tplCodePath, $smartyPluginDirs, $argCms, $argVersion, $schemaPath) {
+ /**
+ * @var string|NULL path in which to store a marker that indicates the last execution of
+ * GenCode. If a matching marker already exists, GenCode doesn't run.
+ */
+ var $digestPath;
+
+ /**
+ * @var string|NULL a digest of the inputs to the code-generator (eg the properties and source files)
+ */
+ var $digest;
+
+ function __construct($CoreDAOCodePath, $sqlCodePath, $phpCodePath, $tplCodePath, $smartyPluginDirs, $argCms, $argVersion, $schemaPath, $digestPath) {
$this->CoreDAOCodePath = $CoreDAOCodePath;
$this->sqlCodePath = $sqlCodePath;
$this->phpCodePath = $phpCodePath;
$this->tplCodePath = $tplCodePath;
+ $this->digestPath = $digestPath;
+ $this->digest = NULL;
// default cms is 'drupal', if not specified
$this->cms = isset($argCms) ? strtolower($argCms) : 'drupal';
*
*/
function main() {
+ if (!empty($this->digestPath) && file_exists($this->digestPath)) {
+ if ($this->getDigest() === file_get_contents($this->digestPath)) {
+ echo "GenCode has previously executed. To force execution, please (a) omit CIVICRM_GENCODE_DIGEST\n";
+ echo "or (b) remove {$this->digestPath} or (c) call GenCode with new parameters.\n";
+ exit();
+ }
+ // Once we start GenCode, the old build is invalid
+ unlink($this->digestPath);
+ }
+
echo "\ncivicrm_domain.version := ". $this->db_version . "\n\n";
if ($this->buildVersion < 1.1) {
echo "The Database is not compatible for this version";
$this->tables = $specification->tables;
$this->runAllTasks();
+
+ if (!empty($this->digestPath)) {
+ file_put_contents($this->digestPath, $this->getDigest());
+ }
}
function runAllTasks() {
// TODO: This configuration can be manipulated dynamically.
- $components = array(
- 'CRM_Core_CodeGen_Config',
- 'CRM_Core_CodeGen_Reflection',
- 'CRM_Core_CodeGen_Schema',
- 'CRM_Core_CodeGen_DAO',
- 'CRM_Core_CodeGen_Test',
- 'CRM_Core_CodeGen_I18n',
- );
+ $components = $this->getTasks();
foreach ($components as $component) {
$task = new $component($this);
}
}
}
+
+ /**
+ * @return array of class names; each class implements CRM_Core_CodeGen_ITask
+ */
+ public function getTasks() {
+ $components = array(
+ 'CRM_Core_CodeGen_Config',
+ 'CRM_Core_CodeGen_Reflection',
+ 'CRM_Core_CodeGen_Schema',
+ 'CRM_Core_CodeGen_DAO',
+ 'CRM_Core_CodeGen_Test',
+ 'CRM_Core_CodeGen_I18n',
+ );
+ return $components;
+ }
+
+ /**
+ * Compute a digest based on the inputs to the code-generator (ie the properties
+ * of the codegen and the source files loaded by the codegen).
+ *
+ * @return string
+ */
+ function getDigest() {
+ if ($this->digest === NULL) {
+ $srcDir = CRM_Core_CodeGen_Util_File::findCoreSourceDir();
+ $files = CRM_Core_CodeGen_Util_File::findManyFiles(array(
+ array("$srcDir/CRM/Core/CodeGen", '*.php'),
+ array("$srcDir/xml", "*.php"),
+ array("$srcDir/xml", "*.tpl"),
+ array("$srcDir/xml", "*.xml"),
+ ));
+
+ $properties = var_export(array(
+ CRM_Core_CodeGen_Util_File::digestAll($files),
+ $this->buildVersion,
+ $this->db_version,
+ $this->cms,
+ $this->CoreDAOCodePath,
+ $this->sqlCodePath,
+ $this->phpCodePath,
+ $this->tplCodePath,
+ $this->schemaPath,
+ $this->getTasks(),
+ ), TRUE);
+
+ $this->digest = md5($properties);
+ }
+ return $this->digest;
+ }
}
return $newTempDir;
}
+
+ /**
+ * Calculate a cumulative digest based on a collection of files
+ *
+ * @param array $files list of file names (strings)
+ * @param callable $digest a one-way hash function (string => string)
+ * @return string
+ */
+ static function digestAll($files, $digest = 'md5') {
+ $buffer = '';
+ foreach ($files as $file) {
+ $buffer .= $digest(file_get_contents($file));
+ }
+ return $digest($buffer);
+ }
+
+ /**
+ * Find the paths to all key files involved in the gen-code process
+ *
+ * @return array
+ * @throws RuntimeException
+ */
+ static function findCoreSourceDir() {
+ $path = str_replace(DIRECTORY_SEPARATOR, '/', __DIR__);
+ if (!preg_match(':(.*)/CRM/Core/CodeGen/Util:', $path, $matches)) {
+ throw new RuntimeException("Failed to determine path of code-gen");
+ }
+
+ return $matches[1];
+ }
+
+ /**
+ * Find files in several directories using several filename patterns
+ *
+ *
+ * @param array $pairs each item is an array(0 => $searchBaseDir, 1 => $filePattern)
+ * @return array of file paths
+ */
+ static function findManyFiles($pairs) {
+ $files = array();
+ foreach ($pairs as $pair) {
+ list ($dir, $pattern) = $pair;
+ $files = array_merge($files, CRM_Utils_File::findFiles($dir, $pattern));
+ }
+ return $files;
+ }
}