Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Intervals class to allow checking for subsets and intersections between constraints #97

Merged
merged 28 commits into from
May 19, 2020
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
56b15a5
Add basic tests and implementation for isSubsetOf
Seldaek May 5, 2020
bb1549d
Add dev-* tests, fixes Constraint><Constraint implementation by spell…
Seldaek May 5, 2020
0f5aa06
Add isContiguous to optimize and pass simple multi constraint compari…
Seldaek May 5, 2020
0218e6d
Fix bug comparing against = constraints
Seldaek May 5, 2020
6726a92
Fix matching of !=x against multi constraints
Seldaek May 5, 2020
006581b
Update wording
Seldaek May 5, 2020
4d5f569
Fix handling of disjunctive multiconstraints
Seldaek May 5, 2020
6ed5932
Clean ups, more tests
Seldaek May 5, 2020
4708f31
Add getIntervals to MultiConstraint to resolve more cases
Seldaek May 5, 2020
9686233
Add additional subset test cases
naderman May 5, 2020
b007ae4
Add failing subset tests
naderman May 5, 2020
639fc07
Fix PHP 5.3 syntax
Seldaek May 6, 2020
6469a85
Proper getIntervals implementation, move isSubsetOf out of constraint…
Seldaek May 7, 2020
e5e4d89
Add support for dev-* constraints in intervals and isSubsetOf
Seldaek May 8, 2020
67b8bb5
Avoid generating invalid intervals
Seldaek May 8, 2020
5170fb7
Fix a few more issues with dev-* by adding a dev* match all when needed
Seldaek May 8, 2020
6a1fa53
Mark a few things as not subset anymore after the dev* changes
Seldaek May 8, 2020
0b0edb3
Use version_compare for safety in case constraints are not normalized…
Seldaek May 8, 2020
5aef5c2
Add Intervals::isIntersectionOf and ensure it is acting the same as -…
Seldaek May 8, 2020
07f0384
Explicitly gate generateIntervals to our internal classes
Seldaek May 8, 2020
dcb965d
Remove sorting of dev constraints to try and fix version_compare disc…
Seldaek May 8, 2020
5468efb
Use same values for zero/+inf bounds as are used in intervals zero/+inf
Seldaek May 8, 2020
4c42914
Rename isIntersectionOf to haveIntersections
Seldaek May 19, 2020
e7ee6a2
Add phpstan annotation
Seldaek May 19, 2020
aaf43b3
Minor refactoring and add phpdocs
Seldaek May 19, 2020
3d72ad3
Fix feedback
Seldaek May 19, 2020
c3e5429
Convert interval arrays to a value object
Seldaek May 19, 2020
8806417
Rename [intervals, devConstraints] return value to [numeric, branches]
Seldaek May 19, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/Constraint/Bound.php
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,14 @@ public function __toString()
*/
public static function zero()
{
return new Bound('0', true);
return new Bound('0.0.0.0-dev', true);
}

/**
* @return self
*/
public static function positiveInfinity()
{
return new Bound((string) PHP_INT_MAX, false);
return new Bound(PHP_INT_MAX.'.0.0.0', false);
}
}
57 changes: 34 additions & 23 deletions src/Constraint/Constraint.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,38 @@ class Constraint implements CompilableConstraintInterface
/** @var Bound */
protected $upperBound;

/**
* Sets operator and version to compare with.
*
* @param string $operator
Seldaek marked this conversation as resolved.
Show resolved Hide resolved
* @param string $version
*
* @throws \InvalidArgumentException if invalid operator is given.
*/
public function __construct($operator, $version)
{
if (!isset(self::$transOpStr[$operator])) {
throw new \InvalidArgumentException(sprintf(
'Invalid operator "%s" given, expected one of: %s',
$operator,
implode(', ', self::getSupportedOperators())
));
}

$this->operator = self::$transOpStr[$operator];
$this->version = $version;
}

public function getVersion()
{
return $this->version;
}

public function getOperator()
{
return self::$transOpInt[$this->operator];
}

/**
* @param ConstraintInterface $provider
*
Expand Down Expand Up @@ -119,28 +151,6 @@ public static function getSupportedOperators()
return array_keys(self::$transOpStr);
}

/**
* Sets operator and version to compare with.
*
* @param string $operator
* @param string $version
*
* @throws \InvalidArgumentException if invalid operator is given.
*/
public function __construct($operator, $version)
{
if (!isset(self::$transOpStr[$operator])) {
throw new \InvalidArgumentException(sprintf(
'Invalid operator "%s" given, expected one of: %s',
$operator,
implode(', ', self::getSupportedOperators())
));
}

$this->operator = self::$transOpStr[$operator];
$this->version = $version;
}

/**
* @param string $a
* @param string $b
Expand Down Expand Up @@ -180,7 +190,8 @@ public function versionCompare($a, $b, $operator, $compareBranches = false)
return \version_compare($a, $b, $operator);
}

public function compile($otherOperator) {
public function compile($otherOperator)
{
if ($this->version[0] === 'd' && 'dev-' === substr($this->version, 0, 4)) {
if (self::OP_EQ === $this->operator) {
if (self::OP_EQ === $otherOperator) {
Expand Down
8 changes: 8 additions & 0 deletions src/Constraint/ConstraintInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,17 @@

namespace Composer\Semver\Constraint;

/**
* DO NOT IMPLEMENT this interface. It is only meant for usage as a type hint
* in libraries relying on composer/semver but creating your own constraint class
* that implements this interface is not a supported use case and will cause the
* composer/semver components to return unexpected results.
*/
Seldaek marked this conversation as resolved.
Show resolved Hide resolved
interface ConstraintInterface
{
/**
* Checks whether the given constraint intersects in any way with this constraint
*
* @param ConstraintInterface $provider
*
* @return bool
Expand Down
2 changes: 1 addition & 1 deletion src/Constraint/MultiConstraint.php
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ private static function optimizeConstraints(array $constraints, $conjunctive)
$left = $constraints[0];
$mergedConstraints = array();
$optimized = false;
for ($i = 1, $l = \count($constraints); $i <$l; $i++) {
for ($i = 1, $l = \count($constraints); $i < $l; $i++) {
$right = $constraints[$i];
if (
$left instanceof MultiConstraint
Expand Down
96 changes: 96 additions & 0 deletions src/Interval.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<?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\Constraint;

class Interval
{
/** @var Constraint */
private $start;
/** @var Constraint */
private $end;

public function __construct(Constraint $start, Constraint $end)
{
$this->start = $start;
$this->end = $end;
}

/**
* @return Constraint
*/
public function getStart()
{
return $this->start;
}

/**
* @return Constraint
*/
public function getEnd()
{
return $this->end;
}

/**
* @return Constraint
*/
public static function zero()
{
static $zero;

if (null === $zero) {
$zero = new Constraint('>=', '0.0.0.0-dev');
}

return $zero;
}

/**
* @return Constraint
*/
public static function positiveInfinity()
{
static $positiveInfinity;

if (null === $positiveInfinity) {
$positiveInfinity = new Constraint('<', PHP_INT_MAX.'.0.0.0');
}

return $positiveInfinity;
}

/**
* @return self
*/
public static function any()
{
return new self(self::zero(), self::positiveInfinity());
}

/**
* @return Constraint
*/
public static function anyDev()
{
static $anyDev;

if (null === $anyDev) {
// this ideally should be an EmptyConstraint but the code expects Constraint instances so
// this makes it work with less workarounds/checks above
$anyDev = new Constraint('==', 'dev*');
}

return $anyDev;
}
}
Loading