diff --git a/setup/modulediscovery.class.inc.php b/setup/modulediscovery.class.inc.php
index 14c1a79d0..c8a7924bd 100644
--- a/setup/modulediscovery.class.inc.php
+++ b/setup/modulediscovery.class.inc.php
@@ -23,6 +23,10 @@
* @license http://opensource.org/licenses/AGPL-3.0
*/
+class MissingDependencyException extends Exception
+{
+}
+
class ModuleDiscovery
{
static $m_aModuleArgs = array(
@@ -106,13 +110,22 @@ class ModuleDiscovery
}
}
- protected static function GetModules($oP = null)
+ /**
+ *
+ * @param bool $bAbortOnMissingDependency ...
+ * @param hash $aModulesToLoad List of modules to search for, defaults to all if ommitted
+ */
+ protected static function GetModules($bAbortOnMissingDependency = false, $aModulesToLoad = null)
{
// Order the modules to take into account their inter-dependencies
$aDependencies = array();
foreach(self::$m_aModules as $sId => $aModule)
{
- $aDependencies[$sId] = $aModule['dependencies'];
+ list($sModuleName, $sModuleVersion) = self::GetModuleName($sId);
+ if (is_null($aModulesToLoad) || in_array($sModuleName, $aModulesToLoad))
+ {
+ $aDependencies[$sId] = $aModule['dependencies'];
+ }
}
ksort($aDependencies);
$aOrderedModules = array();
@@ -137,27 +150,16 @@ class ModuleDiscovery
}
$iLoopCount++;
}
- if (count($aDependencies) >0)
+ if ($bAbortOnMissingDependency && count($aDependencies) > 0)
{
- $sHtml = "
Warning: the following modules have unmet dependencies, and have been ignored:\n";
+ $aModuleDeps = array();
foreach($aDependencies as $sId => $aDeps)
{
$aModule = self::$m_aModules[$sId];
- $sHtml.= "
{$aModule['label']} (id: $sId), depends on: ".implode(', ', $aDeps)."
";
- }
- $sHtml .= "
\n";
- if ($oP instanceof SetupPage)
- {
- $oP->warning($sHtml); // used in the context of the installation
- }
- elseif (class_exists('SetupPage'))
- {
- SetupPage::log_warning($sHtml); // used in the context of ?
- }
- else
- {
- echo $sHtml; // used in the context of the compiler
+ $aModuleDeps[] = "{$aModule['label']} (id: $sId) depends on ".implode(' + ', $aDeps);
}
+ $sMessage = "The following modules have unmet dependencies: ".implode(', ', $aModuleDeps);
+ throw new MissingDependencyException($sMessage);
}
// Return the ordered list, so that the dependencies are met...
$aResult = array();
@@ -207,9 +209,11 @@ class ModuleDiscovery
* Search (on the disk) for all defined iTop modules, load them and returns the list (as an array)
* of the possible iTop modules to install
* @param aSearchDirs Array of directories to search (absolute paths)
+ * @param bool $bAbortOnMissingDependency ...
+ * @param hash $aModulesToLoad List of modules to search for, defaults to all if ommitted
* @return Hash A big array moduleID => ModuleData
*/
- public static function GetAvailableModules($aSearchDirs, $oP = null)
+ public static function GetAvailableModules($aSearchDirs, $bAbortOnMissingDependency = false, $aModulesToLoad = null)
{
if (self::$m_aSearchDirs != $aSearchDirs)
{
@@ -232,12 +236,12 @@ class ModuleDiscovery
clearstatcache();
self::ListModuleFiles(basename($sSearchDir), dirname($sSearchDir));
}
- return self::GetModules($oP);
+ return self::GetModules($bAbortOnMissingDependency, $aModulesToLoad);
}
else
{
// Reuse the previous results
- return self::GetModules($oP);
+ return self::GetModules($bAbortOnMissingDependency, $aModulesToLoad);
}
}
diff --git a/setup/runtimeenv.class.inc.php b/setup/runtimeenv.class.inc.php
index bb78849bb..b11a521cc 100644
--- a/setup/runtimeenv.class.inc.php
+++ b/setup/runtimeenv.class.inc.php
@@ -95,6 +95,8 @@ class RunTimeEnvironment
*
* @param Config $oConfig Defines the target environment (DB)
* @param mixed $modulesPath Either a single string or an array of absolute paths
+ * @param bool $bAbortOnMissingDependency ...
+ * @param hash $aModulesToLoad List of modules to search for, defaults to all if ommitted
* @return hash Array with the following format:
* array =>
* 'iTop' => array(
@@ -118,7 +120,7 @@ class RunTimeEnvironment
* )
* )
*/
- public function AnalyzeInstallation($oConfig, $modulesPath)
+ public function AnalyzeInstallation($oConfig, $modulesPath, $bAbortOnMissingDependency = false, $aModulesToLoad = null)
{
$aRes = array(
ROOT_MODULE => array(
@@ -130,7 +132,7 @@ class RunTimeEnvironment
);
$aDirs = is_array($modulesPath) ? $modulesPath : array($modulesPath);
- $aModules = ModuleDiscovery::GetAvailableModules($aDirs);
+ $aModules = ModuleDiscovery::GetAvailableModules($aDirs, $bAbortOnMissingDependency, $aModulesToLoad);
foreach($aModules as $sModuleId => $aModuleInfo)
{
list($sModuleName, $sModuleVersion) = ModuleDiscovery::GetModuleName($sModuleId);
diff --git a/setup/setuputils.class.inc.php b/setup/setuputils.class.inc.php
index d788e49a2..53a530497 100644
--- a/setup/setuputils.class.inc.php
+++ b/setup/setuputils.class.inc.php
@@ -336,6 +336,33 @@ class SetupUtils
return $aResult;
}
+ /**
+ * Check that the selected modules meet their dependencies
+ */
+ static function CheckSelectedModules($sSourceDir, $sExtensionDir, $aSelectedModules)
+ {
+ $aResult = array();
+ SetupPage::log('Info - CheckSelectedModules');
+
+ $aDirsToScan = array(APPROOT.$sSourceDir);
+ $sExtensionsPath = APPROOT.$sExtensionDir;
+ if (is_dir($sExtensionsPath))
+ {
+ // if the extensions dir exists, scan it for additional modules as well
+ $aDirsToScan[] = $sExtensionsPath;
+ }
+ require_once(APPROOT.'setup/modulediscovery.class.inc.php');
+ try
+ {
+ ModuleDiscovery::GetAvailableModules($aDirsToScan, true, $aSelectedModules);
+ }
+ catch(MissingDependencyException $e)
+ {
+ $aResult[] = new CheckResult(CheckResult::ERROR, $e->getMessage());
+ }
+ return $aResult;
+ }
+
/**
* Check that the backup could be executed
* @param Page $oP The page used only for its 'log' method
@@ -1008,7 +1035,12 @@ EOF
return $sHtml;
}
- public static function AnalyzeInstallation($oWizard)
+ /**
+ *
+ * @param bool $bAbortOnMissingDependency ...
+ * @param array $aModulesToLoad List of modules to search for, defaults to all if ommitted
+ */
+ public static function AnalyzeInstallation($oWizard, $bAbortOnMissingDependency = false, $aModulesToLoad = null)
{
require_once(APPROOT.'/setup/moduleinstaller.class.inc.php');
$oConfig = new Config();
@@ -1048,7 +1080,7 @@ EOF
$aDirsToScan[] = $oWizard->GetParameter('copy_extensions_from');
}
$oProductionEnv = new RunTimeEnvironment();
- $aAvailableModules = $oProductionEnv->AnalyzeInstallation($oConfig, $aDirsToScan);
+ $aAvailableModules = $oProductionEnv->AnalyzeInstallation($oConfig, $aDirsToScan, $bAbortOnMissingDependency, $aModulesToLoad);
return $aAvailableModules;
}
diff --git a/setup/wizardsteps.class.inc.php b/setup/wizardsteps.class.inc.php
index 8383cd698..6738b4887 100644
--- a/setup/wizardsteps.class.inc.php
+++ b/setup/wizardsteps.class.inc.php
@@ -1095,6 +1095,16 @@ class WizStepModulesChoice extends WizardStep
protected function DisplayStep($oPage)
{
+ // Sanity check (not stopper, to let developpers go further...)
+ try
+ {
+ SetupUtils::AnalyzeInstallation($this->oWizard, true);
+ }
+ catch(MissingDependencyException $e)
+ {
+ $oPage->warning($e->getMessage());
+ }
+
$this->bUpgrade = ($this->oWizard->GetParameter('install_mode') != 'install');
$aStepInfo = $this->GetStepInfo();
$oPage->add_style("div.choice { margin: 0.5em;}");
@@ -1657,6 +1667,28 @@ EOF
*/
class WizStepSummary extends WizardStep
{
+ protected $bDependencyCheck = null;
+ protected $sDependencyIssue = null;
+
+ protected function CheckDependencies()
+ {
+ if (is_null($this->bDependencyCheck))
+ {
+ $aSelectedModules = json_decode($this->oWizard->GetParameter('selected_modules'), true);
+ $this->bDependencyCheck = true;
+ try
+ {
+ SetupUtils::AnalyzeInstallation($this->oWizard, true, $aSelectedModules);
+ }
+ catch(MissingDependencyException $e)
+ {
+ $this->bDependencyCheck = false;
+ $this->sDependencyIssue = $e->getMessage();
+ }
+ }
+ return $this->bDependencyCheck;
+ }
+
public function GetTitle()
{
$sMode = $this->oWizard->GetParameter('mode', 'install');
@@ -1684,7 +1716,19 @@ class WizStepSummary extends WizardStep
{
return ' Install ! ';
}
-
+
+ public function CanMoveForward()
+ {
+ if ($this->CheckDependencies())
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
public function ProcessParams($bMoveForward = true)
{
return array('class' => 'WizStepDone', 'state' => '');
@@ -1736,7 +1780,7 @@ class WizStepSummary extends WizardStep
}
EOF
);
-
+
$aInstallParams = $this->BuildConfig();
$sMode = $aInstallParams['mode'];
@@ -1847,6 +1891,11 @@ EOF
$sJSONData = json_encode($aInstallParams);
$oPage->add('');
+ if (!$this->CheckDependencies())
+ {
+ $oPage->error($this->sDependencyIssue);
+ }
+
$oPage->add_ready_script(
<<