Legoktm has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/228132

Change subject: Add composer/semver 0.1.0
......................................................................

Add composer/semver 0.1.0

Will be used in MediaWiki core I778582721.

Bug: T99086
Change-Id: I50d636df321b6aa7a921c8ca1d111f5b0c459ca9
---
M composer.json
M composer.lock
M composer/autoload_classmap.php
M composer/autoload_psr4.php
M composer/installed.json
A composer/semver/CHANGELOG.md
A composer/semver/LICENSE
A composer/semver/README.md
A composer/semver/composer.json
A composer/semver/src/Comparator.php
A composer/semver/src/Constraint/EmptyConstraint.php
A composer/semver/src/Constraint/LinkConstraintInterface.php
A composer/semver/src/Constraint/MultiConstraint.php
A composer/semver/src/Constraint/SpecificConstraint.php
A composer/semver/src/Constraint/VersionConstraint.php
A composer/semver/src/VersionParser.php
16 files changed, 1,335 insertions(+), 1 deletion(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/vendor 
refs/changes/32/228132/1

diff --git a/composer.json b/composer.json
index 0e55797..e3884d1 100644
--- a/composer.json
+++ b/composer.json
@@ -9,6 +9,7 @@
        },
        "prefer-stable": true,
        "require": {
+               "composer/semver": "0.1.0",
                "cssjanus/cssjanus": "1.1.1",
                "kzykhys/pygments": "1.0",
                "leafo/lessphp": "0.5.0",
diff --git a/composer.lock b/composer.lock
index 2f77679..792fa6a 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,9 +4,70 @@
         "Read more about it at 
https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file";,
         "This file is @generated automatically"
     ],
-    "hash": "09e6099a2d48fd0aa20ad2fb526eedcd",
+    "hash": "5fe0e654588289e1b4b522428039ace3",
     "packages": [
         {
+            "name": "composer/semver",
+            "version": "0.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/composer/semver.git";,
+                "reference": "f6469477aa1952f2fcbd0ab52fcc7662f1dd0173"
+            },
+            "dist": {
+                "type": "zip",
+                "url": 
"https://api.github.com/repos/composer/semver/zipball/f6469477aa1952f2fcbd0ab52fcc7662f1dd0173";,
+                "reference": "f6469477aa1952f2fcbd0ab52fcc7662f1dd0173",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.2"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~4.5",
+                "phpunit/phpunit-mock-objects": "~2.3"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "0.1-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Composer\\Semver\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/";,
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Rob Bast",
+                    "email": "[email protected]"
+                },
+                {
+                    "name": "Nils Adermann",
+                    "email": "[email protected]",
+                    "homepage": "http://www.naderman.de";
+                },
+                {
+                    "name": "Jordi Boggiano",
+                    "email": "[email protected]",
+                    "homepage": "http://seld.be";
+                }
+            ],
+            "description": "Semver library that offers utilities, version 
constraint parsing and validation.",
+            "keywords": [
+                "semantic",
+                "semver",
+                "validation",
+                "versioning"
+            ],
+            "time": "2015-07-23 06:21:50"
+        },
+        {
             "name": "cssjanus/cssjanus",
             "version": "v1.1.1",
             "source": {
diff --git a/composer/autoload_classmap.php b/composer/autoload_classmap.php
index a8d8445..86f69e8 100644
--- a/composer/autoload_classmap.php
+++ b/composer/autoload_classmap.php
@@ -16,6 +16,13 @@
     'Cdb\\Writer' => $vendorDir . '/wikimedia/cdb/src/Writer.php',
     'Cdb\\Writer\\DBA' => $vendorDir . '/wikimedia/cdb/src/Writer/DBA.php',
     'Cdb\\Writer\\PHP' => $vendorDir . '/wikimedia/cdb/src/Writer/PHP.php',
+    'Composer\\Semver\\Comparator' => $vendorDir . 
'/composer/semver/src/Comparator.php',
+    'Composer\\Semver\\Constraint\\EmptyConstraint' => $vendorDir . 
'/composer/semver/src/Constraint/EmptyConstraint.php',
+    'Composer\\Semver\\Constraint\\LinkConstraintInterface' => $vendorDir . 
'/composer/semver/src/Constraint/LinkConstraintInterface.php',
+    'Composer\\Semver\\Constraint\\MultiConstraint' => $vendorDir . 
'/composer/semver/src/Constraint/MultiConstraint.php',
+    'Composer\\Semver\\Constraint\\SpecificConstraint' => $vendorDir . 
'/composer/semver/src/Constraint/SpecificConstraint.php',
+    'Composer\\Semver\\Constraint\\VersionConstraint' => $vendorDir . 
'/composer/semver/src/Constraint/VersionConstraint.php',
+    'Composer\\Semver\\VersionParser' => $vendorDir . 
'/composer/semver/src/VersionParser.php',
     'Elastica\\AbstractUpdateAction' => $vendorDir . 
'/ruflin/elastica/lib/Elastica/AbstractUpdateAction.php',
     'Elastica\\Aggregation\\AbstractAggregation' => $vendorDir . 
'/ruflin/elastica/lib/Elastica/Aggregation/AbstractAggregation.php',
     'Elastica\\Aggregation\\AbstractSimpleAggregation' => $vendorDir . 
'/ruflin/elastica/lib/Elastica/Aggregation/AbstractSimpleAggregation.php',
diff --git a/composer/autoload_psr4.php b/composer/autoload_psr4.php
index c9e9ce3..5f09085 100644
--- a/composer/autoload_psr4.php
+++ b/composer/autoload_psr4.php
@@ -11,4 +11,5 @@
     'Wikimedia\\Assert\\' => array($vendorDir . '/wikimedia/assert/src'),
     'Symfony\\Component\\Process\\' => array($vendorDir . '/symfony/process'),
     'Monolog\\' => array($vendorDir . '/monolog/monolog/src/Monolog'),
+    'Composer\\Semver\\' => array($vendorDir . '/composer/semver/src'),
 );
diff --git a/composer/installed.json b/composer/installed.json
index af15ce8..9156f50 100644
--- a/composer/installed.json
+++ b/composer/installed.json
@@ -760,5 +760,68 @@
         ],
         "description": "Provides library of common widgets, layouts, and 
