Merge branch 'develop' into feature/fast-theme-compilation2

This commit is contained in:
odain-cbd
2020-08-17 00:18:15 +02:00
committed by GitHub
217 changed files with 4447 additions and 3598 deletions

View File

@@ -320,14 +320,27 @@ class MFCompiler
}
else
{
/** @var \DOMElement $oClass */
/** @var \MFElement $oClass */
foreach($oClasses as $oClass)
{
$sClass = $oClass->getAttribute("id");
$aAllClasses[] = $sClass;
try
{
$sCompiledCode .= $this->CompileClass($oClass, $sTempTargetDir, $sFinalTargetDir, $sRelativeDir);
$aCompiledClasses = $this->CompileClass($oClass, $sTempTargetDir, $sFinalTargetDir, $sRelativeDir);
foreach ($aCompiledClasses['required_files'] as $sIncludeFile)
{
$sCompiledCode .= "require_once('$sIncludeFile');\n";
}
foreach ($aCompiledClasses['code'] as $sClass => $sCompiledClass)
{
$sClassFileName = DIRECTORY_SEPARATOR.$sRelativeDir.DIRECTORY_SEPARATOR.'src'.DIRECTORY_SEPARATOR.'Model'.DIRECTORY_SEPARATOR.$sClass.'.php';
$sClassFile = "{$sTempTargetDir}{$sClassFileName}";
$this->WritePHPFile($sClassFile, $sModuleName, $sModuleVersion, $sCompiledClass);
$sCompiledCode .= "require_once ('{$sFinalTargetDir}{$sClassFileName}');\n";
}
}
catch (DOMFormatException $e)
{
@@ -468,49 +481,7 @@ EOF;
// Write the code into the given module as model.<module>.php
//
$sResultFile = $sTempTargetDir.'/'.$sRelativeDir.'/model.'.$sModuleName.'.php';
if (is_file($sResultFile))
{
$this->Log("Updating $sResultFile for module $sModuleName in version $sModuleVersion ($iClassCount classes)");
} else
{
$sResultDir = dirname($sResultFile);
if (!is_dir($sResultDir))
{
$this->Log("Creating directory $sResultDir");
mkdir($sResultDir, 0777, true);
}
$this->Log("Creating $sResultFile for module $sModuleName in version $sModuleVersion ($iClassCount classes)");
}
// Compile the module into a single file
//
$sCurrDate = date(DATE_ISO8601);
$sAuthor = 'iTop compiler';
$sLicence = 'http://opensource.org/licenses/AGPL-3.0';
$sFileHeader =
<<<EOF
<?php
//
// File generated by ... on the $sCurrDate
// Please do not edit manually
//
/**
* Classes and menus for $sModuleName (version $sModuleVersion)
*
* @author $sAuthor
* @license $sLicence
*/
EOF;
$ret = file_put_contents($sResultFile, $sFileHeader.$sCompiledCode);
if ($ret === false)
{
$iLen = strlen($sFileHeader.$sCompiledCode);
$fFree = @disk_free_space(dirname($sResultFile));
$aErr = error_get_last();
throw new Exception("Failed to write '$sResultFile'. Last error: '{$aErr['message']}', content to write: $iLen bytes, available free space on disk: $fFree.");
}
$this->WritePHPFile($sResultFile, $sModuleName, $sModuleVersion, $sCompiledCode);
}
else
{
@@ -613,8 +584,8 @@ EOF;
SetupUtils::builddir($sTempTargetDir.'/core');
$sPHPFile = $sTempTargetDir.'/core/main.php';
file_put_contents($sPHPFile, $this->sMainPHPCode);
$sCurrDate = date(DATE_ISO8601);
// Autoload
$sPHPFile = $sTempTargetDir.'/autoload.php';
$sPHPFileContent =
@@ -1020,7 +991,7 @@ EOF
* @param string $sFinalTargetDir
* @param string $sModuleRelativeDir
*
* @return string
* @return array
* @throws \DOMFormatException
*/
protected function CompileClass($oClass, $sTempTargetDir, $sFinalTargetDir, $sModuleRelativeDir)
@@ -1999,7 +1970,7 @@ EOF
$sClassName = $oClass->getAttribute('id');
$bIsAbstractClass = ($oProperties->GetChildText('abstract') == 'true');
$oPhpParent = $oClass->GetUniqueElement('php_parent', false);
$aRequiredFiles = array();
$aRequiredFiles = [];
if ($oPhpParent)
{
$sParentClass = $oPhpParent->GetChildText('name', '');
@@ -2032,8 +2003,7 @@ $sZlists;
EOF;
// some other stuff (magical attributes like friendlyName) are done in MetaModel::InitClasses and though not present in the
// generated PHP
$sPHP = $this->GeneratePhpCodeForClass($sClassName, $sParentClass, $sClassParams, $sInitMethodCalls,
$bIsAbstractClass, $sMethods, $aRequiredFiles, $sCodeComment);
$aPHP[$sClassName] = $this->GeneratePhpCodeForClass($sClassName, $sParentClass, $sClassParams, $sInitMethodCalls, $bIsAbstractClass, $sMethods, $sCodeComment);
// N°931 generates TagFieldData classes for AttributeTag fields
if (!empty($aTagFieldsInfo))
@@ -2062,11 +2032,11 @@ EOF
{
$sTagClassName = static::GetTagDataClassName($sClassName, $sTagFieldName);
$sTagClassParams = var_export($aTagClassParams, true);
$sPHP .= $this->GeneratePhpCodeForClass($sTagClassName, $sTagClassParentClass, $sTagClassParams, $sTagInitMethodCalls);
$aPHP[$sTagClassName] = $this->GeneratePhpCodeForClass($sTagClassName, $sTagClassParentClass, $sTagClassParams, $sTagInitMethodCalls);
}
}
return $sPHP;
return ['code' => $aPHP, 'required_files' => $aRequiredFiles];
}
private static function GetTagDataClassName($sClass, $sAttCode)
@@ -3018,22 +2988,21 @@ EOF;
* @param bool $bIsAbstractClass
* @param string $sMethods
*
* @param array $aRequiredFiles
* @param string $sCodeComment
*
* @return string php code for the class
*/
private function GeneratePhpCodeForClass(
$sClassName, $sParentClassName, $sClassParams, $sInitMethodCalls = '', $bIsAbstractClass = false, $sMethods = '',
$aRequiredFiles = array(), $sCodeComment = ''
$sClassName,
$sParentClassName,
$sClassParams,
$sInitMethodCalls = '',
$bIsAbstractClass = false,
$sMethods = '',
$sCodeComment = ''
) {
$sPHP = "\n\n$sCodeComment\n";
foreach ($aRequiredFiles as $sIncludeFile)
{
$sPHP .= "\nrequire_once('$sIncludeFile');\n";
}
if ($bIsAbstractClass)
{
$sPHP .= 'abstract class '.$sClassName;
@@ -3173,4 +3142,53 @@ XML;
$this->WriteFile("$sTempTargetDir/web.config", $sContent);
}
/**
* @param $sResultFile
* @param $sModuleName
* @param $sModuleVersion
* @param $sCompiledCode
*
* @throws \Exception
*/
protected function WritePHPFile($sResultFile, $sModuleName, $sModuleVersion, $sCompiledCode)
{
if (is_file($sResultFile))
{
$this->Log("Updating $sResultFile for module $sModuleName in version $sModuleVersion");
}
else
{
$sResultDir = dirname($sResultFile);
if (!is_dir($sResultDir))
{
$this->Log("Creating directory $sResultDir");
mkdir($sResultDir, 0777, true);
}
$this->Log("Creating $sResultFile for module $sModuleName in version $sModuleVersion");
}
// Compile the module into a single file
//
$sCurrDate = date(DATE_ISO8601);
$sAuthor = 'iTop compiler';
$sLicence = 'http://opensource.org/licenses/AGPL-3.0';
$sFileHeader =
<<<EOF
<?php
//
// File generated by ... on the $sCurrDate
// Please do not edit manually
//
/**
* Classes and menus for $sModuleName (version $sModuleVersion)
*
* @author $sAuthor
* @license $sLicence
*/
EOF;
$this->WriteFile($sResultFile, $sFileHeader.$sCompiledCode);
}
}

View File

@@ -277,7 +277,6 @@ class iTopExtensionsMap
$oExtension->sVersion = $oXml->Get('version');
$oExtension->bMandatory = ($oXml->Get('mandatory') == 'true');
$oExtension->sMoreInfoUrl = $oXml->Get('more_info_url');
$oExtension->sVersion = $oXml->Get('version');
$oExtension->sSource = $sSource;
$oExtension->sSourceDir = $sSearchDir;

View File

@@ -256,18 +256,21 @@ class MFModule
public function GetDictionaryFiles()
{
$aDictionaries = array();
if ($hDir = opendir($this->sRootDir))
foreach (array($this->sRootDir, $this->sRootDir.'/dictionaries') as $sRootDir)
{
while (($sFile = readdir($hDir)) !== false)
if ($hDir = @opendir($sRootDir))
{
$aMatches = array();
if (preg_match("/^[^\\.]+.dict.".$this->sName.'.php$/i', $sFile,
$aMatches)) // Dictionary files are named like <Lang>.dict.<ModuleName>.php
while (($sFile = readdir($hDir)) !== false)
{
$aDictionaries[] = $this->sRootDir.'/'.$sFile;
$aMatches = array();
if (preg_match("/^[^\\.]+.dict.".$this->sName.'.php$/i', $sFile,
$aMatches)) // Dictionary files are named like <Lang>.dict.<ModuleName>.php
{
$aDictionaries[] = $sRootDir.'/'.$sFile;
}
}
closedir($hDir);
}
closedir($hDir);
}
return $aDictionaries;
@@ -466,18 +469,21 @@ class MFDictModule extends MFModule
public function GetDictionaryFiles()
{
$aDictionaries = array();
if ($hDir = opendir($this->sRootDir))
foreach (array($this->sRootDir, $this->sRootDir.'/dictionaries') as $sRootDir)
{
while (($sFile = readdir($hDir)) !== false)
if ($hDir = @opendir($sRootDir))
{
$aMatches = array();
if (preg_match("/^.*dictionary\\.itop.*.php$/i", $sFile,
$aMatches)) // Dictionary files are named like <Lang>.dict.<ModuleName>.php
while (($sFile = readdir($hDir)) !== false)
{
$aDictionaries[] = $this->sRootDir.'/'.$sFile;
$aMatches = array();
if (preg_match("/^.*dictionary\\.itop.*.php$/i", $sFile,
$aMatches)) // Dictionary files are named like <Lang>.dict.<ModuleName>.php
{
$aDictionaries[] = $sRootDir.'/'.$sFile;
}
}
closedir($hDir);
}
closedir($hDir);
}
return $aDictionaries;
@@ -2898,4 +2904,4 @@ class MFParameters
return $merged;
}
}
}

View File

@@ -134,17 +134,20 @@ class ModuleDiscovery
{
$sModuleName = $aMatches[1];
$sDir = dirname($sFilePath);
if ($hDir = opendir($sDir))
foreach (array($sDir, $sDir.'/dictionaries') as $sRootDir)
{
while (($sFile = readdir($hDir)) !== false)
if ($hDir = @opendir($sRootDir))
{
$aMatches = array();
if (preg_match("/^[^\\.]+.dict.$sModuleName.php$/i", $sFile, $aMatches)) // Dictionary files named like <Lang>.dict.<ModuleName>.php are loaded automatically
while (($sFile = readdir($hDir)) !== false)
{
self::$m_aModules[$sId]['dictionary'][] = self::$m_sModulePath.'/'.$sFile;
$aMatches = array();
if (preg_match("/^[^\\.]+.dict.$sModuleName.php$/i", $sFile, $aMatches)) // Dictionary files named like <Lang>.dict.<ModuleName>.php are loaded automatically
{
self::$m_aModules[$sId]['dictionary'][] = $sRootDir.'/'.$sFile;
}
}
closedir($hDir);
}
closedir($hDir);
}
}
}

