/** * core of the installation * @param ModuleInstallLauncher[] $modules * @param EntryPoint $ep the entrypoint * @param boolean $installWholeApp true if the installation is done during app installation * @param integer $flags to know what to do * @return boolean true if the installation is ok */ protected function _installModules(Resolver $resolver, EntryPoint $ep, $installWholeApp, $flags = 7) { $epId = $ep->getEpId(); $this->notice('install.entrypoint.start', $epId); $ep = $this->entryPoints[$epId]; App::setConfig($ep->getConfigObj()); if ($ep->getConfigObj()->disableInstallers) { $this->notice('install.entrypoint.installers.disabled'); } $moduleschain = $this->resolveDependencies($resolver, $epId); if ($moduleschain === false) { return false; } $componentsToInstall = $this->runPreInstall($moduleschain, $ep, $installWholeApp, $flags); if ($componentsToInstall === false) { $this->warning('install.entrypoint.bad.end', $epId); return false; } $installedModules = $this->runInstall($componentsToInstall, $ep, $epId, $flags); if ($installedModules === false) { $this->warning('install.entrypoint.bad.end', $epId); return false; } $result = $this->runPostInstall($installedModules, $ep, $flags); if (!$result) { $this->warning('install.entrypoint.bad.end', $epId); } else { $this->ok('install.entrypoint.end', $epId); } return $result; }
/** * return the list of objects which are responsible to upgrade the component * from the current installed version of the component. * * this method should be called after verifying and resolving * dependencies. Needed components (modules or plugins) should be * installed/upgraded before calling this method * * @param EntryPoint $ep the entry point * @throw \Jelix\Installer\Exception if an error occurs during the install. * @return ModuleInstaller[] */ function getUpgraders(EntryPoint $ep) { $epId = $ep->getEpId(); if ($this->moduleUpgraders === null) { $this->moduleUpgraders = array(); $p = $this->moduleInfos->getPath() . 'install/'; if (!file_exists($p) || $this->moduleStatuses[$epId]->skipInstaller) { return array(); } // we get the list of files for the upgrade $fileList = array(); if ($handle = opendir($p)) { while (false !== ($f = readdir($handle))) { if (!is_dir($p . $f)) { if (preg_match('/^upgrade_to_([^_]+)_([^\\.]+)\\.php$/', $f, $m)) { $fileList[] = array($f, $m[1], $m[2]); } else { if (preg_match('/^upgrade_([^\\.]+)\\.php$/', $f, $m)) { $fileList[] = array($f, '', $m[1]); } } } } closedir($handle); } if (!count($fileList)) { return array(); } // now we order the list of file foreach ($fileList as $fileInfo) { require_once $p . $fileInfo[0]; $cname = $this->moduleInfos->name . 'ModuleUpgrader_' . $fileInfo[2]; if (!class_exists($cname)) { throw new Exception("module.upgrader.class.not.found", array($cname, $this->name)); } $upgrader = new $cname($this->moduleInfos->name, $fileInfo[2], $this->moduleInfos->getPath(), $fileInfo[1], false); if ($fileInfo[1] && count($upgrader->targetVersions) == 0) { $upgrader->targetVersions = array($fileInfo[1]); } $this->moduleUpgraders[] = $upgrader; } } $list = array(); foreach ($this->moduleUpgraders as $upgrader) { $foundVersion = ''; // check the version foreach ($upgrader->targetVersions as $version) { if (VersionComparator::compareVersion($this->moduleStatuses[$epId]->version, $version) >= 0) { // we don't execute upgraders having a version lower than the installed version (they are old upgrader) continue; } if (VersionComparator::compareVersion($this->moduleInfos->version, $version) < 0) { // we don't execute upgraders having a version higher than the version indicated in the module.xml/jelix-module.json continue; } $foundVersion = $version; // when multiple version are specified, we take the first one which is ok break; } if (!$foundVersion) { continue; } $upgrader->version = $foundVersion; // we have to check now the date of versions // we should not execute the updater in some case. // for example, we have an updater for the 1.2 and 2.3 version // we have the 1.4 installed, and want to upgrade to the 2.5 version // we should not execute the update for 2.3 since modifications have already been // made into the 1.4. The only way to now that, is to compare date of versions if ($upgrader->date != '' && $this->mainInstaller) { $upgraderDate = $this->_formatDate($upgrader->date); // the date of the first version installed into the application $firstVersionDate = $this->_formatDate($this->mainInstaller->installerIni->getValue($this->moduleInfos->name . '.firstversion.date', $epId)); if ($firstVersionDate !== null) { if ($firstVersionDate >= $upgraderDate) { continue; } } // the date of the current installed version $currentVersionDate = $this->_formatDate($this->mainInstaller->installerIni->getValue($this->moduleInfos->name . '.version.date', $epId)); if ($currentVersionDate !== null) { if ($currentVersionDate >= $upgraderDate) { continue; } } } $upgrader->setParameters($this->moduleStatuses[$epId]->parameters); $class = get_class($upgrader); if (!isset($this->upgradersContexts[$class])) { $this->upgradersContexts[$class] = array(); } $upgrader->setEntryPoint($ep, $this->moduleStatuses[$epId]->dbProfile, $this->upgradersContexts[$class]); $list[] = $upgrader; } // now let's sort upgrader, to execute them in the right order (oldest before newest) usort($list, function ($upgA, $upgB) { return VersionComparator::compareVersion($upgA->version, $upgB->version); }); return $list; }
/** * core of the installation * @param ModuleInstallLauncher[] $modules * @param EntryPoint $ep the entrypoint * @param boolean $installWholeApp true if the installation is done during app installation * @param integer $flags to know what to do * @return boolean true if the installation is ok */ protected function _installModules(&$modules, EntryPoint $ep, $installWholeApp, $flags = 3) { $epId = $ep->getEpId(); $this->notice('install.entrypoint.start', $epId); $ep = $this->entryPoints[$epId]; App::setConfig($ep->getConfigObj()); if ($ep->getConfigObj()->disableInstallers) { $this->notice('install.entrypoint.installers.disabled'); } // first, check dependencies of the component, to have the list of component // we should really install. $orderedModules = $ep->getOrderedDependencies($modules, $this); if ($orderedModules === false) { $this->error('install.bad.dependencies'); $this->ok('install.entrypoint.bad.end', $epId); return false; } $this->ok('install.dependencies.ok'); // ----------- pre install // put also available installers into $componentsToInstall for // the next step $componentsToInstall = array(); $result = true; foreach ($orderedModules as $item) { list($component, $toInstall) = $item; try { if ($flags == self::FLAG_MIGRATION_11X) { $this->installerIni->setValue($component->getName() . '.installed', 1, $epId); $this->installerIni->setValue($component->getName() . '.version', $component->getSourceVersion(), $epId); if ($ep->getConfigObj()->disableInstallers) { $upgraders = array(); } else { $upgraders = $component->getUpgraders($ep); foreach ($upgraders as $upgrader) { $upgrader->preInstall(); } } $componentsToInstall[] = array($upgraders, $component, false); } else { if ($toInstall) { if ($ep->getConfigObj()->disableInstallers) { $installer = null; } else { $installer = $component->getInstaller($ep, $installWholeApp); } $componentsToInstall[] = array($installer, $component, $toInstall); if ($flags & self::FLAG_INSTALL_MODULE && $installer) { $installer->preInstall(); } } else { if ($ep->getConfigObj()->disableInstallers) { $upgraders = array(); } else { $upgraders = $component->getUpgraders($ep); } if ($flags & self::FLAG_UPGRADE_MODULE && count($upgraders)) { foreach ($upgraders as $upgrader) { $upgrader->preInstall(); } } $componentsToInstall[] = array($upgraders, $component, $toInstall); } } } catch (Exception $e) { $result = false; $this->error($e->getLocaleKey(), $e->getLocaleParameters()); } catch (\Exception $e) { $result = false; $this->error('install.module.error', array($component->getName(), $e->getMessage())); } } if (!$result) { $this->warning('install.entrypoint.bad.end', $epId); return false; } $installedModules = array(); // ----- installation process try { foreach ($componentsToInstall as $item) { list($installer, $component, $toInstall) = $item; if ($toInstall) { if ($installer && $flags & self::FLAG_INSTALL_MODULE) { $installer->install(); } $this->installerIni->setValue($component->getName() . '.installed', 1, $epId); $this->installerIni->setValue($component->getName() . '.version', $component->getSourceVersion(), $epId); $this->installerIni->setValue($component->getName() . '.version.date', $component->getSourceDate(), $epId); $this->installerIni->setValue($component->getName() . '.firstversion', $component->getSourceVersion(), $epId); $this->installerIni->setValue($component->getName() . '.firstversion.date', $component->getSourceDate(), $epId); $this->ok('install.module.installed', $component->getName()); $installedModules[] = array($installer, $component, true); } else { $lastversion = ''; foreach ($installer as $upgrader) { if ($flags & self::FLAG_UPGRADE_MODULE) { $upgrader->install(); } // we set the version of the upgrade, so if an error occurs in // the next upgrader, we won't have to re-run this current upgrader // during a future update $this->installerIni->setValue($component->getName() . '.version', $upgrader->version, $epId); $this->installerIni->setValue($component->getName() . '.version.date', $upgrader->date, $epId); $this->ok('install.module.upgraded', array($component->getName(), $upgrader->version)); $lastversion = $upgrader->version; } // we set the version to the component version, because the version // of the last upgrader could not correspond to the component version. if ($lastversion != $component->getSourceVersion()) { $this->installerIni->setValue($component->getName() . '.version', $component->getSourceVersion(), $epId); $this->installerIni->setValue($component->getName() . '.version.date', $component->getSourceDate(), $epId); $this->ok('install.module.upgraded', array($component->getName(), $component->getSourceVersion())); } $installedModules[] = array($installer, $component, false); } // we always save the configuration, so it invalidates the cache $ep->getConfigIni()->save(); $this->xmlMapFile->save(); // we re-load configuration file for each module because // previous module installer could have modify it. $compiler = new \Jelix\Core\Config\Compiler($ep->getConfigFile(), $ep->scriptName, $ep->isCliScript); $ep->setConfigObj($compiler->read(true)); App::setConfig($ep->getConfigObj()); } } catch (Exception $e) { $result = false; $this->error($e->getLocaleKey(), $e->getLocaleParameters()); } catch (\Exception $e) { $result = false; $this->error('install.module.error', array($component->getName(), $e->getMessage())); } if (!$result) { $this->warning('install.entrypoint.bad.end', $epId); return false; } // post install foreach ($installedModules as $item) { try { list($installer, $component, $toInstall) = $item; if ($toInstall) { if ($installer && $flags & self::FLAG_INSTALL_MODULE) { $installer->postInstall(); $component->installFinished($ep); } } else { if ($flags & self::FLAG_UPGRADE_MODULE) { foreach ($installer as $upgrader) { $upgrader->postInstall(); $component->upgradeFinished($ep, $upgrader); } } } // we always save the configuration, so it invalidates the cache $ep->getConfigIni()->save(); $this->xmlMapFile->save(); // we re-load configuration file for each module because // previous module installer could have modify it. $compiler = new \Jelix\Core\Config\Compiler($ep->getConfigFile(), $ep->scriptName, $ep->isCliScript); $ep->setConfigObj($compiler->read(true)); App::setConfig($ep->getConfigObj()); } catch (Exception $e) { $result = false; $this->error($e->getLocaleKey(), $e->getLocaleParameters()); } catch (\Exception $e) { $result = false; $this->error('install.module.error', array($component->getName(), $e->getMessage())); } } $this->ok('install.entrypoint.end', $epId); return $result; }