windows.",
         "homepage": "https://www.mediawiki.org/wiki/OOjs_UI";
+    },
+    {
+        "name": "composer/semver",
+        "version": "0.1.0",
+        "version_normalized": "0.1.0.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/composer/semver.git";,
+            "reference": "f6469477aa1952f2fcbd0ab52fcc7662f1dd0173"
+        },
+        "dist": {
+            "type": "zip",
+            "url": 
"https://api.github.com/repos/composer/semver/zipball/f6469477aa1952f2fcbd0ab52fcc7662f1dd0173";,
+            "reference": "f6469477aa1952f2fcbd0ab52fcc7662f1dd0173",
+            "shasum": ""
+        },
+        "require": {
+            "php": ">=5.3.2"
+        },
+        "require-dev": {
+            "phpunit/phpunit": "~4.5",
+            "phpunit/phpunit-mock-objects": "~2.3"
+        },
+        "time": "2015-07-23 06:21:50",
+        "type": "library",
+        "extra": {
+            "branch-alias": {
+                "dev-master": "0.1-dev"
+            }
+        },
+        "installation-source": "dist",
+        "autoload": {
+            "psr-4": {
+                "Composer\\Semver\\": "src"
+            }
+        },
+        "notification-url": "https://packagist.org/downloads/";,
+        "license": [
+            "MIT"
+        ],
+        "authors": [
+            {
+                "name": "Rob Bast",
+                "email": "[email protected]"
+            },
+            {
+                "name": "Nils Adermann",
+                "email": "[email protected]",
+                "homepage": "http://www.naderman.de";
+            },
+            {
+                "name": "Jordi Boggiano",
+                "email": "[email protected]",
+                "homepage": "http://seld.be";
+            }
+        ],
+        "description": "Semver library that offers utilities, version 
constraint parsing and validation.",
+        "keywords": [
+            "semantic",
+            "semver",
+            "validation",
+            "versioning"
+        ]
     }
 ]
