N.890.1 and N.890.2: build a new run time environment into a separate "build" directory, then commit it by the mean of quick and bullet proof file copies/moves. Not yet used in the setup.

SVN:trunk[4881]
This commit is contained in:
Romain Quetiez
2017-08-29 08:08:24 +00:00
parent 43709576c0
commit 3d72060bf5
4 changed files with 174 additions and 19 deletions

View File

@@ -3267,8 +3267,8 @@ abstract class MetaModel
{
if (!method_exists($sClass, $actionHandler))
{
$aErrors[$sClass][] = "Unknown function '$sActionHandler' in transition [$sStateCode/$sStimulusCode] for state attribute '$sStateAttCode'";
$aSugFix[$sClass][] = "Specify a function which prototype is in the form [public function $sActionHandler(\$sStimulusCode){return true;}]";
$aErrors[$sClass][] = "Unknown function '$actionHandler' in transition [$sStateCode/$sStimulusCode] for state attribute '$sStateAttCode'";
$aSugFix[$sClass][] = "Specify a function which prototype is in the form [public function $actionHandler(\$sStimulusCode){return true;}]";
}
}
else // if(is_array($actionHandler))
@@ -4597,7 +4597,7 @@ abstract class MetaModel
protected static $m_aExtensionClasses = array();
protected static function IncludeModule($sToInclude, $sModuleType = null)
public static function IncludeModule($sToInclude, $sModuleType = null)
{
$sFirstChar = substr($sToInclude, 0, 1);
$sSecondChar = substr($sToInclude, 1, 1);

View File

@@ -1025,7 +1025,7 @@ class ApplicationInstaller
// Record which modules are installed...
$oProductionEnv = new RunTimeEnvironment($sTargetEnvironment);
$oProductionEnv->InitDataModel($oConfig, true); // load data model and connect to the database
if (!$oProductionEnv->RecordInstallation($oConfig, $sDataModelVersion, $aSelectedModuleCodes, $aSelectedExtensionCodes, $sModulesDir))
if (!$oProductionEnv->RecordInstallation($oConfig, $sDataModelVersion, $aSelectedModuleCodes, $aSelectedExtensionCodes))
{
throw new Exception("Failed to record the installation information");
}

View File

@@ -93,13 +93,14 @@ class MFCompiler
* @param string $sTargetDir The target directory where to put the resulting files
* @param Page $oP For some output...
* @param bool $bUseSymbolicLinks
* @param bool $bSkipTempDir
* @throws Exception
* @return void
*/
public function Compile($sTargetDir, $oP = null, $bUseSymbolicLinks = false)
public function Compile($sTargetDir, $oP = null, $bUseSymbolicLinks = false, $bSkipTempDir = false)
{
$sFinalTargetDir = $sTargetDir;
if ($bUseSymbolicLinks)
if ($bUseSymbolicLinks || $bSkipTempDir)
{
// Skip the creation of a temporary dictionary, not compatible with symbolic links
$sTempTargetDir = $sFinalTargetDir;
@@ -480,16 +481,16 @@ EOF;
{
$this->Log("Compilation of module $sModuleName in version $sModuleVersion produced not code at all. No file written.");
}
// files to include (PHP datamodels)
foreach($oModule->GetFilesToInclude('business') as $sRelFileName)
{
$aDataModelFiles[] = "MetaModel::IncludeModule('".basename($sFinalTargetDir).'/'.$sRelativeDir.'/'.$sRelFileName."');";
$aDataModelFiles[] = "MetaModel::IncludeModule(MODULESROOT.'/$sRelativeDir/$sRelFileName');";
}
// files to include (PHP webservices providers)
foreach($oModule->GetFilesToInclude('webservices') as $sRelFileName)
{
$aWebservicesFiles[] = "MetaModel::IncludeModule('".basename($sFinalTargetDir).'/'.$sRelativeDir.'/'.$sRelFileName."');";
$aWebservicesFiles[] = "MetaModel::IncludeModule(MODULESROOT.'/$sRelativeDir/$sRelFileName');";
}
} // foreach module
@@ -577,7 +578,7 @@ EOF;
EOF
;
$sPHPFileContent .= "\nMetaModel::IncludeModule('".basename($sFinalTargetDir)."/core/main.php');\n";
$sPHPFileContent .= "\nMetaModel::IncludeModule(MODULESROOT.'/core/main.php');\n";
$sPHPFileContent .= implode("\n", $aDataModelFiles);
$sPHPFileContent .= implode("\n", $aWebservicesFiles);
$sPHPFileContent .= "\nfunction GetModulesInfo()\n{\nreturn ".var_export($aModulesInfo, true).";\n}\n";

View File

@@ -40,20 +40,55 @@ define ('DATAMODEL_MODULE', 'datamodel'); // Convention to store the version of
class RunTimeEnvironment
{
/**
* The name of the environment that the caller wants to build
* @var string sFinalEnv
*/
protected $sFinalEnv;
/**
* Environment into which the build will be performed
* @var string sTargetEnv
*/
protected $sTargetEnv;
/**
* Extensions map of the source environment
* @var iTopExtensionsMap
*/
protected $oExtensionsMap;
public function __construct($sEnvironment = 'production')
/**
* Toolset for building a run-time environment
*
* @param string $sEnvironment (e.g. 'test')
* @param bool $bAutoCommit (make the target environment directly, or build a temporary one)
*/
public function __construct($sEnvironment = 'production', $bAutoCommit = true)
{
$this->sTargetEnv = $sEnvironment;
$this->sFinalEnv = $sEnvironment;
if ($bAutoCommit)
{
// Build directly onto the requested environment
$this->sTargetEnv = $sEnvironment;
}
else
{
// Build into a temporary target
$this->sTargetEnv = $sEnvironment.'-build';
}
$this->oExtensionsMap = null;
}
/**
* Return the full path to the compiled code (do not use after commit)
* @return string
*/
public function GetBuildDir()
{
return APPROOT.'env-'.$this->sTargetEnv;
}
/**
* Callback function for logging the queries run by the setup.
* According to the documentation the function must be defined before passing it to call_user_func...
@@ -429,7 +464,7 @@ class RunTimeEnvironment
}
}
while($bModuleAdded);
$sDeltaFile = APPROOT.'data/'.$this->sTargetEnv.'.delta.xml';
if (file_exists($sDeltaFile))
{
@@ -495,11 +530,12 @@ class RunTimeEnvironment
// No delta was loaded, let's save the datamodel now
$oFactory->SaveToFile(APPROOT.'data/datamodel-'.$this->sTargetEnv.'.xml');
}
$sTargetDir = APPROOT.'env-'.$this->sTargetEnv;
self::MakeDirSafe($sTargetDir);
$bSkipTempDir = ($this->sFinalEnv != $this->sTargetEnv); // No need for a temporary directory if sTargetEnv is already a temporary directory
$oMFCompiler = new MFCompiler($oFactory);
$oMFCompiler->Compile($sTargetDir, null, $bUseSymLinks);
$oMFCompiler->Compile($sTargetDir, null, $bUseSymLinks, $bSkipTempDir);
$sCacheDir = APPROOT.'data/cache-'.$this->sTargetEnv;
SetupUtils::builddir($sCacheDir);
@@ -653,7 +689,7 @@ class RunTimeEnvironment
$oConfig->Set('access_mode', $iPrevAccessMode);
}
public function RecordInstallation(Config $oConfig, $sDataModelVersion, $aSelectedModuleCodes, $aSelectedExtensionCodes, $sModulesRelativePath, $sShortComment = null)
public function RecordInstallation(Config $oConfig, $sDataModelVersion, $aSelectedModuleCodes, $aSelectedExtensionCodes, $sShortComment = null)
{
// Have it work fine even if the DB has been set in read-only mode for the users
$iPrevAccessMode = $oConfig->Get('access_mode');
@@ -698,7 +734,7 @@ class RunTimeEnvironment
// Record installed modules and extensions
//
$aAvailableExtensions = array();
$aAvailableModules = $this->AnalyzeInstallation($oConfig, APPROOT.$sModulesRelativePath);
$aAvailableModules = $this->AnalyzeInstallation($oConfig, $this->GetBuildDir());
foreach($aSelectedModuleCodes as $sModuleId)
{
$aModuleData = $aAvailableModules[$sModuleId];
@@ -870,4 +906,122 @@ class RunTimeEnvironment
}
return $oLatestDM->Get('version');
}
public function Commit()
{
if ($this->sFinalEnv != $this->sTargetEnv)
{
$this->CommitFile(
APPROOT.'data/'.$this->sTargetEnv.'.delta.xml',
APPROOT.'data/'.$this->sFinalEnv.'.delta.xml',
false
);
$this->CommitFile(
APPROOT.'data/datamodel-'.$this->sTargetEnv.'.xml',
APPROOT.'data/datamodel-'.$this->sFinalEnv.'.xml'
);
$this->CommitFile(
APPROOT.'data/datamodel-'.$this->sTargetEnv.'-with-delta.xml',
APPROOT.'data/datamodel-'.$this->sFinalEnv.'-with-delta.xml',
false
);
$this->CommitDir(
APPROOT.'data/'.$this->sTargetEnv.'-modules/',
APPROOT.'data/'.$this->sFinalEnv.'-modules/',
false
);
$this->CommitDir(
APPROOT.'data/cache-'.$this->sTargetEnv,
APPROOT.'data/cache-'.$this->sFinalEnv,
false
);
$this->CommitDir(
APPROOT.'env-'.$this->sTargetEnv,
APPROOT.'env-'.$this->sFinalEnv
);
$sTargetConfig = APPCONF.$this->sTargetEnv.'/config-itop.php';
$sFinalConfig = APPCONF.$this->sFinalEnv.'/config-itop.php';
@chmod($sFinalConfig, 0770); // In case it exists: RWX for owner and group, nothing for others
$this->CommitFile($sTargetConfig, $sFinalConfig);
@chmod($sFinalConfig, 0440); // Read-only for owner and group, nothing for others
}
}
/**
* Overwrite or create the destination file
*
* @param $sSource
* @param $sDest
* @param bool $bSourceMustExist
* @throws Exception
*/
protected function CommitFile($sSource, $sDest, $bSourceMustExist = true)
{
if (file_exists($sSource))
{
SetupUtils::builddir(dirname($sDest));
if (file_exists($sDest))
{
$bRes = @unlink($sDest);
if (!$bRes)
{
throw new Exception('Commit - Failed to cleanup destination file: '.$sDest);
}
}
rename($sSource, $sDest);
}
else
{
// The file does not exist
if ($bSourceMustExist)
{
throw new Exception('Commit - Missing file: '.$sSource);
}
else
{
// Align the destination with the source... make sure there is NO file
if (file_exists($sDest))
{
$bRes = @unlink($sDest);
if (!$bRes)
{
throw new Exception('Commit - Failed to cleanup destination file: '.$sDest);
}
}
}
}
}
/**
* Overwrite or create the destination directory
*
* @param $sSource
* @param $sDest
* @param bool $bSourceMustExist
* @throws Exception
*/
protected function CommitDir($sSource, $sDest, $bSourceMustExist = true)
{
if (file_exists($sSource))
{
SetupUtils::movedir($sSource, $sDest);
}
else
{
// The file does not exist
if ($bSourceMustExist)
{
throw new Exception('Commit - Missing directory: '.$sSource);
}
else
{
// Align the destination with the source... make sure there is NO file
if (file_exists($sDest))
{
SetupUtils::rrmdir($sDest);
}
}
}
}
} // End of class