|
|
|
@ -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
|
|
|
|
|