Turn obsolete relationships and replaced packages into conflict rules
parent
52565a5935
commit
f46aa495da
|
@ -36,7 +36,7 @@ class Pool
|
|||
$this->repositories[] = $repo;
|
||||
|
||||
foreach ($repo->getPackages() as $package) {
|
||||
$package->setId(count($this->packages));
|
||||
$package->setId(count($this->packages) + 1);
|
||||
$this->packages[] = $package;
|
||||
|
||||
foreach ($package->getNames() as $name) {
|
||||
|
@ -53,7 +53,7 @@ class Pool
|
|||
*/
|
||||
public function packageById($id)
|
||||
{
|
||||
return $this->packages[$id];
|
||||
return $this->packages[$id - 1];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -29,7 +29,11 @@ class Solver
|
|||
const RULE_PACKAGE_CONFLICT = 7;
|
||||
const RULE_PACKAGE_NOT_EXIST = 8;
|
||||
const RULE_PACKAGE_REQUIRES = 9;
|
||||
const RULE_LEARNED = 10;
|
||||
const RULE_PACKAGE_OBSOLETES = 10;
|
||||
const RULE_INSTALLED_PACKAGE_OBSOLETES = 11;
|
||||
const RULE_PACKAGE_SAME_NAME = 12;
|
||||
const RULE_PACKAGE_IMPLICIT_OBSOLETES = 13;
|
||||
const RULE_LEARNED = 14;
|
||||
|
||||
protected $policy;
|
||||
protected $pool;
|
||||
|
@ -41,6 +45,7 @@ class Solver
|
|||
protected $addedMap = array();
|
||||
protected $fixMap = array();
|
||||
protected $updateMap = array();
|
||||
protected $noObsoletes = array();
|
||||
protected $watches = array();
|
||||
protected $removeWatches = array();
|
||||
|
||||
|
@ -183,7 +188,7 @@ class Solver
|
|||
* goes with the reason
|
||||
* @return Rule The generated rule
|
||||
*/
|
||||
public function createConflictRule(PackageInterface $issuer, Package $provider, $reason, $reasonData = null)
|
||||
public function createConflictRule(PackageInterface $issuer, PackageInterface $provider, $reason, $reasonData = null)
|
||||
{
|
||||
// ignore self conflict
|
||||
if ($issuer === $provider) {
|
||||
|
@ -287,7 +292,7 @@ class Solver
|
|||
$possibleConflicts = $this->pool->whatProvides($link->getTarget(), $link->getConstraint());
|
||||
|
||||
foreach ($possibleConflicts as $conflict) {
|
||||
if ($dontfix && $this->installed === $conflict->getRepository()) {
|
||||
if ($dontFix && $this->installed === $conflict->getRepository()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -295,6 +300,59 @@ class Solver
|
|||
}
|
||||
}
|
||||
|
||||
// check obsoletes and implicit obsoletes of a package
|
||||
// if ignoreinstalledsobsoletes is not set, we're also checking
|
||||
// obsoletes of installed packages (like newer rpm versions)
|
||||
//
|
||||
/** @TODO: if ($this->noInstalledObsoletes) */
|
||||
if (true) {
|
||||
$noObsoletes = isset($this->noObsoletes[$package->getId()]);
|
||||
$isInstalled = ($this->installed === $package->getRepository());
|
||||
|
||||
foreach ($package->getReplaces() as $link) {
|
||||
$obsoleteProviders = $this->pool->whatProvides($link->getTarget(), $link->getConstraint());
|
||||
|
||||
foreach ($obsoleteProviders as $provider) {
|
||||
if ($provider === $package) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($isInstalled && $dontFix && $this->installed === $provider->getRepository()) {
|
||||
continue; // don't repair installed/installed problems
|
||||
}
|
||||
|
||||
$reason = ($isInstalled) ? self::RULE_INSTALLED_PACKAGE_OBSOLETES : self::RULE_PACKAGE_OBSOLETES;
|
||||
$this->addRule(RuleSet::TYPE_PACKAGE, $this->createConflictRule($package, $provider, $reason, (string) $link));
|
||||
}
|
||||
}
|
||||
|
||||
// check implicit obsoletes
|
||||
// for installed packages we only need to check installed/installed problems (and
|
||||
// only when dontFix is not set), as the others are picked up when looking at the
|
||||
// uninstalled package.
|
||||
if (!$isInstalled || !$dontFix) {
|
||||
$obsoleteProviders = $this->pool->whatProvides($package->getName(), null);
|
||||
|
||||
foreach ($obsoleteProviders as $provider) {
|
||||
if ($provider === $package) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($isInstalled && $this->installed !== $provider->getRepository()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// obsolete same packages even when noObsletes
|
||||
if ($noObsoletes && (!$package->equals($provider))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$reason = ($package->getName() == $provider->getName()) ? self::RULE_PACKAGE_SAME_NAME : self::RULE_PACKAGE_IMPLICIT_OBSOLETES;
|
||||
$this->addRule(RuleSet::TYPE_PACKAGE, $rule = $this->createConflictRule($package, $provider, $reason, (string) $package));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($package->getRecommends() as $link) {
|
||||
foreach ($this->pool->whatProvides($link->getTarget(), $link->getConstraint()) as $recommend) {
|
||||
$workQueue->enqueue($recommend);
|
||||
|
@ -705,6 +763,111 @@ class Solver
|
|||
if ($this->installed === $package->getRepository()) {
|
||||
$disableQueue[] = array('type' => 'update', 'package' => $package);
|
||||
}
|
||||
|
||||
/* all job packages obsolete * /
|
||||
qstart = q->count;
|
||||
pass = 0;
|
||||
memset(&omap, 0, sizeof(omap));
|
||||
FOR_JOB_SELECT(p, pp, select, what)
|
||||
{
|
||||
Id p2, pp2;
|
||||
|
||||
if (pass == 1)
|
||||
map_grow(&omap, installed->end - installed->start);
|
||||
s = pool->solvables + p;
|
||||
if (s->obsoletes)
|
||||
{
|
||||
Id obs, *obsp;
|
||||
obsp = s->repo->idarraydata + s->obsoletes;
|
||||
while ((obs = *obsp++) != 0)
|
||||
FOR_PROVIDES(p2, pp2, obs)
|
||||
{
|
||||
Solvable *ps = pool->solvables + p2;
|
||||
if (ps->repo != installed)
|
||||
continue;
|
||||
if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
|
||||
continue;
|
||||
if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
|
||||
continue;
|
||||
if (pass)
|
||||
MAPSET(&omap, p2 - installed->start);
|
||||
else
|
||||
queue_push2(q, DISABLE_UPDATE, p2);
|
||||
}
|
||||
}
|
||||
FOR_PROVIDES(p2, pp2, s->name)
|
||||
{
|
||||
Solvable *ps = pool->solvables + p2;
|
||||
if (ps->repo != installed)
|
||||
continue;
|
||||
if (!pool->implicitobsoleteusesprovides && ps->name != s->name)
|
||||
continue;
|
||||
if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
|
||||
continue;
|
||||
if (pass)
|
||||
MAPSET(&omap, p2 - installed->start);
|
||||
else
|
||||
queue_push2(q, DISABLE_UPDATE, p2);
|
||||
}
|
||||
if (pass)
|
||||
{
|
||||
for (i = j = qstart; i < q->count; i += 2)
|
||||
{
|
||||
if (MAPTST(&omap, q->elements[i + 1] - installed->start))
|
||||
{
|
||||
MAPCLR(&omap, q->elements[i + 1] - installed->start);
|
||||
q->elements[j + 1] = q->elements[i + 1];
|
||||
j += 2;
|
||||
}
|
||||
}
|
||||
queue_truncate(q, j);
|
||||
}
|
||||
if (q->count == qstart)
|
||||
break;
|
||||
pass++;
|
||||
}
|
||||
if (omap.size)
|
||||
map_free(&omap);
|
||||
|
||||
if (qstart == q->count)
|
||||
return; /* nothing to prune * /
|
||||
if ((set & (SOLVER_SETEVR | SOLVER_SETARCH | SOLVER_SETVENDOR)) == (SOLVER_SETEVR | SOLVER_SETARCH | SOLVER_SETVENDOR))
|
||||
return; /* all is set */
|
||||
|
||||
/* now that we know which installed packages are obsoleted check each of them * /
|
||||
for (i = j = qstart; i < q->count; i += 2)
|
||||
{
|
||||
Solvable *is = pool->solvables + q->elements[i + 1];
|
||||
FOR_JOB_SELECT(p, pp, select, what)
|
||||
{
|
||||
int illegal = 0;
|
||||
s = pool->solvables + p;
|
||||
if ((set & SOLVER_SETEVR) != 0)
|
||||
illegal |= POLICY_ILLEGAL_DOWNGRADE; /* ignore * /
|
||||
if ((set & SOLVER_SETARCH) != 0)
|
||||
illegal |= POLICY_ILLEGAL_ARCHCHANGE; /* ignore * /
|
||||
if ((set & SOLVER_SETVENDOR) != 0)
|
||||
illegal |= POLICY_ILLEGAL_VENDORCHANGE; /* ignore * /
|
||||
illegal = policy_is_illegal(solv, is, s, illegal);
|
||||
if (illegal && illegal == POLICY_ILLEGAL_DOWNGRADE && (set & SOLVER_SETEV) != 0)
|
||||
{
|
||||
/* it's ok if the EV is different * /
|
||||
if (evrcmp(pool, is->evr, s->evr, EVRCMP_COMPARE_EVONLY) != 0)
|
||||
illegal = 0;
|
||||
}
|
||||
if (illegal)
|
||||
break;
|
||||
}
|
||||
if (!p)
|
||||
{
|
||||
/* no package conflicts with the update rule * /
|
||||
/* thus keep the DISABLE_UPDATE * /
|
||||
q->elements[j + 1] = q->elements[i + 1];
|
||||
j += 2;
|
||||
}
|
||||
}
|
||||
queue_truncate(q, j);
|
||||
return;*/
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -908,17 +1071,18 @@ class Solver
|
|||
|
||||
$transaction = array();
|
||||
|
||||
foreach ($this->decisionQueue as $literal) {
|
||||
foreach ($this->decisionQueue as $i => $literal) {
|
||||
$package = $literal->getPackage();
|
||||
|
||||
// wanted & installed || !wanted & !installed
|
||||
if ($literal->isWanted() == ($this->installed == $package->getRepository())) {
|
||||
if ($literal->isWanted() == ($this->installed === $package->getRepository())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$transaction[] = array(
|
||||
'job' => ($literal->isWanted()) ? 'install' : 'remove',
|
||||
'package' => $package,
|
||||
'why' => $this->decisionQueueWhy[$i],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -995,7 +1159,7 @@ class Solver
|
|||
{
|
||||
$packageId = abs($literalId);
|
||||
return (isset($this->decisionMap[$packageId]) && (
|
||||
$this->decisionMap[$packageId] > 0 && !$literalId < 0 ||
|
||||
$this->decisionMap[$packageId] > 0 && !($literalId < 0) ||
|
||||
$this->decisionMap[$packageId] < 0 && $literalId > 0
|
||||
));
|
||||
}
|
||||
|
@ -1654,6 +1818,7 @@ class Solver
|
|||
foreach ($updateRuleLiterals as $ruleLiteral) {
|
||||
if ($this->decidedInstall($ruleLiteral->getPackage())) {
|
||||
// already fulfilled
|
||||
$decisionQueue = array();
|
||||
break;
|
||||
}
|
||||
if ($this->undecided($ruleLiteral->getPackage())) {
|
||||
|
@ -1673,10 +1838,8 @@ class Solver
|
|||
if ($level <= $oLevel) {
|
||||
$repeat = true;
|
||||
}
|
||||
}
|
||||
|
||||
// still undecided? keep package.
|
||||
if (!$repeat && $this->undecided($literal->getPackage())) {
|
||||
} else if (!$repeat && $this->undecided($literal->getPackage())) {
|
||||
// still undecided? keep package.
|
||||
$oLevel = $level;
|
||||
if (isset($this->cleanDepsMap[$literal->getPackageId()])) {
|
||||
// clean deps removes package
|
||||
|
|
|
@ -73,6 +73,16 @@ class SolverTest extends \PHPUnit_Framework_TestCase
|
|||
}
|
||||
|
||||
public function testSolverInstallInstalled()
|
||||
{
|
||||
$this->repoInstalled->addPackage(new MemoryPackage('A', '1.0'));
|
||||
$this->reposComplete();
|
||||
|
||||
$this->request->install('A');
|
||||
|
||||
$this->checkSolverResult(array());
|
||||
}
|
||||
|
||||
public function testSolverInstallInstalledWithAlternative()
|
||||
{
|
||||
$this->repo->addPackage(new MemoryPackage('A', '1.0'));
|
||||
$this->repoInstalled->addPackage(new MemoryPackage('A', '1.0'));
|
||||
|
@ -107,8 +117,6 @@ class SolverTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
public function testSolverUpdateSingle()
|
||||
{
|
||||
$this->markTestIncomplete();
|
||||
|
||||
$this->repoInstalled->addPackage($packageA = new MemoryPackage('A', '1.0'));
|
||||
$this->repo->addPackage($newPackageA = new MemoryPackage('A', '1.1'));
|
||||
$this->reposComplete();
|
||||
|
@ -116,7 +124,9 @@ class SolverTest extends \PHPUnit_Framework_TestCase
|
|||
$this->request->update('A');
|
||||
|
||||
$this->checkSolverResult(array(
|
||||
array('job' => 'update', 'package' => $newPackageA),
|
||||
//array('job' => 'update', 'from' => $packageA, 'to' => $newPackageA),
|
||||
array('job' => 'remove', 'package' => $packageA),
|
||||
array('job' => 'install', 'package' => $newPackageA),
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -155,7 +165,7 @@ class SolverTest extends \PHPUnit_Framework_TestCase
|
|||
array('job' => 'install', 'package' => $packageB),
|
||||
array('job' => 'install', 'package' => $packageA),
|
||||
array('job' => 'remove', 'package' => $packageD),
|
||||
array('job' => 'update', 'package' => $packageC),
|
||||
array('job' => 'update', 'from' => $oldPackageC, 'to' => $packageC),
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -185,6 +195,11 @@ class SolverTest extends \PHPUnit_Framework_TestCase
|
|||
protected function checkSolverResult(array $expected)
|
||||
{
|
||||
$result = $this->solver->solve($this->request);
|
||||
|
||||
foreach ($result as &$step) {
|
||||
unset($step['why']);
|
||||
}
|
||||
|
||||
$this->assertEquals($expected, $result);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue