Browse Source

Add support for hyphen ranges

Jordi Boggiano 10 years ago
parent
commit
ebab9db27a

+ 2 - 1
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` <code>&gt;=1.0,&lt;1.1 &#124; &gt;=1.2</code> | By using comparison operators you can specify ranges of valid versions. Valid operators are `>`, `>=`, `<`, `<=`, `!=`. <br />You can define multiple ranges. Ranges separated by a space (` `) or comma (`,`) will be treated as a **logical AND**. A pipe (<code>&#124;</code>) or double pipe will be treated as a **logical OR**. AND has higher precedence than OR.
+Range          | `>=1.0` `>=1.0 <2.0` <code>&gt;=1.0 &lt;1.1 &#124;&#124; &gt;=1.2</code> | By using comparison operators you can specify ranges of valid versions. Valid operators are `>`, `>=`, `<`, `<=`, `!=`. <br />You can define multiple ranges. Ranges separated by a space (` `) or comma (`,`) will be treated as a **logical AND**. A double pipe (<code>&#124;&#124;</code>) 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.
 

+ 31 - 3
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|[=>< ,]) *[, ] *(?!,|as|$)}', $constraints);
-
+            $andConstraints = preg_split('{(?<!^|as|[=>< ,]) *(?<!-)[, ](?!-) *(?!,|as|$)}', $constraints);
             if (count($andConstraints) > 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<from>'.$versionRegex.') +- +(?P<to>'.$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 {

+ 27 - 0
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
      */