/** * Get dependencies list/install order info * * @param string $chanName * @param string $package * @param \Magento\Framework\Connect\Singleconfig $cache * @param \Magento\Framework\Connect\Config $config * @param mixed $versionMax * @param mixed $versionMin * @param boolean $withDepsRecursive * @param boolean $forceRemote * @param \Magento\Framework\Connect\Rest $rest * @return mixed */ public function getDependenciesList($chanName, $package, $cache, $config, $versionMax = false, $versionMin = false, $withDepsRecursive = true, $forceRemote = false, $rest = null) { static $level = 0; static $_depsHash = array(); static $_deps = array(); static $_failed = array(); $install_state = self::INSTALL_STATE_INSTALL; $version = ''; $message = ''; $level++; try { $chanName = $cache->chanName($chanName); if (!$rest) { $rest = new \Magento\Framework\Connect\Rest($config->protocol); } $rest->setChannel($cache->chanUrl($chanName)); $releases = $rest->getReleases($package); if (!$releases || !count($releases)) { throw new \Exception("No releases for '{$package}', skipping"); } $state = $config->preferred_state ? $config->preferred_state : 'stable'; /** * Check current package version first */ $installedPackage = $cache->getPackage($chanName, $package); if ($installedPackage && is_array($installedPackage)) { $installedRelease = array(array('v' => $installedPackage['version'], 's' => $installedPackage['stability'])); $version = $cache->detectVersionFromRestArray($installedRelease, $versionMin, $versionMax, $state); } if (!$version) { $version = $cache->detectVersionFromRestArray($releases, $versionMin, $versionMax, $state); } if (!$version) { $versionState = $cache->detectVersionFromRestArray($releases, $versionMin, $versionMax); if ($versionState) { /** @var $packageInfo \Magento\Framework\Connect\Package */ $packageInfo = $rest->getPackageReleaseInfo($package, $versionState); if (false !== $packageInfo) { $stability = $packageInfo->getStability(); throw new \Exception("Extension is '{$stability}' please check(or change) stability settings" . " on Magento Connect Manager"); } } throw new \Exception("Version for '{$package}' was not detected"); } $packageInfo = $rest->getPackageReleaseInfo($package, $version); if (false === $packageInfo) { throw new \Exception("Package release '{$package}' not found on server"); } $stability = $packageInfo->getStability(); /** * check is package already installed */ if ($installedPackage = $cache->isPackageInstalled($package)) { if ($chanName == $installedPackage['channel']) { /** * check versions */ if (version_compare($version, $installedPackage['version'], '>')) { $install_state = self::INSTALL_STATE_UPGRADE; } elseif (version_compare($version, $installedPackage['version'], '<')) { $version = $installedPackage['version']; $stability = $installedPackage['stability']; $install_state = self::INSTALL_STATE_WRONG_VERSION; } else { $install_state = self::INSTALL_STATE_ALREADY_INSTALLED; } } else { $install_state = self::INSTALL_STATE_INCOMPATIBLE; } } $deps_tmp = $packageInfo->getDependencyPackages(); /** * Select distinct packages grouped by name */ $dependencies = array(); foreach ($deps_tmp as $row) { if (isset($dependencies[$row['name']])) { if ($installedPackageDep = $cache->isPackageInstalled($row['name'])) { if ($installedPackageDep['channel'] == $row['channel']) { $dependencies[$row['name']] = $row; } } elseif ($config->root_channel == $row['channel']) { $dependencies[$row['name']] = $row; } } else { $dependencies[$row['name']] = $row; } } /** * When we are building dependencies tree we should base this calculations not on full key as on a * unique value but check it by parts. First part which should be checked is EXTENSION_NAME also this part * should be unique globally not per channel. */ if (self::INSTALL_STATE_INCOMPATIBLE != $install_state) { $this->addHashData($_depsHash, $package, $chanName, $version, $stability, $versionMin, $versionMax, $install_state, $message, $dependencies); } if ($withDepsRecursive && self::INSTALL_STATE_INCOMPATIBLE != $install_state) { $flds = array('name', 'channel', 'min', 'max'); foreach ($dependencies as $row) { /** * Converts an array to variables * @var $pChannel string Channel Name * @var $pName string Package Name * @var $pMax string Maximum version number * @var $pMin string Minimum version number */ foreach ($flds as $key) { $varName = "p" . ucfirst($key); ${$varName} = $row[$key]; } $method = __FUNCTION__; /** * When we are building dependencies tree we should base this calculations not on full key as * on a unique value but check it by parts. First part which should be checked is EXTENSION_NAME * also this part should be unique globally not per channel. */ $keyInner = $pName; if (!isset($_depsHash[$keyInner])) { $_deps[] = $row; $this->{$method}($pChannel, $pName, $cache, $config, $pMax, $pMin, $withDepsRecursive, $forceRemote, $rest); } else { $downloaded = $_depsHash[$keyInner]['downloaded_version']; $hasMin = $_depsHash[$keyInner]['min']; $hasMax = $_depsHash[$keyInner]['max']; if ($pMin === $hasMin && $pMax === $hasMax) { continue; } if ($cache->versionInRange($downloaded, $pMin, $pMax)) { continue; } $names = array("pMin", "pMax", "hasMin", "hasMax"); for ($i = 0, $c = count($names); $i < $c; $i++) { if (!isset(${$names[$i]})) { continue; } if (false !== ${$names[$i]}) { continue; } ${$names[$i]} = $i % 2 == 0 ? "0" : "999999999"; } if (!$cache->hasVersionRangeIntersect($pMin, $pMax, $hasMin, $hasMax)) { $reason = "Detected {$pName} conflict of versions: {$hasMin}-{$hasMax} and {$pMin}-{$pMax}"; unset($_depsHash[$keyInner]); $_failed[] = array('name' => $pName, 'channel' => $pChannel, 'max' => $pMax, 'min' => $pMin, 'reason' => $reason); continue; } $newMaxIsLess = version_compare($pMax, $hasMax, "<"); $newMinIsGreater = version_compare($pMin, $hasMin, ">"); $forceMax = $newMaxIsLess ? $pMax : $hasMax; $forceMin = $newMinIsGreater ? $pMin : $hasMin; $this->{$method}($pChannel, $pName, $cache, $config, $forceMax, $forceMin, $withDepsRecursive, $forceRemote, $rest); } } } unset($rest); } catch (\Exception $e) { $_failed[] = array('name' => $package, 'channel' => $chanName, 'max' => $versionMax, 'min' => $versionMin, 'reason' => $e->getMessage()); } $level--; if ($level == 0) { $out = $this->processDepsHash($_depsHash, false); $deps = $_deps; $failed = $_failed; $_depsHash = array(); $_deps = array(); $_failed = array(); return array('deps' => $deps, 'result' => $out, 'failed' => $failed); } return null; }
/** * Display/get installation information for package * @param string $command * @param array $options * @param array $params * @return void|array */ public function doPackagePrepare($command, $options, $params) { $this->cleanupParams($params); $channelAuth = array(); if (isset($options['auth'])) { $channelAuth = $options['auth']; $options['auth'] = null; } try { if (count($params) < 2) { return $this->doError($command, "Argument count should be >= 2"); } $channel = $params[0]; $package = $params[1]; $argVersionMin = isset($params[3]) ? $params[3] : false; $argVersionMax = isset($params[2]) ? $params[2] : false; $ftp = empty($options['ftp']) ? false : $options['ftp']; $packager = $this->getPackager(); if ($ftp) { list($cache, $config, $ftpObj) = $packager->getRemoteConf($ftp); } else { $cache = $this->getSconfig(); $config = $this->config(); } $rest = new \Magento\Framework\Connect\Rest($config->protocol); if (!empty($channelAuth)) { $rest->getLoader()->setCredentials($channelAuth['username'], $channelAuth['password']); } $cache->checkChannel($channel, $config, $rest); $data = $packager->getDependenciesList($channel, $package, $cache, $config, $argVersionMax, $argVersionMin, true, false, $rest); $result = array(); foreach ($data['result'] as $_package) { $_result['channel'] = $_package['channel']; $_result['name'] = $_package['name']; $_result['version'] = $_package['downloaded_version']; $_result['stability'] = $_package['stability']; $_result['install_state'] = $_package['install_state']; $_result['message'] = $_package['message']; $result[] = $_result; } if (!count($data['result']) && isset($data['failed']) && !empty($data['failed'])) { foreach ($data['failed'] as $_package) { $reason = $_package['channel'] . '/' . $_package['name'] . ': ' . $_package['reason']; $this->doError($command, $reason); } } $this->ui()->output(array($command => array('data' => $result, 'title' => "Package installation information for {$params[1]}: "))); } catch (\Exception $e) { $this->doError($command, $e->getMessage()); } }
/** * Check channel, add if valid name and not exist * * @param string $chanName * @param \Magento\Framework\Connect\Config $config * @param \Magento\Framework\Connect\Rest $rest * @return bool * @throws \Exception */ public function checkChannel($chanName, $config, $rest = null) { if ($this->isChannel($chanName)) { return true; } $_validator = new \Magento\Framework\Connect\Validator(); if ($this->isChannelName($chanName)) { $uri = $this->chanUrl($chanName); } elseif ($_validator->validateUrl($chanName)) { $uri = $chanName; } elseif ($chanName) { $uri = $config->protocol . '://' . $chanName; } else { throw new \Exception("'{$chanName}' is not existant channel name / valid uri"); } if ($uri && !$this->isChannel($uri)) { if (!isset($rest)) { $rest = new \Magento\Framework\Connect\Rest($config->protocol); } $rest->setChannel($uri); $data = $rest->getChannelInfo(); $data->uri = $uri; $this->addChannel($data->name, $uri); } return $this->isChannel($uri); }
/** * Get dependencies list/install order info * * @param string $chanName * @param string $package * @param Singleconfig $cache * @param Config $config * @param string|false $versionMax * @param string|false $versionMin * @param bool $withDepsRecursive * @param bool $forceRemote * @return array|void * @throws \Exception */ public function getDependenciesList($chanName, $package, $cache, $config, $versionMax = false, $versionMin = false, $withDepsRecursive = true, $forceRemote = false) { static $level = 0; static $_depsHash = array(); static $_deps = array(); static $_failed = array(); $level++; try { $chanName = $cache->chanName($chanName); $rest = new \Magento\Framework\Connect\Rest($config->protocol); $rest->setChannel($cache->chanUrl($chanName)); $releases = $rest->getReleases($package); if (!$releases || !count($releases)) { throw new \Exception("No releases for: '{$package}', skipping"); } $state = $config->preffered_state ? $confg->preffered_state : 'devel'; $version = $cache->detectVersionFromRestArray($releases, $versionMin, $versionMax, $state); if (!$version) { throw new \Exception("Version for '{$package}' was not detected"); } $packageInfo = $rest->getPackageReleaseInfo($package, $version); if (false === $packageInfo) { throw new \Exception("Package release '{$package}' not found on server"); } unset($rest); $dependencies = $packageInfo->getDependencyPackages(); $keyOuter = $chanName . "/" . $package; //print "Processing outer: {$keyOuter} \n"; $_depsHash[$keyOuter] = array('name' => $package, 'channel' => $chanName, 'downloaded_version' => $version, 'min' => $versionMin, 'max' => $versionMax, 'packages' => $dependencies); if ($withDepsRecursive) { $flds = array('name', 'channel', 'min', 'max'); $fldsCount = count($flds); foreach ($dependencies as $row) { foreach ($flds as $key) { $varName = "p" . ucfirst($key); ${$varName} = $row[$key]; } $method = __FUNCTION__; $keyInner = $pChannel . "/" . $pName; if (!isset($_depsHash[$keyInner])) { $_deps[] = $row; $this->{$method}($pChannel, $pName, $cache, $config, $pMax, $pMin, $withDepsRecursive, $forceRemote, false); } else { $downloaded = $_depsHash[$keyInner]['downloaded_version']; $hasMin = $_depsHash[$keyInner]['min']; $hasMax = $_depsHash[$keyInner]['max']; if ($pMin === $hasMin && $pMax === $hasMax) { //var_dump("Equal requirements, skipping"); continue; } if ($cache->versionInRange($downloaded, $pMin, $pMax)) { //var_dump("Downloaded package matches new range too"); continue; } $names = array("pMin", "pMax", "hasMin", "hasMax"); for ($i = 0, $c = count($names); $i < $c; $i++) { if (!isset(${$names[$i]})) { continue; } if (false !== ${$names[$i]}) { continue; } ${$names[$i]} = $i % 2 == 0 ? "0" : "999999999"; } if (!$cache->hasVersionRangeIntersect($pMin, $pMax, $hasMin, $hasMax)) { $reason = "Detected {$pName} conflict of versions: {$hasMin}-{$hasMax} and {$pMin}-{$pMax}"; unset($_depsHash[$keyInner]); $_failed[] = array('name' => $pName, 'channel' => $pChannel, 'max' => $pMax, 'min' => $pMin, 'reason' => $reason); continue; } $newMaxIsLess = version_compare($pMax, $hasMax, "<"); $newMinIsGreater = version_compare($pMin, $hasMin, ">"); $forceMax = $newMaxIsLess ? $pMax : $hasMax; $forceMin = $newMinIsGreater ? $pMin : $hasMin; //var_dump("Trying to process {$pName} : max {$forceMax} - min {$forceMin}"); $this->{$method}($pChannel, $pName, $cache, $config, $forceMax, $forceMin, $withDepsRecursive, $forceRemote); } } } } catch (\Exception $e) { $_failed[] = array('name' => $package, 'channel' => $chanName, 'max' => $versionMax, 'min' => $versionMin, 'reason' => $e->getMessage()); } $level--; if ($level == 0) { $out = $this->processDepsHash($_depsHash); $deps = $_deps; $failed = $_failed; $_depsHash = array(); $_deps = array(); $_failed = array(); return array('deps' => $deps, 'result' => $out, 'failed' => $failed); } }