/** * {@inheritdoc} */ public function getOutput(OperationInterface $operation, UrlGenerator $urlGenerator = null) { if (!$operation instanceof UpdateOperation) { throw new \LogicException('Operation should be an instance of UpdateOperation'); } $output = []; $initialPackage = $operation->getInitialPackage(); $targetPackage = $operation->getTargetPackage(); $versionFrom = new Version($initialPackage->getVersion(), $initialPackage->getPrettyVersion(), method_exists($initialPackage, 'getFullPrettyVersion') ? $initialPackage->getFullPrettyVersion() : VersionParser::formatVersion($initialPackage)); $versionTo = new Version($targetPackage->getVersion(), $targetPackage->getPrettyVersion(), method_exists($targetPackage, 'getFullPrettyVersion') ? $targetPackage->getFullPrettyVersion() : VersionParser::formatVersion($targetPackage)); $action = 'updated'; if (Comparator::greaterThan($versionFrom->getName(), $versionTo->getName())) { $action = 'downgraded'; } $output[] = sprintf(' - <fg=green>%s</fg=green> %s from <fg=yellow>%s</fg=yellow> to <fg=yellow>%s</fg=yellow>', $initialPackage->getName(), $action, $versionFrom->getPretty(), $versionTo->getPretty()); if ($urlGenerator) { $compareUrl = $urlGenerator->generateCompareUrl($initialPackage->getSourceUrl(), $versionFrom, $targetPackage->getSourceUrl(), $versionTo); if (!empty($compareUrl)) { $output[] = sprintf(' See changes: %s', $compareUrl); } $releaseUrl = $urlGenerator->generateReleaseUrl($this->extractSourceUrl($operation), $versionTo); if (!empty($releaseUrl)) { $output[] = sprintf(' Release notes: %s', $releaseUrl); } } return $output; }
/** * Checks a composer.lock file. * * @param string $lock The path to the composer.lock file * * @return array Result array * * @throws \InvalidArgumentException When the output format is unsupported * @throws \RuntimeException When the lock file does not exist * @throws \RuntimeException When curl does not work or is unavailable */ public function check($lock) { if (is_dir($lock) && file_exists($lock . '/composer.lock')) { $lock = $lock . '/composer.lock'; } elseif (preg_match('/composer\\.json$/', $lock)) { $lock = str_replace('composer.json', 'composer.lock', $lock); } if (!is_file($lock)) { throw new \RuntimeException('Lock file does not exist.'); } $results = array(); $client = new Client(); $vp = new VersionParser(); $data = json_decode(file_get_contents($lock), 1); foreach ($data['packages'] as $package) { $name = $package['name']; $status = 'found'; $localVersion = $vp->normalize($package['version']); $localStatus = $this->parseStatus($localVersion); $stableVersion = 0; $stableStatus = ''; $devVersion = 0; $devStatus = ''; $remoteData = null; try { $response = $client->get("https://packagist.org/packages/{$name}.json"); $body = $response->getBody(); $statusCode = $response->getStatusCode(); if (200 === $statusCode) { $remoteData = json_decode($body, true); } else { $status = 'error'; } } catch (\Exception $e) { $status = 'error'; } if ($remoteData) { foreach ($remoteData['package']['versions'] as $versionName => $versionData) { if ($this->isStable($versionData['version_normalized']) && Comparator::greaterThan($versionData['version_normalized'], $stableVersion)) { $stableVersion = $versionData['version_normalized']; $stableStatus = $this->diffVersion($localVersion, $stableVersion); } } foreach ($remoteData['package']['versions'] as $versionName => $versionData) { if ($this->isTaggedDev($versionData['version_normalized']) && Comparator::greaterThan($versionData['version_normalized'], $devVersion) && Comparator::greaterThan($versionData['version_normalized'], $stableVersion) && ($localVersion === '9999999-dev' || Comparator::greaterThan($versionData['version_normalized'], $localVersion))) { $devVersion = $versionData['version_normalized']; $devStatus = $this->diffVersion($localVersion, $devVersion); } } } else { $stableVersion = 'Not found'; $stableStatus = 'error'; $devVersion = 'Not found'; $devStatus = 'error'; } $results[$name] = array('name' => $name, 'status' => $status, 'localVersion' => $localVersion, 'localStatus' => $localStatus, 'stableVersion' => $stableVersion, 'stableStatus' => $stableStatus, 'devVersion' => $devVersion, 'devStatus' => $devStatus); } return $results; }
/** * Get the last version number from a list of versions. * * @param array $versions * * @return string */ public static function latest(array $versions) { // Normalize version numbers. $versions = array_map(function ($version) { return static::normalize($version); }, $versions); // Get the highest version number. $latest = array_reduce($versions, function ($carry, $item) { // Skip unstable versions. if (VersionParser::parseStability($item) !== 'stable') { return $carry; } return Comparator::greaterThan($carry, $item) ? $carry : $item; }, '0.0.0'); return $latest; }
/** * Compare two version strings to get the named semantic version. * * @access public * * @param string $new_version * @param string $original_version * @return string $name 'major', 'minor', 'patch' */ function get_named_sem_ver($new_version, $original_version) { if (!Comparator::greaterThan($new_version, $original_version)) { return ''; } $parts = explode('-', $original_version); list($major, $minor, $patch) = explode('.', $parts[0]); if (Semver::satisfies($new_version, "{$major}.{$minor}.x")) { return 'patch'; } else { if (Semver::satisfies($new_version, "{$major}.x.x")) { return 'minor'; } else { return 'major'; } } }
/** * Create the module manager * * @param ServiceLocatorInterface $serviceLocator * @return array */ public function createService(ServiceLocatorInterface $serviceLocator) { $manager = new ModuleManager(); $iniReader = new IniReader(); $connection = $serviceLocator->get('Omeka\\Connection'); // Get all modules from the filesystem. foreach (new DirectoryIterator(OMEKA_PATH . '/modules') as $dir) { // Module must be a directory if (!$dir->isDir() || $dir->isDot()) { continue; } $module = $manager->registerModule($dir->getBasename()); // Module directory must contain config/module.ini $iniFile = new SplFileInfo($dir->getPathname() . '/config/module.ini'); if (!$iniFile->isReadable() || !$iniFile->isFile()) { $module->setState(ModuleManager::STATE_INVALID_INI); continue; } $module->setIni($iniReader->fromFile($iniFile->getRealPath())); // Module INI must be valid if (!$manager->iniIsValid($module)) { $module->setState(ModuleManager::STATE_INVALID_INI); continue; } // Module directory must contain Module.php $moduleFile = new SplFileInfo($dir->getPathname() . '/Module.php'); if (!$moduleFile->isReadable() || !$moduleFile->isFile()) { $module->setState(ModuleManager::STATE_INVALID_MODULE); continue; } // Module class must extend Omeka\Module\AbstractModule require_once $moduleFile->getRealPath(); $moduleClass = $dir->getBasename() . '\\Module'; if (!class_exists($moduleClass) || !is_subclass_of($moduleClass, 'Omeka\\Module\\AbstractModule')) { $module->setState(ModuleManager::STATE_INVALID_MODULE); continue; } } // Get all modules from the database, if installed. $dbModules = []; if ($serviceLocator->get('Omeka\\Status')->isInstalled()) { $statement = $connection->prepare("SELECT * FROM module"); $statement->execute(); $dbModules = $statement->fetchAll(); } foreach ($dbModules as $moduleRow) { if (!$manager->isRegistered($moduleRow['id'])) { // Module installed but not in filesystem $module = $manager->registerModule($moduleRow['id']); $module->setDb($moduleRow); $module->setState(ModuleManager::STATE_NOT_FOUND); continue; } $module = $manager->getModule($moduleRow['id']); $module->setDb($moduleRow); if ($module->getState()) { // Module already has state. continue; } $moduleIni = $module->getIni(); if (Comparator::greaterThan($moduleIni['version'], $moduleRow['version'])) { // Module in filesystem is newer version than the installed one. $module->setState(ModuleManager::STATE_NEEDS_UPGRADE); continue; } if ($moduleRow['is_active']) { // Module valid, installed, and active $module->setState(ModuleManager::STATE_ACTIVE); } else { // Module valid, installed, and not active $module->setState(ModuleManager::STATE_NOT_ACTIVE); } } foreach ($manager->getModules() as $id => $module) { if (!$module->getState()) { // Module in filesystem but not installed $module->setState(ModuleManager::STATE_NOT_INSTALLED); } } return $manager; }
/** * Returns update information. */ private function get_updates($assoc_args) { $url = 'https://api.github.com/repos/wp-cli/wp-cli/releases'; $options = array('timeout' => 30); $headers = array('Accept' => 'application/json'); $response = Utils\http_request('GET', $url, $headers, $options); if (!$response->success || 200 !== $response->status_code) { WP_CLI::error(sprintf("Failed to get latest version (HTTP code %d).", $response->status_code)); } $release_data = json_decode($response->body); $updates = array('major' => false, 'minor' => false, 'patch' => false); foreach ($release_data as $release) { // Get rid of leading "v" if there is one set. $release_version = $release->tag_name; if ('v' === substr($release_version, 0, 1)) { $release_version = ltrim($release_version, 'v'); } $update_type = Utils\get_named_sem_ver($release_version, WP_CLI_VERSION); if (!$update_type) { continue; } if (!empty($updates[$update_type]) && !Comparator::greaterThan($release_version, $updates[$update_type]['version'])) { continue; } $updates[$update_type] = array('version' => $release_version, 'update_type' => $update_type, 'package_url' => $release->assets[0]->browser_download_url); } foreach ($updates as $type => $value) { if (empty($value)) { unset($updates[$type]); } } foreach (array('major', 'minor', 'patch') as $type) { if (true === \WP_CLI\Utils\get_flag_value($assoc_args, $type)) { return !empty($updates[$type]) ? array($updates[$type]) : false; } } if (empty($updates) && preg_match('#-alpha-(.+)$#', WP_CLI_VERSION, $matches)) { $version_url = 'https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/NIGHTLY_VERSION'; $response = Utils\http_request('GET', $version_url); if (!$response->success || 200 !== $response->status_code) { WP_CLI::error(sprintf("Failed to get current nightly version (HTTP code %d)", $response->status_code)); } $nightly_version = trim($response->body); if (WP_CLI_VERSION != $nightly_version) { $updates['nightly'] = array('version' => $nightly_version, 'update_type' => 'nightly', 'package_url' => 'https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli-nightly.phar'); } } return array_values($updates); }
/** * Returns update information */ private function get_updates($assoc_args) { global $wp_version; $versions_path = ABSPATH . 'wp-includes/version.php'; include $versions_path; $url = 'https://api.wordpress.org/core/stable-check/1.0/'; $options = array('timeout' => 30); $headers = array('Accept' => 'application/json'); $response = Utils\http_request('GET', $url, $headers, $options); if (!$response->success || 200 !== $response->status_code) { WP_CLI::error("Failed to get latest version list."); } $release_data = json_decode($response->body); $release_versions = array_keys((array) $release_data); usort($release_versions, function ($a, $b) { return 1 === version_compare($a, $b); }); $locale = get_locale(); $compare_version = str_replace('-src', '', $GLOBALS['wp_version']); $updates = array('major' => false, 'minor' => false); foreach ($release_versions as $release_version) { $update_type = Utils\get_named_sem_ver($release_version, $compare_version); if (!$update_type) { continue; } // WordPress follow its own versioning which is roughly equivalent to semver if ('minor' === $update_type) { $update_type = 'major'; } else { if ('patch' === $update_type) { $update_type = 'minor'; } } if (!empty($updates[$update_type]) && !Comparator::greaterThan($release_version, $updates[$update_type]['version'])) { continue; } $updates[$update_type] = array('version' => $release_version, 'update_type' => $update_type, 'package_url' => $this->get_download_url($release_version, $locale)); } foreach ($updates as $type => $value) { if (empty($value)) { unset($updates[$type]); } } foreach (array('major', 'minor') as $type) { if (true === \WP_CLI\Utils\get_flag_value($assoc_args, $type)) { return !empty($updates[$type]) ? array($updates[$type]) : false; } } return array_values($updates); }
/** * Compare two version strings to get the named semantic version. * * @access public * * @param string $new_version * @param string $original_version * @return string $name 'major', 'minor', 'patch' */ function get_named_sem_ver($new_version, $original_version) { if (!Comparator::greaterThan($new_version, $original_version)) { return ''; } $parts = explode('-', $original_version); $bits = explode('.', $parts[0]); $major = $bits[0]; if (isset($bits[1])) { $minor = $bits[1]; } if (isset($bits[2])) { $patch = $bits[2]; } if (!is_null($minor) && Semver::satisfies($new_version, "{$major}.{$minor}.x")) { return 'patch'; } else { if (Semver::satisfies($new_version, "{$major}.x.x")) { return 'minor'; } else { return 'major'; } } }
/** * Check whether Omeka needs a version update. * * An update is needed when the code version is more recent than the * installed version. * * @return bool */ public function needsVersionUpdate() { return Comparator::greaterThan($this->getVersion(), $this->getInstalledVersion()); }
/** * Get sql file list ordered by floats * @param string $module * @param string $action * @param float specific version * @param float current version * @return array array sorted according to version */ public function getSqlFileListOrdered($module, $action, $specific = null, $current = null) { $ary = $this->getSqlFileList($module, $action); asort($ary); $sem = new Comparator(); if (strpos($current, 'v') === 0) { $current = substr($current, 1); } if (isset($specific)) { $ary = array_reverse($ary); if ($specific == 1) { foreach ($ary as $key => $val) { $val = substr($val, 0, -4); if (strpos($val, 'v') === 0) { $val = substr($val, 1); } if ($sem->greaterThan($val, $current)) { unset($ary[$key]); } } } else { foreach ($ary as $key => $val) { $val = substr($val, 0, -4); if (strpos($val, 'v') === 0) { $val = substr($val, 1); } if ($sem->lessThan($val, $specific)) { unset($ary[$key]); } if ($sem->greaterThan($val, $current)) { unset($ary[$key]); } } } } return $ary; }
/** * Returns update information */ private function get_updates($assoc_args) { wp_version_check(); $from_api = get_site_transient('update_core'); if (!$from_api) { return array(); } $compare_version = str_replace('-src', '', $GLOBALS['wp_version']); $updates = array('major' => false, 'minor' => false); foreach ($from_api->updates as $offer) { $update_type = Utils\get_named_sem_ver($offer->version, $compare_version); if (!$update_type) { continue; } // WordPress follow its own versioning which is roughly equivalent to semver if ('minor' === $update_type) { $update_type = 'major'; } else { if ('patch' === $update_type) { $update_type = 'minor'; } } if (!empty($updates[$update_type]) && !Comparator::greaterThan($offer->version, $updates[$update_type]['version'])) { continue; } $updates[$update_type] = array('version' => $offer->version, 'update_type' => $update_type, 'package_url' => !empty($offer->packages->partial) ? $offer->packages->partial : $offer->packages->full); } foreach ($updates as $type => $value) { if (empty($value)) { unset($updates[$type]); } } foreach (array('major', 'minor') as $type) { if (true === \WP_CLI\Utils\get_flag_value($assoc_args, $type)) { return !empty($updates[$type]) ? array($updates[$type]) : false; } } return array_values($updates); }