Compare commits

..

2 Commits

Author SHA1 Message Date
Lenaick
9c6baaeef4 N°9984 - Exclude auto-select modules from selection check in unattended-install when not specified in choices (#1032) 2026-08-28 10:38:02 +02:00
Lenaick
e769e53653 N°9984 - Error while compiling iTop 3.3 with PMP Extended (#1029)
* N°9984 - Error while compiling iTop 3.3 with PMP Extended

* N°9984 - Error while compiling iTop 3.3 with PMP Extended
2026-08-28 10:01:44 +02:00
9 changed files with 71 additions and 100 deletions

View File

@@ -205,7 +205,7 @@ class DataFeatureRemovalController extends Controller
$oExtensionsMap = \iTopExtensionsMap::GetExtensionsMap($oRuntimeEnvironment->GetBuildEnv());
// Removed modules are stored as static for FindModules()
$oExtensionsMap->DeclareExtensionAsRemoved($aRemovedExtensions);
$aSelectedModules = $oRuntimeEnvironment->GetModulesToLoadFromChoices($oConfig, $aSelectedExtensions);
$aSelectedModules = $oRuntimeEnvironment->GetModulesToLoadFromSelectedExtensions($oConfig, $aSelectedExtensions);
}
DataFeatureRemovalLog::Debug(
@@ -217,7 +217,7 @@ class DataFeatureRemovalController extends Controller
Session::Unset('bForceCompilation');
} else {
if (count($aSelectedModules) === 0) {
$aSelectedModules = $oRuntimeEnvironment->GetModulesToLoadFromChoices($oConfig, $aSelectedExtensions);
$aSelectedModules = $oRuntimeEnvironment->GetModulesToLoadFromSelectedExtensions($oConfig, $aSelectedExtensions);
}
}
DataFeatureRemovalLog::Debug(__METHOD__.": modules", null, ['selected_modules' => $aSelectedModules]);

View File

@@ -34,7 +34,7 @@ class InstallationChoicesToModuleConverter
}
/**
* @param array<string> $aInstallationChoices
* @param array<string> $aSelectedExtensions
* @param array<string> $aSearchDirs
* @param string|null $sInstallationFilePath
* @param array|null $aExtensionDirs : module/extension dirs to load if they are compliant with choices
@@ -42,7 +42,7 @@ class InstallationChoicesToModuleConverter
* @return array<string>
* @throws \ModuleInstallationException
*/
public function GetModules(array $aInstallationChoices, array $aSearchDirs, ?string $sInstallationFilePath = null, ?array $aExtensionDirs = null): array
public function GetModules(array $aSelectedExtensions, array $aSearchDirs, ?string $sInstallationFilePath = null, ?array $aExtensionDirs = null): array
{
$aPackageModules = $this->GetAllModules($aSearchDirs);
@@ -54,9 +54,9 @@ class InstallationChoicesToModuleConverter
if (!is_array($aSteps)) {
return [];
}
$aInstalledModuleNames = $this->FindInstalledPackageModules($aPackageModules, $aInstallationChoices, $aSteps);
$aInstalledModuleNames = $this->FindInstalledPackageModules($aPackageModules, $aSelectedExtensions, $aSteps);
} else {
$aInstalledModuleNames = $this->FindInstalledPackageModules($aPackageModules, $aInstallationChoices);
$aInstalledModuleNames = $this->FindInstalledPackageModules($aPackageModules, $aSelectedExtensions);
}
$aInstalledModules = [];
@@ -68,20 +68,39 @@ class InstallationChoicesToModuleConverter
}
if (!is_null($aExtensionDirs)) {
foreach (array_keys($this->GetAllModules($aExtensionDirs)) as $sModuleId) {
$oModule = new Module($sModuleId);
foreach ($this->GetAllModules($aExtensionDirs) as $sModuleId => $aModule) {
if (!isset($aModule['auto_select'])) {
$oModule = new Module($sModuleId);
$sPreviousModuleId = $aInstalledModules[$oModule->GetModuleName()] ?? null;
if (is_null($sPreviousModuleId)) {
$aInstalledModules[$oModule->GetModuleName()] = $sModuleId;
continue;
}
$sPreviousModuleId = $aInstalledModules[$oModule->GetModuleName()] ?? null;
if (is_null($sPreviousModuleId)) {
$aInstalledModules[$oModule->GetModuleName()] = $sModuleId;
continue;
}
$oPreviousModule = new Module($sPreviousModuleId);
if (version_compare($oModule->GetVersion(), $oPreviousModule->GetVersion(), '>')) {
$aInstalledModules[$oModule->GetModuleName()] = $sModuleId;
$oPreviousModule = new Module($sPreviousModuleId);
if (version_compare($oModule->GetVersion(), $oPreviousModule->GetVersion(), '>')) {
$aInstalledModules[$oModule->GetModuleName()] = $sModuleId;
}
}
}
foreach ($this->GetAllModules($aExtensionDirs) as $sModuleId => $aModule) {
if ($this->IsAutoSelectedModule($aInstalledModules, $sModuleId, $aModule)) {
$oModule = new Module($sModuleId);
$sPreviousModuleId = $aInstalledModules[$oModule->GetModuleName()] ?? null;
if (is_null($sPreviousModuleId)) {
$aInstalledModules[$oModule->GetModuleName()] = $sModuleId;
continue;
}
$oPreviousModule = new Module($sPreviousModuleId);
if (version_compare($oModule->GetVersion(), $oPreviousModule->GetVersion(), '>')) {
$aInstalledModules[$oModule->GetModuleName()] = $sModuleId;
}
}
}
}
return array_values($aInstalledModules);

View File

@@ -1288,7 +1288,7 @@ class RunTimeEnvironment
$oConfig = new Config(utils::GetConfigFilePath($sSourceEnv));
$this->InitExtensionMap($oConfig);
$aSelectedExtensions = $this->GetExtensionMap()->GetSelectedExtensions($oConfig, $aAddedExtensions, []);
$aSelectedModules = $this->GetModulesToLoadFromChoices($oConfig, $aSelectedExtensions);
$aSelectedModules = $this->GetModulesToLoadFromSelectedExtensions($oConfig, $aSelectedExtensions);
return $this->DoCompile($aSelectedExtensions, [], $aSelectedModules, $bUseSymLinks ?? false);
}
@@ -1494,14 +1494,14 @@ class RunTimeEnvironment
* Return modules based on installation choices+package
*
* @param \Config $oConfig
* @param array|bool $aChoices
* @param array|bool $aSelectedExtensions
*
* @return array|null
* @throws \ModuleInstallationException
*/
public function GetModulesToLoadFromChoices(Config $oConfig, array|bool $aChoices): ?array
public function GetModulesToLoadFromSelectedExtensions(Config $oConfig, array|bool $aSelectedExtensions): ?array
{
if (false === $aChoices) {
if (false === $aSelectedExtensions) {
return null;
}
@@ -1515,16 +1515,14 @@ class RunTimeEnvironment
}
$aExtensionDirs = [];
$aFromSelectedExtensionModules = [];
foreach ($this->GetExtensionMap()->GetAllExtensions() as $oExtension) {
if (in_array($oExtension->sCode, $aChoices) && is_dir($oExtension->sSourceDir)) {
if (in_array($oExtension->sCode, $aSelectedExtensions) && is_dir($oExtension->sSourceDir)) {
$aExtensionDirs [] = $oExtension->sSourceDir;
$aFromSelectedExtensionModules = array_merge($aFromSelectedExtensionModules, $oExtension->aModules);
}
}
SetupLog::Info(__METHOD__, null, ['ext_dirs' => $aExtensionDirs]);
$aModuleIdsToLoad = InstallationChoicesToModuleConverter::GetInstance()->GetModules($aChoices, $aSearchDirs, $sInstallFilePath, $aExtensionDirs);
$aModuleIdsToLoad = InstallationChoicesToModuleConverter::GetInstance()->GetModules($aSelectedExtensions, $aSearchDirs, $sInstallFilePath, $aExtensionDirs);
$aModulesToLoad = [];
foreach ($aModuleIdsToLoad as $sModuleId) {

View File

@@ -343,7 +343,7 @@ class InstallationFileService
$aUnselectableModules = [];
$bIsExtensionSelectable = true;
foreach ($oExtension->aModules as $sModuleId) {
if (array_key_exists($sModuleId, $this->aSelectedModules)) {
if (array_key_exists($sModuleId, $this->aSelectedModules) || array_key_exists($sModuleId, $this->aAutoSelectModules)) {
//already selected
continue;
}

View File

@@ -97,18 +97,24 @@ class WizStepLandingBeforeAudit extends WizStepModulesChoice
}
}
}
// Save the choices for the summary step
$sDisplayChoices = '<ul>';
$i = 0;
foreach ($this->aSteps as $aStepInfo) {
$sDisplayChoices .= $this->GetSelectedModules($aStepInfo, $aSelectedComponents[$i], $aModules, '', '', $aExtensions);
$i++;
}
$sDisplayChoices .= '</ul>';
$this->oWizard->SetParameter('display_choices', $sDisplayChoices);
} else {
$this->GetWizardSteps();
$aSelectedComponents = $this->GetSelectedComponents($this->aSteps, $this->oWizard->GetParameter('selected_extensions', '[]'));
}
// Save the choices for the summary step
$sDisplayChoices = '<ul>';
$aModules = [];
$aExtensions = [];
$i = 0;
foreach ($this->aSteps as $aStepInfo) {
$sDisplayChoices .= $this->GetSelectedModules($aStepInfo, $aSelectedComponents[$i], $aModules, '', '', $aExtensions);
$i++;
}
$sDisplayChoices .= '</ul>';
$this->oWizard->SetParameter('display_choices', $sDisplayChoices);
$this->oWizard->SetParameter('selected_modules', json_encode(array_keys($aModules)));
return new WizardState(WizStepDataAudit::class);
}

View File

@@ -229,14 +229,14 @@ class WizStepModulesChoice extends AbstractWizStepInstall
$sExtensionCode = $aAlternativeInfo["extension_code"] ?? null;
if (in_array($sExtensionCode, $aExtensions)) {
$aStepRes = $this->ProcessSelectedOption($sCurrentIndex, $i, $aStepRes, $aAlternativeInfo, $aExtensions);
$aStepRes = $this->ProcessSelectedOption($sCurrentIndex, $i, $aStepRes, $aAlternativeInfo, $aExtensions, true);
break;
}
}
}
/**
* @param string $sCurrentIndex
* @param string $sCurrentId
* @param int|string $i
* @param array $aStepRes
* @param mixed $aOptionsInfo
@@ -244,18 +244,19 @@ class WizStepModulesChoice extends AbstractWizStepInstall
*
* @return array
*/
public function ProcessSelectedOption(string $sCurrentIndex, int|string $i, array $aStepRes, mixed $aOptionsInfo, array $aExtensions): array
public function ProcessSelectedOption(string $sCurrentId, int|string $i, array $aStepRes, mixed $aOptionsInfo, array $aExtensions, bool $bIsAlternative = false): array
{
$sNextIndex = "{$sCurrentIndex}_{$i}";
$aStepRes[$sNextIndex] = $sNextIndex;
$sNextId = "{$sCurrentId}_{$i}";
$sNextName = $bIsAlternative ? "{$sCurrentId}_0" : $sNextId;
$aStepRes[$sNextName] = $sNextId;
$aSubOptions = $aOptionsInfo['sub_options'] ?? null;
if (!is_null($aSubOptions) && is_array($aSubOptions)) {
$this->ProcessOptions($sNextIndex, $aSubOptions, $aExtensions, $aStepRes);
$this->ProcessAlternatives($sNextIndex, $aSubOptions, $aExtensions, $aStepRes);
$this->ProcessOptions($sNextId, $aSubOptions, $aExtensions, $aStepRes);
$this->ProcessAlternatives($sNextId, $aSubOptions, $aExtensions, $aStepRes);
}
$this->ProcessAlternatives($sNextIndex, $aOptionsInfo, $aExtensions, $aStepRes);
$this->ProcessAlternatives($sNextId, $aOptionsInfo, $aExtensions, $aStepRes);
return $aStepRes;
}
@@ -796,10 +797,6 @@ EOF
$bDisabled = !$bDisableUninstallCheck;
}
if ($bDisabled) {
$bChecked = $bInstalled;
}
if (isset($aChoice['sub_options'])) {
$aOptions = $aChoice['sub_options']['options'] ?? [];
foreach ($aOptions as $index => $aSubChoice) {

View File

@@ -73,7 +73,7 @@ class UnitTestRunTimeEnvironment extends RunTimeEnvironment
$oConfig = new Config(utils::GetConfigFilePath($sSourceEnv));
$this->InitExtensionMap($oConfig);
$aSelectedExtensions = $this->GetExtensionMap()->GetSelectedExtensions($oConfig, $aAddedExtensions, []);
$aSelectedModules = $this->GetModulesToLoadFromChoices($oConfig, $aSelectedExtensions);
$aSelectedModules = $this->GetModulesToLoadFromSelectedExtensions($oConfig, $aSelectedExtensions);
return $this->DoCompile(array_keys($aSelectedExtensions), [], $aSelectedModules, $bUseSymLinks ?? false);
} catch (DOMFormatException $e) {
$sFileName = $sSourceEnv.'.delta.xml';

View File

@@ -693,54 +693,6 @@ class WizStepModulesChoiceTest extends ItopTestCase
'mandatory' => false,
],
],
'#node17 - An installed non uninstallable extension should be checked and disabled when the "disable uninstallation check" flag is not set, even if it is not selected' => [
'aExtensionsOnDiskOrDb' => [
'itop-ext1' => [
'installed' => true,
],
],
'aWizardStepDefinition' => [
'extension_code' => 'itop-ext1',
'uninstallable' => false,
],
'aSelectedComponents' => [],
'bDisableUninstallChecks' => false,
'aExpectedFlags' => [
'uninstallable' => false,
'missing' => false,
'installed' => true,
'disabled' => true,
'checked' => true,
'dependency_issue' => false,
'mandatory' => false,
],
],
'#node18 - An installed but not selected extension with missing dependencies without force uninstall should be checked and disabled, even if it is not selected' => [
'aExtensionsOnDiskOrDb' => [
'itop-ext1' => [
'installed' => true,
'missing_dependencies' => [
'itop-ext1-1',
],
],
],
'aWizardStepDefinition' => [
'extension_code' => 'itop-ext1',
'uninstallable' => true,
'missing_dependencies' => true,
],
'aSelectedComponents' => [],
'bDisableUninstallChecks' => false,
'aExpectedFlags' => [
'uninstallable' => true,
'missing' => false,
'installed' => true,
'disabled' => true,
'checked' => true,
'dependency_issue' => true,
'mandatory' => false,
],
],
];
}
@@ -1687,10 +1639,10 @@ HTML,
$aParams = new XMLParameters(__DIR__.'/ressources/installation_330.xml');
$aSteps = $aParams->Get('steps', []);
$aSelectedExtensions = ["itop-config-mgmt-core","itop-config-mgmt-datacenter","itop-config-mgmt-end-user","itop-config-mgmt-storage","itop-config-mgmt-virtualization","itop-container-mgmt","itop-service-mgmt-enterprise","itop-ticket-mgmt-simple-ticket","itop-ticket-mgmt-simple-ticket-enhanced-portal","itop-change-mgmt-simple","itop-kown-error-mgmt","itop-problem-mgmt","combodo-oauth2-client","combodo-mfa-extended","combodo-data-replication","combodo-api-playground","combodo-snapshot"];
$aSelectedExtensions = ["itop-config-mgmt-core","itop-config-mgmt-datacenter","itop-config-mgmt-end-user","itop-config-mgmt-storage","itop-config-mgmt-virtualization","itop-container-mgmt","itop-service-mgmt-service-provider","itop-ticket-mgmt-itil","itop-ticket-mgmt-itil-user-request","itop-ticket-mgmt-itil-incident", "itop-ticket-mgmt-itil-enhanced-portal","itop-change-mgmt-simple","itop-kown-error-mgmt","itop-problem-mgmt","combodo-oauth2-client","combodo-mfa-extended","combodo-data-replication","combodo-api-playground","combodo-snapshot"];
$aRes = $this->oWizStepModulesChoiceFake->GetSelectedComponents($aSteps, json_encode($aSelectedExtensions));
$aExpected = json_decode('[{"_0":"_0","_1":"_1","_2":"_2","_3":"_3","_4":"_4","_4_0":"_4_0"},{"_0":"_0"},{"_0":"_0","_0_0":"_0_0"},{"_0":"_0"},{"_0":"_0","_1":"_1"}]', true);
$aExpected = json_decode('[{"_0":"_0","_1":"_1","_2":"_2","_3":"_3","_4":"_4","_4_0":"_4_0"},{"_0":"_1"},{"_0":"_1","_1_0":"_1_0", "_1_1": "_1_1", "_1_2": "_1_2"},{"_0":"_0"},{"_0":"_0","_1":"_1"}]', true);
$this->assertEquals($aExpected, $aRes);
}

View File

@@ -8,7 +8,6 @@ use Combodo\iTop\Setup\FeatureRemoval\SetupAudit;
use Combodo\iTop\Test\UnitTest\ItopCustomDatamodelTestCase;
use Combodo\iTop\Test\UnitTest\Service\UnitTestRunTimeEnvironment;
use Config;
use MetaModel;
use RunTimeEnvironment;
use SetupUtils;
use utils;
@@ -69,7 +68,7 @@ class SetupAuditTest extends ItopCustomDatamodelTestCase
$oConfig = new Config(utils::GetConfigFilePath($this->GetTestEnvironment()));
$aRemovedExtensions = ['nominal_ext1', 'finalclass_ext2'];
$aSelectedExtensions = DataFeatureRemoverExtensionService::GetInstance()->GetExtensionMap()->GetSelectedExtensions($oConfig, ['finalclass_ext1', 'finalclass_ext3'], $aRemovedExtensions);
$aSelectedModules = $oRuntimeEnvironment->GetModulesToLoadFromChoices($oConfig, $aSelectedExtensions);
$aSelectedModules = $oRuntimeEnvironment->GetModulesToLoadFromSelectedExtensions($oConfig, $aSelectedExtensions);
$oRuntimeEnvironment->DoCompile($aSelectedExtensions, $aRemovedExtensions, $aSelectedModules);