Skip to content

Commit 03e25a2

Browse files
committed
Merge branch 'faf/moduledependency-enhancement' into develop
2 parents d8121b5 + 24048d2 commit 03e25a2

21 files changed

+1692
-488
lines changed

datamodels/2.x/itop-endusers-devices/datamodel.itop-enduser-devices.xml renamed to datamodels/2.x/itop-endusers-devices/datamodel.itop-endusers-devices.xml

File renamed without changes.

datamodels/2.x/itop-hub-connector/hubruntimeenvironment.class.inc.php

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<?php
2+
23
class HubRunTimeEnvironment extends RunTimeEnvironment
3-
{
4+
{
45
/**
56
* Constructor
67
* @param string $sEnvironment
@@ -9,21 +10,18 @@ class HubRunTimeEnvironment extends RunTimeEnvironment
910
public function __construct($sEnvironment = 'production', $bAutoCommit = true)
1011
{
1112
parent::__construct($sEnvironment, $bAutoCommit);
12-
13-
if ($sEnvironment != $this->sTargetEnv)
14-
{
15-
if (is_dir(APPROOT.'/env-'.$this->sTargetEnv))
16-
{
17-
SetupUtils::rrmdir(APPROOT.'/env-'.$this->sTargetEnv);
18-
}
19-
if (is_dir(APPROOT.'/data/'.$this->sTargetEnv.'-modules'))
20-
{
21-
SetupUtils::rrmdir(APPROOT.'/data/'.$this->sTargetEnv.'-modules');
22-
}
13+
14+
if ($sEnvironment != $this->sTargetEnv) {
15+
if (is_dir(APPROOT.'/env-'.$this->sTargetEnv)) {
16+
SetupUtils::rrmdir(APPROOT.'/env-'.$this->sTargetEnv);
17+
}
18+
if (is_dir(APPROOT.'/data/'.$this->sTargetEnv.'-modules')) {
19+
SetupUtils::rrmdir(APPROOT.'/data/'.$this->sTargetEnv.'-modules');
20+
}
2321
SetupUtils::copydir(APPROOT.'/data/'.$sEnvironment.'-modules', APPROOT.'/data/'.$this->sTargetEnv.'-modules');
2422
}
2523
}
26-
24+
2725
/**
2826
* Update the includes for the target environment
2927
* @param Config $oConfig
@@ -32,29 +30,31 @@ public function UpdateIncludes(Config $oConfig)
3230
{
3331
$oConfig->UpdateIncludes('env-'.$this->sTargetEnv); // TargetEnv != FinalEnv
3432
}
35-
33+
3634
/**
3735
* Move an extension (path to folder of this extension) to the target environment
3836
* @param string $sExtensionDirectory The folder of the extension
3937
* @throws Exception
4038
*/
4139
public function MoveExtension($sExtensionDirectory)
4240
{
43-
if (!is_dir(APPROOT.'/data/'.$this->sTargetEnv.'-modules'))
44-
{
45-
if (!mkdir(APPROOT.'/data/'.$this->sTargetEnv.'-modules')) throw new Exception("ERROR: failed to create directory:'".(APPROOT.'/data/'.$this->sTargetEnv.'-modules')."'");
41+
if (!is_dir(APPROOT.'/data/'.$this->sTargetEnv.'-modules')) {
42+
if (!mkdir(APPROOT.'/data/'.$this->sTargetEnv.'-modules')) {
43+
throw new Exception("ERROR: failed to create directory:'".(APPROOT.'/data/'.$this->sTargetEnv.'-modules')."'");
44+
}
4645
}
4746
$sDestinationPath = APPROOT.'/data/'.$this->sTargetEnv.'-modules/';
48-
47+
4948
// Make sure that the destination directory of the extension does not already exist
50-
if (is_dir($sDestinationPath.basename($sExtensionDirectory)))
51-
{
52-
// Cleanup before moving...
53-
SetupUtils::rrmdir($sDestinationPath.basename($sExtensionDirectory));
49+
if (is_dir($sDestinationPath.basename($sExtensionDirectory))) {
50+
// Cleanup before moving...
51+
SetupUtils::rrmdir($sDestinationPath.basename($sExtensionDirectory));
52+
}
53+
if (!rename($sExtensionDirectory, $sDestinationPath.basename($sExtensionDirectory))) {
54+
throw new Exception("ERROR: failed move directory:'$sExtensionDirectory' to '".$sDestinationPath.basename($sExtensionDirectory)."'");
5455
}
55-
if (!rename($sExtensionDirectory, $sDestinationPath.basename($sExtensionDirectory))) throw new Exception("ERROR: failed move directory:'$sExtensionDirectory' to '".$sDestinationPath.basename($sExtensionDirectory)."'");
5656
}
57-
57+
5858
/**
5959
* Move the selected extensions located in the given directory in data/<target-env>-modules
6060
* @param string $sDownloadedExtensionsDir The directory to scan
@@ -63,10 +63,8 @@ public function MoveExtension($sExtensionDirectory)
6363
*/
6464
public function MoveSelectedExtensions($sDownloadedExtensionsDir, $aSelectedExtensionDirs)
6565
{
66-
foreach(glob($sDownloadedExtensionsDir.'*', GLOB_ONLYDIR) as $sExtensionDir)
67-
{
68-
if (in_array(basename($sExtensionDir), $aSelectedExtensionDirs))
69-
{
66+
foreach (glob($sDownloadedExtensionsDir.'*', GLOB_ONLYDIR) as $sExtensionDir) {
67+
if (in_array(basename($sExtensionDir), $aSelectedExtensionDirs)) {
7068
$this->MoveExtension($sExtensionDir);
7169
}
7270
}

datamodels/2.x/itop-oauth-client/module.itop-oauth-client.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
//
1818
'dependencies' => [
1919
'itop-welcome-itil/3.1.0,',
20+
'itop-profiles-itil/3.1.0', //SuperUser id 117
2021
],
2122
'mandatory' => false,
2223
'visible' => true,

datamodels/2.x/itop-portal-base/module.itop-portal-base.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
'category' => 'Portal',
2929
// Setup
3030
'dependencies' => [
31+
'itop-attachments/3.2.1', //CMDBChangeOpAttachmentRemoved
3132
],
3233
'mandatory' => true,
3334
'visible' => false,

datamodels/2.x/itop-tickets/module.itop-tickets.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
//
1414
'dependencies' => [
1515
'itop-structure/2.7.1',
16+
'itop-portal/3.0.0', // module_design_itop_design->module_designs->itop-portal
1617
],
1718
'mandatory' => false,
1819
'visible' => true,

lib/autoload.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@
1414
echo $err;
1515
}
1616
}
17-
throw new RuntimeException($err);
17+
trigger_error(
18+
$err,
19+
E_USER_ERROR
20+
);
1821
}
1922

2023
require_once __DIR__ . '/composer/autoload_real.php';

lib/composer/autoload_psr4.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161
'Psr\\Cache\\' => array($vendorDir . '/psr/cache/src'),
6262
'PhpParser\\' => array($vendorDir . '/nikic/php-parser/lib/PhpParser'),
6363
'Pelago\\Emogrifier\\' => array($vendorDir . '/pelago/emogrifier/src'),
64-
'League\\OAuth2\\Client\\' => array($vendorDir . '/league/oauth2-google/src', $vendorDir . '/league/oauth2-client/src'),
64+
'League\\OAuth2\\Client\\' => array($vendorDir . '/league/oauth2-client/src', $vendorDir . '/league/oauth2-google/src'),
6565
'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'),
6666
'GuzzleHttp\\Promise\\' => array($vendorDir . '/guzzlehttp/promises/src'),
6767
'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'),

lib/composer/autoload_static.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -340,8 +340,8 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
340340
),
341341
'League\\OAuth2\\Client\\' =>
342342
array (
343-
0 => __DIR__ . '/..' . '/league/oauth2-google/src',
344-
1 => __DIR__ . '/..' . '/league/oauth2-client/src',
343+
0 => __DIR__ . '/..' . '/league/oauth2-client/src',
344+
1 => __DIR__ . '/..' . '/league/oauth2-google/src',
345345
),
346346
'GuzzleHttp\\Psr7\\' =>
347347
array (

lib/composer/platform_check.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@
3636
echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
3737
}
3838
}
39-
throw new \RuntimeException(
40-
'Composer detected issues in your platform: ' . implode(' ', $issues)
39+
trigger_error(
40+
'Composer detected issues in your platform: ' . implode(' ', $issues),
41+
E_USER_ERROR
4142
);
4243
}
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
<?php
2+
3+
namespace Combodo\iTop\Setup\ModuleDependency;
4+
5+
require_once(APPROOT.'/setup/runtimeenv.class.inc.php');
6+
use Combodo\iTop\PhpParser\Evaluation\PhpExpressionEvaluator;
7+
use ModuleFileReaderException;
8+
use RunTimeEnvironment;
9+
10+
/**
11+
* Class that handles a module dependency
12+
* Dependency expression example : (moduleA/123 || moduleB>456)
13+
*/
14+
class DependencyExpression
15+
{
16+
private static PhpExpressionEvaluator $oPhpExpressionEvaluator;
17+
18+
private string $sDependencyExpression;
19+
private bool $bValid = true;
20+
private bool $bResolved = false;
21+
22+
/**
23+
* @var array<string, bool> $aRemainingModuleNamesToResolve
24+
*/
25+
private array $aRemainingModuleNamesToResolve;
26+
27+
/**
28+
* @var array<string, array> $aParamsPerModuleId
29+
*/
30+
private array $aParamsPerModuleId;
31+
32+
public function __construct(string $sDependencyExpression)
33+
{
34+
$this->sDependencyExpression = $sDependencyExpression;
35+
$this->aParamsPerModuleId = [];
36+
$this->aRemainingModuleNamesToResolve = [];
37+
38+
if (preg_match_all('/([^\(\)&| ]+)/', $sDependencyExpression, $aMatches)) {
39+
foreach ($aMatches as $aMatch) {
40+
foreach ($aMatch as $sModuleId) {
41+
if (! array_key_exists($sModuleId, $this->aParamsPerModuleId)) {
42+
// $sModuleId in the dependency string is made of a <name>/<optional_operator><version>
43+
// where the operator is < <= = > >= (by default >=)
44+
$aModuleMatches = [];
45+
if (preg_match('|^([^/]+)/(<?>?=?)([^><=]+)$|', $sModuleId, $aModuleMatches)) {
46+
$sModuleName = $aModuleMatches[1];
47+
$this->aRemainingModuleNamesToResolve[$sModuleName] = true;
48+
$sOperator = $aModuleMatches[2];
49+
if ($sOperator == '') {
50+
$sOperator = '>=';
51+
}
52+
$sExpectedVersion = $aModuleMatches[3];
53+
$this->aParamsPerModuleId[$sModuleId] = [$sModuleName, $sOperator, $sExpectedVersion];
54+
}
55+
}
56+
}
57+
}
58+
} else {
59+
$this->bValid = false;
60+
}
61+
}
62+
63+
private static function GetPhpExpressionEvaluator(): PhpExpressionEvaluator
64+
{
65+
if (!isset(static::$oPhpExpressionEvaluator)) {
66+
static::$oPhpExpressionEvaluator = new PhpExpressionEvaluator([], RunTimeEnvironment::STATIC_CALL_AUTOSELECT_WHITELIST);
67+
}
68+
69+
return static::$oPhpExpressionEvaluator;
70+
}
71+
72+
/**
73+
* Return module names potentially required by current dependency
74+
* @return array
75+
*/
76+
public function GetRemainingModuleNamesToResolve(): array
77+
{
78+
return array_keys($this->aRemainingModuleNamesToResolve);
79+
}
80+
81+
public function IsResolved(): bool
82+
{
83+
return $this->bResolved;
84+
}
85+
86+
/**
87+
* Check if dependency is resolved with current list of module versions
88+
* @param array $aModuleVersions: versions by module names dict
89+
* @param array $aSelectedModules: modules names dict
90+
*
91+
* @return void
92+
*/
93+
public function UpdateModuleResolutionState(array $aModuleVersions, array $aSelectedModules): void
94+
{
95+
if (!$this->bValid) {
96+
return;
97+
}
98+
99+
$aReplacements = [];
100+
foreach ($this->aParamsPerModuleId as $sModuleId => list($sModuleName, $sOperator, $sExpectedVersion)) {
101+
if (array_key_exists($sModuleName, $aModuleVersions)) {
102+
// module is present, check the version
103+
$sCurrentVersion = $aModuleVersions[$sModuleName];
104+
if (version_compare($sCurrentVersion, $sExpectedVersion, $sOperator)) {
105+
if (array_key_exists($sModuleName, $this->aRemainingModuleNamesToResolve)) {
106+
unset($this->aRemainingModuleNamesToResolve[$sModuleName]);
107+
}
108+
$aReplacements[$sModuleId] = '(true)'; // Add parentheses to protect against invalid condition causing
109+
// a function call that results in a runtime fatal error
110+
} else {
111+
$aReplacements[$sModuleId] = '(false)'; // Add parentheses to protect against invalid condition causing
112+
// a function call that results in a runtime fatal error
113+
}
114+
} else {
115+
// module is not present
116+
$aReplacements[$sModuleId] = '(false)'; // Add parentheses to protect against invalid condition causing
117+
// a function call that results in a runtime fatal error
118+
}
119+
}
120+
121+
foreach ($this->aRemainingModuleNamesToResolve as $sModuleName => $c) {
122+
if (array_key_exists($sModuleName, $aSelectedModules)) {
123+
// This module is actually a prerequisite
124+
if (!array_key_exists($sModuleName, $aModuleVersions)) {
125+
return;
126+
}
127+
}
128+
}
129+
130+
$bResult = false;
131+
$sBooleanExpr = str_replace(array_keys($aReplacements), array_values($aReplacements), $this->sDependencyExpression);
132+
try {
133+
$bResult = self::GetPhpExpressionEvaluator()->ParseAndEvaluateBooleanExpression($sBooleanExpr);
134+
} catch (ModuleFileReaderException $e) {
135+
//logged already
136+
echo "Failed to parse the boolean Expression = '$sBooleanExpr'<br/>";
137+
}
138+
139+
$this->bResolved = $bResult;
140+
}
141+
142+
public function IsValid(): bool
143+
{
144+
return $this->bValid;
145+
}
146+
}

0 commit comments

Comments
 (0)