Added dependency jelix/version

This commit is contained in:
Netkas 2022-10-22 00:44:07 -04:00
parent 03185d3dc7
commit a142bd0665
14 changed files with 1502 additions and 1 deletions

1
.gitignore vendored
View file

@ -9,6 +9,7 @@ build
# Autoload files
src/ncc/ThirdParty/defuse/php-encryption/autoload_spl.php
src/ncc/ThirdParty/jelix/version/autoload_spl.php
src/ncc/ThirdParty/nikic/PhpParser/autoload_spl.php
src/ncc/ThirdParty/Symfony/polyfill-ctype/autoload_spl.php
src/ncc/ThirdParty/Symfony/polyfill-mbstring/autoload_spl.php

25
LICENSE
View file

@ -329,4 +329,27 @@ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
------------------------
jelix - version
Copyright (C) 2009-2016 Laurent Jouanneau
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.

View file

@ -6,6 +6,7 @@ SRC_PATH=src
autoload:
# Generates/creates all the autoloader files
make $(SRC_PATH)/ncc/ThirdParty/defuse/php-encryption/autoload_spl.php
make $(SRC_PATH)/ncc/ThirdParty/jelix/version/autoload_spl.php
make $(SRC_PATH)/ncc/ThirdParty/nikic/php-parser/autoload_spl.php
make $(SRC_PATH)/ncc/ThirdParty/Symfony/polyfill-ctype/autoload_spl.php
make $(SRC_PATH)/ncc/ThirdParty/Symfony/polyfill-mbstring/autoload_spl.php
@ -23,6 +24,10 @@ $(SRC_PATH)/ncc/ThirdParty/defuse/php-encryption/autoload_spl.php:
$(PHPCC) $(PHPAB) --output $(SRC_PATH)/ncc/ThirdParty/defuse/php-encryption/autoload_spl.php \
$(SRC_PATH)/ncc/ThirdParty/defuse/php-encryption
$(SRC_PATH)/ncc/ThirdParty/jelix/version/autoload_spl.php:
$(PHPCC) $(PHPAB) --output $(SRC_PATH)/ncc/ThirdParty/jelix/version/autoload_spl.php \
$(SRC_PATH)/ncc/ThirdParty/jelix/version
$(SRC_PATH)/ncc/ThirdParty/nikic/php-parser/autoload_spl.php:
$(PHPCC) $(PHPAB) --output $(SRC_PATH)/ncc/ThirdParty/nikic/PhpParser/autoload_spl.php \
$(SRC_PATH)/ncc/ThirdParty/nikic/PhpParser
@ -97,6 +102,7 @@ clean:
rm -rf $(BUILD_PATH)
rm -f $(SRC_PATH)/ncc/autoload_spl.php
rm -f $(SRC_PATH)/ncc/ThirdParty/defuse/php-encryption/autoload_spl.php
rm -f $(SRC_PATH)/ncc/ThirdParty/jelix/version/autoload_spl.php
rm -f $(SRC_PATH)/ncc/ThirdParty/nikic/PhpParser/autoload_spl.php
rm -f $(SRC_PATH)/ncc/ThirdParty/Symfony/polyfill-ctype/autoload_spl.php
rm -f $(SRC_PATH)/ncc/ThirdParty/Symfony/polyfill-mbstring/autoload_spl.php

View file

@ -0,0 +1,18 @@
Copyright (C) 2009-2016 Laurent Jouanneau
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.

View file

