summaryrefslogtreecommitdiff
path: root/src/solver.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/solver.c')
-rw-r--r--src/solver.c418
1 files changed, 88 insertions, 330 deletions
diff --git a/src/solver.c b/src/solver.c
index 5d1052d..037b33d 100644
--- a/src/solver.c
+++ b/src/solver.c
@@ -31,242 +31,6 @@
#define RULES_BLOCK 63
-/********************************************************************
- *
- * dependency check helpers
- *
- */
-
-/*-------------------------------------------------------------------
- * handle split provides
- *
- * a splitprovides dep looks like
- * namespace:splitprovides(pkg REL_WITH path)
- * and is only true if pkg is installed and contains the specified path.
- * we also make sure that pkg is selected for an update, otherwise the
- * update would always be forced onto the user.
- * Map m is the map used when called from dep_possible.
- */
-
-static int
-solver_is_updating(Solver *solv, Id p)
-{
- /* check if the update rule is true */
- Pool *pool = solv->pool;
- Rule *r;
- Id l, pp;
- if (solv->decisionmap[p] >= 0)
- return 0; /* old package stayed */
- r = solv->rules + solv->updaterules + (p - solv->installed->start);
- FOR_RULELITERALS(l, pp, r)
- if (l > 0 && l != p && solv->decisionmap[l] > 0)
- return 1;
- return 0;
-}
-
-int
-solver_splitprovides(Solver *solv, Id dep, Map *m)
-{
- Pool *pool = solv->pool;
- Id p, pp;
- Reldep *rd;
- Solvable *s;
-
- if (!solv->dosplitprovides || !solv->installed)
- return 0;
- if (!ISRELDEP(dep))
- return 0;
- rd = GETRELDEP(pool, dep);
- if (rd->flags != REL_WITH)
- return 0;
- /*
- * things are a bit tricky here if pool->addedprovides == 1, because most split-provides are in
- * a non-standard location. If we simply call pool_whatprovides, we'll drag in the complete
- * file list. Instead we rely on pool_addfileprovides ignoring the addfileprovidesfiltered flag
- * for installed packages and check the lazywhatprovidesq (ignoring the REL_WITH part, but
- * we filter the package name further down anyway).
- */
- if (pool->addedfileprovides == 1 && !ISRELDEP(rd->evr) && !pool->whatprovides[rd->evr])
- pp = pool_searchlazywhatprovidesq(pool, rd->evr);
- else
- pp = pool_whatprovides(pool, dep);
- while ((p = pool->whatprovidesdata[pp++]) != 0)
- {
- /* here we have packages that provide the correct name and contain the path,
- * now do extra filtering */
- s = pool->solvables + p;
- if (s->repo != solv->installed || s->name != rd->name)
- continue;
- /* check if the package is updated. if m is set, we're called from dep_possible */
- if (m || solver_is_updating(solv, p))
- return 1;
- }
- return 0;
-}
-
-int
-solver_dep_fulfilled_cplx(Solver *solv, Reldep *rd)
-{
- Pool *pool = solv->pool;
- if (rd->flags == REL_COND)
- {
- if (ISRELDEP(rd->evr))
- {
- Reldep *rd2 = GETRELDEP(pool, rd->evr);
- if (rd2->flags == REL_ELSE)
- {
- if (solver_dep_fulfilled(solv, rd2->name))
- return solver_dep_fulfilled(solv, rd->name);
- return solver_dep_fulfilled(solv, rd2->evr);
- }
- }
- if (solver_dep_fulfilled(solv, rd->name))
- return 1;
- return !solver_dep_fulfilled(solv, rd->evr);
- }
- if (rd->flags == REL_UNLESS)
- {
- if (ISRELDEP(rd->evr))
- {
- Reldep *rd2 = GETRELDEP(pool, rd->evr);
- if (rd2->flags == REL_ELSE)
- {
- if (!solver_dep_fulfilled(solv, rd2->name))
- return solver_dep_fulfilled(solv, rd->name);
- return solver_dep_fulfilled(solv, rd2->evr);
- }
- }
- if (!solver_dep_fulfilled(solv, rd->name))
- return 0;
- return !solver_dep_fulfilled(solv, rd->evr);
- }
- if (rd->flags == REL_AND)
- {
- if (!solver_dep_fulfilled(solv, rd->name))
- return 0;
- return solver_dep_fulfilled(solv, rd->evr);
- }
- if (rd->flags == REL_OR)
- {
- if (solver_dep_fulfilled(solv, rd->name))
- return 1;
- return solver_dep_fulfilled(solv, rd->evr);
- }
- return 0;
-}
-
-
-/* mirrors solver_dep_fulfilled, but returns 2 if a new package
- * was involved */
-static int
-solver_dep_fulfilled_alreadyinstalled(Solver *solv, Id dep)
-{
- Pool *pool = solv->pool;
- Id p, pp;
- int r;
-
- if (ISRELDEP(dep))
- {
- Reldep *rd = GETRELDEP(pool, dep);
- if (rd->flags == REL_COND)
- {
- int r1, r2;
- if (ISRELDEP(rd->evr))
- {
- Reldep *rd2 = GETRELDEP(pool, rd->evr);
- if (rd2->flags == REL_ELSE)
- {
- r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd2->name);
- if (r1)
- {
- r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
- return r2 && r1 == 2 ? 2 : r2;
- }
- return solver_dep_fulfilled_alreadyinstalled(solv, rd2->evr);
- }
- }
- r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
- r2 = !solver_dep_fulfilled_alreadyinstalled(solv, rd->evr);
- if (!r1 && !r2)
- return 0;
- return r1 == 2 ? 2 : 1;
- }
- if (rd->flags == REL_UNLESS)
- {
- int r1, r2;
- if (ISRELDEP(rd->evr))
- {
- Reldep *rd2 = GETRELDEP(pool, rd->evr);
- if (rd2->flags == REL_ELSE)
- {
- r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd2->name);
- if (r1)
- {
- r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd2->evr);
- return r2 && r1 == 2 ? 2 : r2;
- }
- return solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
- }
- }
- /* A AND NOT(B) */
- r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
- r2 = !solver_dep_fulfilled_alreadyinstalled(solv, rd->evr);
- if (!r1 || !r2)
- return 0;
- return r1 == 2 ? 2 : 1;
- }
- if (rd->flags == REL_AND)
- {
- int r2, r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
- if (!r1)
- return 0;
- r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd->evr);
- if (!r2)
- return 0;
- return r1 == 2 || r2 == 2 ? 2 : 1;
- }
- if (rd->flags == REL_OR)
- {
- int r2, r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
- r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd->evr);
- if (!r1 && !r2)
- return 0;
- return r1 == 2 || r2 == 2 ? 2 : 1;
- }
- if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES)
- return solver_splitprovides(solv, rd->evr, 0);
- if (rd->flags == REL_NAMESPACE && solv->installsuppdepq)
- {
- Queue *q = solv->installsuppdepq;
- int i;
- for (i = 0; i < q->count; i++)
- if (q->elements[i] == dep || q->elements[i] == rd->name)
- return 2;
- }
- }
- r = 0;
- FOR_PROVIDES(p, pp, dep)
- if (solv->decisionmap[p] > 0)
- {
- Solvable *s = pool->solvables + p;
- if (s->repo && s->repo != solv->installed)
- return 2;
- r = 1;
- }
- return r;
-}
-
-static int
-solver_is_supplementing_alreadyinstalled(Solver *solv, Solvable *s)
-{
- Id sup, *supp;
- supp = s->repo->idarraydata + s->supplements;
- while ((sup = *supp++) != 0)
- if (solver_dep_fulfilled_alreadyinstalled(solv, sup) == 2)
- return 1;
- return 0;
-}
-
static Id
autouninstall(Solver *solv, Id *problem)
{
@@ -495,6 +259,10 @@ makeruledecisions(Solver *solv)
continue;
}
+ POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "ANALYZE UNSOLVABLE ASSERTION ----------------------\n");
+ IF_POOLDEBUG (SOLV_DEBUG_UNSOLVABLE)
+ solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + ri);
+
/*
* find the decision which is the "opposite" of the rule
*/
@@ -540,6 +308,8 @@ makeruledecisions(Solver *solv)
}
assert(solv->decisionq_why.elements[i] > 0);
+ IF_POOLDEBUG (SOLV_DEBUG_UNSOLVABLE)
+ solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + solv->decisionq_why.elements[i]);
/*
* conflict with a pkg rule ?
@@ -2002,56 +1772,6 @@ resolve_jobrules(Solver *solv, int level, int disablerules, Queue *dq)
return level;
}
-static int
-cleandeps_check_mistakes(Solver *solv)
-{
- Pool *pool = solv->pool;
- Rule *r;
- Id p, pp;
- int i;
- int mademistake = 0;
-
- if (!solv->cleandepsmap.size)
- return 0;
- /* check for mistakes */
- for (i = solv->installed->start; i < solv->installed->end; i++)
- {
- if (!MAPTST(&solv->cleandepsmap, i - solv->installed->start))
- continue;
- r = solv->rules + solv->featurerules + (i - solv->installed->start);
- /* a mistake is when the featurerule is true but the updaterule is false */
- if (!r->p)
- continue;
- FOR_RULELITERALS(p, pp, r)
- if (p > 0 && solv->decisionmap[p] > 0)
- break;
- if (!p)
- continue; /* feature rule is not true */
- r = solv->rules + solv->updaterules + (i - solv->installed->start);
- if (!r->p)
- continue;
- FOR_RULELITERALS(p, pp, r)
- if (p > 0 && solv->decisionmap[p] > 0)
- break;
- if (p)
- continue; /* update rule is true */
- POOL_DEBUG(SOLV_DEBUG_SOLVER, "cleandeps mistake: ");
- solver_printruleclass(solv, SOLV_DEBUG_SOLVER, r);
- POOL_DEBUG(SOLV_DEBUG_SOLVER, "feature rule: ");
- solver_printruleclass(solv, SOLV_DEBUG_SOLVER, solv->rules + solv->featurerules + (i - solv->installed->start));
- if (!solv->cleandeps_mistakes)
- {
- solv->cleandeps_mistakes = solv_calloc(1, sizeof(Queue));
- queue_init(solv->cleandeps_mistakes);
- }
- queue_push(solv->cleandeps_mistakes, i);
- MAPCLR(&solv->cleandepsmap, i - solv->installed->start);
- solver_reenablepolicyrules_cleandeps(solv, i);
- mademistake = 1;
- }
- return mademistake;
-}
-
static void
prune_to_update_targets(Solver *solv, Id *cp, Queue *q)
{
@@ -2398,7 +2118,7 @@ add_complex_recommends(Solver *solv, Id rec, Queue *dq, Map *dqmap)
{
if (solv->decisionmap[p] < 0)
continue;
- if (solv->dupmap_all && solv->installed && pool->solvables[p].repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start))))
+ if (solv->process_orphans && solv->installed && pool->solvables[p].repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start))))
continue;
}
queue_push(dq, p);
@@ -2553,7 +2273,7 @@ resolve_weak(Solver *solv, int level, int disablerules, Queue *dq, Queue *dqs, i
}
else if (solv->decisionmap[p] == 0)
{
- if (solv->dupmap_all && solv->installed && pool->solvables[p].repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start))))
+ if (solv->process_orphans && solv->installed && pool->solvables[p].repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start))))
continue;
queue_pushunique(dq, p);
}
@@ -2570,7 +2290,7 @@ resolve_weak(Solver *solv, int level, int disablerules, Queue *dq, Queue *dqs, i
continue;
if (!solver_is_supplementing(solv, s))
continue;
- if (solv->dupmap_all && solv->installed && s->repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, i - solv->installed->start))))
+ if (solv->process_orphans && solv->installed && s->repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, i - solv->installed->start))))
continue;
if (solv->isdisfavormap.size && MAPTST(&solv->isdisfavormap, i))
continue; /* disfavored supplements, do not install */
@@ -2794,6 +2514,35 @@ resolve_weak(Solver *solv, int level, int disablerules, Queue *dq, Queue *dqs, i
return level;
}
+static int
+resolve_cleandeps(Solver *solv, int level, int disablerules, int *rerunp)
+{
+ Pool *pool = solv->pool;
+ Repo *installed = solv->installed;
+ int olevel;
+ Id p;
+ Solvable *s;
+
+ if (!installed || !solv->cleandepsmap.size)
+ return level;
+ POOL_DEBUG(SOLV_DEBUG_SOLVER, "deciding cleandeps packages\n");
+ for (p = installed->start; p < installed->end; p++)
+ {
+ s = pool->solvables + p;
+ if (s->repo != installed)
+ continue;
+ if (solv->decisionmap[p] != 0 || !MAPTST(&solv->cleandepsmap, p - installed->start))
+ continue;
+ POOL_DEBUG(SOLV_DEBUG_POLICY, "cleandeps erasing %s\n", pool_solvid2str(pool, p));
+ olevel = level;
+ level = setpropagatelearn(solv, level, -p, 0, 0, SOLVER_REASON_CLEANDEPS_ERASE);
+ if (level < olevel)
+ break;
+ }
+ if (p < installed->end)
+ *rerunp = 1;
+ return level;
+}
static int
resolve_orphaned(Solver *solv, int level, int disablerules, Queue *dq, int *rerunp)
@@ -2999,24 +2748,12 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
/* decide leftover cleandeps packages */
if (solv->cleandepsmap.size && solv->installed)
- {
- for (p = solv->installed->start; p < solv->installed->end; p++)
- {
- s = pool->solvables + p;
- if (s->repo != solv->installed)
- continue;
- if (solv->decisionmap[p] == 0 && MAPTST(&solv->cleandepsmap, p - solv->installed->start))
- {
- POOL_DEBUG(SOLV_DEBUG_POLICY, "cleandeps erasing %s\n", pool_solvid2str(pool, p));
- olevel = level;
- level = setpropagatelearn(solv, level, -p, 0, 0, SOLVER_REASON_CLEANDEPS_ERASE);
- if (level < olevel)
- break;
- }
- }
- if (p < solv->installed->end)
- continue;
- }
+ {
+ int rerun = 0;
+ level = resolve_cleandeps(solv, level, disablerules, &rerun);
+ if (rerun)
+ continue;
+ }
/* at this point we have a consistent system. now do the extras... */
@@ -3056,7 +2793,7 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
continue; /* back to main loop */
}
- if (solv->installed && solv->cleandepsmap.size && cleandeps_check_mistakes(solv))
+ if (solv->installed && solv->cleandepsmap.size && solver_check_cleandeps_mistakes(solv))
{
solver_reset(solv);
level = 0; /* restart from scratch */
@@ -3366,7 +3103,7 @@ solver_addjobrule(Solver *solv, Id p, Id p2, Id d, Id job, int weak)
}
static inline void
-add_cleandeps_package(Solver *solv, Id p)
+add_cleandeps_updatepkg(Solver *solv, Id p)
{
if (!solv->cleandeps_updatepkgs)
{
@@ -3405,7 +3142,7 @@ add_update_target(Solver *solv, Id p, Id how)
MAPSET(&solv->bestupdatemap, pi - installed->start);
}
if (how & SOLVER_CLEANDEPS)
- add_cleandeps_package(solv, pi);
+ add_cleandeps_updatepkg(solv, pi);
queue_push2(solv->update_targets, pi, p);
/* check if it's ok to keep the installed package */
if (s->evr == si->evr && solvable_identical(s, si))
@@ -3434,7 +3171,7 @@ add_update_target(Solver *solv, Id p, Id how)
MAPSET(&solv->bestupdatemap, pi - installed->start);
}
if (how & SOLVER_CLEANDEPS)
- add_cleandeps_package(solv, pi);
+ add_cleandeps_updatepkg(solv, pi);
queue_push2(solv->update_targets, pi, p);
}
}
@@ -3677,7 +3414,7 @@ solver_solve(Solver *solv, Queue *job)
queue_insertn(&solv->job, 0, pool->pooljobs.count, pool->pooljobs.elements);
job = &solv->job;
- /* free old stuff in jase we re-run a solver */
+ /* free old stuff in case we re-run a solver */
queuep_free(&solv->update_targets);
queuep_free(&solv->cleandeps_updatepkgs);
queue_empty(&solv->ruleassertions);
@@ -3693,9 +3430,9 @@ solver_solve(Solver *solv, Queue *job)
map_zerosize(&solv->bestupdatemap);
solv->fixmap_all = 0;
map_zerosize(&solv->fixmap);
- solv->dupmap_all = 0;
map_zerosize(&solv->dupmap);
map_zerosize(&solv->dupinvolvedmap);
+ solv->process_orphans = 0;
solv->droporphanedmap_all = 0;
map_zerosize(&solv->droporphanedmap);
solv->allowuninstall_all = 0;
@@ -3794,7 +3531,7 @@ solver_solve(Solver *solv, Queue *job)
if (how & SOLVER_CLEANDEPS)
{
FOR_REPO_SOLVABLES(installed, p, s)
- add_cleandeps_package(solv, p);
+ add_cleandeps_updatepkg(solv, p);
}
}
else if (select == SOLVER_SOLVABLE_REPO)
@@ -3810,7 +3547,7 @@ solver_solve(Solver *solv, Queue *job)
if (how & SOLVER_CLEANDEPS)
{
FOR_REPO_SOLVABLES(installed, p, s)
- add_cleandeps_package(solv, p);
+ add_cleandeps_updatepkg(solv, p);
}
break;
}
@@ -3840,7 +3577,7 @@ solver_solve(Solver *solv, Queue *job)
MAPSET(&solv->bestupdatemap, p - installed->start);
}
if (how & SOLVER_CLEANDEPS)
- add_cleandeps_package(solv, p);
+ add_cleandeps_updatepkg(solv, p);
targeted = 0;
}
if (!targeted || solv->noautotarget)
@@ -3916,17 +3653,9 @@ solver_solve(Solver *solv, Queue *job)
}
break;
case SOLVER_DISTUPGRADE:
+ needduprules = 1;
if (select == SOLVER_SOLVABLE_ALL)
- {
- solv->dupmap_all = 1;
- solv->updatemap_all = 1;
- if (how & SOLVER_FORCEBEST)
- solv->bestupdatemap_all = 1;
- }
- if ((how & SOLVER_TARGETED) != 0)
- needduprules = 1;
- if (!solv->dupmap_all || solv->allowuninstall || solv->allowuninstall_all || solv->allowuninstallmap.size || solv->keep_orphans)
- needduprules = 1;
+ solv->process_orphans = 1;
break;
default:
break;
@@ -4049,7 +3778,7 @@ solver_solve(Solver *solv, Queue *job)
continue;
}
/* it's also orphaned if the feature rule consists just of the installed package */
- if (!solv->dupmap_all && sr->p == i && !sr->d && !sr->w2)
+ if (!solv->process_orphans && sr->p == i && !sr->d && !sr->w2)
queue_push(&solv->orphaned, i);
if (!solver_rulecmp(solv, r, sr))
@@ -4307,7 +4036,7 @@ solver_solve(Solver *solv, Queue *job)
else
solv->infarchrules = solv->infarchrules_end = solv->nrules;
- if (needduprules)
+ if (solv->dupinvolvedmap_all || solv->dupinvolvedmap.size)
solver_addduprules(solv, &addedmap);
else
solv->duprules = solv->duprules_end = solv->nrules;
@@ -4398,7 +4127,7 @@ solver_solve(Solver *solv, Queue *job)
solver_disablepolicyrules(solv);
/* break orphans if requested */
- if (solv->dupmap_all && solv->orphaned.count && solv->break_orphans)
+ if (solv->process_orphans && solv->orphaned.count && solv->break_orphans)
solver_breakorphans(solv);
/*
@@ -4435,6 +4164,35 @@ void solver_get_orphaned(Solver *solv, Queue *orphanedq)
queue_init_clone(orphanedq, &solv->orphaned);
}
+void solver_get_cleandeps(Solver *solv, Queue *cleandepsq)
+{
+ Pool *pool = solv->pool;
+ Repo *installed = solv->installed;
+ Solvable *s;
+ Rule *r;
+ Id p, pp, pr;
+
+ queue_empty(cleandepsq);
+ if (!installed || !solv->cleandepsmap.size)
+ return;
+ FOR_REPO_SOLVABLES(installed, p, s)
+ {
+ if (!MAPTST(&solv->cleandepsmap, p - installed->start) || solv->decisionmap[p] >= 0)
+ continue;
+ /* now check the update rule */
+ r = solv->rules + solv->updaterules + (p - solv->installed->start);
+ if (r->p)
+ {
+ FOR_RULELITERALS(pr, pp, r)
+ if (solv->decisionmap[pr] > 0)
+ break;
+ if (pr)
+ continue;
+ }
+ queue_push(cleandepsq, p);
+ }
+}
+
void solver_get_recommendations(Solver *solv, Queue *recommendationsq, Queue *suggestionsq, int noselected)
{
Pool *pool = solv->pool;
@@ -4805,7 +4563,7 @@ solver_describe_weakdep_decision(Solver *solv, Id p, Queue *whyq)
for (i = 1; i < pool->nsolvables; i++)
{
Id *recp, rec, pp2, p2;
- if (solv->decisionmap[i] < 0 || solv->decisionmap[i] >= level)
+ if (solv->decisionmap[i] <= 0 || solv->decisionmap[i] >= level)
continue;
s = pool->solvables + i;
if (!s->recommends)