diff --git a/composer/semver/CHANGELOG.md b/composer/semver/CHANGELOG.md
new file mode 100644
index 0000000..37d29de
--- /dev/null
+++ b/composer/semver/CHANGELOG.md
@@ -0,0 +1,16 @@
+# Change Log
+
+All notable changes to this project will be documented in this file.
+This project adheres to [Semantic Versioning](http://semver.org/).
+
+### [0.1.0] 2015-07-23
+
+  * Added: `Composer\Semver\Comparator`, various methods to compare versions.
+  * Added: various documents such as README.md, LICENSE, etc.
+  * Added: configuration files for Git, Travis, php-cs-fixer, phpunit.
+  * Break: the following namespaces were renamed:
+    - Namespace: `Composer\Package\Version` -> `Composer\Semver`
+    - Namespace: `Composer\Package\LinkConstraint` -> 
`Composer\Semver\Constraint`
+    - Namespace: `Composer\Test\Package\Version` -> `Composer\Test\Semver`
+    - Namespace: `Composer\Test\Package\LinkConstraint` -> 
`Composer\Test\Semver\Constraint`
+  * Changed: code style using php-cs-fixer.
diff --git a/composer/semver/LICENSE b/composer/semver/LICENSE
new file mode 100644
index 0000000..4669758
--- /dev/null
+++ b/composer/semver/LICENSE
@@ -0,0 +1,19 @@
+Copyright (C) 2015 Composer
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/composer/semver/README.md b/composer/semver/README.md
new file mode 100644
index 0000000..c0b34ce
--- /dev/null
+++ b/composer/semver/README.md
@@ -0,0 +1,50 @@
+composer/semver
+===============
+
+Semver library that offers utilities, version constraint parsing and 
validation.
+
+Originally written as part of 
[composer/composer](https://github.com/composer/composer),
+now extracted and made available as a stand-alone library.
+
+[![Build 
Status](https://travis-ci.org/composer/semver.svg?branch=master)](https://travis-ci.org/composer/semver)
+
+Installation
+------------
+
+Install the latest version with:
+
+```bash
+$ composer require composer/semver
+```
+
+Requirements
+------------
+
+* PHP 5.3.2 is required but using the latest version of PHP is highly 
recommended.
+
+Basic usage
+-----------
+
+The `Composer\Semver\Comparator` class provides the following high-level
+functions for comparing versions:
+
+* greaterThan
+* greaterThanOrEqualTo
+* lessThan
+* lessThanOrEqualTo
+* equalTo
+* notEqualTo
+
+Each function takes two version strings as arguments. For example:
+
+```php
+use Composer\Semver\Comparator;
+
+Comparator::greaterThan('1.25.0', '1.24.0'); // 1.25.0 > 1.24.0
+```
+
+
+License
+-------
+
+composer/semver is licensed under the MIT License, see the LICENSE file for 
details.
diff --git a/composer/semver/composer.json b/composer/semver/composer.json
new file mode 100644
index 0000000..b996186
--- /dev/null
+++ b/composer/semver/composer.json
@@ -0,0 +1,57 @@
+{
+    "name": "composer/semver",
+    "description": "Semver library that offers utilities, version constraint 
parsing and validation.",
+    "type": "library",
+    "license": "MIT",
+    "keywords": [
+        "semver",
+        "semantic",
+        "versioning",
+        "validation"
+    ],
+    "authors": [
+        {
+            "name": "Nils Adermann",
+            "email": "[email protected]",
+            "homepage": "http://www.naderman.de";
+        },
+        {
+            "name": "Jordi Boggiano",
+            "email": "[email protected]",
+            "homepage": "http://seld.be";
+        },
+        {
+            "name": "Rob Bast",
+            "email": "[email protected]"
+        }
+    ],
+    "support": {
+        "irc": "irc://irc.freenode.org/composer",
+        "issues": "https://github.com/composer/semver/issues";
+    },
+    "require": {
+        "php": ">=5.3.2"
+    },
+    "require-dev": {
+        "phpunit/phpunit": "~4.5",
+        "phpunit/phpunit-mock-objects": "~2.3"
+    },
+    "autoload": {
+        "psr-4": {
+            "Composer\\Semver\\": "src"
+        }
+    },
+    "autoload-dev": {
+        "psr-4": {
+            "Composer\\Semver\\Test\\": "tests"
+        }
+    },
+    "extra": {
+        "branch-alias": {
+            "dev-master": "0.1-dev"
+        }
+    },
+    "scripts": {
+        "test": "phpunit"
+    }
+}
diff --git a/composer/semver/src/Comparator.php 
b/composer/semver/src/Comparator.php
new file mode 100644
index 0000000..8afce22
--- /dev/null
+++ b/composer/semver/src/Comparator.php
@@ -0,0 +1,121 @@
+<?php
+
+/*
+ * This file is part of composer/semver.
+ *
+ * (c) Composer <https://github.com/composer>
+ *
+ * For the full copyright and license information, please view
+ * the LICENSE file that was distributed with this source code.
+ */
+
+namespace Composer\Semver;
+
+use Composer\Semver\Constraint\VersionConstraint;
+
+class Comparator
+{
+    /**
+     * Whether $version1 > $version2.
+     *
+     * @param string $version1
+     * @param string $version2
+     *
+     * @return bool
+     */
+    public static function greaterThan($version1, $version2)
+    {
+        return self::compare($version1, '>', $version2);
+    }
+
+    /**
+     * Whether $version1 >= $version2.
+     *
+     * @param string $version1
+     * @param string $version2
+     *
+     * @return bool
+     */
+    public static function greaterThanOrEqualTo($version1, $version2)
+    {
+        return self::compare($version1, '>=', $version2);
+    }
+
+    /**
+     * Whether $version1 < $version2.
+     *
+     * @param string $version1
+     * @param string $version2
+     *
+     * @return bool
+     */
+    public static function lessThan($version1, $version2)
+    {
+        return self::compare($version1, '<', $version2);
+    }
+
+    /**
+     * Whether $version1 <= $version2.
+     *
+     * @param string $version1
+     * @param string $version2
+     *
+     * @return bool
+     */
+    public static function lessThanOrEqualTo($version1, $version2)
+    {
+        return self::compare($version1, '<=', $version2);
+    }
+
+    /**
+     * Whether $version1 == $version2.
+     *
+     * @param string $version1
+     * @param string $version2
+     *
+     * @return bool
+     */
+    public static function equalTo($version1, $version2)
+    {
+        return self::compare($version1, '==', $version2);
+    }
+
+    /**
+     * Whether $version1 != $version2.
+     *
+     * @param string $version1
+     * @param string $version2
+     *
+     * @return bool
+     */
+    public static function notEqualTo($version1, $version2)
+    {
+        return self::compare($version1, '!=', $version2);
+    }
+
+    /**
+     * Evaluate $version1 $operator $version2.
+     *
+     * @param string $version1
+     * @param string $operator Comparison operator like ">" or "<=", etc.
+     * @param string $version2
+     *
+     * @throws \InvalidArgumentException
+     *
+     * @return bool
+     */
+    public static function compare($version1, $operator, $version2)
+    {
+        if (!in_array($operator, VersionConstraint::getSupportedOperators())) {
+            throw new \InvalidArgumentException(sprintf(
+                'Operator "%s" not supported, expected one of: %s',
+                $operator,
+                implode(', ', VersionConstraint::getSupportedOperators())
+            ));
+        }
+
+        $constraint = new VersionConstraint($operator, $version2);
+
+        return $constraint->matches(new VersionConstraint('==', $version1));
+    }
+}
diff --git a/composer/semver/src/Constraint/EmptyConstraint.php 
b/composer/semver/src/Constraint/EmptyConstraint.php
new file mode 100644
index 0000000..f906030
--- /dev/null
+++ b/composer/semver/src/Constraint/EmptyConstraint.php
@@ -0,0 +1,61 @@
+<?php
+
+/*
+ * This file is part of composer/semver.
+ *
+ * (c) Composer <https://github.com/composer>
+ *
+ * For the full copyright and license information, please view
+ * the LICENSE file that was distributed with this source code.
+ */
+
+namespace Composer\Semver\Constraint;
+
+/**
+ * Defines an absence of constraints.
+ *
+ * @author Jordi Boggiano <[email protected]>
+ */
+class EmptyConstraint implements LinkConstraintInterface
+{
+    /** @var string */
+    protected $prettyString;
+
+    /**
+     * @param LinkConstraintInterface $provider
+     *
+     * @return bool
+     */
+    public function matches(LinkConstraintInterface $provider)
+    {
+        return true;
+    }
+
+    /**
+     * @param $prettyString
+     */
+    public function setPrettyString($prettyString)
+    {
+        $this->prettyString = $prettyString;
+    }
+
+    /**
+     * @return string
+     */
+    public function getPrettyString()
+    {
+        if ($this->prettyString) {
+            return $this->prettyString;
+        }
+
+        return $this->__toString();
+    }
+
+    /**
+     * @return string
+     */
+    public function __toString()
+    {
+        return '[]';
+    }
+}
diff --git a/composer/semver/src/Constraint/LinkConstraintInterface.php 
b/composer/semver/src/Constraint/LinkConstraintInterface.php
new file mode 100644
index 0000000..21f3421
--- /dev/null
+++ b/composer/semver/src/Constraint/LinkConstraintInterface.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of composer/semver.
+ *
+ * (c) Composer <https://github.com/composer>
+ *
+ * For the full copyright and license information, please view
+ * the LICENSE file that was distributed with this source code.
+ */
+
+namespace Composer\Semver\Constraint;
+
+/**
+ * Defines a constraint on a link between two packages.
+ *
+ * @author Nils Adermann <[email protected]>
+ */
+interface LinkConstraintInterface
+{
+    public function matches(LinkConstraintInterface $provider);
+
+    public function setPrettyString($prettyString);
+
+    public function getPrettyString();
+
+    public function __toString();
+}
diff --git a/composer/semver/src/Constraint/MultiConstraint.php 
b/composer/semver/src/Constraint/MultiConstraint.php
new file mode 100644
index 0000000..a688439
--- /dev/null
+++ b/composer/semver/src/Constraint/MultiConstraint.php
@@ -0,0 +1,101 @@
+<?php
+
+/*
+ * This file is part of composer/semver.
+ *
+ * (c) Composer <https://github.com/composer>
+ *
+ * For the full copyright and license information, please view
+ * the LICENSE file that was distributed with this source code.
+ */
+
+namespace Composer\Semver\Constraint;
+
+/**
+ * Defines a conjunctive or disjunctive set of constraints on the target of a 
package link.
+ *
+ * @author Nils Adermann <[email protected]>
+ * @author Jordi Boggiano <[email protected]>
+ */
+class MultiConstraint implements LinkConstraintInterface
+{
+    /** @var array */
+    protected $constraints;
+
+    /** @var string */
+    protected $prettyString;
+
+    /** @var bool */
+    protected $conjunctive;
+
+    /**
+     * Sets operator and version to compare a package with.
+     *
+     * @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, $conjunctive = true)
+    {
+        $this->constraints = $constraints;
+        $this->conjunctive = $conjunctive;
+    }
+
+    /**
+     * @param LinkConstraintInterface $provider
+     *
+     * @return bool
+     */
+    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;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * @param string $prettyString
+     */
+    public function setPrettyString($prettyString)
+    {
+        $this->prettyString = $prettyString;
+    }
+
+    /**
+     * @return string
+     */
+    public function getPrettyString()
+    {
+        if ($this->prettyString) {
+            return $this->prettyString;
+        }
+
+        return $this->__toString();
+    }
+
+    /**
+     * @return string
+     */
+    public function __toString()
+    {
+        $constraints = array();
+        foreach ($this->constraints as $constraint) {
+            $constraints[] = $constraint->__toString();
+        }
+
+        return '[' . implode($this->conjunctive ? ' ' : ' || ', $constraints) 
. ']';
+    }
+}
diff --git a/composer/semver/src/Constraint/SpecificConstraint.php 
b/composer/semver/src/Constraint/SpecificConstraint.php
new file mode 100644
index 0000000..334dd1f
--- /dev/null
+++ b/composer/semver/src/Constraint/SpecificConstraint.php
@@ -0,0 +1,65 @@
+<?php
+
+/*
+ * This file is part of composer/semver.
+ *
+ * (c) Composer <https://github.com/composer>
+ *
+ * For the full copyright and license information, please view
+ * the LICENSE file that was distributed with this source code.
+ */
+
+namespace Composer\Semver\Constraint;
+
+/**
+ * Provides a common basis for specific package link constraints.
+ *
+ * @author Nils Adermann <[email protected]>
+ */
+abstract class SpecificConstraint implements LinkConstraintInterface
+{
+    /** @var string */
+    protected $prettyString;
+
+    /**
+     * @param LinkConstraintInterface $provider
+     *
+     * @return bool
+     */
+    public function matches(LinkConstraintInterface $provider)
+    {
+        if ($provider instanceof MultiConstraint) {
+            // turn matching around to find a match
+            return $provider->matches($this);
+        } elseif ($provider instanceof $this) {
+            // see note at bottom of this class declaration
+            return $this->matchSpecific($provider);
+        }
+
+        return true;
+    }
+
+    /**
+     * @param string $prettyString
+     */
+    public function setPrettyString($prettyString)
+    {
+        $this->prettyString = $prettyString;
+    }
+
+    /**
+     * @return string
+     */
+    public function getPrettyString()
+    {
+        if ($this->prettyString) {
+            return $this->prettyString;
+        }
+
+        return $this->__toString();
+    }
+
+    // implementations must implement a method of this format:
+    // not declared abstract here because type hinting violates parameter 
coherence (TODO right word?)
+    // public function matchSpecific(<SpecificConstraintType> $provider);
+}
diff --git a/composer/semver/src/Constraint/VersionConstraint.php 
b/composer/semver/src/Constraint/VersionConstraint.php
new file mode 100644
index 0000000..94f5b5e
--- /dev/null
+++ b/composer/semver/src/Constraint/VersionConstraint.php
@@ -0,0 +1,150 @@
+<?php
+
+/*
+ * This file is part of composer/semver.
+ *
+ * (c) Composer <https://github.com/composer>
+ *
+ * For the full copyright and license information, please view
+ * the LICENSE file that was distributed with this source code.
+ */
+
+namespace Composer\Semver\Constraint;
+
+/**
+ * Constrains a package link based on package version.
+ *
+ * Version numbers must be compatible with version_compare
+ *
+ * @author Nils Adermann <[email protected]>
+ */
+class VersionConstraint extends SpecificConstraint
+{
+    const OP_EQ = 0;
+    const OP_LT = 1;
+    const OP_LE = 2;
+    const OP_GT = 3;
+    const OP_GE = 4;
+    const OP_NE = 5;
+
+    private static $transOpStr = array(
+        '=' => self::OP_EQ,
+        '==' => self::OP_EQ,
+        '<' => self::OP_LT,
+        '<=' => self::OP_LE,
+        '>' => self::OP_GT,
+        '>=' => self::OP_GE,
+        '<>' => self::OP_NE,
+        '!=' => self::OP_NE,
+    );
+
+    private static $transOpInt = array(
+        self::OP_EQ => '==',
+        self::OP_LT => '<',
+        self::OP_LE => '<=',
+        self::OP_GT => '>',
+        self::OP_GE => '>=',
+        self::OP_NE => '!=',
+    );
+
+    private $operator;
+    private $version;
+
+    /**
+     * Get all supported comparison operators.
+     *
+     * @return array
+     */
+    public static function getSupportedOperators()
+    {
+        return array_keys(self::$transOpStr);
+    }
+
+    /**
+     * Sets operator and version to compare a package with.
+     *
+     * @param string $operator A comparison operator
+     * @param string $version A version to compare to
+     */
+    public function __construct($operator, $version)
+    {
+        $this->operator = self::$transOpStr[$operator];
+        $this->version = $version;
+    }
+
+    /**
+     * @param string $a
+     * @param string $b
+     * @param string $operator
+     * @param bool|false $compareBranches
+     *
+     * @return bool|mixed
+     */
+    public function versionCompare($a, $b, $operator, $compareBranches = false)
+    {
+        $aIsBranch = 'dev-' === substr($a, 0, 4);
+        $bIsBranch = 'dev-' === substr($b, 0, 4);
+        if ($aIsBranch && $bIsBranch) {
+            return $operator === '==' && $a === $b;
+        }
+
+        // when branches are not comparable, we make sure dev branches never 
match anything
+        if (!$compareBranches && ($aIsBranch || $bIsBranch)) {
+            return false;
+        }
+
+        return version_compare($a, $b, $operator);
+    }
+
+    /**
+     * @param VersionConstraint $provider
+     * @param bool $compareBranches
+     *
+     * @return bool
+     */
+    public function matchSpecific(VersionConstraint $provider, 
$compareBranches = false)
+    {
+        $noEqualOp = str_replace('=', '', self::$transOpInt[$this->operator]);
+        $providerNoEqualOp = str_replace('=', '', 
self::$transOpInt[$provider->operator]);
+
+        $isEqualOp = self::OP_EQ === $this->operator;
+        $isNonEqualOp = self::OP_NE === $this->operator;
+        $isProviderEqualOp = self::OP_EQ === $provider->operator;
+        $isProviderNonEqualOp = self::OP_NE === $provider->operator;
+
+        // '!=' operator is match when other operator is not '==' operator or 
version is not match
+        // these kinds of comparisons always have a solution
+        if ($isNonEqualOp || $isProviderNonEqualOp) {
+            return !$isEqualOp && !$isProviderEqualOp
+                || $this->versionCompare($provider->version, $this->version, 
'!=', $compareBranches);
+        }
+
+        // an example for the condition is <= 2.0 & < 1.0
+        // these kinds of comparisons always have a solution
+        if ($this->operator !== self::OP_EQ && $noEqualOp === 
$providerNoEqualOp) {
+            return true;
+        }
+
+        if ($this->versionCompare($provider->version, $this->version, 
self::$transOpInt[$this->operator], $compareBranches)) {
+            // special case, e.g. require >= 1.0 and provide < 1.0
+            // 1.0 >= 1.0 but 1.0 is outside of the provided interval
+            if ($provider->version === $this->version
+                && self::$transOpInt[$provider->operator] === 
$providerNoEqualOp
+                && self::$transOpInt[$this->operator] !== $noEqualOp) {
+                return false;
+            }
+
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * @return string
+     */
+    public function __toString()
+    {
+        return self::$transOpInt[$this->operator] . ' ' . $this->version;
+    }
+}
diff --git a/composer/semver/src/VersionParser.php 
b/composer/semver/src/VersionParser.php
new file mode 100644
index 0000000..f70d2c3
--- /dev/null
+++ b/composer/semver/src/VersionParser.php
@@ -0,0 +1,533 @@
+<?php
+
+/*
+ * This file is part of composer/semver.
+ *
+ * (c) Composer <https://github.com/composer>
+ *
+ * For the full copyright and license information, please view
+ * the LICENSE file that was distributed with this source code.
+ */
+
+namespace Composer\Semver;
+
+use Composer\Semver\Constraint\EmptyConstraint;
+use Composer\Semver\Constraint\LinkConstraintInterface;
+use Composer\Semver\Constraint\MultiConstraint;
+use Composer\Semver\Constraint\VersionConstraint;
+
+/**
+ * Version parser.
+ *
+ * @author Jordi Boggiano <[email protected]>
+ */
+class VersionParser
+{
+    /** @var string */
+    private static $modifierRegex = 
'[._-]?(?:(stable|beta|b|RC|alpha|a|patch|pl|p)(?:[.-]?(\d+))?)?([.-]?dev)?';
+
+    /** @var array */
+    private static $stabilities = array(
+        'stable', 'RC', 'beta', 'alpha', 'dev',
+    );
+
+    /**
+     * Returns the stability of a version.
+     *
+     * @param string $version
+     *
+     * @return string
+     */
+    public static function parseStability($version)
+    {
+        $version = preg_replace('{#.+$}i', '', $version);
+
+        if ('dev-' === substr($version, 0, 4) || '-dev' === substr($version, 
-4)) {
+            return 'dev';
+        }
+
+        preg_match('{' . self::$modifierRegex . '$}i', strtolower($version), 
$match);
+        if (!empty($match[3])) {
+            return 'dev';
+        }
+
+        if (!empty($match[1])) {
+            if ('beta' === $match[1] || 'b' === $match[1]) {
+                return 'beta';
+            }
+            if ('alpha' === $match[1] || 'a' === $match[1]) {
+                return 'alpha';
+            }
+            if ('rc' === $match[1]) {
+                return 'RC';
+            }
+        }
+
+        return 'stable';
+    }
+
+    /**
+     * @param string $stability
+     *
+     * @return string
+     */
+    public static function normalizeStability($stability)
+    {
+        $stability = strtolower($stability);
+
+        return $stability === 'rc' ? 'RC' : $stability;
+    }
+
+    /**
+     * Normalizes a version string to be able to perform comparisons on it.
+     *
+     * @param string $version
+     * @param string $fullVersion optional complete version string to give 
more context
+     *
+     * @throws \UnexpectedValueException
+     *
+     * @return string
+     */
+    public function normalize($version, $fullVersion = null)
+    {
+        $version = trim($version);
+        if (null === $fullVersion) {
+            $fullVersion = $version;
+        }
+
+        // ignore aliases and just assume the alias is required instead of the 
source
+        if (preg_match('{^([^,\s]+) +as +([^,\s]+)$}', $version, $match)) {
+            $version = $match[1];
+        }
+
+        // ignore build metadata
+        if (preg_match('{^([^,\s+]+)\+[^\s]+$}', $version, $match)) {
+            $version = $match[1];
+        }
+
+        // match master-like branches
+        if (preg_match('{^(?:dev-)?(?:master|trunk|default)$}i', $version)) {
+            return '9999999-dev';
+        }
+
+        if ('dev-' === strtolower(substr($version, 0, 4))) {
+            return 'dev-' . substr($version, 4);
+        }
+
+        // match classical versioning
+        if (preg_match('{^v?(\d{1,3})(\.\d+)?(\.\d+)?(\.\d+)?' . 
self::$modifierRegex . '$}i', $version, $matches)) {
+            $version = $matches[1]
+                . (!empty($matches[2]) ? $matches[2] : '.0')
+                . (!empty($matches[3]) ? $matches[3] : '.0')
+                . (!empty($matches[4]) ? $matches[4] : '.0');
+            $index = 5;
+        } elseif 
(preg_match('{^v?(\d{4}(?:[.:-]?\d{2}){1,6}(?:[.:-]?\d{1,3})?)' . 
self::$modifierRegex . '$}i', $version, $matches)) { // match date-based 
versioning
+            $version = preg_replace('{\D}', '-', $matches[1]);
+            $index = 2;
+        } elseif (preg_match('{^v?(\d{4,})(\.\d+)?(\.\d+)?(\.\d+)?' . 
self::$modifierRegex . '$}i', $version, $matches)) {
+            $version = $matches[1]
+                . (!empty($matches[2]) ? $matches[2] : '.0')
+                . (!empty($matches[3]) ? $matches[3] : '.0')
+                . (!empty($matches[4]) ? $matches[4] : '.0');
+            $index = 5;
+        }
+
+        // add version modifiers if a version was matched
+        if (isset($index)) {
+            if (!empty($matches[$index])) {
+                if ('stable' === $matches[$index]) {
+                    return $version;
+                }
+                $version .= '-' . $this->expandStability($matches[$index]) . 
(!empty($matches[$index + 1]) ? $matches[$index + 1] : '');
+            }
+
+            if (!empty($matches[$index + 2])) {
+                $version .= '-dev';
+            }
+
+            return $version;
+        }
+
+        // match dev branches
+        if (preg_match('{(.*?)[.-]?dev$}i', $version, $match)) {
+            try {
+                return $this->normalizeBranch($match[1]);
+            } catch (\Exception $e) {
+            }
+        }
+
+        $extraMessage = '';
+        if (preg_match('{ +as +' . preg_quote($version) . '$}', $fullVersion)) 
{
+            $extraMessage = ' in "' . $fullVersion . '", the alias must be an 
exact version';
+        } elseif (preg_match('{^' . preg_quote($version) . ' +as +}', 
$fullVersion)) {
+            $extraMessage = ' in "' . $fullVersion . '", the alias source must 
be an exact version, if it is a branch name you should prefix it with dev-';
+        }
+
+        throw new \UnexpectedValueException('Invalid version string "' . 
$version . '"' . $extraMessage);
+    }
+
+    /**
+     * Extract numeric prefix from alias, if it is in numeric format, suitable 
for version comparison.
+     *
+     * @param string $branch Branch name (e.g. 2.1.x-dev)
+     *
+     * @return string|false Numeric prefix if present (e.g. 2.1.) or false
+     */
+    public function parseNumericAliasPrefix($branch)
+    {
+        if (preg_match('/^(?P<version>(\d+\\.)*\d+)(?:\.x)?-dev$/i', $branch, 
$matches)) {
+            return $matches['version'] . '.';
+        }
+
+        return false;
+    }
+
+    /**
+     * Normalizes a branch name to be able to perform comparisons on it.
+     *
+     * @param string $name
+     *
+     * @return string
+     */
+    public function normalizeBranch($name)
+    {
+        $name = trim($name);
+
+        if (in_array($name, array('master', 'trunk', 'default'))) {
+            return $this->normalize($name);
+        }
+
+        if 
(preg_match('#^v?(\d+)(\.(?:\d+|[xX*]))?(\.(?:\d+|[xX*]))?(\.(?:\d+|[xX*]))?$#i',
 $name, $matches)) {
+            $version = '';
+            for ($i = 1; $i < 5; ++$i) {
+                $version .= isset($matches[$i]) ? str_replace(array('*', 'X'), 
'x', $matches[$i]) : '.x';
+            }
+
+            return str_replace('x', '9999999', $version) . '-dev';
+        }
+
+        return 'dev-' . $name;
+    }
+
+    /**
+     * Parses as constraint string into LinkConstraint objects.
+     *
+     * @param string $constraints
+     *
+     * @return LinkConstraintInterface
+     */
+    public function parseConstraints($constraints)
+    {
+        $prettyConstraint = $constraints;
+
+        if (preg_match('{^([^,\s]*?)@(' . implode('|', self::$stabilities) . 
')$}i', $constraints, $match)) {
+            $constraints = empty($match[1]) ? '*' : $match[1];
+        }
+
+        if (preg_match('{^(dev-[^,\s@]+?|[^,\s@]+?\.x-dev)#.+$}i', 
$constraints, $match)) {
+            $constraints = $match[1];
+        }
+
+        $orConstraints = preg_split('{\s*\|\|?\s*}', trim($constraints));
+        $orGroups = array();
+        foreach ($orConstraints as $constraints) {
+            $andConstraints = preg_split('{(?<!^|as|[=>< ,]) *(?<!-)[, ](?!-) 
*(?!,|as|$)}', $constraints);
+            if (count($andConstraints) > 1) {
+                $constraintObjects = array();
+                foreach ($andConstraints as $constraint) {
+                    foreach ($this->parseConstraint($constraint) as 
$parsedConstraint) {
+                        $constraintObjects[] = $parsedConstraint;
+                    }
+                }
+            } else {
+                $constraintObjects = 
$this->parseConstraint($andConstraints[0]);
+            }
+
+            if (1 === count($constraintObjects)) {
+                $constraint = $constraintObjects[0];
+            } else {
+                $constraint = new MultiConstraint($constraintObjects);
+            }
+
+            $orGroups[] = $constraint;
+        }
+
+        if (1 === count($orGroups)) {
+            $constraint = $orGroups[0];
+        } else {
+            $constraint = new MultiConstraint($orGroups, false);
+        }
+
+        $constraint->setPrettyString($prettyConstraint);
+
+        return $constraint;
+    }
+
+    /**
+     * @param string $constraint
+     *
+     * @return array
+     */
+    private function parseConstraint($constraint)
+    {
+        if (preg_match('{^([^,\s]+?)@(' . implode('|', self::$stabilities) . 
')$}i', $constraint, $match)) {
+            $constraint = $match[1];
+            if ($match[2] !== 'stable') {
+                $stabilityModifier = $match[2];
+            }
+        }
+
+        if (preg_match('{^[xX*](\.[xX*])*$}i', $constraint)) {
+            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('{^~>?' . $versionRegex . '$}i', $constraint, 
$matches)) {
+            if (substr($constraint, 0, 2) === '~>') {
+                throw new \UnexpectedValueException(
+                    'Could not parse version constraint ' . $constraint . ': ' 
.
+                    'Invalid operator "~>", you probably meant to use the "~" 
operator'
+                );
+            }
+
+            // Work out which position in the version we are operating at
+            if (isset($matches[4]) && '' !== $matches[4]) {
+                $position = 4;
+            } elseif (isset($matches[3]) && '' !== $matches[3]) {
+                $position = 3;
+            } elseif (isset($matches[2]) && '' !== $matches[2]) {
+                $position = 2;
+            } else {
+                $position = 1;
+            }
+
+            // Calculate the stability suffix
+            $stabilitySuffix = '';
+            if (!empty($matches[5])) {
+                $stabilitySuffix .= '-' . $this->expandStability($matches[5]) 
. (!empty($matches[6]) ? $matches[6] : '');
+            }
+
+            if (!empty($matches[7])) {
+                $stabilitySuffix .= '-dev';
+            }
+
+            if (!$stabilitySuffix) {
+                $stabilitySuffix = '-dev';
+            }
+            $lowVersion = $this->manipulateVersionString($matches, $position, 
0) . $stabilitySuffix;
+            $lowerBound = new VersionConstraint('>=', $lowVersion);
+
+            // For upper bound, we increment the position of one more 
significance,
+            // but highPosition = 0 would be illegal
+            $highPosition = max(1, $position - 1);
+            $highVersion = $this->manipulateVersionString($matches, 
$highPosition, 1) . '-dev';
+            $upperBound = new VersionConstraint('<', $highVersion);
+
+            return array(
+                $lowerBound,
+                $upperBound,
+            );
+        }
+
+        // match caret constraints
+        if (preg_match('{^\^' . $versionRegex . '($)}i', $constraint, 
$matches)) {
+            // Work out which position in the version we are operating at
+            if ('0' !== $matches[1] || '' === $matches[2]) {
+                $position = 1;
+            } elseif ('0' !== $matches[2] || '' === $matches[3]) {
+                $position = 2;
+            } else {
+                $position = 3;
+            }
+
+            // Calculate the stability suffix
+            $stabilitySuffix = '';
+            if (empty($matches[5]) && empty($matches[7])) {
+                $stabilitySuffix .= '-dev';
+            }
+
+            $lowVersion = $this->normalize(substr($constraint . 
$stabilitySuffix, 1));
+            $lowerBound = new VersionConstraint('>=', $lowVersion);
+
+            // For upper bound, we increment the position of one more 
significance,
+            // but highPosition = 0 would be illegal
+            $highVersion = $this->manipulateVersionString($matches, $position, 
1) . '-dev';
+            $upperBound = new VersionConstraint('<', $highVersion);
+
+            return array(
+                $lowerBound,
+                $upperBound,
+            );
+        }
+
+        // match wildcard constraints
+        if (preg_match('{^(\d+)(?:\.(\d+))?(?:\.(\d+))?\.[xX*]$}', 
$constraint, $matches)) {
+            if (isset($matches[3]) && '' !== $matches[3]) {
+                $position = 3;
+            } elseif (isset($matches[2]) && '' !== $matches[2]) {
+                $position = 2;
+            } else {
+                $position = 1;
+            }
+
+            $lowVersion = $this->manipulateVersionString($matches, $position) 
. '-dev';
+            $highVersion = $this->manipulateVersionString($matches, $position, 
1) . '-dev';
+
+            if ($lowVersion === '0.0.0.0-dev') {
+                return array(new VersionConstraint('<', $highVersion));
+            }
+
+            return array(
+                new VersionConstraint('>=', $lowVersion),
+                new VersionConstraint('<', $highVersion),
+            );
+        }
+
+        // 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);
+
+            $empty = function ($x) {
+                return ($x === 0 || $x === '0') ? false : empty($x);
+            };
+
+            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 {
+                $version = $this->normalize($matches[2]);
+
+                if (!empty($stabilityModifier) && 
$this->parseStability($version) === 'stable') {
+                    $version .= '-' . $stabilityModifier;
+                } elseif ('<' === $matches[1] || '>=' === $matches[1]) {
+                    if (!preg_match('/-' . self::$modifierRegex . '$/', 
strtolower($matches[2]))) {
+                        if (substr($matches[2], 0, 4) !== 'dev-') {
+                            $version .= '-dev';
+                        }
+                    }
+                }
+
+                return array(new VersionConstraint($matches[1] ?: '=', 
$version));
+            } catch (\Exception $e) {
+            }
+        }
+
+        $message = 'Could not parse version constraint ' . $constraint;
+        if (isset($e)) {
+            $message .= ': ' . $e->getMessage();
+        }
+
+        throw new \UnexpectedValueException($message);
+    }
+
+    /**
+     * Increment, decrement, or simply pad a version number.
+     *
+     * Support function for {@link parseConstraint()}
+     *
+     * @param array $matches Array with version parts in array indexes 1,2,3,4
+     * @param int $position 1,2,3,4 - which segment of the version to decrement
+     * @param int $increment
+     * @param string $pad The string to pad version parts after $position
+     *
+     * @return string The new version
+     */
+    private function manipulateVersionString($matches, $position, $increment = 
0, $pad = '0')
+    {
+        for ($i = 4; $i > 0; --$i) {
+            if ($i > $position) {
+                $matches[$i] = $pad;
+            } elseif ($i === $position && $increment) {
+                $matches[$i] += $increment;
+                // If $matches[$i] was 0, carry the decrement
+                if ($matches[$i] < 0) {
+                    $matches[$i] = $pad;
+                    --$position;
+
+                    // Return null on a carry overflow
+                    if ($i === 1) {
+                        return;
+                    }
+                }
+            }
+        }
+
+        return $matches[1] . '.' . $matches[2] . '.' . $matches[3] . '.' . 
$matches[4];
+    }
+
+    private function expandStability($stability)
+    {
+        $stability = strtolower($stability);
+
+        switch ($stability) {
+            case 'a':
+                return 'alpha';
+            case 'b':
+                return 'beta';
+            case 'p':
+            case 'pl':
+                return 'patch';
+            case 'rc':
+                return 'RC';
+            default:
+                return $stability;
+        }
+    }
+
+    /**
+     * Parses a name/version pairs and returns an array of pairs.
+     *
+     * @param array $pairs a set of package/version pairs separated by ":", 
"=" or " "
+     *
+     * @return array[] array of arrays containing a name and (if provided) a 
version
+     */
+    public function parseNameVersionPairs(array $pairs)
+    {
+        $pairs = array_values($pairs);
+        $result = array();
+
+        for ($i = 0, $count = count($pairs); $i < $count; ++$i) {
+            $pair = preg_replace('{^([^=: ]+)[=: ](.*)$}', '$1 $2', 
trim($pairs[$i]));
+            if (false === strpos($pair, ' ') && isset($pairs[$i + 1]) && false 
=== strpos($pairs[$i + 1], '/')) {
+                $pair .= ' ' . $pairs[$i + 1];
+                ++$i;
+            }
+
+            if (strpos($pair, ' ')) {
+                list($name, $version) = explode(' ', $pair, 2);
+                $result[] = array('name' => $name, 'version' => $version);
+            } else {
+                $result[] = array('name' => $pair);
+            }
+        }
+
+        return $result;
+    }
+}

-- 
To view, visit https://gerrit.wikimedia.org/r/228132
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I50d636df321b6aa7a921c8ca1d111f5b0c459ca9
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/vendor
Gerrit-Branch: master
Gerrit-Owner: Legoktm <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to