From ebab9db27ac3887babc8404107dd448d974b2f43 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 8 Dec 2014 13:44:42 +0000 Subject: [PATCH] Add support for hyphen ranges --- doc/01-basic-usage.md | 3 +- .../Package/Version/VersionParser.php | 34 +++++++++++++++++-- .../Package/Version/VersionParserTest.php | 27 +++++++++++++++ 3 files changed, 60 insertions(+), 4 deletions(-) diff --git a/doc/01-basic-usage.md b/doc/01-basic-usage.md index 493c42cd4..d3a130ff3 100644 --- a/doc/01-basic-usage.md +++ b/doc/01-basic-usage.md @@ -75,7 +75,8 @@ Version constraints can be specified in a few different ways. Name | Example | Description -------------- | ------------------------------------------------------------------ | ----------- Exact version | `1.0.2` | You can specify the exact version of a package. -Range | `>=1.0` `>=1.0,<2.0` >=1.0,<1.1 | >=1.2 | By using comparison operators you can specify ranges of valid versions. Valid operators are `>`, `>=`, `<`, `<=`, `!=`.
You can define multiple ranges. Ranges separated by a space (` `) or comma (`,`) will be treated as a **logical AND**. A pipe (|) or double pipe will be treated as a **logical OR**. AND has higher precedence than OR. +Range | `>=1.0` `>=1.0 <2.0` >=1.0 <1.1 || >=1.2 | By using comparison operators you can specify ranges of valid versions. Valid operators are `>`, `>=`, `<`, `<=`, `!=`.
You can define multiple ranges. Ranges separated by a space (` `) or comma (`,`) will be treated as a **logical AND**. A double pipe (||) will be treated as a **logical OR**. AND has higher precedence than OR. +Hyphen Range | `1.0 - 2.0` | Inclusive set of versions. Partial versions on the right include are completed with a wildcard. For example `1.0 - 2.0` is equivalent to `>=1.0.0 <2.1` as the `2.0` becomes `2.0.*`. On the other hand `1.0.0 - 2.1.0` is equivalent to `>=1.0.0 <=2.1.0`. Wildcard | `1.0.*` | You can specify a pattern with a `*` wildcard. `1.0.*` is the equivalent of `>=1.0,<1.1`. Tilde Operator | `~1.2` | Very useful for projects that follow semantic versioning. `~1.2` is equivalent to `>=1.2,<2.0`. For more details, read the next section below. diff --git a/src/Composer/Package/Version/VersionParser.php b/src/Composer/Package/Version/VersionParser.php index 9b5df66b0..c10e85939 100644 --- a/src/Composer/Package/Version/VersionParser.php +++ b/src/Composer/Package/Version/VersionParser.php @@ -233,8 +233,7 @@ class VersionParser $orConstraints = preg_split('{\s*\|\|?\s*}', trim($constraints)); $orGroups = array(); foreach ($orConstraints as $constraints) { - $andConstraints = preg_split('{(?< ,]) *[, ] *(?!,|as|$)}', $constraints); - + $andConstraints = preg_split('{(?< ,]) *(? 1) { $constraintObjects = array(); foreach ($andConstraints as $constraint) { @@ -277,12 +276,14 @@ class VersionParser return array(new EmptyConstraint); } + $versionRegex = '(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:\.(\d+))?'.self::$modifierRegex; + // match tilde constraints // like wildcard constraints, unsuffixed tilde constraints say that they must be greater than the previous // version, to ensure that unstable instances of the current version are allowed. // however, if a stability suffix is added to the constraint, then a >= match on the current version is // used instead - if (preg_match('{^~>?(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:\.(\d+))?'.self::$modifierRegex.'?$}i', $constraint, $matches)) { + if (preg_match('{^~>?'.$versionRegex.'$}i', $constraint, $matches)) { if (substr($constraint, 0, 2) === '~>') { throw new \UnexpectedValueException( 'Could not parse version constraint '.$constraint.': '. @@ -352,6 +353,33 @@ class VersionParser ); } + // match hyphen constraints + if (preg_match('{^(?P'.$versionRegex.') +- +(?P'.$versionRegex.')($)}i', $constraint, $matches)) { + // Calculate the stability suffix + $lowStabilitySuffix = ''; + if (empty($matches[6]) && empty($matches[8])) { + $lowStabilitySuffix = '-dev'; + } + + $lowVersion = $this->normalize($matches['from']); + $lowerBound = new VersionConstraint('>=', $lowVersion . $lowStabilitySuffix); + + $highVersion = $matches[10]; + if ((!empty($matches[11]) && !empty($matches[12])) || !empty($matches[14]) || !empty($matches[16])) { + $highVersion = $this->normalize($matches['to']); + $upperBound = new VersionConstraint('<=', $highVersion); + } else { + $highMatch = array('', $matches[10], $matches[11], $matches[12], $matches[13]); + $highVersion = $this->manipulateVersionString($highMatch, empty($matches[11]) ? 1 : 2, 1) . '-dev'; + $upperBound = new VersionConstraint('<', $highVersion); + } + + return array( + $lowerBound, + $upperBound + ); + } + // match operators constraints if (preg_match('{^(<>|!=|>=?|<=?|==?)?\s*(.*)}', $constraint, $matches)) { try { diff --git a/tests/Composer/Test/Package/Version/VersionParserTest.php b/tests/Composer/Test/Package/Version/VersionParserTest.php index 2ed19c416..58b4c9e36 100644 --- a/tests/Composer/Test/Package/Version/VersionParserTest.php +++ b/tests/Composer/Test/Package/Version/VersionParserTest.php @@ -294,6 +294,33 @@ class VersionParserTest extends \PHPUnit_Framework_TestCase ); } + /** + * @dataProvider hyphenConstraints + */ + public function testParseHyphen($input, $min, $max) + { + $parser = new VersionParser; + if ($min) { + $expected = new MultiConstraint(array($min, $max)); + } else { + $expected = $max; + } + + $this->assertSame((string) $expected, (string) $parser->parseConstraints($input)); + } + + public function hyphenConstraints() + { + return array( + array('1 - 2', new VersionConstraint('>=', '1.0.0.0-dev'), new VersionConstraint('<', '3.0.0.0-dev')), + array('1.2.3 - 2.3.4.5', new VersionConstraint('>=', '1.2.3.0-dev'), new VersionConstraint('<=', '2.3.4.5')), + array('1.2-beta - 2.3', new VersionConstraint('>=', '1.2.0.0-beta'), new VersionConstraint('<', '2.4.0.0-dev')), + array('1.2-beta - 2.3-dev', new VersionConstraint('>=', '1.2.0.0-beta'), new VersionConstraint('<=', '2.3.0.0-dev')), + array('1.2-RC - 2.3.1', new VersionConstraint('>=', '1.2.0.0-RC'), new VersionConstraint('<=', '2.3.1.0')), + array('1.2.3-alpha - 2.3-RC', new VersionConstraint('>=', '1.2.3.0-alpha'), new VersionConstraint('<=', '2.3.0.0-RC')), + ); + } + /** * @dataProvider multiConstraintProvider */