require_once 'CRM/Core/ClassLoader.php';
CRM_Core_ClassLoader::singleton()->register();
-$genCode = new CRM_GenCode_Main('../CRM/Core/DAO/', '../sql/', '../', '../templates/');
-$genCode->main(
- @$argv[2],
- @$argv[3],
- empty($argv[1]) ? 'schema/Schema.xml' : $argv[1]
+$genCode = new CRM_GenCode_Main(
+ '../CRM/Core/DAO/', // $CoreDAOCodePath
+ '../sql/', // $sqlCodePath
+ '../', // $phpCodePath
+ '../templates/', // $tplCodePath
+ array('../packages/Smarty/plugins', '../CRM/Core/Smarty/plugins'), // smarty plugin dirs
+ @$argv[3], // cms
+ empty($argv[2]) ? NULL : $argv[2], // db version
+ empty($argv[1]) ? 'schema/Schema.xml' : $argv[1], // schema file
+ getenv('CIVICRM_GENCODE_DIGEST') ? getenv('CIVICRM_GENCODE_DIGEST') : NULL // path to digest file
);
+$genCode->main();
class CRM_GenCode_Util_File {
static function createDir($dir, $perm = 0755) {
}
$newTempDir = $tempDir . '/' . $prefix . rand(1, 10000);
+ if (function_exists('posix_geteuid')) {
+ $newTempDir .= '_' . posix_geteuid();
+ }
if (file_exists($newTempDir)) {
self::removeDir($newTempDir);
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 path to the main Civi source tree
+ *
+ * @return string
+ * @throws RuntimeException
+ */
+ static function findCoreSourceDir() {
+ $path = str_replace(DIRECTORY_SEPARATOR, '/', __DIR__);
+ if (!preg_match(':(.*)/xml:', $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;
+ }
}
class CRM_GenCode_Main {
var $buildVersion;
+ var $db_version;
var $compileDir;
var $classNames;
+ var $cms; // drupal, joomla, wordpress
var $CoreDAOCodePath;
var $sqlCodePath;
var $phpCodePath;
var $tplCodePath;
+ var $schemaPath; // ex: schema/Schema.xml
+
+ /**
+ * @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;
var $smarty;
- function __construct($CoreDAOCodePath, $sqlCodePath, $phpCodePath, $tplCodePath) {
+ function __construct($CoreDAOCodePath, $sqlCodePath, $phpCodePath, $tplCodePath, $smartyPluginDirs, $argCms, $argVersion, $schemaPath, $digestPath) {
$this->CoreDAOCodePath = $CoreDAOCodePath;
$this->sqlCodePath = $sqlCodePath;
$this->phpCodePath = $phpCodePath;
$this->tplCodePath = $tplCodePath;
+ $this->cms = $argCms;
+ $this->digestPath = $digestPath;
+ $this->digest = NULL;
require_once 'Smarty/Smarty.class.php';
$this->smarty = new Smarty();
$this->smarty->template_dir = './templates';
- $this->smarty->plugins_dir = array('../packages/Smarty/plugins', '../CRM/Core/Smarty/plugins');
+ $this->smarty->plugins_dir = $smartyPluginDirs;
$this->compileDir = CRM_GenCode_Util_File::createTempDir('templates_c_');
$this->smarty->compile_dir = $this->compileDir;
$this->smarty->clear_all_cache();
$this->beautifier->setNewLine("\n");
CRM_GenCode_Util_File::createDir($this->sqlCodePath);
+
+ $versionFile = "version.xml";
+ $versionXML = &$this->parseInput($versionFile);
+ $this->db_version = $versionXML->version_no;
+ $this->buildVersion = preg_replace('/^(\d{1,2}\.\d{1,2})\.(\d{1,2}|\w{4,7})$/i', '$1', $this->db_version);
+ if (isset($argVersion)) {
+ // change the version to that explicitly passed, if any
+ $this->db_version = $argVersion;
+ }
+
+ $this->schemaPath = $schemaPath;
}
function __destruct() {
/**
* Automatically generate a variety of files
*
- * @param $argVersion string, optional
- * @param $argCms string, optional; "drupal" or "joomla"
- * @param $file, the path to the XML schema file
*/
- function main($argVersion, $argCms, $file) {
- $versionFile = "version.xml";
- $versionXML = &$this->parseInput($versionFile);
- $db_version = $versionXML->version_no;
- $this->buildVersion = preg_replace('/^(\d{1,2}\.\d{1,2})\.(\d{1,2}|\w{4,7})$/i', '$1', $db_version);
- if (isset($argVersion)) {
- // change the version to that explicitly passed, if any
- $db_version = $argVersion;
+ function main() {
+ if (!empty($this->digestPath) && file_exists($this->digestPath) && $this->hasExpectedFiles()) {
+ 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 := $db_version\n\n";
+
+
+ echo "\ncivicrm_domain.version := ". $this->db_version . "\n\n";
if ($this->buildVersion < 1.1) {
echo "The Database is not compatible for this version";
exit();
exit();
}
- $this->generateTemplateVersion($db_version);
+ $this->generateTemplateVersion();
- $this->setupCms($argCms, $db_version);
+ $this->setupCms($this->db_version);
- echo "Parsing input file $file\n";
- $dbXML = $this->parseInput($file);
+ echo "Parsing input file ".$this->schemaPath."\n";
+ $dbXML = $this->parseInput($this->schemaPath);
// print_r( $dbXML );
echo "Extracting database information\n";
// $this->generateDropSql($archiveTables, 'civicrm_archive_drop.mysql');
$this->generateNavigation();
- $this->generateLocalDataSql($db_version, $this->findLocales());
+ $this->generateLocalDataSql($this->findLocales());
$this->generateSample();
$this->generateInstallLangs();
$this->generateDAOs($tables);
$this->generateSchemaStructure($tables);
+
+ if (!empty($this->digestPath)) {
+ file_put_contents($this->digestPath, $this->getDigest());
+ }
}
function generateListAll($tables) {
file_put_contents($this->sqlCodePath . "civicrm_navigation.mysql", $this->smarty->fetch('civicrm_navigation.tpl'));
}
- function generateLocalDataSql($db_version, $locales) {
+ function generateLocalDataSql($locales) {
$this->reset_smarty_assignments();
global $tsLocale;
$data[] = $this->smarty->fetch('civicrm_data.tpl');
$data[] = $this->smarty->fetch('civicrm_navigation.tpl');
- $data[] = " UPDATE civicrm_domain SET version = '$db_version';";
+ $data[] = " UPDATE civicrm_domain SET version = '" . $this->db_version . "';";
$data = implode("\n", $data);
$this->beautifier->save();
}
- function generateTemplateVersion($dbVersion) {
- file_put_contents($this->tplCodePath . "/CRM/common/version.tpl", $dbVersion);
+ function generateTemplateVersion() {
+ file_put_contents($this->tplCodePath . "/CRM/common/version.tpl", $this->db_version);
}
function findLocales() {
return $locales;
}
- function setupCms($argCms, $db_version) {
+ function setupCms() {
// default cms is 'drupal', if not specified
- $cms = isset($argCms) ? strtolower($argCms) : 'drupal';
- if (!in_array($cms, array(
- 'drupal', 'joomla'))) {
- echo "Config file for '{$cms}' not known.";
+ $this->cms = isset($this->cms) ? strtolower($this->cms) : 'drupal';
+ if (!in_array($this->cms, array(
+ 'drupal', 'joomla', 'wordpress'))) {
+ echo "Config file for '{$this->cms}' not known.";
exit();
}
- elseif ($cms !== 'joomla') {
- echo "Generating civicrm.config.php\n";
- copy("../{$cms}/civicrm.config.php.{$cms}", '../civicrm.config.php');
+ elseif ($this->cms !== 'joomla') {
+ $configTemplate = $this->findConfigTemplate($this->cms);
+ if ($configTemplate) {
+ echo "Generating civicrm.config.php\n";
+ copy($configTemplate, '../civicrm.config.php');
+ } else {
+ throw new Exception("Failed to locate template for civicrm.config.php");
+ }
}
echo "Generating civicrm-version file\n";
- $this->smarty->assign('db_version', $db_version);
- $this->smarty->assign('cms', ucwords($cms));
+ $this->smarty->assign('db_version', $this->db_version);
+ $this->smarty->assign('cms', ucwords($this->cms));
file_put_contents($this->phpCodePath . "civicrm-version.php", $this->smarty->fetch('civicrm_version.tpl'));
}
+ /**
+ * @param string $cms "drupal"|"wordpress"
+ * @return null|string path to config template
+ */
+ public function findConfigTemplate($cms) {
+ $candidates = array();
+ switch ($cms) {
+ case 'drupal':
+ $candidates[] = "../drupal/civicrm.config.php.drupal";
+ $candidates[] = "../../drupal/civicrm.config.php.drupal";
+ break;
+ case 'wordpress':
+ $candidates[] = "../../civicrm.config.php.wordpress";
+ $candidates[] = "../WordPress/civicrm.config.php.wordpress";
+ $candidates[] = "../drupal/civicrm.config.php.drupal";
+ break;
+ }
+ foreach ($candidates as $candidate) {
+ if (file_exists($candidate)) {
+ return $candidate;
+ break;
+ }
+ }
+ return NULL;
+ }
+
// -----------------------------
// ---- Schema manipulation ----
// -----------------------------
}
$field['required'] = $this->value('required', $fieldXML);
+ $field['collate'] = $this->value('collate', $fieldXML);
$field['comment'] = $this->value('comment', $fieldXML);
$field['default'] = $this->value('default', $fieldXML);
$field['import'] = $this->value('import', $fieldXML);
$this->smarty->clear_all_cache();
$this->smarty->assign('generated', "DO NOT EDIT. Generated by " . basename(__FILE__));
}
+
+
+ /**
+ * 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_GenCode_Util_File::findCoreSourceDir();
+ $files = CRM_GenCode_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_GenCode_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;
+ }
+
+ function getExpectedFiles() {
+ return array(
+ $this->sqlCodePath . '/civicrm.mysql',
+ $this->phpCodePath . '/CRM/Contact/DAO/Contact.php',
+ );
+ }
+
+ function hasExpectedFiles() {
+ foreach ($this->getExpectedFiles() as $file) {
+ if (!file_exists($file)) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+ }
}