@ -0,0 +1,170 @@
<?php
/**
* @author Laurent Jouanneau
* @copyright 2016-2018 Laurent Jouanneau
*
* @link http://www.jelix.org
* @licence MIT
*/
namespace Jelix\Version;
class Parser
{
private function __construct()
{
}
/**
* Is able to parse semantic version syntax or any other version syntax.
*
* @param string $version
* @param array $options list of options for the parser.
* 'removeWildcard' => false
*
* @return Version
*/
public static function parse($version, $options = array())
{
if ($version instanceof Version) {
// for backward compatibility
return clone $version;
}
$options = array_merge(array(
'removeWildcard' => false
), $options);
// extract meta data
$vers = explode('+', $version, 2);
$metadata = '';
if (count($vers) > 1) {
$metadata = $vers[1];
}
$version = $vers[0];
// extract secondary version
$allVersions = preg_split('/(-|:)([0-9]+|\\*)($|\\.|-)/', $version, 2, PREG_SPLIT_DELIM_CAPTURE);
$version = $allVersions[0];
$stabilityVersion = array();
// extract stability part
$vers = explode('-', $version, 2);
if (count($vers) > 1) {
$stabilityVersion = explode('.', $vers[1]);
}
// extract version parts
$versionHasWildcard = false;
$vers = explode('.', $vers[0]);
foreach ($vers as $k => $number) {
if (!is_numeric($number)) {
if (preg_match('/^([0-9]+)([a-zA-Z]+|\\*)([0-9]*|\\*?)(.*)$/', $number, $m)) {
// we got a number like '8a2', '5beta4', '3alpha*' ..
// so it defines a stability version
$vers[$k] = intval($m[1]);
if ($m[2] === '*') {
if ((isset($m[3]) && $m[3] !== '') || (isset($m[4]) && $m[4] !== '')) {
throw new \Exception('Bad version syntax on "'.$version.'"');
}
$vers = array_slice($vers, 0, $k+1);
$versionHasWildcard = true;
if (!$options['removeWildcard']) {
$vers[$k+1] = '*';
}
break;
}
$sv = array($m[2]);
if (isset($m[3]) && $m[3] !== '') {
$sv[] = intval($m[3]);
}
if (isset($m[4]) && $m[4] !== '') {
$sv[] = $m[4];
}
$stabilityVersion = array_merge(
$sv,
array_slice($vers, $k + 1),
$stabilityVersion
);
$vers = array_slice($vers, 0, $k + 1);
break;
} elseif ($number == '*') {
$versionHasWildcard = true;
$vers = array_slice($vers, 0, $k);
if (!$options['removeWildcard']) {
$vers[$k] = '*';
}
break;
} else {
throw new \Exception('Bad version syntax on "'.$version.'"');
}
} else {
if ($versionHasWildcard) {
throw new \Exception('Bad version syntax on "'.$version.'", wildcard should be the last part.');
}
$vers[$k] = intval($number);
}
}
$stab = array();
foreach ($stabilityVersion as $k => $part) {
if (preg_match('/^[a-z]+$/', $part)) {
$stab[] = self::normalizeStability($part);
} elseif (preg_match('/^[0-9]+$/', $part)) {
$stab[] = intval($part);
} else {
$m = preg_split('/([0-9]+)/', $part, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
foreach ($m as $p) {
$stab[] = self::normalizeStability($p);
}
}
}
if ($versionHasWildcard && (count($stab) > 1 || (count($stab)==1 && $stab[0] != 'stable')) ) {
throw new \Exception('Bad version syntax on "'.$version.'", wildcard should be the last part.');
}
if (count($allVersions) > 1 && $allVersions[1] != '') {
if ($allVersions[2] == '*') {
if ($options['removeWildcard']) {
$secondaryVersion = null;
$secondaryVersionSeparator = '-';
}
else {
if ($allVersions[1] == '-' && count($stab) == 0) {
$stab = array('*');
$secondaryVersionSeparator = ':';
$secondaryVersion = null;
}
else {
$secondaryVersionSeparator = $allVersions[1];
$secondaryVersion = new Version(array('*'));
}
}
}
else {
$secondaryVersion = self::parse($allVersions[2].$allVersions[3].$allVersions[4], $options);
$secondaryVersionSeparator = $allVersions[1];
}
}
else {
$secondaryVersion = null;
$secondaryVersionSeparator = '-';
}
return new Version($vers, $stab, $metadata, $secondaryVersion, $secondaryVersionSeparator);
}
protected static function normalizeStability($stab)
{
$stab = strtolower($stab);
if ($stab == 'a') {
$stab = 'alpha';
}
if ($stab == 'b') {
$stab = 'beta';
}
return $stab;
}
}

View file

@ -0,0 +1,165 @@
This PHP library parse any version syntax, including [semantic version](https://semver.org). It allows
also to compare versions, using Composer version constraints syntax.
# installation
You can install it from Composer. In your project:
```
composer require "jelix/version"
```
# Usage
## Parsing
Use the `Jelix\Version\Parser` class to retrieve a `Jelix\Version\Version` object
containing all versions informations.
```php
$version = \Jelix\Version\Parser::parse('1.2.3b2');
$version->toString(); // '1.2.3-beta.2'
$version->getMajor(); // 1
$version->getMinor(); // 2
$version->getPatch(); // 3
$version->getStabilityVersion(); // array('beta', '2')
$version->getNextMajorVersion(); // Version object for '2.0.0'
$version->getNextMinorVersion(); // Version object for '1.3.0'
$version->getNextPatchVersion(); // Version object for '1.2.4'
$version->getBranchVersion(); // '1.2'
```
Example of supported version syntaxes:
- 1.0, 1.2.3
- 1.2-alpha, 1.2a, 1.2alpha, 1.2alpha.3, 1.2a1.3
- 1.2.3-beta, 1.2b, 1.2beta, 1.2beta.3, 1.2b3.4
- 1.2RC, 1.2-rc.4.5
- 1.2-dev, 1.2b1-dev, 1.2b1-dev.9, 1.2RC-dev, 1.2RC2-dev.1700
The parser support also 'secondary versions', i.e. versions appended to a version
after a `-` or a `:`.
Ex: `1.2.3-1.4.5`, `1.2.3:1.4.5`. Here, `1.4.5` is a secondary version.
When retrieving a `Version` object for such versions, you can access to the secondary
version through a method `getSecondaryVersion()` which returns a `Version` object:
```php
$version = \Jelix\Version\Parser::parse('1.2.3:1.4.5');
$version->toString(); // '1.2.3:1.4.5'
$version->toString(true, false); // '1.2.3'
$version2 = $version->getSecondaryVersion();
$version2->toString(); // '1.4.5'
$version->getNextMajorVersion(); // Version object for '2.0.0'
$version->getNextMinorVersion(); // Version object for '1.3.0'
$version->getNextPatchVersion(); // Version object for '1.2.4'
$version->getBranchVersion(); // '1.2'
```
## Simple comparison
```php
$v1 = '1.2.3';
$v2 = '1.4.5';
$result = \Jelix\Version\VersionComparator::compareVersion($v1, $v2);
```
`compareVersion()` returns:
- `-1` if $v1 < $v2
- `0` if $v1 == $v2
- `1` if $v1 > $v2
Example to compare two versions:
```php
\Jelix\Version\VersionComparator::compareVersion('1.2pre','1.2RC');
```
Secondary versions are also compared if primary versions are equals.
In this case, if one of the version string does not contain a
secondary version, then it is considered having the '0.0' version number,
so it is considered as lower version than the version having a secondary
version.
You have also an other method `compare()` taking `Version` objects as parameters:
```php
$v1 = \Jelix\Version\Parser::parse('1.2.3');
$v2 = \Jelix\Version\Parser::parse('1.4.5');
$result = \Jelix\Version\VersionComparator::compare($v1, $v2);
```
## Comparison with range
`compareVersionRange()` allows you to use operator to compare version. It
is compatible with version constraints supported by Composer.
- comparison operators: `>`, `<`, `>=`, `<=`, `=`, `!=`
- no operator means `=`
- `~` : specify a range between the version and the next major version
(excluding the next major version itself and its unstable variant)
- `~1.2` is equivalent to `>=1.2 <2.0.0-dev`
- `~1.2.3` is equivalent to `>=1.2.3 <1.3.0-dev`
- '^' : specify a range between the version and the next minor version
- `^1.2.3` is equivalent to `>=1.2.3 <1.3.0`
- `^0.3` is equivalent to `>=0.3.0 <0.4.0`
- hyphen separator to specify a range : '1.2 - 1.5'
- `1.0 - 2.0` is equivalent to `>=1.0.0 <2.1` (as 2.0 is interpreted as 2.0.*)
- `1.0.0 - 2.1.0` is equivalent to `>=1.0.0 <=2.1.0`
- It supports also version wildcards with or without operators: `1.*`, `1.2.*`
You can combine several constraints with boolean operators :
- AND operator: `,` or ` `
- OR operator: `||` or `|`.
```php
// check if 0.5 is between 0.8 and 1.0 or if it is higher than 2.0
\Jelix\Version\VersionComparator::compareVersionRange('0.5','<1.0,>0.8|>2.0');
// check if 0.5 is between 0.8 and 1.0
\Jelix\Version\VersionComparator::compareVersionRange('0.5','0.8 - 1.0');
// with a wildcard
\Jelix\Version\VersionComparator::compareVersionRange('1.1', '1.1.*'); // returns true
\Jelix\Version\VersionComparator::compareVersionRange('1.1.2', '1.2.*'); // returns false
\Jelix\Version\VersionComparator::compareVersionRange('1.3.0', '>=1.2.*'); // returns true
```
Note: comparison with a range is done only on primary version. If a version string contains
a secondary version, this secondary version is not compared. To compare a secondary version
with a range, you should retrieve the secondary version with the `getSecondaryVersion()` method.
```php
$version = Jelix\Version\Parser::parse('1.2.3:1.0.0');
\Jelix\Version\VersionComparator::compareVersionRange($version, '>=1.2.*'); // returns true
$version2 = $version->getSecondaryVersion();
$version2->toString(); // '1.0.0'
\Jelix\Version\VersionComparator::compareVersionRange($version2, '>=1.2.*'); // returns false
```
# History
Ancesters of these classes have been included for years into the [Jelix Framework](http://jelix.org)
until Jelix 1.6, and has been released in 2016 into a separate repository.

View file

@ -0,0 +1 @@
2.0.1

View file

@ -0,0 +1,364 @@
<?php
/**
* @author Laurent Jouanneau
* @copyright 2016-2020 Laurent Jouanneau
*
* @link http://www.jelix.org
* @licence MIT
*/
namespace Jelix\Version;
/**
* Embed version informations.
*/
class Version
{
/**
* @var int[] list of numbers of the version (ex: [1,2,3] for 1.2.3)
*/
private $version = array();
/**
* @var string[] list of stability informations (ex: ['alpha', '2'] for 1.2.3-alpha.2)
*/
private $stabilityVersion = array();
/**
* @var string any informations that are after a '+' in a semantic version
*/
private $buildMetadata = '';
/**
* @var Version|null secondary version, i.e. a version after a ':' or a '-'
*/
private $secondaryVersion = null;
private $secondaryVersionSeparator = '-';
private $wildcard = 0;
const WILDCARD_ON_VERSION = 1;
const WILDCARD_ON_STABILITY_VERSION = 2;
/**
* @param int[] $version list of numbers of the version
* (ex: [1,2,3] for 1.2.3)
* @param string[] $stabilityVersion list of stability informations
* that are informations following a '-' in a semantic version
* (ex: ['alpha', '2'] for 1.2.3-alpha.2)
* @param string build metadata the metadata, informations that
* are after a '+' in a semantic version
* (ex: 'build-56458' for 1.2.3-alpha.2+build-56458)
*
* @param Version|null $secondaryVersion secondary version, i.e. a version after a ':'
*/
public function __construct(array $version,
array $stabilityVersion = array(),
$buildMetadata = '',
$secondaryVersion = null,
$secondaryVersionSeparator = '-')
{
$this->version = count($version) ? $version: array(0);
$this->stabilityVersion = $stabilityVersion;
if (in_array('*', $this->stabilityVersion, true)) {
$this->wildcard |= self::WILDCARD_ON_STABILITY_VERSION;
}
if (in_array('*', $this->version, true)) {
$this->wildcard |= self::WILDCARD_ON_VERSION;
}
$this->buildMetadata = $buildMetadata;
$this->secondaryVersion = $secondaryVersion;
$this->secondaryVersionSeparator = $secondaryVersionSeparator;
}
public function __toString()
{
return $this->toString();
}
/**
* @param bool $withPatch true, it returns always x.y.z even
* if no patch or minor version was given
* @param bool $withSecondaryVersion set to false to not include secondary version
*/
public function toString($withPatch = true, $withSecondaryVersion = true)
{
$version = $this->version;
if (!($this->wildcard & self::WILDCARD_ON_VERSION) && $withPatch && count($version) < 3) {
$version = array_pad($version, 3, 0);
}
if ($this->stabilityVersion) {
$stability = '-'.implode('.', $this->stabilityVersion);
}
else {
$stability = '';
}
if ($this->secondaryVersion && $withSecondaryVersion) {
$secondary = $this->secondaryVersion->toString();
if ($stability == '-*' && $secondary == '*') {
$secondary = '';
}
else {
$secondary = $this->secondaryVersionSeparator.$secondary;
}
}
else {
$secondary = '';
}
$vers = implode('.', $version).$stability.$secondary;
if ($this->buildMetadata) {
$vers .= '+'.$this->buildMetadata;
}
return $vers;
}
/**
* @return integer 0 if there is no wildcard, else one of the constant WILDCARD_ON_*
*/
public function hasWildcard () {
return $this->wildcard;
}
public function getMajor()
{
return $this->version[0];
}
public function hasMinor()
{
return isset($this->version[1]);
}
public function getMinor()
{
if (isset($this->version[1])) {
return $this->version[1];
}
if ($this->version[0] === '*') {
return '*';
}
return 0;
}
public function hasPatch()
{
return isset($this->version[2]);
}
public function getPatch()
{
if (isset($this->version[2])) {
return $this->version[2];
}
if ($this->getMinor() === '*') {
return '*';
}
return 0;
}
public function getTailNumbers()
{
if (count($this->version) > 3) {
return array_slice($this->version, 3);
}
return array();
}
public function getVersionArray()
{
return $this->version;
}
public function getBranchVersion()
{
return $this->version[0].'.'.$this->getMinor();
}
public function getStabilityVersion()
{
return $this->stabilityVersion;
}
public function getBuildMetadata()
{
return $this->buildMetadata;
}
/**
* @return Version|null
*/
public function getSecondaryVersion() {
return $this->secondaryVersion;
}
public function getSecondaryVersionSeparator() {
return $this->secondaryVersionSeparator;
}
/**
* Returns the next major version
* 2.1.3 -> 3.0.0
* 2.1b1.4 -> 3.0.0.
*
* @return Version the next version
*/
public function getNextMajorVersion($ignoreStability = true)
{
if ($this->version[0] === '*') {
return new Version(array('*'));
}
if (!$ignoreStability && count($this->stabilityVersion) && $this->stabilityVersion[0] != 'stable') {
return new Version($this->version);
}
return new Version(array(($this->version[0] + 1), 0));
}
/**
* Returns the next minor version
* 2.1.3 -> 2.2.0
* 2.1 -> 2.2.0
* 2.1b1.4 -> 2.1.0
*
* @return Version the next version
*/
public function getNextMinorVersion($ignoreStability = true)
{
if ($this->getMinor() === '*') {
return new Version(array('*'));
}
if (!$ignoreStability && count($this->stabilityVersion) && $this->stabilityVersion[0] != 'stable') {
return new Version($this->version);
}
return new Version(array($this->version[0],($this->getMinor() + 1)));
}
/**
* Returns the next patch version
* 2.1.3 -> 2.1.4
* 2.1b1.4 -> 2.1.0
*
* @return Version the next version
*/
public function getNextPatchVersion($ignoreStability = true)
{
if ($this->getPatch() === '*') {
return new Version(array('*'));
}
if (!$ignoreStability && count($this->stabilityVersion) && $this->stabilityVersion[0] != 'stable') {
return new Version($this->version);
}
return new Version(array($this->version[0], $this->getMinor(), ($this->getPatch() + 1)));
}
/**
* returns the next version, by incrementing the last
* number, whatever it is.
* If the version has a stability information (alpha, beta etc..),
* it returns only the version without stability version.
*
* @return Version the next version
*/
public function getNextTailVersion($ignoreStability = false)
{
if (!$ignoreStability && count($this->stabilityVersion) && $this->stabilityVersion[0] != 'stable') {
return new Version($this->version);
}
$v = $this->version;
$last = count($v) - 1;
if ($v[$last] == '*' && $last >= 1) {
$v = array_slice($v, 0, $last);
$last --;
}
$v[$last]++;
return new Version($v);
}
/**
* Returns the version having the next major stability version
*
* @return Version
*/
public function getNextStabilityVersion()
{
if (!count($this->stabilityVersion) || $this->stabilityVersion[0] == 'stable') {
if (count($this->version) > 3) {
$v = $this->getNextTailVersion();
}
else {
$v = $this->getNextPatchVersion();
}
return new Version($v->getVersionArray(), array('dev'));
}
$stability = $this->stabilityVersion[0];
if ($stability === 'dev' || $stability === 'pre') {
$stability = 'alpha';
}
else if ($stability === 'alpha') {
$stability = 'beta';
}
else if ($stability === 'beta') {
$stability = 'rc';
}
else if ($stability === 'rc') {
return new Version($this->version);
}
else if (is_numeric($stability)) {
$stability ++;
}
return new Version($this->version, array($stability));
}
/**
* Returns the version having the next tail stability version
*
* @return Version
*/
public function getNextTailStabilityVersion()
{
if (!count($this->stabilityVersion) || $this->stabilityVersion[0] === 'stable') {
if (count($this->version) > 3) {
$v = $this->getNextTailVersion();
}
else {
$v = $this->getNextPatchVersion();
}
return new Version($v->getVersionArray(), array('dev'));
}
$last = count($this->stabilityVersion) - 1;
$stability = $this->stabilityVersion[$last];
if ($stability === 'dev' || $stability === 'pre') {
$stability = 'alpha';
}
else if ($stability === 'alpha') {
$stability = 'beta';
}
else if ($stability === 'beta') {
$stability = 'rc';
}
else if ($stability === 'rc') {
return new Version($this->version);
}
else if (is_numeric($stability)) {
$stability ++;
}
$stabVer = $this->stabilityVersion;
$stabVer[$last] = $stability;
return new Version($this->version, $stabVer);
}
}

View file

@ -0,0 +1,561 @@
<?php
/**
* @author Laurent Jouanneau
* @copyright 2008-2017 Laurent Jouanneau
*
* @link http://www.jelix.org
* @licence MIT
*/
namespace Jelix\Version;
/**
* class to compare version numbers. it supports the following keywords:
* "pre", "-dev", "b", "beta", "a", "alpha".
* It supports also the "*" wildcard. This wildcard must be the last part
* of the version number.
*/
class VersionComparator
{
/**
* Compare two version objects.
*
* @return int
* - 0 if versions are equals
* - -1 if $version1 is lower than $version2
* - 1 if $version1 is higher than $version2
*/
public static function compare(Version $version1, Version $version2)
{
if ($version1->hasWildcard() && $version2->hasWildcard()) {
throw new \Exception("Cannot compare two wildcard versions");
}
if ($version1->hasWildcard()) {
if ($version1->getMajor() === '*') {
return 0;
}
list($v1, $v2) = self::getBoundsFromWildcardVersion($version1);
if (self::compareVersionRange($version2, self::getRangeOperatorFromBounds($v1, $v2))) {
return 0;
}
$ltRange = new VersionRangeUnaryOperator(VersionRangeUnaryOperator::OP_LT, $v1);
if (self::compareVersionRange($version2, $ltRange)) {
return 1;
}
return -1;
}
else if ($version2->hasWildcard()) {
if ($version2->getMajor() === '*') {
return 0;
}
list($v1, $v2) = self::getBoundsFromWildcardVersion($version2);
if (self::compareVersionRange($version1, self::getRangeOperatorFromBounds($v1, $v2))) {
return 0;
}
$ltRange = new VersionRangeUnaryOperator(VersionRangeUnaryOperator::OP_LT, $v1);
if (self::compareVersionRange($version1, $ltRange)) {
return -1;
}
return 1;
}
if ($version1->toString() == $version2->toString()) {
return 0;
}
$v1 = $version1->getVersionArray();
$v2 = $version2->getVersionArray();
if (count($v1) > count($v2)) {
$v2 = array_pad($v2, count($v1), 0);
} elseif (count($v1) < count($v2)) {
$v1 = array_pad($v1, count($v2), 0);
}
// version comparison
foreach ($v1 as $k => $v) {
if ($v === $v2[$k]) {
continue;
}
if ($v < $v2[$k]) {
return -1;
} else {
return 1;
}
}
// stability comparison
// dev/pre < alpha < beta < RC < stable
$s1 = $version1->getStabilityVersion();
$s2 = $version2->getStabilityVersion();
if (count($s1) > count($s2)) {
$s2 = array_pad($s2, count($s1), '');
} elseif (count($s1) < count($s2)) {
$s1 = array_pad($s1, count($s2), '');
}
foreach ($s1 as $k => $v) {
if ($v === '*' || $s2[$k] === '*') {
return 0;
}
if ($v === $s2[$k]) {
continue;
}
if ($v === '') {
if (!is_numeric($s2[$k])) {
return 1;
} else {
$v = '0';
}
} elseif ($s2[$k] === '') {
if (!is_numeric($v)) {
return -1;
} else {
$s2[$k] = '0';
}
}
if (is_numeric($v)) {
if (is_numeric($s2[$k])) {
$v1 = intval($v);
$v2 = intval($s2[$k]);
if ($v1 == $v2) {
continue;
}
if ($v1 < $v2) {
return -1;
}
return 1;
} else {
return -1;
}
} elseif (is_numeric($s2[$k])) {
return -1;
} else {
if ($v === 'dev' || $v === 'pre') {
$v = 'aaaaaaaaaa';
}
$v2 = $s2[$k];
if ($v2 === 'dev' || $v2 === 'pre') {
$v2 = 'aaaaaaaaaa';
}
$r = strcmp($v, $v2);
if ($r > 0) {
return 1;
} elseif ($r < 0) {
return -1;
}
}
}
$sv1 = $version1->getSecondaryVersion();
$sv2 = $version2->getSecondaryVersion();
if (($sv1 instanceof Version) || ($sv2 instanceof Version)) {
if (($sv1 instanceof Version) && ($sv2 instanceof Version)) {
return self::compare($sv1, $sv2);
}
else if ($sv1 instanceof Version) {
return 1;
}
else if ($sv2 instanceof Version) {
return -1;
}
}
return 0;
}
/**
* Compare two version as string.
*
* It supports wildcard in one of the version
*
* @param string $version1
* @param string $version2
*
* @return int 0 if equal, -1 if $version1 < $version2, 1 if $version1 > $version2
*/
public static function compareVersion($version1, $version2)
{
if ($version1 == $version2) {
return 0;
}
$v1 = Parser::parse($version1);
$v2 = Parser::parse($version2);
return self::compare($v1, $v2);
}
protected static function normalizeVersionNumber(&$n)
{
$n[2] = strtolower($n[2]);
if ($n[2] === 'pre' || $n[2] === 'dev' || $n[2] === '-dev') {
$n[2] = '_';
$n[3] = '';
$n[4] = 'dev';
}
if (!isset($n[4])) {
$n[4] = '';
} else {
$n[4] = strtolower($n[4]);
if ($n[4] === 'pre' || $n[4] === '-dev') {
$n[4] = 'dev';
}
}
if ($n[2] === 'a') {
$n[2] = 'alpha';
} elseif ($n[2] === 'b') {
$n[2] = 'beta';
} elseif ($n[2] === '') {
$n[2] = 'zzz';
}
}
/**
* create a string representing a version number in a manner that it could
* be easily to be compared with an other serialized version. useful to
* do comparison in a database for example.
*
* It doesn't support all version notation. Use serializeVersion2 instead.
*
* @param int $starReplacement 1 if it should replace by max value, 0 for min value
* @deprecated
*/
public static function serializeVersion($version, $starReplacement = 0, $pad = 4)
{
$vers = explode('.', $version);
$r = '/^([0-9]+)([a-zA-Z]*|pre|-?dev)([0-9]*)(pre|-?dev)?$/';
$sver = '';
foreach ($vers as $k => $v) {
if ($v === '*') {
--$k;
break;
}
$pm = preg_match($r, $v, $m);
if ($pm) {
self::normalizeVersionNumber($m);
$m[1] = str_pad($m[1], ($k > 1 ? 10 : 3), '0', STR_PAD_LEFT);
$m[2] = substr($m[2], 0, 1); // alpha/beta
$m[3] = ($m[3] === '' ? '99' : str_pad($m[3], 2, '0', STR_PAD_LEFT)); // alpha/beta number
$m[4] = ($m[4] === 'dev' ? 'd' : 'z');
if ($k) {
$sver .= '.';
}
$sver .= $m[1].$m[2].$m[3].$m[4];
} else {
throw new \Exception("version number '" . $version . "' cannot be serialized");
}
}
for ($i = $k + 1; $i < $pad; ++$i) {
if ($i > 0) {
$sver .= '.';
}
if ($starReplacement > 0) {
$sver .= ($i > 1 ? '9999999999' : '999').'z99z';
} else {
$sver .= ($i > 1 ? '0000000000' : '000').'a00a';
}
}
return $sver;
}
/**
* create a string representing a version number in a manner that it could
* be easily to be compared with an other serialized version. useful to
* do comparison in a database for example.
*
* It does not serialize secondary versions, so you should serialize them separatly.
*
* @param string $version
* @param int $starReplacement 1 if it should replace '*' by max value, 0 for min value
*/
public static function serializeVersion2($version, $starReplacement = 0, $maxpad = 10)
{
// remove meta data
$vers = explode('+', $version, 2);
$version = $vers[0];
// remove secondary version
$allVersions = preg_split('/(-|:)([0-9]+)($|\.|-)/', $version, 2, PREG_SPLIT_DELIM_CAPTURE);
$version = $allVersions[0];
$version = preg_replace("/([0-9])([a-z])/i", "\\1-\\2", $version);
$version = preg_replace("/([a-z])([0-9])/i", "\\1.\\2", $version);
$extensions = explode('-', $version, 3);
$serial = '';
$extensions = array_pad($extensions, 3, '0');
foreach ($extensions as $ext) {
$currentUnstable = 'z';
$vers = explode('.', $ext);
$vers = array_pad($vers, 5, "0");
foreach($vers as $k => $v) {
$pad = ($k > 1 ? $maxpad : 3);
if ($v === '*') {
if ($starReplacement > 0) {
$vers[$k] = $currentUnstable.($k > 1 ? '9999999999' : '999');
} else {
$vers[$k] = $currentUnstable.($k > 1 ? '0000000000' : '000');
}
}
else if (is_numeric($v)) {
$vers[$k] = $currentUnstable.str_pad($v, $pad, '0', STR_PAD_LEFT);
}
else if ($v == 'dev' || $v == 'pre') {
$currentUnstable = '_';
$vers[$k] = '_'.str_pad('', $pad, '0');
}
else {
$currentUnstable = strtolower(substr($v, 0, 1));
$vers[$k] = $currentUnstable.str_repeat('0', $pad);
}
}
if ($serial) {
$serial .= '-';
}
$serial .= implode('', $vers);
}
return $serial;
}
/**
* Compare a version with a given range.
*
* It does not compare with secondary version.
*
* @param string|Version $version a version number
* @param string|VersionRangeOperatorInterface $range a version expression respecting Composer range syntax
*
* @return bool true if the given version match the given range
*/
public static function compareVersionRange($version, $range)
{
if (is_object($range) && $range instanceof VersionRangeOperatorInterface) {
$rangeStr = (string) $range;
}
else {
$rangeStr = $range;
$range = self::compileRange($range);
}
if ($rangeStr === '' || $version === '') {
return true;
}
if (is_string($version)) {
$v1 = Parser::parse($version);
}
else {
$v1 = $version;
}
if ($v1->toString(true, false) === $rangeStr) {
return true;
}
return $range->compare($v1);
}
/**
* @return VersionRangeOperatorInterface
*/
protected static function compileRange($range)
{
$or = preg_split('/\s*\|\|\s*/', $range, 2);
if (count($or) > 1) {
$left = self::compileRange($or[0]);
$right = self::compileRange($or[1]);
return new VersionRangeBinaryOperator(VersionRangeBinaryOperator::OP_OR, $left, $right);
}
$or = preg_split('/\s*\|\s*/', $range, 2);
if (count($or) > 1) {
$left = self::compileRange($or[0]);
$right = self::compileRange($or[1]);
return new VersionRangeBinaryOperator(VersionRangeBinaryOperator::OP_OR, $left, $right);
}
$and = preg_split("/\\s*,\\s*/", $range, 2);
if (count($and) > 1) {
$left = self::compileRange($and[0]);
$right = self::compileRange($and[1]);
return new VersionRangeBinaryOperator(VersionRangeBinaryOperator::OP_AND, $left, $right);
}
$and = preg_split("/(?<!-)\\s+(?!-)/", $range, 2);
if (count($and) > 1) {
$left = self::compileRange($and[0]);
$right = self::compileRange($and[1]);
return new VersionRangeBinaryOperator(VersionRangeBinaryOperator::OP_AND, $left, $right);
}
$between = preg_split("/\\s+\\-\\s+/", $range, 2);
if (count($between) > 1) {
// 1.0 - 2.0 is equivalent to >=1.0.0 <2.1
// 1.0.0 - 2.1.0 is equivalent to >=1.0.0 <=2.1.0
$v1 = Parser::parse($between[0]);
$left = new VersionRangeUnaryOperator(VersionRangeUnaryOperator::OP_GTE, $v1);
$v2 = Parser::parse($between[1]);
if ($v2->hasPatch()) {
$right = new VersionRangeUnaryOperator(VersionRangeUnaryOperator::OP_LTE, $v2);
} elseif ($v2->hasMinor()) {
$v2 = $v2->getNextMinorVersion();
$right = new VersionRangeUnaryOperator(VersionRangeUnaryOperator::OP_LT, $v2);
} else {
$v2 = $v2->getNextMajorVersion();
$right = new VersionRangeUnaryOperator(VersionRangeUnaryOperator::OP_LT, $v2);
}
return new VersionRangeBinaryOperator(VersionRangeBinaryOperator::OP_AND, $left, $right);
}
$val = trim($range);
if (preg_match("/^([\\!>=<~^]+)(.*)$/", $val, $m)) {
$v1 = Parser::parse($m[2]);
switch ($m[1]) {
case '=':
$op = VersionRangeUnaryOperator::OP_EQ;
break;
case '<':
$op = VersionRangeUnaryOperator::OP_LT;
break;
case '>':
$op = VersionRangeUnaryOperator::OP_GT;
break;
case '<=':
$op = VersionRangeUnaryOperator::OP_LTE;
break;
case '>=':
$op = VersionRangeUnaryOperator::OP_GTE;
break;
case '!=':
$op = VersionRangeUnaryOperator::OP_DIFF;
break;
case '~':
// ~1.2 is equivalent to >=1.2 <2.0.0
// ~1.2.3 is equivalent to >=1.2.3 <1.3.0
if ($v1->hasPatch()) {
$v2 = Parser::parse($v1->getNextMinorVersion().'-dev');
} else {
$v2 = Parser::parse($v1->getNextMajorVersion().'-dev');
}
$left = new VersionRangeUnaryOperator(VersionRangeUnaryOperator::OP_GTE, $v1);
$right = new VersionRangeUnaryOperator(VersionRangeUnaryOperator::OP_LT, $v2);
return new VersionRangeBinaryOperator(VersionRangeBinaryOperator::OP_AND, $left, $right);
case '^':
// ^1.2.3 is equivalent to >=1.2.3 <3.0.0
// ^0.3 as >=0.3.0 <0.4.0
// ^0.3.2 as >=0.3.2 <0.4.0
$v2 = Parser::parse($v1->getNextMajorVersion().'-dev');
$left = new VersionRangeUnaryOperator(VersionRangeUnaryOperator::OP_GTE, $v1);
$right = new VersionRangeUnaryOperator(VersionRangeUnaryOperator::OP_LT, $v2);
return new VersionRangeBinaryOperator(VersionRangeBinaryOperator::OP_AND, $left, $right);
default:
throw new \Exception('Version comparator: bad operator in the range '.$range);
}
return new VersionRangeUnaryOperator($op, $v1);
} elseif ($val === '*') {
return new VersionRangeTrueOperator();
}
$v1 = Parser::parse($val);
if (!$v1->hasWildcard()) {
return new VersionRangeUnaryOperator(VersionRangeUnaryOperator::OP_EQ, $v1);
}
if (preg_match('/^(.+)(\.\*)$/', $val, $m)) {
return self::getRangeFromWildcardVersion($v1);
}
return new VersionRangeUnaryOperator(VersionRangeUnaryOperator::OP_EQ, Parser::parse($range));
}
/**
* @param Version $version
* @return Version[]
* @throws \Exception
*/
protected static function getBoundsFromWildcardVersion(Version $version)
{
$versionArr = $version->getVersionArray();
foreach ($versionArr as $k => $vNum) {
if ($vNum === '*') {
$versionArr[$k] = 0;
}
}
$stability = $version->getStabilityVersion();
if (!count($stability)) {
$v2 = $version->getNextTailVersion();
$v2 = new Version($v2->getVersionArray(), array('dev'),'', $v2->getSecondaryVersion());
$v1 = new Version($versionArr, array('dev'),'', $version->getSecondaryVersion());
} else {
if ($version->hasWildcard() & $version::WILDCARD_ON_STABILITY_VERSION) {
$majorStability = array();
$foundWildcard = false;
foreach ($stability as $k => $vNum) {
if ($vNum === '*') {
$stability[$k] = ($k ==0 ?'dev': 0);
$foundWildcard = true;
}
else if (!$foundWildcard) {
$majorStability[$k] = $vNum;
}
}
$v1 = new Version($versionArr, $stability, '', $version->getSecondaryVersion());
$v2 = new Version($version->getVersionArray(), $majorStability,'', $version->getSecondaryVersion());
$v2 = $v2->getNextStabilityVersion();
}
else if ($stability[0] !== '' && $stability[0] !== 'stable') {
$v2 = new Version($version->getVersionArray(), array(), '', $version->getSecondaryVersion());
$v2 = $v2->getNextTailVersion();
$v2 = new Version($v2->getVersionArray(), array('dev'),'', $v2->getSecondaryVersion());
$v1 = new Version($versionArr, $stability, '', $version->getSecondaryVersion());
} else {
$v1 = new Version($versionArr, array(), '', $version->getSecondaryVersion());
$v2 = $version->getNextTailVersion();
}
}
return array($v1, $v2);
}
/**
* @param Version $version
* @return VersionRangeOperatorInterface
* @throws \Exception
*/
public static function getRangeFromWildcardVersion(Version $version)
{
// 1.4.* -> >=1.4.0.0-dev <1.5.0.0-dev
// 1.4.*-stable -> >=1.4.0.0 <1.5.0.0
// 1.2.* -> >= 1.2.0-dev <1.3.0-dev
// 1.2.3.* -> >= 1.2.3.0-dev <1.2.4-dev
// 1.2.*-alpha.2', '>= 1.2.0-alpha.2 <1.3.0-dev
list($v1, $v2) = self::getBoundsFromWildcardVersion($version);
return self::getRangeOperatorFromBounds($v1, $v2);
}
protected static function getRangeOperatorFromBounds($v1, $v2)
{
$left = new VersionRangeUnaryOperator(VersionRangeUnaryOperator::OP_GTE, $v1);
if ($v2->hasWildcard()) {
$right = new VersionRangeUnaryOperator(VersionRangeUnaryOperator::OP_LTE, $v2);
}
else {
$right = new VersionRangeUnaryOperator(VersionRangeUnaryOperator::OP_LT, $v2);
}
return new VersionRangeBinaryOperator(VersionRangeBinaryOperator::OP_AND, $left, $right);
}
}

View file

@ -0,0 +1,71 @@
<?php
/**
* @author Laurent Jouanneau
* @copyright 2008-2020 Laurent Jouanneau
*
* @link http://www.jelix.org
* @licence MIT
*/
namespace Jelix\Version;
/**
* Represents a binary operator (AND or OR) in a version range expression.
*/
class VersionRangeBinaryOperator implements VersionRangeOperatorInterface
{
const OP_OR = 0;
const OP_AND = 1;
protected $op = -1;
/**
* @var VersionRangeOperatorInterface|null
*/
protected $left = null;
/**
* @var VersionRangeOperatorInterface|null
*/
protected $right = null;
/**
* @param int $operator one of OP_*
*/
public function __construct($operator,
VersionRangeOperatorInterface $left,
VersionRangeOperatorInterface $right)
{
$this->op = $operator;
$this->left = $left;
$this->right = $right;
}
public function compare(Version $value)
{
if ($this->op == self::OP_OR) {
if ($this->left->compare($value)) {
return true;
}
if ($this->right->compare($value)) {
return true;
}
return false;
}
if (!$this->left->compare($value)) {
return false;
}
if (!$this->right->compare($value)) {
return false;
}
return true;
}
public function __toString()
{
return '('.((string)$this->left).') '.($this->op?'AND':'OR').' ('.((string)$this->right).')';
}
}

View file

@ -0,0 +1,18 @@
<?php
/**
* @author Laurent Jouanneau
* @copyright 2008-2020 Laurent Jouanneau
*
* @link http://www.jelix.org
* @licence MIT
*/
namespace Jelix\Version;
interface VersionRangeOperatorInterface
{
/**
* @return bool
*/
public function compare(Version $value);
}

View file

@ -0,0 +1,24 @@
<?php
/**
* @author Laurent Jouanneau
* @copyright 2008-2020 Laurent Jouanneau
*
* @link http://www.jelix.org
* @licence MIT
*/
namespace Jelix\Version;
class VersionRangeTrueOperator implements VersionRangeOperatorInterface
{
public function compare(Version $value)
{
return true;
}
function __toString()
{
return 'true';
}
}

View file

@ -0,0 +1,75 @@
<?php
/**
* @author Laurent Jouanneau
* @copyright 2008-2020 Laurent Jouanneau
*
* @link http://www.jelix.org
* @licence MIT
*/
namespace Jelix\Version;
/**
* Represents an unary operator (>,<,=,!=,<=,>=,~) in a version range expression.
*/
class VersionRangeUnaryOperator implements VersionRangeOperatorInterface
{
const OP_EQ = 0;
const OP_LT = 1;
const OP_GT = 2;
const OP_GTE = 3;
const OP_LTE = 4;
const OP_DIFF = 5;
protected $op = -1;
protected $operand = null;
/**
* @param int $operator one of OP_*
* @param Version $version the version used to compare
*/
public function __construct($operator, Version $version)
{
$this->op = $operator;
$this->operand = $version;
}
public function compare(Version $value)
{
$result = VersionComparator::compare($value, $this->operand);
//$op = array('=', '<','>', '>=', '<=', '!=');
//echo "Result compare(".$value.", ".$this->operand.") (op= ".$op[$this->op].") = ";
switch ($this->op) {
case self::OP_EQ:
//echo ( $result === 0? 'ok': 'bad')."\n";
return $result === 0;
case self::OP_LT:
//echo ($result === -1 ? 'ok': 'bad')."\n";
return $result === -1;
case self::OP_GT:
//echo ( $result === 1? 'ok': 'bad')."\n";
return $result === 1;
case self::OP_LTE:
//echo ( $result < 1 ? 'ok': 'bad')."\n";
return $result < 1;
break;
case self::OP_GTE:
//echo ( $result > -1 ? 'ok': 'bad')."\n";
return $result > -1;
break;
case self::OP_DIFF:
//echo ( $result != 0 ? 'ok': 'bad')."\n";
return $result != 0;
}
return false;
}
function __toString()
{
$op = array('=', '<','>', '>=', '<=', '!=');
return $op[$this->op].$this->operand;
}
}

View file

@ -7,6 +7,10 @@
"vendor": "defuse",
"package_name": "php-encryption"
},
{
"vendor": "jelix",
"package_name": "version"
},
{
"vendor": "nikic",
"package_name": "PhpParser"