Przeglądaj źródła

#721 Unmet dependencies not detected

git-svn-id: http://svn.code.sf.net/p/itop/code/trunk@2739 a333f486-631f-4898-b8df-5754b55c2be0
romainq 12 lat temu
rodzic
commit
682f300b1e

+ 25 - 21
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 = "<ul><b>Warning: the following modules have unmet dependencies, and have been ignored:</b>\n";			
+			$aModuleDeps = array();			
 			foreach($aDependencies as $sId => $aDeps)
 			{
 				$aModule = self::$m_aModules[$sId];
-				$sHtml.= "<li>{$aModule['label']} (id: $sId), depends on: ".implode(', ', $aDeps)."</li>";
-			}
-			$sHtml .= "</ul>\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);
 		}
 	}
 	

+ 4 - 2
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);

+ 34 - 2
setup/setuputils.class.inc.php

@@ -337,6 +337,33 @@ class SetupUtils
 	}
 
 	/**
+	 * 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
 	 * @return array An array of CheckResults objects
@@ -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;
 	}

+ 51 - 2
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('<input type="hidden" id="installer_parameters" value="'.htmlentities($sJSONData, ENT_QUOTES, 'UTF-8').'"/>');
 
+		if (!$this->CheckDependencies())
+		{
+			$oPage->error($this->sDependencyIssue);
+		}
+
 		$oPage->add_ready_script(
 <<<EOF
 	$("#params_summary div").addClass('closed');