Browse Source

Merge branch 'disjunctive'

Jordi Boggiano 12 years ago
parent
commit
9d948eb795

+ 18 - 4
src/Composer/Package/LinkConstraint/MultiConstraint.php

@@ -13,27 +13,41 @@
 namespace Composer\Package\LinkConstraint;
 
 /**
- * Defines a conjunctive set of constraints on the target of a package link
+ * Defines a conjunctive or disjunctive set of constraints on the target of a package link
  *
  * @author Nils Adermann <naderman@naderman.de>
+ * @author Jordi Boggiano <j.boggiano@seld.be>
  */
 class MultiConstraint implements LinkConstraintInterface
 {
     protected $constraints;
     protected $prettyString;
+    protected $conjunctive;
 
     /**
      * Sets operator and version to compare a package with
      *
-     * @param array $constraints A conjunctive set of constraints
+     * @param array $constraints A set of constraints
+     * @param bool  $conjunctive Whether the constraints should be treated as conjunctive or disjunctive
      */
-    public function __construct(array $constraints)
+    public function __construct(array $constraints, $conjunctive = true)
     {
         $this->constraints = $constraints;
+        $this->conjunctive = $conjunctive;
     }
 
     public function matches(LinkConstraintInterface $provider)
     {
+        if (false === $this->conjunctive) {
+            foreach ($this->constraints as $constraint) {
+                if ($constraint->matches($provider)) {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+
         foreach ($this->constraints as $constraint) {
             if (!$constraint->matches($provider)) {
                 return false;
@@ -64,6 +78,6 @@ class MultiConstraint implements LinkConstraintInterface
             $constraints[] = $constraint->__toString();
         }
 
-        return '['.implode(', ', $constraints).']';
+        return '['.implode($this->conjunctive ? ', ' : ' | ', $constraints).']';
     }
 }

+ 22 - 10
src/Composer/Package/Version/VersionParser.php

@@ -222,21 +222,33 @@ class VersionParser
             $constraints = $match[1];
         }
 
-        $constraints = preg_split('{\s*,\s*}', trim($constraints));
+        $orConstraints = preg_split('{\s*\|\s*}', trim($constraints));
+        $orGroups = array();
+        foreach ($orConstraints as $constraints) {
+            $andConstraints = preg_split('{\s*,\s*}', $constraints);
+
+            if (count($andConstraints) > 1) {
+                $constraintObjects = array();
+                foreach ($andConstraints as $constraint) {
+                    $constraintObjects = array_merge($constraintObjects, $this->parseConstraint($constraint));
+                }
+            } else {
+                $constraintObjects = $this->parseConstraint($andConstraints[0]);
+            }
 
-        if (count($constraints) > 1) {
-            $constraintObjects = array();
-            foreach ($constraints as $constraint) {
-                $constraintObjects = array_merge($constraintObjects, $this->parseConstraint($constraint));
+            if (1 === count($constraintObjects)) {
+                $constraint = $constraintObjects[0];
+            } else {
+                $constraint = new MultiConstraint($constraintObjects);
             }
-        } else {
-            $constraintObjects = $this->parseConstraint($constraints[0]);
+
+            $orGroups[] = $constraint;
         }
 
-        if (1 === count($constraintObjects)) {
-            $constraint = $constraintObjects[0];
+        if (1 === count($orGroups)) {
+            $constraint = $orGroups[0];
         } else {
-            $constraint = new MultiConstraint($constraintObjects);
+            $constraint = new MultiConstraint($orGroups, false);
         }
 
         $constraint->setPrettyString($prettyConstraint);

+ 24 - 0
tests/Composer/Test/Fixtures/installer/disjunctive-multi-constraints.test

@@ -0,0 +1,24 @@
+--TEST--
+Disjunctive multi constraints work
+--COMPOSER--
+{
+    "repositories": [
+        {
+            "type": "package",
+            "package": [
+                { "name": "foo", "version": "1.1.0" },
+                { "name": "foo", "version": "1.0.0" },
+                { "name": "bar", "version": "1.1.0", "require": { "foo": "1.0.*" } }
+            ]
+        }
+    ],
+    "require": {
+        "bar": "1.*",
+        "foo": "1.0.*|1.1.*"
+    }
+}
+--RUN--
+install
+--EXPECT--
+Installing foo (1.0.0)
+Installing bar (1.1.0)

+ 11 - 0
tests/Composer/Test/Package/Version/VersionParserTest.php

@@ -285,6 +285,17 @@ class VersionParserTest extends \PHPUnit_Framework_TestCase
         $this->assertSame((string) $multi, (string) $parser->parseConstraints('>2.0,<=3.0'));
     }
 
+    public function testParseConstraintsMultiDisjunctiveHasPrioOverConjuctive()
+    {
+        $parser = new VersionParser;
+        $first = new VersionConstraint('>', '2.0.0.0');
+        $second = new VersionConstraint('<', '2.0.5.0-dev');
+        $third = new VersionConstraint('>', '2.0.6.0');
+        $multi1 = new MultiConstraint(array($first, $second));
+        $multi2 = new MultiConstraint(array($multi1, $third), false);
+        $this->assertSame((string) $multi2, (string) $parser->parseConstraints('>2.0,<2.0.5 | >2.0.6'));
+    }
+
     public function testParseConstraintsMultiWithStabilities()
     {
         $parser = new VersionParser;