1
0
Fork 0

Add support for caret (^) operator

pull/2596/head
Jordi Boggiano 2014-12-08 15:39:52 +00:00
parent ebab9db27a
commit f363f9d370
3 changed files with 79 additions and 8 deletions

View File

@ -72,18 +72,19 @@ means any version in the `1.0` development branch. It would match `1.0.0`,
Version constraints can be specified in a few different ways. Version constraints can be specified in a few different ways.
Name | Example | Description Name | Example | Description
-------------- | ------------------------------------------------------------------ | ----------- -------------- | ------------------------------------------------------------------------ | -----------
Exact version | `1.0.2` | You can specify the exact version of a package. Exact version | `1.0.2` | You can specify the exact version of a package.
Range | `>=1.0` `>=1.0 <2.0` <code>&gt;=1.0 &lt;1.1 &#124;&#124; &gt;=1.2</code> | By using comparison operators you can specify ranges of valid versions. Valid operators are `>`, `>=`, `<`, `<=`, `!=`. <br />You can define multiple ranges. Ranges separated by a space (` `) or comma (`,`) will be treated as a **logical AND**. A double pipe (<code>&#124;&#124;</code>) will be treated as a **logical OR**. AND has higher precedence than OR. Range | `>=1.0` `>=1.0 <2.0` <code>&gt;=1.0 &lt;1.1 &#124;&#124; &gt;=1.2</code> | By using comparison operators you can specify ranges of valid versions. Valid operators are `>`, `>=`, `<`, `<=`, `!=`. <br />You can define multiple ranges. Ranges separated by a space (` `) or comma (`,`) will be treated as a **logical AND**. A double pipe (<code>&#124;&#124;</code>) will be treated as a **logical OR**. AND has higher precedence than OR.
Hyphen Range | `1.0 - 2.0` | Inclusive set of versions. Partial versions on the right include are completed with a wildcard. For example `1.0 - 2.0` is equivalent to `>=1.0.0 <2.1` as the `2.0` becomes `2.0.*`. On the other hand `1.0.0 - 2.1.0` is equivalent to `>=1.0.0 <=2.1.0`. Hyphen Range | `1.0 - 2.0` | Inclusive set of versions. Partial versions on the right include are completed with a wildcard. For example `1.0 - 2.0` is equivalent to `>=1.0.0 <2.1` as the `2.0` becomes `2.0.*`. On the other hand `1.0.0 - 2.1.0` is equivalent to `>=1.0.0 <=2.1.0`.
Wildcard | `1.0.*` | You can specify a pattern with a `*` wildcard. `1.0.*` is the equivalent of `>=1.0,<1.1`. Wildcard | `1.0.*` | You can specify a pattern with a `*` wildcard. `1.0.*` is the equivalent of `>=1.0 <1.1`.
Tilde Operator | `~1.2` | Very useful for projects that follow semantic versioning. `~1.2` is equivalent to `>=1.2,<2.0`. For more details, read the next section below. Tilde Operator | `~1.2` | Very useful for projects that follow semantic versioning. `~1.2` is equivalent to `>=1.2 <2.0`. For more details, read the next section below.
Caret Operator | `^1.2.3` | Very useful for projects that follow semantic versioning. `^1.2.3` is equivalent to `>=1.2.3 <2.0`. For more details, read the next section below.
### Next Significant Release (Tilde Operator) ### Next Significant Release (Tilde and Caret Operators)
The `~` operator is best explained by example: `~1.2` is equivalent to The `~` operator is best explained by example: `~1.2` is equivalent to
`>=1.2,<2.0`, while `~1.2.3` is equivalent to `>=1.2.3,<1.3`. As you can see `>=1.2 <2.0.0`, while `~1.2.3` is equivalent to `>=1.2.3 <1.3.0`. As you can see
it is mostly useful for projects respecting [semantic it is mostly useful for projects respecting [semantic
versioning](http://semver.org/). A common usage would be to mark the minimum versioning](http://semver.org/). A common usage would be to mark the minimum
minor version you depend on, like `~1.2` (which allows anything up to, but not minor version you depend on, like `~1.2` (which allows anything up to, but not
@ -91,6 +92,12 @@ including, 2.0). Since in theory there should be no backwards compatibility
breaks until 2.0, that works well. Another way of looking at it is that using breaks until 2.0, that works well. Another way of looking at it is that using
`~` specifies a minimum version, but allows the last digit specified to go up. `~` specifies a minimum version, but allows the last digit specified to go up.
The `^` operator behaves very similarly but it sticks closer to semantic
versioning, and will always allow non-breaking updates. For example `^1.2.3`
is equivalent to `>=1.2.3 <2.0.0` as none of the releases until 2.0 should
break backwards compatibility. For pre-1.0 versions it also acts with safety
in mind and treats `^0.3` as `>=0.3.0 <0.4.0`
> **Note:** Though `2.0-beta.1` is strictly before `2.0`, a version constraint > **Note:** Though `2.0-beta.1` is strictly before `2.0`, a version constraint
> like `~1.2` would not install it. As said above `~1.2` only means the `.2` > like `~1.2` would not install it. As said above `~1.2` only means the `.2`
> can change but the `1.` part is fixed. > can change but the `1.` part is fixed.

View File

@ -330,6 +330,37 @@ class VersionParser
); );
} }
// 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 // match wildcard constraints
if (preg_match('{^(\d+)(?:\.(\d+))?(?:\.(\d+))?\.[xX*]$}', $constraint, $matches)) { if (preg_match('{^(\d+)(?:\.(\d+))?(?:\.(\d+))?\.[xX*]$}', $constraint, $matches)) {
if (isset($matches[3]) && '' !== $matches[3]) { if (isset($matches[3]) && '' !== $matches[3]) {

View File

@ -294,6 +294,39 @@ class VersionParserTest extends \PHPUnit_Framework_TestCase
); );
} }
/**
* @dataProvider caretConstraints
*/
public function testParseCaretWildcard($input, $min, $max)
{
$parser = new VersionParser;
if ($min) {
$expected = new MultiConstraint(array($min, $max));
} else {
$expected = $max;
}
$this->assertSame((string) $expected, (string) $parser->parseConstraints($input));
}
public function caretConstraints()
{
return array(
array('^1', new VersionConstraint('>=', '1.0.0.0-dev'), new VersionConstraint('<', '2.0.0.0-dev')),
array('^0', new VersionConstraint('>=', '0.0.0.0-dev'), new VersionConstraint('<', '1.0.0.0-dev')),
array('^0.0', new VersionConstraint('>=', '0.0.0.0-dev'), new VersionConstraint('<', '0.1.0.0-dev')),
array('^1.2', new VersionConstraint('>=', '1.2.0.0-dev'), new VersionConstraint('<', '2.0.0.0-dev')),
array('^1.2.3-beta.2', new VersionConstraint('>=', '1.2.3.0-beta2'), new VersionConstraint('<', '2.0.0.0-dev')),
array('^1.2.3.4', new VersionConstraint('>=', '1.2.3.4-dev'), new VersionConstraint('<', '2.0.0.0-dev')),
array('^1.2.3', new VersionConstraint('>=', '1.2.3.0-dev'), new VersionConstraint('<', '2.0.0.0-dev')),
array('^0.2.3', new VersionConstraint('>=', '0.2.3.0-dev'), new VersionConstraint('<', '0.3.0.0-dev')),
array('^0.2', new VersionConstraint('>=', '0.2.0.0-dev'), new VersionConstraint('<', '0.3.0.0-dev')),
array('^0.0.3', new VersionConstraint('>=', '0.0.3.0-dev'), new VersionConstraint('<', '0.0.4.0-dev')),
array('^0.0.3-alpha', new VersionConstraint('>=', '0.0.3.0-alpha'), new VersionConstraint('<', '0.0.4.0-dev')),
array('^0.0.3-dev', new VersionConstraint('>=', '0.0.3.0-dev'), new VersionConstraint('<', '0.0.4.0-dev')),
);
}
/** /**
* @dataProvider hyphenConstraints * @dataProvider hyphenConstraints
*/ */