diff options
Diffstat (limited to 'src/solver.c')
-rw-r--r-- | src/solver.c | 418 |
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) |