annotate vendor/composer/semver/src/VersionParser.php @ 0:c75dbcec494b

Initial commit from drush-created site
author Chris Cannam
date Thu, 05 Jul 2018 14:24:15 +0000
parents
children 12f9dff5fda9
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 /*
Chris@0 4 * This file is part of composer/semver.
Chris@0 5 *
Chris@0 6 * (c) Composer <https://github.com/composer>
Chris@0 7 *
Chris@0 8 * For the full copyright and license information, please view
Chris@0 9 * the LICENSE file that was distributed with this source code.
Chris@0 10 */
Chris@0 11
Chris@0 12 namespace Composer\Semver;
Chris@0 13
Chris@0 14 use Composer\Semver\Constraint\ConstraintInterface;
Chris@0 15 use Composer\Semver\Constraint\EmptyConstraint;
Chris@0 16 use Composer\Semver\Constraint\MultiConstraint;
Chris@0 17 use Composer\Semver\Constraint\Constraint;
Chris@0 18
Chris@0 19 /**
Chris@0 20 * Version parser.
Chris@0 21 *
Chris@0 22 * @author Jordi Boggiano <j.boggiano@seld.be>
Chris@0 23 */
Chris@0 24 class VersionParser
Chris@0 25 {
Chris@0 26 /**
Chris@0 27 * Regex to match pre-release data (sort of).
Chris@0 28 *
Chris@0 29 * Due to backwards compatibility:
Chris@0 30 * - Instead of enforcing hyphen, an underscore, dot or nothing at all are also accepted.
Chris@0 31 * - Only stabilities as recognized by Composer are allowed to precede a numerical identifier.
Chris@0 32 * - Numerical-only pre-release identifiers are not supported, see tests.
Chris@0 33 *
Chris@0 34 * |--------------|
Chris@0 35 * [major].[minor].[patch] -[pre-release] +[build-metadata]
Chris@0 36 *
Chris@0 37 * @var string
Chris@0 38 */
Chris@0 39 private static $modifierRegex = '[._-]?(?:(stable|beta|b|RC|alpha|a|patch|pl|p)((?:[.-]?\d+)*+)?)?([.-]?dev)?';
Chris@0 40
Chris@0 41 /** @var array */
Chris@0 42 private static $stabilities = array('stable', 'RC', 'beta', 'alpha', 'dev');
Chris@0 43
Chris@0 44 /**
Chris@0 45 * Returns the stability of a version.
Chris@0 46 *
Chris@0 47 * @param string $version
Chris@0 48 *
Chris@0 49 * @return string
Chris@0 50 */
Chris@0 51 public static function parseStability($version)
Chris@0 52 {
Chris@0 53 $version = preg_replace('{#.+$}i', '', $version);
Chris@0 54
Chris@0 55 if ('dev-' === substr($version, 0, 4) || '-dev' === substr($version, -4)) {
Chris@0 56 return 'dev';
Chris@0 57 }
Chris@0 58
Chris@0 59 preg_match('{' . self::$modifierRegex . '(?:\+.*)?$}i', strtolower($version), $match);
Chris@0 60 if (!empty($match[3])) {
Chris@0 61 return 'dev';
Chris@0 62 }
Chris@0 63
Chris@0 64 if (!empty($match[1])) {
Chris@0 65 if ('beta' === $match[1] || 'b' === $match[1]) {
Chris@0 66 return 'beta';
Chris@0 67 }
Chris@0 68 if ('alpha' === $match[1] || 'a' === $match[1]) {
Chris@0 69 return 'alpha';
Chris@0 70 }
Chris@0 71 if ('rc' === $match[1]) {
Chris@0 72 return 'RC';
Chris@0 73 }
Chris@0 74 }
Chris@0 75
Chris@0 76 return 'stable';
Chris@0 77 }
Chris@0 78
Chris@0 79 /**
Chris@0 80 * @param string $stability
Chris@0 81 *
Chris@0 82 * @return string
Chris@0 83 */
Chris@0 84 public static function normalizeStability($stability)
Chris@0 85 {
Chris@0 86 $stability = strtolower($stability);
Chris@0 87
Chris@0 88 return $stability === 'rc' ? 'RC' : $stability;
Chris@0 89 }
Chris@0 90
Chris@0 91 /**
Chris@0 92 * Normalizes a version string to be able to perform comparisons on it.
Chris@0 93 *
Chris@0 94 * @param string $version
Chris@0 95 * @param string $fullVersion optional complete version string to give more context
Chris@0 96 *
Chris@0 97 * @throws \UnexpectedValueException
Chris@0 98 *
Chris@0 99 * @return string
Chris@0 100 */
Chris@0 101 public function normalize($version, $fullVersion = null)
Chris@0 102 {
Chris@0 103 $version = trim($version);
Chris@0 104 if (null === $fullVersion) {
Chris@0 105 $fullVersion = $version;
Chris@0 106 }
Chris@0 107
Chris@0 108 // strip off aliasing
Chris@0 109 if (preg_match('{^([^,\s]++) ++as ++([^,\s]++)$}', $version, $match)) {
Chris@0 110 $version = $match[1];
Chris@0 111 }
Chris@0 112
Chris@0 113 // match master-like branches
Chris@0 114 if (preg_match('{^(?:dev-)?(?:master|trunk|default)$}i', $version)) {
Chris@0 115 return '9999999-dev';
Chris@0 116 }
Chris@0 117
Chris@0 118 // if requirement is branch-like, use full name
Chris@0 119 if ('dev-' === strtolower(substr($version, 0, 4))) {
Chris@0 120 return 'dev-' . substr($version, 4);
Chris@0 121 }
Chris@0 122
Chris@0 123 // strip off build metadata
Chris@0 124 if (preg_match('{^([^,\s+]++)\+[^\s]++$}', $version, $match)) {
Chris@0 125 $version = $match[1];
Chris@0 126 }
Chris@0 127
Chris@0 128 // match classical versioning
Chris@0 129 if (preg_match('{^v?(\d{1,5})(\.\d++)?(\.\d++)?(\.\d++)?' . self::$modifierRegex . '$}i', $version, $matches)) {
Chris@0 130 $version = $matches[1]
Chris@0 131 . (!empty($matches[2]) ? $matches[2] : '.0')
Chris@0 132 . (!empty($matches[3]) ? $matches[3] : '.0')
Chris@0 133 . (!empty($matches[4]) ? $matches[4] : '.0');
Chris@0 134 $index = 5;
Chris@0 135 // match date(time) based versioning
Chris@0 136 } elseif (preg_match('{^v?(\d{4}(?:[.:-]?\d{2}){1,6}(?:[.:-]?\d{1,3})?)' . self::$modifierRegex . '$}i', $version, $matches)) {
Chris@0 137 $version = preg_replace('{\D}', '.', $matches[1]);
Chris@0 138 $index = 2;
Chris@0 139 }
Chris@0 140
Chris@0 141 // add version modifiers if a version was matched
Chris@0 142 if (isset($index)) {
Chris@0 143 if (!empty($matches[$index])) {
Chris@0 144 if ('stable' === $matches[$index]) {
Chris@0 145 return $version;
Chris@0 146 }
Chris@0 147 $version .= '-' . $this->expandStability($matches[$index]) . (!empty($matches[$index + 1]) ? ltrim($matches[$index + 1], '.-') : '');
Chris@0 148 }
Chris@0 149
Chris@0 150 if (!empty($matches[$index + 2])) {
Chris@0 151 $version .= '-dev';
Chris@0 152 }
Chris@0 153
Chris@0 154 return $version;
Chris@0 155 }
Chris@0 156
Chris@0 157 // match dev branches
Chris@0 158 if (preg_match('{(.*?)[.-]?dev$}i', $version, $match)) {
Chris@0 159 try {
Chris@0 160 return $this->normalizeBranch($match[1]);
Chris@0 161 } catch (\Exception $e) {
Chris@0 162 }
Chris@0 163 }
Chris@0 164
Chris@0 165 $extraMessage = '';
Chris@0 166 if (preg_match('{ +as +' . preg_quote($version) . '$}', $fullVersion)) {
Chris@0 167 $extraMessage = ' in "' . $fullVersion . '", the alias must be an exact version';
Chris@0 168 } elseif (preg_match('{^' . preg_quote($version) . ' +as +}', $fullVersion)) {
Chris@0 169 $extraMessage = ' in "' . $fullVersion . '", the alias source must be an exact version, if it is a branch name you should prefix it with dev-';
Chris@0 170 }
Chris@0 171
Chris@0 172 throw new \UnexpectedValueException('Invalid version string "' . $version . '"' . $extraMessage);
Chris@0 173 }
Chris@0 174
Chris@0 175 /**
Chris@0 176 * Extract numeric prefix from alias, if it is in numeric format, suitable for version comparison.
Chris@0 177 *
Chris@0 178 * @param string $branch Branch name (e.g. 2.1.x-dev)
Chris@0 179 *
Chris@0 180 * @return string|false Numeric prefix if present (e.g. 2.1.) or false
Chris@0 181 */
Chris@0 182 public function parseNumericAliasPrefix($branch)
Chris@0 183 {
Chris@0 184 if (preg_match('{^(?P<version>(\d++\\.)*\d++)(?:\.x)?-dev$}i', $branch, $matches)) {
Chris@0 185 return $matches['version'] . '.';
Chris@0 186 }
Chris@0 187
Chris@0 188 return false;
Chris@0 189 }
Chris@0 190
Chris@0 191 /**
Chris@0 192 * Normalizes a branch name to be able to perform comparisons on it.
Chris@0 193 *
Chris@0 194 * @param string $name
Chris@0 195 *
Chris@0 196 * @return string
Chris@0 197 */
Chris@0 198 public function normalizeBranch($name)
Chris@0 199 {
Chris@0 200 $name = trim($name);
Chris@0 201
Chris@0 202 if (in_array($name, array('master', 'trunk', 'default'))) {
Chris@0 203 return $this->normalize($name);
Chris@0 204 }
Chris@0 205
Chris@0 206 if (preg_match('{^v?(\d++)(\.(?:\d++|[xX*]))?(\.(?:\d++|[xX*]))?(\.(?:\d++|[xX*]))?$}i', $name, $matches)) {
Chris@0 207 $version = '';
Chris@0 208 for ($i = 1; $i < 5; ++$i) {
Chris@0 209 $version .= isset($matches[$i]) ? str_replace(array('*', 'X'), 'x', $matches[$i]) : '.x';
Chris@0 210 }
Chris@0 211
Chris@0 212 return str_replace('x', '9999999', $version) . '-dev';
Chris@0 213 }
Chris@0 214
Chris@0 215 return 'dev-' . $name;
Chris@0 216 }
Chris@0 217
Chris@0 218 /**
Chris@0 219 * Parses a constraint string into MultiConstraint and/or Constraint objects.
Chris@0 220 *
Chris@0 221 * @param string $constraints
Chris@0 222 *
Chris@0 223 * @return ConstraintInterface
Chris@0 224 */
Chris@0 225 public function parseConstraints($constraints)
Chris@0 226 {
Chris@0 227 $prettyConstraint = $constraints;
Chris@0 228
Chris@0 229 if (preg_match('{^([^,\s]*?)@(' . implode('|', self::$stabilities) . ')$}i', $constraints, $match)) {
Chris@0 230 $constraints = empty($match[1]) ? '*' : $match[1];
Chris@0 231 }
Chris@0 232
Chris@0 233 if (preg_match('{^(dev-[^,\s@]+?|[^,\s@]+?\.x-dev)#.+$}i', $constraints, $match)) {
Chris@0 234 $constraints = $match[1];
Chris@0 235 }
Chris@0 236
Chris@0 237 $orConstraints = preg_split('{\s*\|\|?\s*}', trim($constraints));
Chris@0 238 $orGroups = array();
Chris@0 239 foreach ($orConstraints as $constraints) {
Chris@0 240 $andConstraints = preg_split('{(?<!^|as|[=>< ,]) *(?<!-)[, ](?!-) *(?!,|as|$)}', $constraints);
Chris@0 241 if (count($andConstraints) > 1) {
Chris@0 242 $constraintObjects = array();
Chris@0 243 foreach ($andConstraints as $constraint) {
Chris@0 244 foreach ($this->parseConstraint($constraint) as $parsedConstraint) {
Chris@0 245 $constraintObjects[] = $parsedConstraint;
Chris@0 246 }
Chris@0 247 }
Chris@0 248 } else {
Chris@0 249 $constraintObjects = $this->parseConstraint($andConstraints[0]);
Chris@0 250 }
Chris@0 251
Chris@0 252 if (1 === count($constraintObjects)) {
Chris@0 253 $constraint = $constraintObjects[0];
Chris@0 254 } else {
Chris@0 255 $constraint = new MultiConstraint($constraintObjects);
Chris@0 256 }
Chris@0 257
Chris@0 258 $orGroups[] = $constraint;
Chris@0 259 }
Chris@0 260
Chris@0 261 if (1 === count($orGroups)) {
Chris@0 262 $constraint = $orGroups[0];
Chris@0 263 } elseif (2 === count($orGroups)
Chris@0 264 // parse the two OR groups and if they are contiguous we collapse
Chris@0 265 // them into one constraint
Chris@0 266 && $orGroups[0] instanceof MultiConstraint
Chris@0 267 && $orGroups[1] instanceof MultiConstraint
Chris@0 268 && 2 === count($orGroups[0]->getConstraints())
Chris@0 269 && 2 === count($orGroups[1]->getConstraints())
Chris@0 270 && ($a = (string) $orGroups[0])
Chris@0 271 && substr($a, 0, 3) === '[>=' && (false !== ($posA = strpos($a, '<', 4)))
Chris@0 272 && ($b = (string) $orGroups[1])
Chris@0 273 && substr($b, 0, 3) === '[>=' && (false !== ($posB = strpos($b, '<', 4)))
Chris@0 274 && substr($a, $posA + 2, -1) === substr($b, 4, $posB - 5)
Chris@0 275 ) {
Chris@0 276 $constraint = new MultiConstraint(array(
Chris@0 277 new Constraint('>=', substr($a, 4, $posA - 5)),
Chris@0 278 new Constraint('<', substr($b, $posB + 2, -1)),
Chris@0 279 ));
Chris@0 280 } else {
Chris@0 281 $constraint = new MultiConstraint($orGroups, false);
Chris@0 282 }
Chris@0 283
Chris@0 284 $constraint->setPrettyString($prettyConstraint);
Chris@0 285
Chris@0 286 return $constraint;
Chris@0 287 }
Chris@0 288
Chris@0 289 /**
Chris@0 290 * @param string $constraint
Chris@0 291 *
Chris@0 292 * @throws \UnexpectedValueException
Chris@0 293 *
Chris@0 294 * @return array
Chris@0 295 */
Chris@0 296 private function parseConstraint($constraint)
Chris@0 297 {
Chris@0 298 if (preg_match('{^([^,\s]+?)@(' . implode('|', self::$stabilities) . ')$}i', $constraint, $match)) {
Chris@0 299 $constraint = $match[1];
Chris@0 300 if ($match[2] !== 'stable') {
Chris@0 301 $stabilityModifier = $match[2];
Chris@0 302 }
Chris@0 303 }
Chris@0 304
Chris@0 305 if (preg_match('{^v?[xX*](\.[xX*])*$}i', $constraint)) {
Chris@0 306 return array(new EmptyConstraint());
Chris@0 307 }
Chris@0 308
Chris@0 309 $versionRegex = 'v?(\d++)(?:\.(\d++))?(?:\.(\d++))?(?:\.(\d++))?' . self::$modifierRegex . '(?:\+[^\s]+)?';
Chris@0 310
Chris@0 311 // Tilde Range
Chris@0 312 //
Chris@0 313 // Like wildcard constraints, unsuffixed tilde constraints say that they must be greater than the previous
Chris@0 314 // version, to ensure that unstable instances of the current version are allowed. However, if a stability
Chris@0 315 // suffix is added to the constraint, then a >= match on the current version is used instead.
Chris@0 316 if (preg_match('{^~>?' . $versionRegex . '$}i', $constraint, $matches)) {
Chris@0 317 if (substr($constraint, 0, 2) === '~>') {
Chris@0 318 throw new \UnexpectedValueException(
Chris@0 319 'Could not parse version constraint ' . $constraint . ': ' .
Chris@0 320 'Invalid operator "~>", you probably meant to use the "~" operator'
Chris@0 321 );
Chris@0 322 }
Chris@0 323
Chris@0 324 // Work out which position in the version we are operating at
Chris@0 325 if (isset($matches[4]) && '' !== $matches[4]) {
Chris@0 326 $position = 4;
Chris@0 327 } elseif (isset($matches[3]) && '' !== $matches[3]) {
Chris@0 328 $position = 3;
Chris@0 329 } elseif (isset($matches[2]) && '' !== $matches[2]) {
Chris@0 330 $position = 2;
Chris@0 331 } else {
Chris@0 332 $position = 1;
Chris@0 333 }
Chris@0 334
Chris@0 335 // Calculate the stability suffix
Chris@0 336 $stabilitySuffix = '';
Chris@0 337 if (!empty($matches[5])) {
Chris@0 338 $stabilitySuffix .= '-' . $this->expandStability($matches[5]) . (!empty($matches[6]) ? $matches[6] : '');
Chris@0 339 }
Chris@0 340
Chris@0 341 if (!empty($matches[7])) {
Chris@0 342 $stabilitySuffix .= '-dev';
Chris@0 343 }
Chris@0 344
Chris@0 345 if (!$stabilitySuffix) {
Chris@0 346 $stabilitySuffix = '-dev';
Chris@0 347 }
Chris@0 348
Chris@0 349 $lowVersion = $this->manipulateVersionString($matches, $position, 0) . $stabilitySuffix;
Chris@0 350 $lowerBound = new Constraint('>=', $lowVersion);
Chris@0 351
Chris@0 352 // For upper bound, we increment the position of one more significance,
Chris@0 353 // but highPosition = 0 would be illegal
Chris@0 354 $highPosition = max(1, $position - 1);
Chris@0 355 $highVersion = $this->manipulateVersionString($matches, $highPosition, 1) . '-dev';
Chris@0 356 $upperBound = new Constraint('<', $highVersion);
Chris@0 357
Chris@0 358 return array(
Chris@0 359 $lowerBound,
Chris@0 360 $upperBound,
Chris@0 361 );
Chris@0 362 }
Chris@0 363
Chris@0 364 // Caret Range
Chris@0 365 //
Chris@0 366 // Allows changes that do not modify the left-most non-zero digit in the [major, minor, patch] tuple.
Chris@0 367 // In other words, this allows patch and minor updates for versions 1.0.0 and above, patch updates for
Chris@0 368 // versions 0.X >=0.1.0, and no updates for versions 0.0.X
Chris@0 369 if (preg_match('{^\^' . $versionRegex . '($)}i', $constraint, $matches)) {
Chris@0 370 // Work out which position in the version we are operating at
Chris@0 371 if ('0' !== $matches[1] || '' === $matches[2]) {
Chris@0 372 $position = 1;
Chris@0 373 } elseif ('0' !== $matches[2] || '' === $matches[3]) {
Chris@0 374 $position = 2;
Chris@0 375 } else {
Chris@0 376 $position = 3;
Chris@0 377 }
Chris@0 378
Chris@0 379 // Calculate the stability suffix
Chris@0 380 $stabilitySuffix = '';
Chris@0 381 if (empty($matches[5]) && empty($matches[7])) {
Chris@0 382 $stabilitySuffix .= '-dev';
Chris@0 383 }
Chris@0 384
Chris@0 385 $lowVersion = $this->normalize(substr($constraint . $stabilitySuffix, 1));
Chris@0 386 $lowerBound = new Constraint('>=', $lowVersion);
Chris@0 387
Chris@0 388 // For upper bound, we increment the position of one more significance,
Chris@0 389 // but highPosition = 0 would be illegal
Chris@0 390 $highVersion = $this->manipulateVersionString($matches, $position, 1) . '-dev';
Chris@0 391 $upperBound = new Constraint('<', $highVersion);
Chris@0 392
Chris@0 393 return array(
Chris@0 394 $lowerBound,
Chris@0 395 $upperBound,
Chris@0 396 );
Chris@0 397 }
Chris@0 398
Chris@0 399 // X Range
Chris@0 400 //
Chris@0 401 // Any of X, x, or * may be used to "stand in" for one of the numeric values in the [major, minor, patch] tuple.
Chris@0 402 // A partial version range is treated as an X-Range, so the special character is in fact optional.
Chris@0 403 if (preg_match('{^v?(\d++)(?:\.(\d++))?(?:\.(\d++))?(?:\.[xX*])++$}', $constraint, $matches)) {
Chris@0 404 if (isset($matches[3]) && '' !== $matches[3]) {
Chris@0 405 $position = 3;
Chris@0 406 } elseif (isset($matches[2]) && '' !== $matches[2]) {
Chris@0 407 $position = 2;
Chris@0 408 } else {
Chris@0 409 $position = 1;
Chris@0 410 }
Chris@0 411
Chris@0 412 $lowVersion = $this->manipulateVersionString($matches, $position) . '-dev';
Chris@0 413 $highVersion = $this->manipulateVersionString($matches, $position, 1) . '-dev';
Chris@0 414
Chris@0 415 if ($lowVersion === '0.0.0.0-dev') {
Chris@0 416 return array(new Constraint('<', $highVersion));
Chris@0 417 }
Chris@0 418
Chris@0 419 return array(
Chris@0 420 new Constraint('>=', $lowVersion),
Chris@0 421 new Constraint('<', $highVersion),
Chris@0 422 );
Chris@0 423 }
Chris@0 424
Chris@0 425 // Hyphen Range
Chris@0 426 //
Chris@0 427 // Specifies an inclusive set. If a partial version is provided as the first version in the inclusive range,
Chris@0 428 // then the missing pieces are replaced with zeroes. If a partial version is provided as the second version in
Chris@0 429 // the inclusive range, then all versions that start with the supplied parts of the tuple are accepted, but
Chris@0 430 // nothing that would be greater than the provided tuple parts.
Chris@0 431 if (preg_match('{^(?P<from>' . $versionRegex . ') +- +(?P<to>' . $versionRegex . ')($)}i', $constraint, $matches)) {
Chris@0 432 // Calculate the stability suffix
Chris@0 433 $lowStabilitySuffix = '';
Chris@0 434 if (empty($matches[6]) && empty($matches[8])) {
Chris@0 435 $lowStabilitySuffix = '-dev';
Chris@0 436 }
Chris@0 437
Chris@0 438 $lowVersion = $this->normalize($matches['from']);
Chris@0 439 $lowerBound = new Constraint('>=', $lowVersion . $lowStabilitySuffix);
Chris@0 440
Chris@0 441 $empty = function ($x) {
Chris@0 442 return ($x === 0 || $x === '0') ? false : empty($x);
Chris@0 443 };
Chris@0 444
Chris@0 445 if ((!$empty($matches[11]) && !$empty($matches[12])) || !empty($matches[14]) || !empty($matches[16])) {
Chris@0 446 $highVersion = $this->normalize($matches['to']);
Chris@0 447 $upperBound = new Constraint('<=', $highVersion);
Chris@0 448 } else {
Chris@0 449 $highMatch = array('', $matches[10], $matches[11], $matches[12], $matches[13]);
Chris@0 450 $highVersion = $this->manipulateVersionString($highMatch, $empty($matches[11]) ? 1 : 2, 1) . '-dev';
Chris@0 451 $upperBound = new Constraint('<', $highVersion);
Chris@0 452 }
Chris@0 453
Chris@0 454 return array(
Chris@0 455 $lowerBound,
Chris@0 456 $upperBound,
Chris@0 457 );
Chris@0 458 }
Chris@0 459
Chris@0 460 // Basic Comparators
Chris@0 461 if (preg_match('{^(<>|!=|>=?|<=?|==?)?\s*(.*)}', $constraint, $matches)) {
Chris@0 462 try {
Chris@0 463 $version = $this->normalize($matches[2]);
Chris@0 464
Chris@0 465 if (!empty($stabilityModifier) && $this->parseStability($version) === 'stable') {
Chris@0 466 $version .= '-' . $stabilityModifier;
Chris@0 467 } elseif ('<' === $matches[1] || '>=' === $matches[1]) {
Chris@0 468 if (!preg_match('/-' . self::$modifierRegex . '$/', strtolower($matches[2]))) {
Chris@0 469 if (substr($matches[2], 0, 4) !== 'dev-') {
Chris@0 470 $version .= '-dev';
Chris@0 471 }
Chris@0 472 }
Chris@0 473 }
Chris@0 474
Chris@0 475 return array(new Constraint($matches[1] ?: '=', $version));
Chris@0 476 } catch (\Exception $e) {
Chris@0 477 }
Chris@0 478 }
Chris@0 479
Chris@0 480 $message = 'Could not parse version constraint ' . $constraint;
Chris@0 481 if (isset($e)) {
Chris@0 482 $message .= ': ' . $e->getMessage();
Chris@0 483 }
Chris@0 484
Chris@0 485 throw new \UnexpectedValueException($message);
Chris@0 486 }
Chris@0 487
Chris@0 488 /**
Chris@0 489 * Increment, decrement, or simply pad a version number.
Chris@0 490 *
Chris@0 491 * Support function for {@link parseConstraint()}
Chris@0 492 *
Chris@0 493 * @param array $matches Array with version parts in array indexes 1,2,3,4
Chris@0 494 * @param int $position 1,2,3,4 - which segment of the version to increment/decrement
Chris@0 495 * @param int $increment
Chris@0 496 * @param string $pad The string to pad version parts after $position
Chris@0 497 *
Chris@0 498 * @return string The new version
Chris@0 499 */
Chris@0 500 private function manipulateVersionString($matches, $position, $increment = 0, $pad = '0')
Chris@0 501 {
Chris@0 502 for ($i = 4; $i > 0; --$i) {
Chris@0 503 if ($i > $position) {
Chris@0 504 $matches[$i] = $pad;
Chris@0 505 } elseif ($i === $position && $increment) {
Chris@0 506 $matches[$i] += $increment;
Chris@0 507 // If $matches[$i] was 0, carry the decrement
Chris@0 508 if ($matches[$i] < 0) {
Chris@0 509 $matches[$i] = $pad;
Chris@0 510 --$position;
Chris@0 511
Chris@0 512 // Return null on a carry overflow
Chris@0 513 if ($i === 1) {
Chris@0 514 return;
Chris@0 515 }
Chris@0 516 }
Chris@0 517 }
Chris@0 518 }
Chris@0 519
Chris@0 520 return $matches[1] . '.' . $matches[2] . '.' . $matches[3] . '.' . $matches[4];
Chris@0 521 }
Chris@0 522
Chris@0 523 /**
Chris@0 524 * Expand shorthand stability string to long version.
Chris@0 525 *
Chris@0 526 * @param string $stability
Chris@0 527 *
Chris@0 528 * @return string
Chris@0 529 */
Chris@0 530 private function expandStability($stability)
Chris@0 531 {
Chris@0 532 $stability = strtolower($stability);
Chris@0 533
Chris@0 534 switch ($stability) {
Chris@0 535 case 'a':
Chris@0 536 return 'alpha';
Chris@0 537 case 'b':
Chris@0 538 return 'beta';
Chris@0 539 case 'p':
Chris@0 540 case 'pl':
Chris@0 541 return 'patch';
Chris@0 542 case 'rc':
Chris@0 543 return 'RC';
Chris@0 544 default:
Chris@0 545 return $stability;
Chris@0 546 }
Chris@0 547 }
Chris@0 548 }