Merge pull request #60 from naderman/master
Implementation of the DefaultPolicy specs regarding prefered packagespull/44/merge
commit
72f69e6109
|
@ -63,24 +63,125 @@ class DefaultPolicy implements PolicyInterface
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getPriority(Pool $pool, PackageInterface $package)
|
||||||
|
{
|
||||||
|
return $pool->getPriority($package->getRepository());
|
||||||
|
}
|
||||||
|
|
||||||
public function selectPreferedPackages(Pool $pool, RepositoryInterface $installed, array $literals)
|
public function selectPreferedPackages(Pool $pool, RepositoryInterface $installed, array $literals)
|
||||||
{
|
{
|
||||||
$newest = $this->selectNewestPackages($installed, $literals);
|
$packages = $this->groupLiteralsByNamePreferInstalled($installed, $literals);
|
||||||
|
|
||||||
$selected = array();
|
foreach ($packages as &$literals) {
|
||||||
foreach ($newest as $literal) {
|
$policy = $this;
|
||||||
if ($literal->getPackage()->getRepository() === $installed) {
|
usort($literals, function ($a, $b) use ($policy, $pool, $installed) {
|
||||||
$selected[] = $literal;
|
return $policy->compareByPriorityPreferInstalled($pool, $installed, $a->getPackage(), $b->getPackage(), true);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach ($packages as &$literals) {
|
||||||
|
$literals = $this->pruneToBestVersion($literals);
|
||||||
|
|
||||||
|
$literals = $this->pruneToHighestPriorityOrInstalled($pool, $installed, $literals);
|
||||||
}
|
}
|
||||||
if (count($selected)) {
|
|
||||||
|
$selected = call_user_func_array('array_merge', $packages);
|
||||||
|
|
||||||
|
// now sort the result across all packages to respect replaces across packages
|
||||||
|
usort($selected, function ($a, $b) use ($policy, $pool, $installed) {
|
||||||
|
return $policy->compareByPriorityPreferInstalled($pool, $installed, $a->getPackage(), $b->getPackage());
|
||||||
|
});
|
||||||
|
|
||||||
return $selected;
|
return $selected;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $newest;
|
protected function groupLiteralsByNamePreferInstalled(RepositoryInterface $installed, $literals)
|
||||||
|
{
|
||||||
|
$packages = array();
|
||||||
|
foreach ($literals as $literal) {
|
||||||
|
$packageName = $literal->getPackage()->getName();
|
||||||
|
|
||||||
|
if (!isset($packages[$packageName])) {
|
||||||
|
$packages[$packageName] = array();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function selectNewestPackages(RepositoryInterface $installed, array $literals)
|
if ($literal->getPackage()->getRepository() === $installed) {
|
||||||
|
array_unshift($packages[$packageName], $literal);
|
||||||
|
} else {
|
||||||
|
$packages[$packageName][] = $literal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $packages;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function compareByPriorityPreferInstalled(Pool $pool, RepositoryInterface $installed, PackageInterface $a, PackageInterface $b, $ignoreReplace = false)
|
||||||
|
{
|
||||||
|
if ($a->getRepository() === $b->getRepository()) {
|
||||||
|
|
||||||
|
if (!$ignoreReplace) {
|
||||||
|
// return original, not replaced
|
||||||
|
if ($this->replaces($a, $b)) {
|
||||||
|
return 1; // use b
|
||||||
|
}
|
||||||
|
if ($this->replaces($b, $a)) {
|
||||||
|
return -1; // use a
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// priority equal, sort by package id to make reproducible
|
||||||
|
if ($a->getId() === $b->getId()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ($a->getId() < $b->getId()) ? -1 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($a->getRepository() === $installed) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($b->getRepository() === $installed) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ($this->getPriority($pool, $a) > $this->getPriority($pool, $b)) ? -1 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function replaces(PackageInterface $source, PackageInterface $target)
|
||||||
|
{
|
||||||
|
foreach ($source->getReplaces() as $link) {
|
||||||
|
if ($link->getTarget() === $target->getName() &&
|
||||||
|
(null === $link->getConstraint() ||
|
||||||
|
$link->getConstraint()->matches(new VersionConstraint('==', $target->getVersion())))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function pruneToBestVersion($literals)
|
||||||
|
{
|
||||||
|
$bestLiterals = array($literals[0]);
|
||||||
|
$bestPackage = $literals[0]->getPackage();
|
||||||
|
foreach ($literals as $i => $literal) {
|
||||||
|
if (0 === $i) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->versionCompare($literal->getPackage(), $bestPackage, '>')) {
|
||||||
|
$bestPackage = $literal->getPackage();
|
||||||
|
$bestLiterals = array($literal);
|
||||||
|
} else if ($this->versionCompare($literal->getPackage(), $bestPackage, '==')) {
|
||||||
|
$bestLiterals[] = $literal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $bestLiterals;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function selectNewestPackages(RepositoryInterface $installed, array $literals)
|
||||||
{
|
{
|
||||||
$maxLiterals = array($literals[0]);
|
$maxLiterals = array($literals[0]);
|
||||||
$maxPackage = $literals[0]->getPackage();
|
$maxPackage = $literals[0]->getPackage();
|
||||||
|
@ -99,4 +200,32 @@ class DefaultPolicy implements PolicyInterface
|
||||||
|
|
||||||
return $maxLiterals;
|
return $maxLiterals;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function pruneToHighestPriorityOrInstalled(Pool $pool, RepositoryInterface $installed, array $literals)
|
||||||
|
{
|
||||||
|
$selected = array();
|
||||||
|
|
||||||
|
$priority = null;
|
||||||
|
|
||||||
|
foreach ($literals as $literal) {
|
||||||
|
$package = $literal->getPackage();
|
||||||
|
|
||||||
|
if ($package->getRepository() === $installed) {
|
||||||
|
$selected[] = $literal;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $priority) {
|
||||||
|
$priority = $this->getPriority($pool, $package);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->getPriority($pool, $package) != $priority) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$selected[] = $literal;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $selected;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,11 @@ class Pool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getPriority(RepositoryInterface $repo)
|
||||||
|
{
|
||||||
|
return array_search($repo, $this->repositories, true);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the package object for a given package id.
|
* Retrieves the package object for a given package id.
|
||||||
*
|
*
|
||||||
|
|
|
@ -64,15 +64,15 @@ class DefaultPolicyTest extends \PHPUnit_Framework_TestCase
|
||||||
$this->assertEquals($expected, $selected);
|
$this->assertEquals($expected, $selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSelectInstalled()
|
public function testSelectNewestOverInstalled()
|
||||||
{
|
{
|
||||||
$this->repo->addPackage($packageA = new MemoryPackage('A', '1.0'));
|
$this->repo->addPackage($packageA = new MemoryPackage('A', '2.0'));
|
||||||
$this->repoInstalled->addPackage($packageAInstalled = new MemoryPackage('A', '1.0'));
|
$this->repoInstalled->addPackage($packageAInstalled = new MemoryPackage('A', '1.0'));
|
||||||
$this->pool->addRepository($this->repo);
|
$this->pool->addRepository($this->repo);
|
||||||
$this->pool->addRepository($this->repoInstalled);
|
$this->pool->addRepository($this->repoInstalled);
|
||||||
|
|
||||||
$literals = array(new Literal($packageA, true), new Literal($packageAInstalled, true));
|
$literals = array(new Literal($packageA, true), new Literal($packageAInstalled, true));
|
||||||
$expected = array(new Literal($packageAInstalled, true));
|
$expected = array(new Literal($packageA, true));
|
||||||
|
|
||||||
$selected = $this->policy->selectPreferedPackages($this->pool, $this->repoInstalled, $literals);
|
$selected = $this->policy->selectPreferedPackages($this->pool, $this->repoInstalled, $literals);
|
||||||
|
|
||||||
|
@ -81,8 +81,6 @@ class DefaultPolicyTest extends \PHPUnit_Framework_TestCase
|
||||||
|
|
||||||
public function testSelectLastRepo()
|
public function testSelectLastRepo()
|
||||||
{
|
{
|
||||||
$this->markTestIncomplete();
|
|
||||||
|
|
||||||
$this->repoImportant = new ArrayRepository;
|
$this->repoImportant = new ArrayRepository;
|
||||||
|
|
||||||
$this->repo->addPackage($packageA = new MemoryPackage('A', '1.0'));
|
$this->repo->addPackage($packageA = new MemoryPackage('A', '1.0'));
|
||||||
|
@ -101,8 +99,6 @@ class DefaultPolicyTest extends \PHPUnit_Framework_TestCase
|
||||||
|
|
||||||
public function testSelectAllProviders()
|
public function testSelectAllProviders()
|
||||||
{
|
{
|
||||||
$this->markTestIncomplete();
|
|
||||||
|
|
||||||
$this->repo->addPackage($packageA = new MemoryPackage('A', '1.0'));
|
$this->repo->addPackage($packageA = new MemoryPackage('A', '1.0'));
|
||||||
$this->repo->addPackage($packageB = new MemoryPackage('B', '2.0'));
|
$this->repo->addPackage($packageB = new MemoryPackage('B', '2.0'));
|
||||||
|
|
||||||
|
@ -119,29 +115,8 @@ class DefaultPolicyTest extends \PHPUnit_Framework_TestCase
|
||||||
$this->assertEquals($expected, $selected);
|
$this->assertEquals($expected, $selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSelectNewestProvider()
|
public function testPreferNonReplacingFromSameRepo()
|
||||||
{
|
{
|
||||||
$this->markTestIncomplete();
|
|
||||||
|
|
||||||
$this->repo->addPackage($packageA = new MemoryPackage('A', '1.0'));
|
|
||||||
$this->repo->addPackage($packageB = new MemoryPackage('B', '2.0'));
|
|
||||||
|
|
||||||
$packageA->setProvides(array(new Link('A', 'X', new VersionConstraint('==', '2.0'), 'provides')));
|
|
||||||
$packageB->setProvides(array(new Link('B', 'X', new VersionConstraint('==', '1.0'), 'provides')));
|
|
||||||
|
|
||||||
$this->pool->addRepository($this->repo);
|
|
||||||
|
|
||||||
$literals = array(new Literal($packageA, true), new Literal($packageB, true));
|
|
||||||
$expected = array(new Literal($packageA, true));
|
|
||||||
|
|
||||||
$selected = $this->policy->selectPreferedPackages($this->pool, $this->repoInstalled, $literals);
|
|
||||||
|
|
||||||
$this->assertEquals($expected, $selected);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testSelectNonReplacingFromSameRepo()
|
|
||||||
{
|
|
||||||
$this->markTestIncomplete();
|
|
||||||
|
|
||||||
$this->repo->addPackage($packageA = new MemoryPackage('A', '1.0'));
|
$this->repo->addPackage($packageA = new MemoryPackage('A', '1.0'));
|
||||||
$this->repo->addPackage($packageB = new MemoryPackage('B', '2.0'));
|
$this->repo->addPackage($packageB = new MemoryPackage('B', '2.0'));
|
||||||
|
@ -151,7 +126,7 @@ class DefaultPolicyTest extends \PHPUnit_Framework_TestCase
|
||||||
$this->pool->addRepository($this->repo);
|
$this->pool->addRepository($this->repo);
|
||||||
|
|
||||||
$literals = array(new Literal($packageA, true), new Literal($packageB, true));
|
$literals = array(new Literal($packageA, true), new Literal($packageB, true));
|
||||||
$expected = array(new Literal($packageA, true));
|
$expected = array(new Literal($packageA, true), new Literal($packageB, true));
|
||||||
|
|
||||||
$selected = $this->policy->selectPreferedPackages($this->pool, $this->repoInstalled, $literals);
|
$selected = $this->policy->selectPreferedPackages($this->pool, $this->repoInstalled, $literals);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue