Turn obsolete relationships and replaced packages into conflict rules

main
Nils Adermann 13 years ago
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…
Cancel
Save