View File

@@ -39,6 +39,50 @@ class CheckResult
$this->sLabel = $sLabel;
$this->sDescription = $sDescription;
}
/**
* @return string
* @since 2.8.0 N°2214
*/
public function __toString()
{
$sPrintDesc = (empty($this->sDescription)) ? '' : " ({$this->sDescription})";
return "{$this->sLabel}$sPrintDesc";
}
/**
* @param \CheckResult[] $aResults
*
* @return \CheckResult[] only elements that are error (iSeverity===ERROR)
*
* @since 2.8.0 N°2214
*/
public static function KeepOnlyErrors($aResults)
{
return array_filter($aResults,
static function ($v)
{
if ($v->iSeverity === CheckResult::ERROR) {
return $v;
}
},
ARRAY_FILTER_USE_BOTH);
}
/**
* @param \CheckResult[] $aResults
*
* @return string[]
* @uses \CheckResult::__toString
*
* @since 2.8.0 N°2214
*/
public static function FromObjectsToStrings($aResults)
{
return array_map(function ($value) {
return $value->__toString();
}, $aResults);
}
}
/**
@@ -50,15 +94,15 @@ class CheckResult
class SetupUtils
{
// -- Minimum versions (requirements : forbids installation if not met)
const PHP_MIN_VERSION = '5.6.0'; // 5.6 will be supported until the end of 2018 (see http://php.net/supported-versions.php)
const PHP_MIN_VERSION = '7.1.3'; // 7 will be supported until the end of 2019 (see http://php.net/supported-versions.php)
const MYSQL_MIN_VERSION = '5.6.0'; // 5.6 to have fulltext on InnoDB for Tags fields (N°931)
const MYSQL_NOT_VALIDATED_VERSION = ''; // MySQL 8 is now OK (N°2010 in 2.7.0) but has no query cache so mind the perf on large volumes !
// -- versions that will be the minimum in next iTop major release (warning if not met)
const PHP_NEXT_MIN_VERSION = '7.1.3'; // we are aiming on switching to Symfony 4 in iTop 2.8
const PHP_NEXT_MIN_VERSION = ''; //
const MYSQL_NEXT_MIN_VERSION = ''; // no new MySQL requirement for next iTop version
// -- First recent version that is not yet validated by Combodo (warning)
const PHP_NOT_VALIDATED_VERSION = '7.5.0';
const PHP_NOT_VALIDATED_VERSION = '8.0.0';
const MIN_MEMORY_LIMIT = 33554432; // 32 * 1024 * 1024 - we can use expressions in const since PHP 5.6 but we are in the setup !
const SUHOSIN_GET_MAX_VALUE_LENGTH = 2048;
@@ -370,6 +414,37 @@ class SetupUtils
return $aResult;
}
/**
* @param \CLIPage $oCliPage
* @param int $iExitCode
*
* @since 2.8.0 N°2214
*/
public static function CheckPhpAndExtensionsForCli($oCliPage, $iExitCode = -1)
{
$aPhpCheckResults = self::CheckPhpAndExtensions();
$aPhpCheckErrors = CheckResult::KeepOnlyErrors($aPhpCheckResults);
if (empty($aPhpCheckErrors))
{
return;
}
$sMessageTitle = 'Error: PHP minimum requirements are not met !';
$oCliPage->p($sMessageTitle);
$aPhpCheckErrorsForPrint = CheckResult::FromObjectsToStrings($aPhpCheckErrors);
foreach ($aPhpCheckErrorsForPrint as $sError)
{
$oCliPage->p(' * '.$sError);
}
$oCliPage->output();
// some CLI scripts are launched automatically
// we need a log so that we don't miss errors after migration !
IssueLog::Error($oCliPage->s_title.' '.$sMessageTitle, 'CLI', $aPhpCheckErrorsForPrint);
exit($iExitCode);
}
/**
* @param CheckResult[] $aResult checks log
*/