|
|
|
<?php
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This file is part of Composer.
|
|
|
|
*
|
|
|
|
* (c) Nils Adermann <naderman@naderman.de>
|
|
|
|
* Jordi Boggiano <j.boggiano@seld.be>
|
|
|
|
*
|
|
|
|
* For the full copyright and license information, please view the LICENSE
|
|
|
|
* file that was distributed with this source code.
|
|
|
|
*/
|
|
|
|
|
|
|
|
namespace Composer\DependencyResolver;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @author Nils Adermann <naderman@naderman.de>
|
|
|
|
*/
|
|
|
|
class RuleWatchGraph
|
|
|
|
{
|
|
|
|
protected $watches = array();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Alters watch chains for a rule.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
public function insert(RuleWatchNode $node)
|
|
|
|
{
|
|
|
|
if ($node->getRule()->isAssertion()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach (array($node->watch1, $node->watch2) as $literal) {
|
|
|
|
if (!isset($this->watches[$literal])) {
|
|
|
|
$this->watches[$literal] = new RuleWatchChain;
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->watches[$literal]->unshift($node);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public function contains($literal)
|
|
|
|
{
|
|
|
|
return isset($this->watches[$literal]);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function propagateLiteral($literal, $level, $skipCallback, $conflictCallback, $decideCallback)
|
|
|
|
{
|
|
|
|
if (!isset($this->watches[$literal])) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->watches[$literal]->rewind();
|
|
|
|
while ($this->watches[$literal]->valid()) {
|
|
|
|
$node = $this->watches[$literal]->current();
|
|
|
|
$otherWatch = $node->getOtherWatch($literal);
|
|
|
|
|
|
|
|
if (!$node->getRule()->isDisabled() && !call_user_func($skipCallback, $otherWatch)) {
|
|
|
|
$ruleLiterals = $node->getRule()->getLiterals();
|
|
|
|
|
|
|
|
$alternativeLiterals = array_filter($ruleLiterals, function ($ruleLiteral) use ($literal, $otherWatch, $conflictCallback) {
|
|
|
|
return $literal !== $ruleLiteral &&
|
|
|
|
$otherWatch !== $ruleLiteral &&
|
|
|
|
!call_user_func($conflictCallback, $ruleLiteral);
|
|
|
|
});
|
|
|
|
|
|
|
|
if ($alternativeLiterals) {
|
|
|
|
reset($alternativeLiterals);
|
|
|
|
$this->moveWatch($literal, current($alternativeLiterals), $node);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (call_user_func($conflictCallback, $otherWatch)) {
|
|
|
|
return $node->getRule();
|
|
|
|
}
|
|
|
|
|
|
|
|
call_user_func($decideCallback, $otherWatch, $level, $node->getRule());
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->watches[$literal]->next();
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function moveWatch($fromLiteral, $toLiteral, $node)
|
|
|
|
{
|
|
|
|
if (!isset($this->watches[$toLiteral])) {
|
|
|
|
$this->watches[$toLiteral] = new RuleWatchChain;
|
|
|
|
}
|
|
|
|
|
|
|
|
$node->moveWatch($fromLiteral, $toLiteral);
|
|
|
|
$this->watches[$fromLiteral]->remove();
|
|
|
|
$this->watches[$toLiteral]->unshift($node);
|
|
|
|
}
|
|
|
|
}
|