diff --git a/.gitignore b/.gitignore index 9b3cd79..570cd0f 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/LICENSE b/LICENSE index 65f5cdd..3fad6f1 100644 --- a/LICENSE +++ b/LICENSE @@ -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. \ No newline at end of file +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. \ No newline at end of file diff --git a/Makefile b/Makefile index 24172f7..4a75d0f 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/src/ncc/ThirdParty/jelix/version/LICENCE b/src/ncc/ThirdParty/jelix/version/LICENCE new file mode 100644 index 0000000..37b8dcc --- /dev/null +++ b/src/ncc/ThirdParty/jelix/version/LICENCE @@ -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. \ No newline at end of file diff --git a/src/ncc/ThirdParty/jelix/version/Parser.php b/src/ncc/ThirdParty/jelix/version/Parser.php new file mode 100644 index 0000000..de5528c --- /dev/null +++ b/src/ncc/ThirdParty/jelix/version/Parser.php @@ -0,0 +1,170 @@ + 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; + } +} diff --git a/src/ncc/ThirdParty/jelix/version/README.md b/src/ncc/ThirdParty/jelix/version/README.md new file mode 100644 index 0000000..0456917 --- /dev/null +++ b/src/ncc/ThirdParty/jelix/version/README.md @@ -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. + diff --git a/src/ncc/ThirdParty/jelix/version/VERSION b/src/ncc/ThirdParty/jelix/version/VERSION new file mode 100644 index 0000000..10bf840 --- /dev/null +++ b/src/ncc/ThirdParty/jelix/version/VERSION @@ -0,0 +1 @@ +2.0.1 \ No newline at end of file diff --git a/src/ncc/ThirdParty/jelix/version/Version.php b/src/ncc/ThirdParty/jelix/version/Version.php new file mode 100644 index 0000000..66a6a39 --- /dev/null +++ b/src/ncc/ThirdParty/jelix/version/Version.php @@ -0,0 +1,364 @@ +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); + } +} diff --git a/src/ncc/ThirdParty/jelix/version/VersionComparator.php b/src/ncc/ThirdParty/jelix/version/VersionComparator.php new file mode 100644 index 0000000..efb8006 --- /dev/null +++ b/src/ncc/ThirdParty/jelix/version/VersionComparator.php @@ -0,0 +1,561 @@ +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("/(? 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); + } + +} diff --git a/src/ncc/ThirdParty/jelix/version/VersionRangeBinaryOperator.php b/src/ncc/ThirdParty/jelix/version/VersionRangeBinaryOperator.php new file mode 100644 index 0000000..6eb7082 --- /dev/null +++ b/src/ncc/ThirdParty/jelix/version/VersionRangeBinaryOperator.php @@ -0,0 +1,71 @@ +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).')'; + } +} diff --git a/src/ncc/ThirdParty/jelix/version/VersionRangeOperatorInterface.php b/src/ncc/ThirdParty/jelix/version/VersionRangeOperatorInterface.php new file mode 100644 index 0000000..7d58f63 --- /dev/null +++ b/src/ncc/ThirdParty/jelix/version/VersionRangeOperatorInterface.php @@ -0,0 +1,18 @@ +,<,=,!=,<=,>=,~) 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; + } +} diff --git a/src/ncc/version.json b/src/ncc/version.json index 3c7cb65..aab248b 100644 --- a/src/ncc/version.json +++ b/src/ncc/version.json @@ -7,6 +7,10 @@ "vendor": "defuse", "package_name": "php-encryption" }, + { + "vendor": "jelix", + "package_name": "version" + }, { "vendor": "nikic", "package_name": "PhpParser"