if (v > 0)
{
+ if (v >= solv->infarchrules && v < solv->infarchrules_end)
+ {
+ Pool *pool = solv->pool;
+ Id name = pool->solvables[-solv->rules[v].p].name;
+ while (v > solv->infarchrules && pool->solvables[-solv->rules[v - 1].p].name == name)
+ v--;
+ for (; v < solv->infarchrules_end && pool->solvables[-solv->rules[v].p].name == name; v++)
+ disablerule(solv, solv->rules + v);
+ return;
+ }
+ if (v >= solv->duprules && v < solv->duprules_end)
+ {
+ Pool *pool = solv->pool;
+ Id name = pool->solvables[-solv->rules[v].p].name;
+ while (v > solv->duprules && pool->solvables[-solv->rules[v - 1].p].name == name)
+ v--;
+ for (; v < solv->duprules_end && pool->solvables[-solv->rules[v].p].name == name; v++)
+ disablerule(solv, solv->rules + v);
+ return;
+ }
disablerule(solv, solv->rules + v);
return;
}
if (v > 0)
{
+ if (v >= solv->infarchrules && v < solv->infarchrules_end)
+ {
+ Pool *pool = solv->pool;
+ Id name = pool->solvables[-solv->rules[v].p].name;
+ while (v > solv->infarchrules && pool->solvables[-solv->rules[v - 1].p].name == name)
+ v--;
+ for (; v < solv->infarchrules_end && pool->solvables[-solv->rules[v].p].name == name; v++)
+ enablerule(solv, solv->rules + v);
+ return;
+ }
+ if (v >= solv->duprules && v < solv->duprules_end)
+ {
+ Pool *pool = solv->pool;
+ Id name = pool->solvables[-solv->rules[v].p].name;
+ while (v > solv->duprules && pool->solvables[-solv->rules[v - 1].p].name == name)
+ v--;
+ for (; v < solv->duprules_end && pool->solvables[-solv->rules[v].p].name == name; v++)
+ enablerule(solv, solv->rules + v);
+ return;
+ }
if (v >= solv->featurerules && v < solv->featurerules_end)
{
/* do not enable feature rule if update rule is enabled */
/* FIXME: maybe also look at SOLVER_INSTALL|SOLVABLE_ONE_OF */
/*-------------------------------------------------------------------
- * disable update rules
+ * disable update rules depending on enabled job
+ * if jobidx is set we just disabled this job, so we may want
+ * to re-enable some rules
+ * otherwise we disable all update rules that conflict with some job.
*/
static void
Repo *installed;
Rule *r;
Id lastjob = -1;
+ Map nolockrules;
installed = solv->installed;
- if (!installed)
- return;
if (jobidx != -1)
{
}
}
/* go through all enabled job rules */
+ map_init(&nolockrules, pool->nsolvables);
MAPZERO(&solv->noupdate);
for (i = solv->jobrules; i < solv->jobrules_end; i++)
{
if (select != SOLVER_SOLVABLE)
break;
s = pool->solvables + what;
+ FOR_PROVIDES(p, pp, s->name)
+ {
+ Solvable *ps = pool->solvables + p;
+ if (ps->name == s->name)
+ MAPSET(&nolockrules, p);
+ }
+ if (!installed)
+ break;
if (solv->noobsoletes.size && MAPTST(&solv->noobsoletes, what))
break;
if (s->repo == installed)
while ((obs = *obsp++) != 0)
FOR_PROVIDES(p, pp, obs)
{
- if (pool->solvables[p].repo != installed)
+ Solvable *ps = pool->solvables + p;
+ if (ps->repo != installed)
continue;
- if (!solv->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p, obs))
+ if (!solv->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
continue;
MAPSET(&solv->noupdate, p - installed->start);
}
}
FOR_PROVIDES(p, pp, s->name)
{
- if (!solv->implicitobsoleteusesprovides && pool->solvables[p].name != s->name)
+ Solvable *ps = pool->solvables + p;
+ if (ps->repo != installed)
+ continue;
+ if (!solv->implicitobsoleteusesprovides && ps->name != s->name)
continue;
- if (pool->solvables[p].repo == installed)
- MAPSET(&solv->noupdate, p - installed->start);
+ MAPSET(&solv->noupdate, p - installed->start);
}
break;
case SOLVER_ERASE:
+ if (!installed)
+ break;
FOR_JOB_SELECT(p, pp, select, what)
if (pool->solvables[p].repo == installed)
MAPSET(&solv->noupdate, p - installed->start);
how = job->elements[jobidx];
what = job->elements[jobidx + 1];
select = how & SOLVER_SELECTMASK;
+ if ((how & SOLVER_JOBMASK) == SOLVER_INSTALL && select == SOLVER_SOLVABLE)
+ {
+ /* check if we need to enable some lock rule */
+ for (i = solv->infarchrules, r = solv->rules + i; i < solv->infarchrules_end; i++, r++)
+ {
+ if (r->p != -what || r->d >= 0 || !MAPTST(&nolockrules, -r->p))
+ continue;
+ enablerule(solv, r);
+ IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
+ {
+ POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "@@@ re-enabling ");
+ solver_printrule(solv, SAT_DEBUG_SOLUTIONS, r);
+ }
+ }
+ for (i = solv->duprules, r = solv->rules + i; i < solv->duprules_end; i++, r++)
+ {
+ if (r->p != -what || r->d >= 0 || !MAPTST(&nolockrules, -r->p))
+ continue;
+ enablerule(solv, r);
+ IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
+ {
+ POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "@@@ re-enabling ");
+ solver_printrule(solv, SAT_DEBUG_SOLUTIONS, r);
+ }
+ }
+ }
+ map_free(&nolockrules);
+ if (!installed)
+ return;
switch (how & SOLVER_JOBMASK)
{
case SOLVER_INSTALL:
return;
}
- for (i = 0; i < installed->nsolvables; i++)
+ for (i = solv->infarchrules, r = solv->rules + i; i < solv->infarchrules_end; i++, r++)
{
- r = solv->rules + solv->updaterules + i;
- if (r->d >= 0 && MAPTST(&solv->noupdate, i))
- disablerule(solv, r); /* was enabled, need to disable */
- r = solv->rules + solv->featurerules + i;
- if (r->d >= 0 && MAPTST(&solv->noupdate, i))
- disablerule(solv, r); /* was enabled, need to disable */
+ if (r->p < 0 && r->d >= 0 && MAPTST(&nolockrules, -r->p))
+ disablerule(solv, r); /* was enabled, need to disable */
+ }
+ for (i = solv->duprules, r = solv->rules + i; i < solv->duprules_end; i++, r++)
+ {
+ if (r->p < 0 && r->d >= 0 && MAPTST(&nolockrules, -r->p))
+ disablerule(solv, r); /* was enabled, need to disable */
+ }
+ map_free(&nolockrules);
+ if (installed)
+ {
+ for (i = 0; i < installed->nsolvables; i++)
+ {
+ r = solv->rules + solv->updaterules + i;
+ if (r->d >= 0 && MAPTST(&solv->noupdate, i))
+ disablerule(solv, r); /* was enabled, need to disable */
+ r = solv->rules + solv->featurerules + i;
+ if (r->d >= 0 && MAPTST(&solv->noupdate, i))
+ disablerule(solv, r); /* was enabled, need to disable */
+ }
}
}
addrule(solv, -n, 0); /* uninstallable */
}
+ /* yet another SUSE hack, sigh */
+ if (pool->nscallback && !strncmp("product:", id2str(pool, s->name), 8))
+ {
+ Id buddy = pool->nscallback(pool, pool->nscallbackdata, NAMESPACE_PRODUCTBUDDY, n);
+ if (buddy > 0 && buddy != SYSTEMSOLVABLE && buddy != n && buddy < pool->nsolvables)
+ {
+ addrule(solv, n, -buddy);
+ addrule(solv, buddy, -n);
+ }
+ }
+
/*-----------------------------------------
* check requires of s
*/
if (!qs->count)
{
if (allow_all)
- return 0;
+ return 0; /* orphaned, don't create feature rule */
+ /* check if this is an orphaned package */
policy_findupdatepackages(solv, s, qs, 1);
if (!qs->count)
- return 0; /* orphaned */
+ return 0; /* orphaned, don't create update rule */
qs->count = 0;
- return -SYSTEMSOLVABLE;
+ return -SYSTEMSOLVABLE; /* supported but not installable */
}
if (allow_all)
return s - pool->solvables;
return -SYSTEMSOLVABLE;
}
+/* add packages from the dup repositories to the update candidates
+ * this isn't needed for the global dup mode as all packages are
+ * from dup repos in that case */
+static void
+addduppackages(Solver *solv, Solvable *s, Queue *qs)
+{
+ Queue dupqs;
+ Id p, dupqsbuf[64];
+ int i;
+ int oldnoupdateprovide = solv->noupdateprovide;
+
+ queue_init_buffer(&dupqs, dupqsbuf, sizeof(dupqsbuf)/sizeof(*dupqsbuf));
+ solv->noupdateprovide = 1;
+ policy_findupdatepackages(solv, s, &dupqs, 2);
+ solv->noupdateprovide = oldnoupdateprovide;
+ for (i = 0; i < dupqs.count; i++)
+ {
+ p = dupqs.elements[i];
+ if (MAPTST(&solv->dupmap, p))
+ queue_pushunique(qs, p);
+ }
+ queue_free(&dupqs);
+}
+
/*-------------------------------------------------------------------
*
* add rule for update
p = finddistupgradepackages(solv, s, &qs, allow_all);
else
policy_findupdatepackages(solv, s, &qs, allow_all);
+ if (!allow_all && !solv->distupgrade && solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))
+ addduppackages(solv, s, &qs);
+
if (!allow_all && qs.count && solv->noobsoletes.size)
{
int i, j;
/* turn rule into problem */
if (why >= solv->jobrules && why < solv->jobrules_end)
why = -(solv->ruletojob.elements[why - solv->jobrules] + 1);
+ /* normalize dup/infarch rules */
+ if (why > solv->infarchrules && why < solv->infarchrules_end)
+ {
+ Id name = pool->solvables[-solv->rules[why].p].name;
+ while (why > solv->infarchrules && pool->solvables[-solv->rules[why - 1].p].name == name)
+ why--;
+ }
+ if (why > solv->duprules && why < solv->duprules_end)
+ {
+ Id name = pool->solvables[-solv->rules[why].p].name;
+ while (why > solv->duprules && pool->solvables[-solv->rules[why - 1].p].name == name)
+ why--;
+ }
+
/* return if problem already countains our rule */
if (solv->problems.count)
{
map_free(&solv->weakrulemap);
map_free(&solv->noobsoletes);
+ map_free(&solv->updatemap);
+ map_free(&solv->dupmap);
+ map_free(&solv->dupinvolvedmap);
+
sat_free(solv->decisionmap);
sat_free(solv->rules);
sat_free(solv->watches);
if (level < systemlevel && solv->installed && solv->installed->nsolvables)
{
- if (!solv->updatesystem)
+ Repo *installed = solv->installed;
+ FOR_REPO_SOLVABLES(installed, i, s)
{
- /*
- * Normal run (non-updating)
- * Keep as many packages installed as possible
- */
- POOL_DEBUG(SAT_DEBUG_STATS, "installing old packages\n");
-
- for (i = solv->installed->start; i < solv->installed->end; i++)
- {
- s = pool->solvables + i;
-
- /* skip if not installed */
- if (s->repo != solv->installed)
- continue;
-
- /* skip if already decided */
- if (solv->decisionmap[i] != 0)
- continue;
-
- r = solv->rules + solv->updaterules + (i - solv->installed->start);
- if (!r->p) /* update rule == feature rule? */
- r = r - solv->updaterules + solv->featurerules;
- if (r->p != i) /* allowed to keep package? */
- continue;
-
- POOL_DEBUG(SAT_DEBUG_PROPAGATE, "keeping %s\n", solvable2str(pool, s));
-
- olevel = level;
- level = setpropagatelearn(solv, level, i, disablerules, r->p ? r - solv->rules : 0);
+ Rule *rr;
+ Id d;
- if (level == 0) /* unsolvable */
- {
- queue_free(&dq);
- queue_free(&dqs);
- return;
- }
- if (level <= olevel)
- break;
- }
- systemlevel = level + 1;
- if (i < solv->installed->end)
+ if (MAPTST(&solv->noupdate, i - installed->start))
continue;
- }
- else if (solv->noobsoletes.size && solv->multiversionupdaters)
- {
- /* see if we can multi-version install the newest package */
- for (i = solv->installed->start; i < solv->installed->end; i++)
+ if (solv->decisionmap[i] > 0)
+ continue;
+ r = solv->rules + solv->updaterules + (i - installed->start);
+ rr = r;
+ if (!rr->p || rr->d < 0) /* disabled -> look at feature rule */
+ rr -= solv->installed->end - solv->installed->start;
+ if (!rr->p) /* identical to update rule? */
+ rr = r;
+ if (!rr->p)
+ continue; /* orpaned package */
+
+ queue_empty(&dq);
+ if (solv->decisionmap[i] < 0 || solv->updatesystem || (solv->updatemap.size && MAPTST(&solv->updatemap, i - installed->start)) || rr->p != i)
{
- Id d;
- s = pool->solvables + i;
- if (s->repo != solv->installed)
- continue;
- if (MAPTST(&solv->noupdate, i - solv->installed->start))
- continue;
- d = solv->multiversionupdaters[i - solv->installed->start];
- if (!d)
- continue;
- queue_empty(&dq);
- queue_push(&dq, i);
- while ((p = pool->whatprovidesdata[d++]) != 0)
- if (solv->decisionmap[p] >= 0)
- queue_push(&dq, p);
- policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE);
- p = dq.elements[0];
- if (p != i && solv->decisionmap[p] == 0)
+ if (solv->noobsoletes.size && solv->multiversionupdaters
+ && (d = solv->multiversionupdaters[i - installed->start]) != 0)
{
- r = solv->rules + solv->featurerules + (i - solv->installed->start);
- if (!r->p) /* update rule == feature rule? */
- r = r - solv->featurerules + solv->updaterules;
- olevel = level;
- POOL_DEBUG(SAT_DEBUG_POLICY, "installing (multi-version) %s\n", solvable2str(pool, pool->solvables + p));
- level = setpropagatelearn(solv, level, p, disablerules, r->p ? r - solv->rules : 0);
- if (level == 0)
+ /* special multiversion handling, make sure best version is chosen */
+ queue_push(&dq, i);
+ while ((p = pool->whatprovidesdata[d++]) != 0)
+ if (solv->decisionmap[p] >= 0)
+ queue_push(&dq, p);
+ policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE);
+ p = dq.elements[0];
+ if (p != i && solv->decisionmap[p] == 0)
{
- queue_free(&dq);
- queue_free(&dqs);
- return;
+ rr = solv->rules + solv->featurerules + (i - solv->installed->start);
+ if (!rr->p) /* update rule == feature rule? */
+ rr = rr - solv->featurerules + solv->updaterules;
+ dq.count = 1;
}
- if (level <= olevel)
- break;
+ else
+ dq.count = 0;
}
- p = i;
- /* now that the best version is installed, try to
- * keep the original one */
- if (solv->decisionmap[p]) /* already decided? */
- continue;
- r = solv->rules + solv->updaterules + (i - solv->installed->start);
- if (!r->p) /* update rule == feature rule? */
- r = r - solv->updaterules + solv->featurerules;
- if (r->p == p) /* allowed to keep package? */
+ else
{
- olevel = level;
- POOL_DEBUG(SAT_DEBUG_POLICY, "keeping (multi-version) %s\n", solvable2str(pool, pool->solvables + p));
- level = setpropagatelearn(solv, level, p, disablerules, r - solv->rules);
- if (level == 0)
+ /* update to best package */
+ FOR_RULELITERALS(p, dp, rr)
{
- queue_free(&dq);
- queue_free(&dqs);
- return;
+ if (solv->decisionmap[p] > 0)
+ {
+ dq.count = 0; /* already fulfilled */
+ break;
+ }
+ if (!solv->decisionmap[p])
+ queue_push(&dq, p);
}
- if (level <= olevel)
- break;
}
}
- systemlevel = level + 1;
- if (i < solv->installed->end)
- continue;
- }
-
- POOL_DEBUG(SAT_DEBUG_STATS, "resolving update/feature rules\n");
-
- for (i = solv->installed->start, r = solv->rules + solv->updaterules; i < solv->installed->end; i++, r++)
- {
- Rule *rr;
- s = pool->solvables + i;
- if (s->repo != solv->installed)
- continue;
-
- /* skip if already decided */
- if (solv->decisionmap[i] > 0)
- continue;
-
- /* noupdate is set if a job is erasing the installed solvable or installing a specific version */
- if (MAPTST(&solv->noupdate, i - solv->installed->start))
- continue;
-
- rr = r;
- if (rr->d < 0) /* disabled -> look at feature rule */
- rr -= solv->installed->end - solv->installed->start;
- if (!rr->p) /* identical to update rule? */
- rr = r;
- if (!rr->p || rr->d < 0)
- continue; /* no such rule (orpaned package) or disabled */
-
- queue_empty(&dq);
- FOR_RULELITERALS(p, dp, rr)
- {
- if (solv->decisionmap[p] > 0)
- break;
- if (solv->decisionmap[p] == 0)
- queue_push(&dq, p);
- }
- if (!p && dq.count) /* neither fulfilled nor empty */
+ /* install best version */
+ if (dq.count)
{
olevel = level;
level = selectandinstall(solv, level, &dq, disablerules, rr - solv->rules);
if (level <= olevel)
break;
}
- /* if still undecided, keep it */
+ /* if still undecided keep package */
if (solv->decisionmap[i] == 0)
{
olevel = level;
}
}
systemlevel = level + 1;
- if (i < solv->installed->end)
+ if (i < installed->end)
continue;
}
if (solv->distupgrade && solv->installed)
{
+ int installedone = 0;
+
/* let's see if we can install some unsupported package */
POOL_DEBUG(SAT_DEBUG_STATS, "deciding unsupported packages\n");
for (i = 0; i < solv->orphaned.count; i++)
{
p = solv->orphaned.elements[i];
- if (!solv->decisionmap[p])
- break;
- }
- if (i < solv->orphaned.count)
- {
- p = solv->orphaned.elements[i];
+ if (solv->decisionmap[p])
+ continue; /* already decided */
+ olevel = level;
if (solv->distupgrade_removeunsupported)
{
POOL_DEBUG(SAT_DEBUG_STATS, "removing unsupported %s\n", solvable2str(pool, pool->solvables + p));
{
POOL_DEBUG(SAT_DEBUG_STATS, "keeping unsupported %s\n", solvable2str(pool, pool->solvables + p));
level = setpropagatelearn(solv, level, p, 0, 0);
+ installedone = 1;
}
- continue;
+ if (level < olevel)
+ break;
}
+ if (installedone || i < solv->orphaned.count)
+ continue;
}
if (solv->solution_callback)
/* enable refined rules again */
for (i = 0; i < disabled.count; i++)
enableproblem(solv, disabled.elements[i]);
+ queue_free(&disabled);
/* disable problem rules again */
/* FIXME! */
{
why = solution.elements[j];
/* must be either job descriptor or update rule */
- assert(why < 0 || (why >= solv->updaterules && why < solv->updaterules_end));
#if 0
solver_printproblem(solv, why);
#endif
queue_push(&solutions, 0);
queue_push(&solutions, -why);
}
+ else if (why >= solv->infarchrules && why < solv->infarchrules_end)
+ {
+ Id p, name;
+ /* infarch rule, find replacement */
+ assert(solv->rules[why].p < 0);
+ name = pool->solvables[-solv->rules[why].p].name;
+ while (why >= solv->infarchrules && pool->solvables[-solv->rules[why - 1].p].name == name)
+ why--;
+ p = 0;
+ for (; why < solv->infarchrules_end && pool->solvables[-solv->rules[why].p].name == name; why++)
+ if (solv->decisionmap[-solv->rules[why].p] > 0)
+ {
+ p = -solv->rules[why].p;
+ break;
+ }
+ if (!p)
+ p = -solv->rules[why].p; /* XXX: what to do here? */
+ queue_push(&solutions, SOLVER_SOLUTION_INFARCH);
+ queue_push(&solutions, p);
+ }
+ else if (why >= solv->duprules && why < solv->duprules_end)
+ {
+ Id p, name;
+ /* dist upgrade rule, find replacement */
+ assert(solv->rules[why].p < 0);
+ name = pool->solvables[-solv->rules[why].p].name;
+ while (why >= solv->infarchrules && pool->solvables[-solv->rules[why - 1].p].name == name)
+ why--;
+ p = 0;
+ for (; why < solv->infarchrules_end && pool->solvables[-solv->rules[why].p].name == name; why++)
+ if (solv->decisionmap[-solv->rules[why].p] > 0)
+ {
+ p = -solv->rules[why].p;
+ break;
+ }
+ if (!p)
+ p = -solv->rules[why].p; /* XXX: what to do here? */
+ queue_push(&solutions, SOLVER_SOLUTION_DISTUPGRADE);
+ queue_push(&solutions, p);
+ }
else
{
/* update rule, find replacement package */
Id p, *dp, rp = 0;
Rule *rr;
+
+ assert(why >= solv->updaterules && why < solv->updaterules_end);
+ /* check if this is a false positive, i.e. the update rule is fulfilled */
+ rr = solv->rules + why;
+ FOR_RULELITERALS(p, dp, rr)
+ if (p > 0 && solv->decisionmap[p] > 0)
+ break;
+ if (p)
+ continue; /* false alarm */
+
p = solv->installed->start + (why - solv->updaterules);
rr = solv->rules + solv->featurerules + (why - solv->updaterules);
if (!rr->p)
Id p, d, w2, pp, req, *reqp, con, *conp, obs, *obsp, *dp;
assert(rid > 0);
+ if (rid >= solv->infarchrules && rid < solv->infarchrules_end)
+ {
+ r = solv->rules + rid;
+ *depp = r->p < 0 ? pool->solvables[-r->p].name : 0;
+ *sourcep = 0;
+ *targetp = 0;
+ return SOLVER_PROBLEM_INFARCH_RULE;
+ }
+ if (rid >= solv->duprules && rid < solv->duprules_end)
+ {
+ r = solv->rules + rid;
+ *depp = r->p < 0 ? pool->solvables[-r->p].name : 0;
+ *sourcep = 0;
+ *targetp = 0;
+ return SOLVER_PROBLEM_DISTUPGRADE_RULE;
+ }
if (rid >= solv->jobrules && rid < solv->jobrules_end)
{
assert(rid > 0);
if (rid >= solv->learntrules)
findproblemrule_internal(solv, solv->learnt_why.elements[rid - solv->learntrules], &lreqr, &lconr, &lsysr, &ljobr);
- else if (rid >= solv->jobrules && rid < solv->jobrules_end)
+ else if ((rid >= solv->jobrules && rid < solv->jobrules_end) || (rid >= solv->infarchrules && rid < solv->infarchrules_end) || (rid >= solv->duprules && rid < solv->duprules_end))
{
if (!*jobrp)
*jobrp = rid;
/********************************************************************/
/* main() */
+
+static void
+addinfarchrules(Solver *solv, Map *addedmap)
+{
+ Pool *pool = solv->pool;
+ int first, i, j;
+ Id p, pp, a, aa, bestarch;
+ Solvable *s, *ps, *bests;
+ Queue badq, allowedarchs;
+
+ queue_init(&badq);
+ queue_init(&allowedarchs);
+ solv->infarchrules = solv->nrules;
+ for (i = 1; i < pool->nsolvables; i++)
+ {
+ if (i == SYSTEMSOLVABLE || !MAPTST(addedmap, i))
+ continue;
+ s = pool->solvables + i;
+ first = i;
+ bestarch = 0;
+ bests = 0;
+ queue_empty(&allowedarchs);
+ FOR_PROVIDES(p, pp, s->name)
+ {
+ ps = pool->solvables + p;
+ if (ps->name != s->name || !MAPTST(addedmap, p))
+ continue;
+ if (p == i)
+ first = 0;
+ if (first)
+ break;
+ a = ps->arch;
+ a = (a <= pool->lastarch) ? pool->id2arch[a] : 0;
+ if (a != 1 && pool->installed && ps->repo == pool->installed && !solv->distupgrade)
+ queue_pushunique(&allowedarchs, ps->arch); /* also ok to keep this architecture */
+ if (a && a != 1 && (!bestarch || a < bestarch))
+ {
+ bestarch = a;
+ bests = ps;
+ }
+ }
+ if (first)
+ continue;
+ /* speed up common case where installed package already has best arch */
+ if (allowedarchs.count == 1 && bests && allowedarchs.elements[0] == bests->arch)
+ allowedarchs.count--; /* installed arch is best */
+ queue_empty(&badq);
+ FOR_PROVIDES(p, pp, s->name)
+ {
+ ps = pool->solvables + p;
+ if (ps->name != s->name || !MAPTST(addedmap, p))
+ continue;
+ a = ps->arch;
+ a = (a <= pool->lastarch) ? pool->id2arch[a] : 0;
+ if (a != 1 && bestarch && ((a ^ bestarch) & 0xffff0000) != 0)
+ {
+ for (j = 0; j < allowedarchs.count; j++)
+ {
+ aa = allowedarchs.elements[j];
+ if (ps->arch == aa)
+ break;
+ aa = (aa <= pool->lastarch) ? pool->id2arch[aa] : 0;
+ if (aa && ((a ^ aa) & 0xffff0000) == 0)
+ break; /* compatible */
+ }
+ if (j == allowedarchs.count)
+ queue_push(&badq, p);
+ }
+ }
+ if (!badq.count)
+ continue;
+ /* block all solvables in the badq! */
+ for (j = 0; j < badq.count; j++)
+ {
+ p = badq.elements[j];
+ addrule(solv, -p, 0);
+ }
+ }
+ queue_free(&badq);
+ queue_free(&allowedarchs);
+ solv->infarchrules_end = solv->nrules;
+}
+
+static void
+createdupmaps(Solver *solv, Queue *job)
+{
+ Pool *pool = solv->pool;
+ Repo *repo;
+ Id how, what, p, pi, pp, obs, *obsp;
+ Solvable *s, *ps;
+ int i;
+
+ map_init(&solv->dupmap, pool->nsolvables);
+ map_init(&solv->dupinvolvedmap, pool->nsolvables);
+ for (i = 0; i < job->count; i += 2)
+ {
+ how = job->elements[i];
+ what = job->elements[i + 1];
+ switch (how & SOLVER_JOBMASK)
+ {
+ case SOLVER_DISTUPGRADE:
+ if (what < 0 || what > pool->nrepos)
+ break;
+ repo = pool->repos[what];
+ FOR_REPO_SOLVABLES(repo, p, s)
+ {
+ MAPSET(&solv->dupmap, p);
+ FOR_PROVIDES(pi, pp, s->name)
+ {
+ ps = pool->solvables + pi;
+ if (ps->name != s->name)
+ continue;
+ MAPSET(&solv->dupinvolvedmap, pi);
+ }
+ if (s->obsoletes)
+ {
+ /* FIXME: check obsoletes/provides combination */
+ obsp = s->repo->idarraydata + s->obsoletes;
+ while ((obs = *obsp++) != 0)
+ {
+ FOR_PROVIDES(pi, pp, obs)
+ {
+ if (!solv->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + pi, obs))
+ continue;
+ MAPSET(&solv->dupinvolvedmap, pi);
+ }
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ MAPCLR(&solv->dupinvolvedmap, SYSTEMSOLVABLE);
+}
+
+static void
+freedupmaps(Solver *solv)
+{
+ map_free(&solv->dupmap);
+ map_free(&solv->dupinvolvedmap);
+}
+
+static void
+addduprules(Solver *solv, Map *addedmap)
+{
+ Pool *pool = solv->pool;
+ Id p, pp;
+ Solvable *s, *ps;
+ int first, i;
+
+ solv->duprules = solv->nrules;
+ for (i = 1; i < pool->nsolvables; i++)
+ {
+ if (i == SYSTEMSOLVABLE || !MAPTST(addedmap, i))
+ continue;
+ s = pool->solvables + i;
+ first = i;
+ FOR_PROVIDES(p, pp, s->name)
+ {
+ ps = pool->solvables + p;
+ if (ps->name != s->name || !MAPTST(addedmap, p))
+ continue;
+ if (p == i)
+ first = 0;
+ if (first)
+ break;
+ if (!MAPTST(&solv->dupinvolvedmap, p))
+ continue;
+ if (solv->installed && ps->repo == solv->installed)
+ {
+ if (!solv->updatemap.size)
+ map_init(&solv->updatemap, pool->nsolvables);
+ MAPSET(&solv->updatemap, p);
+ if (!MAPTST(&solv->dupmap, p))
+ {
+ Id ip, ipp;
+ /* is installed identical to a good one? */
+ FOR_PROVIDES(ip, ipp, s->name)
+ {
+ Solvable *is = pool->solvables + ip;
+ if (!MAPTST(&solv->dupmap, ip))
+ continue;
+ if (is->evr == s->evr && solvable_identical(s, is))
+ break;
+ }
+ if (!ip)
+ addrule(solv, -p, 0); /* no match, sorry */
+ }
+ }
+ else if (!MAPTST(&solv->dupmap, p))
+ addrule(solv, -p, 0);
+ }
+ }
+ solv->duprules_end = solv->nrules;
+}
+
/*
*
* solve job queue
int goterase;
Rule *r;
int now, solve_start;
+ int hasdupjob = 0;
solve_start = sat_timems(0);
POOL_DEBUG(SAT_DEBUG_STATS, "solver started\n");
FOR_JOB_SELECT(p, pp, select, what)
addrpmrulesforupdaters(solv, pool->solvables + what, &addedmap, 0);
break;
+ case SOLVER_DISTUPGRADE:
+ if (!solv->distupgrade)
+ hasdupjob = 1;
+ break;
+ default:
+ break;
}
}
POOL_DEBUG(SAT_DEBUG_STATS, "added %d rpm rules for packages involved in a job\n", solv->nrules - oldnrules);
POOL_DEBUG(SAT_DEBUG_STATS, "decisions so far: %d\n", solv->decisionq.count);
POOL_DEBUG(SAT_DEBUG_STATS, "rpm rule creation took %d ms\n", sat_timems(now));
+ /* create dup maps if needed. We need the maps to create our
+ * update rules */
+ if (hasdupjob)
+ createdupmaps(solv, job);
+
/*
* create feature rules
*
queue_push(&solv->weakruleq, solv->nrules - 1);
}
break;
+ case SOLVER_DISTUPGRADE:
+ POOL_DEBUG(SAT_DEBUG_JOB, "job: distupgrade repo #%d\n", what);
+ break;
default:
POOL_DEBUG(SAT_DEBUG_JOB, "job: unknown job\n");
break;
assert(solv->ruletojob.count == solv->nrules - solv->jobrules);
solv->jobrules_end = solv->nrules;
+ /* now create infarch and dup rules */
+ addinfarchrules(solv, &addedmap);
+ if (hasdupjob)
+ {
+ addduprules(solv, &addedmap);
+ freedupmaps(solv); /* no longer needed */
+ }
+ else
+ solv->duprules = solv->duprules_end = solv->nrules;
+
/* all rules created
* --------------------------------------------------------------
* prepare for solving
map_free(&installcandidatemap);
queue_free(&q);
+ POOL_DEBUG(SAT_DEBUG_STATS, "%d rpm rules, %d job rules, %d infarch rules, %d dup rules\n", solv->rpmrules_end - 1, solv->jobrules_end - solv->jobrules, solv->infarchrules_end - solv->infarchrules, solv->duprules_end - solv->duprules);
+
/* create weak map */
map_init(&solv->weakrulemap, solv->nrules);
for (i = 0; i < solv->weakruleq.count; i++)
queue_init(&redoq);
goterase = 0;
/* disable all erase jobs (including weak "keep uninstalled" rules) */
- for (i = solv->jobrules, r = solv->rules + i; i < solv->learntrules; i++, r++)
+ for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++)
{
if (r->d < 0) /* disabled ? */
continue;
--- /dev/null
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <zlib.h>
+
+#include "pool.h"
+#include "poolarch.h"
+#include "repo_solv.h"
+#include "repo_susetags.h"
+#include "repo_rpmmd.h"
+#include "solver.h"
+
+static ssize_t
+cookie_gzread(void *cookie, char *buf, size_t nbytes)
+{
+ return gzread((gzFile *)cookie, buf, nbytes);
+}
+
+static int
+cookie_gzclose(void *cookie)
+{
+ return gzclose((gzFile *)cookie);
+}
+
+FILE *
+myfopen(const char *fn)
+{
+ cookie_io_functions_t cio;
+ char *suf;
+ gzFile *gzf;
+
+ if (!fn)
+ return 0;
+ suf = strrchr(fn, '.');
+ if (!suf || strcmp(suf, ".gz") != 0)
+ return fopen(fn, "r");
+ gzf = gzopen(fn, "r");
+ if (!gzf)
+ return 0;
+ memset(&cio, 0, sizeof(cio));
+ cio.read = cookie_gzread;
+ cio.close = cookie_gzclose;
+ return fopencookie(gzf, "r", cio);
+}
+
+int
+main(int argc, char **argv)
+{
+ Pool *pool;
+ Solver *solv;
+ Queue job;
+ Queue rids;
+ Queue cand;
+ Queue archlocks;
+ char *arch;
+ int i, j;
+ Id p;
+ Id rpmid, rpmarch, rpmrel, archlock;
+ int status = 0;
+ int nocheck = 0;
+
+ archlock = 0;
+ arch = argv[1];
+ pool = pool_create();
+ pool_setarch(pool, arch);
+ for (i = 2; i < argc; i++)
+ {
+ FILE *fp;
+ int l;
+
+ if (!strcmp(argv[i], "--nocheck"))
+ {
+ if (!nocheck)
+ nocheck = pool->nsolvables;
+ continue;
+ }
+ l = strlen(argv[i]);
+ if (!strcmp(argv[i], "-"))
+ fp = stdin;
+ else if ((fp = myfopen(argv[i])) == 0)
+ {
+ perror(argv[i]);
+ exit(1);
+ }
+ Repo *repo = repo_create(pool, argv[i]);
+ if (l >= 8 && !strcmp(argv[i] + l - 8, "packages"))
+ {
+ repo_add_susetags(repo, fp, 0, 0, 0);
+ }
+ else if (l >= 11 && !strcmp(argv[i] + l - 11, "packages.gz"))
+ {
+ repo_add_susetags(repo, fp, 0, 0, 0);
+ }
+ else if (l >= 14 && !strcmp(argv[i] + l - 14, "primary.xml.gz"))
+ {
+ repo_add_rpmmd(repo, fp, 0, 0);
+ }
+ else if (repo_add_solv(repo, fp))
+ {
+ fprintf(stderr, "could not add repo %s\n", argv[i]);
+ exit(1);
+ }
+ if (fp != stdin)
+ fclose(fp);
+ }
+ pool_addfileprovides(pool);
+ pool_createwhatprovides(pool);
+ rpmid = str2id(pool, "rpm", 0);
+ rpmarch = str2id(pool, arch, 0);
+ rpmrel = 0;
+ if (rpmid && rpmarch)
+ {
+ for (p = 1; p < pool->nsolvables; p++)
+ {
+ Solvable *s = pool->solvables + p;
+ if (s->name == rpmid && s->arch == rpmarch)
+ break;
+ }
+ if (p < pool->nsolvables)
+ rpmrel = rel2id(pool, rpmid, rpmarch, REL_ARCH, 1);
+ }
+
+ queue_init(&job);
+ queue_init(&rids);
+ queue_init(&cand);
+ queue_init(&archlocks);
+ for (p = 1; p < pool->nsolvables; p++)
+ {
+ Solvable *s = pool->solvables + p;
+ if (!s->repo)
+ continue;
+ if (!pool_installable(pool, s))
+ continue;
+ if (rpmrel && s->arch != rpmarch)
+ {
+ Id rp, rpp;
+ FOR_PROVIDES(rp, rpp, s->name)
+ {
+ if (pool->solvables[rp].name != s->name)
+ continue;
+ if (pool->solvables[rp].arch == rpmarch)
+ break;
+ }
+ if (rp)
+ {
+ queue_push(&archlocks, p);
+ continue;
+ }
+ }
+ queue_push(&cand, p);
+ }
+
+ if (archlocks.count)
+ {
+ archlock = pool_queuetowhatprovides(pool, &archlocks);
+ }
+ /* prune cand by doing weak installs */
+ while (cand.count)
+ {
+ solv = solver_create(pool);
+ queue_empty(&job);
+ for (i = 0; i < cand.count; i++)
+ {
+ p = cand.elements[i];
+ queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_WEAK);
+ queue_push(&job, p);
+ }
+ if (rpmrel)
+ {
+ queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_NAME);
+ queue_push(&job, rpmrel);
+ }
+ if (archlock)
+ {
+ queue_push(&job, SOLVER_LOCK|SOLVER_SOLVABLE_ONE_OF);
+ queue_push(&job, archlock);
+ }
+ solv->dontinstallrecommended = 1;
+ solver_solve(solv, &job);
+ /* prune... */
+ for (i = j = 0; i < cand.count; i++)
+ {
+ p = cand.elements[i];
+ if (solv->decisionmap[p] <= 0)
+ {
+ cand.elements[j++] = p;
+ continue;
+ }
+#if 0
+ Solvable *s = pool->solvables + p;
+ if (!strcmp(id2str(pool, s->name), "libusb-compat-devel"))
+ {
+ cand.elements[j++] = p;
+ continue;
+ }
+#endif
+ }
+ cand.count = j;
+ if (i == j)
+ break;
+ }
+
+ /* now check every candidate */
+ for (i = 0; i < cand.count; i++)
+ {
+ Solvable *s;
+
+ p = cand.elements[i];
+ if (nocheck && p >= nocheck)
+ continue;
+ s = pool->solvables + p;
+ solv = solver_create(pool);
+ queue_empty(&job);
+ queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE);
+ queue_push(&job, p);
+ if (rpmrel)
+ {
+ queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_NAME);
+ queue_push(&job, rpmrel);
+ }
+ if (archlock)
+ {
+ queue_push(&job, SOLVER_LOCK|SOLVER_SOLVABLE_ONE_OF);
+ queue_push(&job, archlock);
+ }
+ solv->dontinstallrecommended = 1;
+ solver_solve(solv, &job);
+ if (solv->problems.count)
+ {
+ Id problem = 0;
+ Solvable *s2;
+
+ status = 1;
+ printf("can't install %s:\n", solvable2str(pool, s));
+ while ((problem = solver_next_problem(solv, problem)) != 0)
+ {
+ solver_findallproblemrules(solv, problem, &rids);
+ for (j = 0; j < rids.count; j++)
+ {
+ Id probr = rids.elements[j];
+ Id dep, source, target;
+ switch (solver_problemruleinfo(solv, &job, probr, &dep, &source, &target))
+ {
+ case SOLVER_PROBLEM_UPDATE_RULE:
+ break;
+ case SOLVER_PROBLEM_JOB_RULE:
+ break;
+ case SOLVER_PROBLEM_RPM_RULE:
+ printf(" some dependency problem\n");
+ break;
+ case SOLVER_PROBLEM_JOB_NOTHING_PROVIDES_DEP:
+ printf(" nothing provides requested %s\n", dep2str(pool, dep));
+ break;
+ case SOLVER_PROBLEM_NOT_INSTALLABLE:
+ s = pool_id2solvable(pool, source);
+ printf(" package %s is not installable\n", solvable2str(pool, s));
+ break;
+ case SOLVER_PROBLEM_NOTHING_PROVIDES_DEP:
+ s = pool_id2solvable(pool, source);
+ printf(" nothing provides %s needed by %s\n", dep2str(pool, dep), solvable2str(pool, s));
+ if (ISRELDEP(dep))
+ {
+ Reldep *rd = GETRELDEP(pool, dep);
+ if (!ISRELDEP(rd->name))
+ {
+ Id rp, rpp;
+ FOR_PROVIDES(rp, rpp, rd->name)
+ printf(" (we have %s)\n", solvable2str(pool, pool->solvables + rp));
+ }
+ }
+ break;
+ case SOLVER_PROBLEM_SAME_NAME:
+ s = pool_id2solvable(pool, source);
+ s2 = pool_id2solvable(pool, target);
+ printf(" cannot install both %s and %s\n", solvable2str(pool, s), solvable2str(pool, s2));
+ break;
+ case SOLVER_PROBLEM_PACKAGE_CONFLICT:
+ s = pool_id2solvable(pool, source);
+ s2 = pool_id2solvable(pool, target);
+ printf(" package %s conflicts with %s provided by %s\n", solvable2str(pool, s), dep2str(pool, dep), solvable2str(pool, s2));
+ break;
+ case SOLVER_PROBLEM_PACKAGE_OBSOLETES:
+ s = pool_id2solvable(pool, source);
+ s2 = pool_id2solvable(pool, target);
+ printf(" package %s obsoletes %s provided by %s\n", solvable2str(pool, s), dep2str(pool, dep), solvable2str(pool, s2));
+ break;
+ case SOLVER_PROBLEM_DEP_PROVIDERS_NOT_INSTALLABLE:
+ s = pool_id2solvable(pool, source);
+ printf(" package %s requires %s, but none of the providers can be installed\n", solvable2str(pool, s), dep2str(pool, dep));
+ break;
+ case SOLVER_PROBLEM_SELF_CONFLICT:
+ s = pool_id2solvable(pool, source);
+ printf(" package %s conflicts with %s provided by itself\n", solvable2str(pool, s), dep2str(pool, dep));
+ break;
+ }
+ }
+ }
+ }
+#if 0
+ else
+ {
+ if (!strcmp(id2str(pool, s->name), "libusb-compat-devel"))
+ {
+ solver_printdecisions(solv);
+ }
+ }
+#endif
+ solver_free(solv);
+ }
+ exit(status);
+}