X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fsolver.c;h=c75974661119ef8b6bf164db42ea18ec76ec6903;hb=51a3a2ac14ea0b18ccbe47ce771d5c962aa0800a;hp=c6cad6b51da28a49baae47a052362c56eef1b200;hpb=fd257fb9c490f4af3fbfb71c4d099fe876be28eb;p=platform%2Fupstream%2Flibsolv.git diff --git a/src/solver.c b/src/solver.c index c6cad6b..c759746 100644 --- a/src/solver.c +++ b/src/solver.c @@ -217,13 +217,24 @@ autouninstall(Solver *solv, Id *problem) Rule *r; if (m && !MAPTST(m, v - solv->updaterules)) continue; - /* check if identical to feature rule, we don't like that */ + /* check if identical to feature rule, we don't like that (except for orphans) */ r = solv->rules + solv->featurerules + (v - solv->updaterules); if (!r->p) { /* update rule == feature rule */ if (v > lastfeature) lastfeature = v; + /* prefer orphaned packages in dup mode */ + if (solv->keep_orphans) + { + r = solv->rules + v; + if (!r->d && !r->w2 && r->p == (solv->installed->start + (v - solv->updaterules))) + { + lastfeature = v; + lastupdate = 0; + break; + } + } continue; } if (v > lastupdate) @@ -330,6 +341,7 @@ makeruledecisions(Solver *solv) assert(solv->decisionq.count == 0); queue_push(&solv->decisionq, SYSTEMSOLVABLE); queue_push(&solv->decisionq_why, 0); + queue_push2(&solv->decisionq_reason, 0, 0); solv->decisionmap[SYSTEMSOLVABLE] = 1; /* installed at level '1' */ decisionstart = solv->decisionq.count; @@ -896,18 +908,7 @@ revert(Solver *solv, int level) solv->branches.count -= solv->branches.elements[solv->branches.count - 2]; if (solv->recommends_index > solv->decisionq.count) solv->recommends_index = -1; /* rebuild recommends/suggests maps */ - if (solv->decisionq.count < solv->decisioncnt_jobs) - solv->decisioncnt_jobs = 0; - if (solv->decisionq.count < solv->decisioncnt_update) - solv->decisioncnt_update = 0; - if (solv->decisionq.count < solv->decisioncnt_keep) - solv->decisioncnt_keep = 0; - if (solv->decisionq.count < solv->decisioncnt_resolve) - solv->decisioncnt_resolve = 0; - if (solv->decisionq.count < solv->decisioncnt_weak) - solv->decisioncnt_weak= 0; - if (solv->decisionq.count < solv->decisioncnt_orphan) - solv->decisioncnt_orphan = 0; + solv->decisionq_reason.count = level + 1; } /*------------------------------------------------------------------- @@ -1100,9 +1101,9 @@ solver_reset(Solver *solv) } queue_empty(&solv->decisionq_why); queue_empty(&solv->decisionq); + queue_empty(&solv->decisionq_reason); solv->recommends_index = -1; solv->propagate_index = 0; - solv->decisioncnt_update = solv->decisioncnt_keep = solv->decisioncnt_resolve = solv->decisioncnt_weak = solv->decisioncnt_orphan = 0; queue_empty(&solv->branches); /* adapt learnt rule status to new set of enabled/disabled rules */ @@ -1323,7 +1324,7 @@ analyze_unsolvable(Solver *solv, Rule *cr, int disablerules) */ static int -setpropagatelearn(Solver *solv, int level, Id decision, int disablerules, Id ruleid) +setpropagatelearn(Solver *solv, int level, Id decision, int disablerules, Id ruleid, Id reason) { Pool *pool = solv->pool; Rule *r, *lr; @@ -1337,6 +1338,7 @@ setpropagatelearn(Solver *solv, int level, Id decision, int disablerules, Id rul solv->decisionmap[-decision] = -level; queue_push(&solv->decisionq, decision); queue_push(&solv->decisionq_why, -ruleid); /* <= 0 -> free decision */ + queue_push(&solv->decisionq_reason, reason); } assert(ruleid >= 0 && level > 0); for (;;) @@ -1365,7 +1367,7 @@ setpropagatelearn(Solver *solv, int level, Id decision, int disablerules, Id rul } static void -reorder_dq_for_jobrules(Solver *solv, int level, Queue *dq) +reorder_dq_for_future_installed(Solver *solv, int level, Queue *dq) { Pool *pool = solv->pool; int i, j, haveone = 0, dqcount = dq->count; @@ -1421,6 +1423,8 @@ reorder_dq_for_jobrules(Solver *solv, int level, Queue *dq) solv->recommends_index = -1; queue_truncate(&solv->decisionq, decisionqcount); } + /* but obey favored maps */ + policy_prefer_favored(solv, dq); } /*------------------------------------------------------------------- @@ -1451,7 +1455,7 @@ takebranch(Solver *solv, int pos, int end, const char *msg, int disablerules) { Pool *pool = solv->pool; int level; - Id p, why; + Id p, why, reason; #if 0 { int i; @@ -1471,7 +1475,8 @@ takebranch(Solver *solv, int pos, int end, const char *msg, int disablerules) /* hack: revert simply sets the count, so we can still access the reverted elements */ why = -solv->decisionq_why.elements[solv->decisionq_why.count]; assert(why >= 0); - return setpropagatelearn(solv, level, p, disablerules, why); + reason = solv->decisionq_reason.elements[level + 1]; + return setpropagatelearn(solv, level, p, disablerules, why, reason); } /*------------------------------------------------------------------- @@ -1486,23 +1491,23 @@ takebranch(Solver *solv, int pos, int end, const char *msg, int disablerules) */ static int -selectandinstall(Solver *solv, int level, Queue *dq, int disablerules, Id ruleid) +selectandinstall(Solver *solv, int level, Queue *dq, int disablerules, Id ruleid, Id reason) { Pool *pool = solv->pool; Id p; if (dq->count > 1) policy_filter_unwanted(solv, dq, POLICY_MODE_CHOOSE); - /* if we're resolving job rules and didn't resolve the installed packages yet, + /* if we're resolving rules and didn't resolve the installed packages yet, * do some special supplements ordering */ - if (dq->count > 1 && ruleid >= solv->jobrules && ruleid < solv->jobrules_end && solv->installed && !solv->focus_installed) - reorder_dq_for_jobrules(solv, level, dq); + if (dq->count > 1 && solv->do_extra_reordering) + reorder_dq_for_future_installed(solv, level, dq); /* if we have multiple candidates we open a branch */ if (dq->count > 1) createbranch(solv, level, dq, 0, ruleid); p = dq->elements[0]; POOL_DEBUG(SOLV_DEBUG_POLICY, "installing %s\n", pool_solvid2str(pool, p)); - return setpropagatelearn(solv, level, p, disablerules, ruleid); + return setpropagatelearn(solv, level, p, disablerules, ruleid, reason); } @@ -1543,6 +1548,7 @@ solver_create(Pool *pool) queue_init(&solv->ruletojob); queue_init(&solv->decisionq); queue_init(&solv->decisionq_why); + queue_init(&solv->decisionq_reason); queue_init(&solv->problems); queue_init(&solv->orphaned); queue_init(&solv->learnt_why); @@ -1568,80 +1574,6 @@ solver_create(Pool *pool) } -static int -resolve_jobrules(Solver *solv, int level, int disablerules, Queue *dq) -{ - Pool *pool = solv->pool; - int oldlevel = level; - int i, olevel; - Rule *r; - - POOL_DEBUG(SOLV_DEBUG_SOLVER, "resolving job rules\n"); - if (!solv->decisioncnt_jobs) - solv->decisioncnt_jobs = solv->decisionq.count; - for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++) - { - Id l, pp; - if (r->d < 0) /* ignore disabled rules */ - continue; - queue_empty(dq); - FOR_RULELITERALS(l, pp, r) - { - if (l < 0) - { - if (solv->decisionmap[-l] <= 0) - break; - } - else - { - if (solv->decisionmap[l] > 0) - break; - if (solv->decisionmap[l] == 0) - queue_push(dq, l); - } - } - if (l || !dq->count) - continue; - /* prune to installed if not updating */ - if (dq->count > 1 && solv->installed && !solv->updatemap_all && - !(solv->job.elements[solv->ruletojob.elements[i - solv->jobrules]] & SOLVER_ORUPDATE)) - { - int j, k; - for (j = k = 0; j < dq->count; j++) - { - Solvable *s = pool->solvables + dq->elements[j]; - if (s->repo == solv->installed) - { - dq->elements[k++] = dq->elements[j]; - if (solv->updatemap.size && MAPTST(&solv->updatemap, dq->elements[j] - solv->installed->start)) - { - k = 0; /* package wants to be updated, do not prune */ - break; - } - } - } - if (k) - dq->count = k; - } - olevel = level; - level = selectandinstall(solv, level, dq, disablerules, i); - if (level <= olevel) - { - if (level == olevel) - { - i--; - r--; - continue; /* try something else */ - } - if (level < oldlevel) - return level; - /* redo from start of jobrules */ - i = solv->jobrules - 1; - r = solv->rules + i; - } - } - return level; -} /*------------------------------------------------------------------- * @@ -1674,6 +1606,7 @@ solver_free(Solver *solv) queue_free(&solv->ruletojob); queue_free(&solv->decisionq); queue_free(&solv->decisionq_why); + queue_free(&solv->decisionq_reason); queue_free(&solv->learnt_why); queue_free(&solv->learnt_pool); queue_free(&solv->problems); @@ -1690,6 +1623,8 @@ solver_free(Solver *solv) queuep_free(&solv->recommendscplxq); queuep_free(&solv->suggestscplxq); queuep_free(&solv->brokenorphanrules); + queuep_free(&solv->favorq); + queuep_free(&solv->recommendsruleq); map_free(&solv->recommendsmap); map_free(&solv->suggestsmap); @@ -1705,6 +1640,8 @@ solver_free(Solver *solv) map_free(&solv->droporphanedmap); map_free(&solv->cleandepsmap); map_free(&solv->allowuninstallmap); + map_free(&solv->favormap); + map_free(&solv->isdisfavormap); solv_free(solv->decisionmap); solv_free(solv->rules); @@ -1764,10 +1701,18 @@ solver_get_flag(Solver *solv, int flag) return solv->break_orphans; case SOLVER_FLAG_FOCUS_INSTALLED: return solv->focus_installed; + case SOLVER_FLAG_FOCUS_BEST: + return solv->focus_best; case SOLVER_FLAG_YUM_OBSOLETES: return solv->do_yum_obsoletes; case SOLVER_FLAG_NEED_UPDATEPROVIDE: return solv->needupdateprovide; + case SOLVER_FLAG_URPM_REORDER: + return solv->urpmreorder; + case SOLVER_FLAG_STRONG_RECOMMENDS: + return solv->strongrecommends; + case SOLVER_FLAG_INSTALL_ALSO_UPDATES: + return solv->install_also_updates; default: break; } @@ -1840,12 +1785,24 @@ solver_set_flag(Solver *solv, int flag, int value) case SOLVER_FLAG_FOCUS_INSTALLED: solv->focus_installed = value; break; + case SOLVER_FLAG_FOCUS_BEST: + solv->focus_best = value; + break; case SOLVER_FLAG_YUM_OBSOLETES: solv->do_yum_obsoletes = value; break; case SOLVER_FLAG_NEED_UPDATEPROVIDE: solv->needupdateprovide = value; break; + case SOLVER_FLAG_URPM_REORDER: + solv->urpmreorder = value; + break; + case SOLVER_FLAG_STRONG_RECOMMENDS: + solv->strongrecommends = value; + break; + case SOLVER_FLAG_INSTALL_ALSO_UPDATES: + solv->install_also_updates = value; + break; default: break; } @@ -1853,6 +1810,81 @@ solver_set_flag(Solver *solv, int flag, int value) } static int +resolve_jobrules(Solver *solv, int level, int disablerules, Queue *dq) +{ + Pool *pool = solv->pool; + int oldlevel = level; + int i, olevel; + Rule *r; + + POOL_DEBUG(SOLV_DEBUG_SOLVER, "resolving job rules\n"); + for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++) + { + Id l, pp; + if (r->d < 0) /* ignore disabled rules */ + continue; + queue_empty(dq); + FOR_RULELITERALS(l, pp, r) + { + if (l < 0) + { + if (solv->decisionmap[-l] <= 0) + break; + } + else + { + if (solv->decisionmap[l] > 0) + break; + if (solv->decisionmap[l] == 0) + queue_push(dq, l); + } + } + if (l || !dq->count) + continue; + /* prune to installed if not updating */ + if (dq->count > 1 && solv->installed && !solv->updatemap_all && + !solv->install_also_updates && + !(solv->job.elements[solv->ruletojob.elements[i - solv->jobrules]] & SOLVER_ORUPDATE)) + { + int j = dq->count, k; + if (solv->updatemap.size) + { + /* do not prune if an installed package wants to be updated */ + for (j = 0; j < dq->count; j++) + if (pool->solvables[dq->elements[j]].repo == solv->installed + && MAPTST(&solv->updatemap, dq->elements[j] - solv->installed->start)) + break; + } + if (j == dq->count) + { + for (j = k = 0; j < dq->count; j++) + if (pool->solvables[dq->elements[j]].repo == solv->installed) + dq->elements[k++] = dq->elements[j]; + if (k) + dq->count = k; + } + } + olevel = level; + level = selectandinstall(solv, level, dq, disablerules, i, SOLVER_REASON_RESOLVE_JOB); + if (level <= olevel) + { + if (level == olevel) + { + i--; + r--; + continue; /* try something else */ + } + if (level < oldlevel) + return level; + /* redo from start of jobrules */ + i = solv->jobrules - 1; + r = solv->rules + i; + } + } + return level; +} + +static int cleandeps_check_mistakes(Solver *solv) { Pool *pool = solv->pool; @@ -1920,6 +1952,291 @@ prune_to_update_targets(Solver *solv, Id *cp, Queue *q) queue_truncate(q, j); } +static int +resolve_installed(Solver *solv, int level, int disablerules, Queue *dq) +{ + Pool *pool = solv->pool; + Repo *installed = solv->installed; + int i, n, pass; + int installedpos = solv->installedpos; + Solvable *s; + Id p, pp; + int olevel, origlevel = level; + + POOL_DEBUG(SOLV_DEBUG_SOLVER, "resolving installed packages\n"); + if (!installedpos) + installedpos = installed->start; + /* we use two passes if we need to update packages + * to create a better user experience */ + for (pass = solv->updatemap.size ? 0 : 1; pass < 2; ) + { + int passlevel = level; + Id *specialupdaters = solv->specialupdaters; + /* start with installedpos, the position that gave us problems the last time */ + for (i = installedpos, n = installed->start; n < installed->end; i++, n++) + { + Rule *r, *rr; + Id d; + + if (i == installed->end) + i = installed->start; + s = pool->solvables + i; + if (s->repo != installed) + continue; + + if (solv->decisionmap[i] > 0 && (!specialupdaters || !specialupdaters[i - installed->start])) + continue; /* already decided */ + if (!pass && solv->updatemap.size && !MAPTST(&solv->updatemap, i - installed->start)) + continue; /* updates first */ + 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 or pseudo package */ + + /* check if we should update this package to the latest version + * noupdate is set for erase jobs, in that case we want to deinstall + * the installed package and not replace it with a newer version + * rr->p != i is for dup jobs where the installed package cannot be kept */ + if (dq->count) + queue_empty(dq); + if (!MAPTST(&solv->noupdate, i - installed->start) && (solv->decisionmap[i] < 0 || solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, i - installed->start)) || (rr->p && rr->p != i))) + { + if (specialupdaters && (d = specialupdaters[i - installed->start]) != 0) + { + /* special multiversion handling, make sure best version is chosen */ + if (rr->p == i && solv->decisionmap[i] >= 0) + queue_push(dq, i); + while ((p = pool->whatprovidesdata[d++]) != 0) + if (solv->decisionmap[p] >= 0) + queue_push(dq, p); + if (dq->count && solv->update_targets && solv->update_targets->elements[i - installed->start]) + prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[i - installed->start], dq); + if (dq->count) + { + policy_filter_unwanted(solv, dq, POLICY_MODE_CHOOSE); + p = dq->elements[0]; + if (p != i && solv->decisionmap[p] == 0) + { + 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; + } + else + dq->count = 0; + } + } + else + { + /* update to best package of the update rule */ + FOR_RULELITERALS(p, pp, rr) + { + if (solv->decisionmap[p] > 0) + { + dq->count = 0; /* already fulfilled */ + break; + } + if (!solv->decisionmap[p]) + queue_push(dq, p); + } + } + } + if (dq->count && solv->update_targets && solv->update_targets->elements[i - installed->start]) + prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[i - installed->start], dq); + /* install best version */ + if (dq->count) + { + olevel = level; + level = selectandinstall(solv, level, dq, disablerules, rr - solv->rules, SOLVER_REASON_UPDATE_INSTALLED); + if (level <= olevel) + { + if (level < passlevel) + break; /* trouble */ + if (level < olevel) + n = installed->start; /* redo all */ + i--; + n--; + continue; + } + } + /* if still undecided keep package */ + if (solv->decisionmap[i] == 0) + { + olevel = level; + if (solv->cleandepsmap.size && MAPTST(&solv->cleandepsmap, i - installed->start)) + { +#if 0 + POOL_DEBUG(SOLV_DEBUG_POLICY, "cleandeps erasing %s\n", pool_solvid2str(pool, i)); + level = setpropagatelearn(solv, level, -i, disablerules, 0, SOLVER_REASON_CLEANDEPS_ERASE); +#else + continue; +#endif + } + else + { + POOL_DEBUG(SOLV_DEBUG_POLICY, "keeping %s\n", pool_solvid2str(pool, i)); + level = setpropagatelearn(solv, level, i, disablerules, r - solv->rules, SOLVER_REASON_KEEP_INSTALLED); + } + if (level <= olevel) + { + if (level < passlevel) + break; /* trouble */ + if (level < olevel) + n = installed->start; /* redo all */ + i--; + n--; + continue; /* retry with learnt rule */ + } + } + } + if (n < installed->end) + { + installedpos = i; /* retry problem solvable next time */ + if (level < origlevel) + break; /* ran into trouble */ + /* re-run all passes */ + pass = solv->updatemap.size ? 0 : 1; + continue; + } + /* reset installedpos, advance to next pass */ + installedpos = installed->start; + pass++; + } + solv->installedpos = installedpos; + return level; +} + +static int +resolve_dependencies(Solver *solv, int level, int disablerules, Queue *dq) +{ + Pool *pool = solv->pool; + int i, j, n; + int postponed; + Rule *r; + int origlevel = level; + Id p, *dp; + + /* + * decide + */ + POOL_DEBUG(SOLV_DEBUG_POLICY, "deciding unresolved rules\n"); + postponed = 0; + for (i = 1, n = 1; ; i++, n++) + { + if (n >= solv->nrules) + { + if (postponed <= 0) + break; + i = postponed; + postponed = -1; + n = 1; + } + if (i == solv->nrules) + i = 1; + r = solv->rules + i; + if (r->d < 0) /* ignore disabled rules */ + continue; + if (r->p < 0) /* most common cases first */ + { + if (r->d == 0 || solv->decisionmap[-r->p] <= 0) + continue; + } + if (dq->count) + queue_empty(dq); + if (r->d == 0) + { + /* binary or unary rule */ + /* need two positive undecided literals, r->p already checked above */ + if (r->w2 <= 0) + continue; + if (solv->decisionmap[r->p] || solv->decisionmap[r->w2]) + continue; + queue_push(dq, r->p); + queue_push(dq, r->w2); + } + else + { + /* make sure that + * all negative literals are installed + * no positive literal is installed + * i.e. the rule is not fulfilled and we + * just need to decide on the positive literals + * (decisionmap[-r->p] for the r->p < 0 case is already checked above) + */ + if (r->p >= 0) + { + if (solv->decisionmap[r->p] > 0) + continue; + if (solv->decisionmap[r->p] == 0) + queue_push(dq, r->p); + } + dp = pool->whatprovidesdata + r->d; + while ((p = *dp++) != 0) + { + if (p < 0) + { + if (solv->decisionmap[-p] <= 0) + break; + } + else + { + if (solv->decisionmap[p] > 0) + break; + if (solv->decisionmap[p] == 0) + queue_push(dq, p); + } + } + if (p) + continue; + } + IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE) + { + POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "unfulfilled "); + solver_printruleclass(solv, SOLV_DEBUG_PROPAGATE, r); + } + /* dq->count < 2 cannot happen as this means that + * the rule is unit */ + assert(dq->count > 1); + + /* prune to cleandeps packages */ + if (solv->cleandepsmap.size && solv->installed) + { + Repo *installed = solv->installed; + for (j = 0; j < dq->count; j++) + if (pool->solvables[dq->elements[j]].repo == installed && MAPTST(&solv->cleandepsmap, dq->elements[j] - installed->start)) + break; + if (j < dq->count) + { + dq->elements[0] = dq->elements[j]; + queue_truncate(dq, 1); + } + } + + if (dq->count > 1 && postponed >= 0) + { + policy_filter_unwanted(solv, dq, POLICY_MODE_CHOOSE_NOREORDER); + if (dq->count > 1) + { + if (!postponed) + postponed = i; + continue; + } + } + + level = selectandinstall(solv, level, dq, disablerules, r - solv->rules, SOLVER_REASON_RESOLVE); + if (level < origlevel) + break; /* trouble */ + /* something changed, so look at all rules again */ + n = 0; + } + return level; +} + + #ifdef ENABLE_COMPLEX_DEPS static void @@ -2052,6 +2369,381 @@ do_complex_recommendations(Solver *solv, Id rec, Map *m, int noselected) #endif +static void +prune_disfavored(Solver *solv, Queue *plist) +{ + int i, j; + if (!solv->isdisfavormap.size) + return; + for (i = j = 0; i < plist->count; i++) + { + Id p = plist->elements[i]; + if (!MAPTST(&solv->isdisfavormap, p)) + plist->elements[j++] = p; + } + if (i != j) + queue_truncate(plist, j); +} + +static int +resolve_weak(Solver *solv, int level, int disablerules, Queue *dq, Queue *dqs, int *rerunp) +{ + Pool *pool = solv->pool; + int i, j, qcount; + int olevel; + Solvable *s; + Map dqmap; + int decisioncount; + Id p; + + POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended packages\n"); + if (dq->count) + queue_empty(dq); /* recommended packages */ + if (dqs->count) + queue_empty(dqs); /* supplemented packages */ + for (i = 1; i < pool->nsolvables; i++) + { + if (solv->decisionmap[i] < 0) + continue; + s = pool->solvables + i; + if (solv->decisionmap[i] > 0) + { + /* installed, check for recommends */ + Id *recp, rec, pp, p; + if (!solv->addalreadyrecommended && s->repo == solv->installed) + continue; + /* XXX need to special case AND ? */ + if (s->recommends) + { + recp = s->repo->idarraydata + s->recommends; + while ((rec = *recp++) != 0) + { +#ifdef ENABLE_COMPLEX_DEPS + if (pool_is_complex_dep(pool, rec)) + { + add_complex_recommends(solv, rec, dq, 0); + continue; + } +#endif + qcount = dq->count; + FOR_PROVIDES(p, pp, rec) + { + if (solv->decisionmap[p] > 0) + { + dq->count = qcount; + break; + } + 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)))) + continue; + queue_pushunique(dq, p); + } + } + } + } + } + else + { + /* not yet installed, check if supplemented */ + if (!s->supplements) + continue; + if (!pool_installable(pool, s)) + 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)))) + continue; + if (solv->isdisfavormap.size && MAPTST(&solv->isdisfavormap, i)) + continue; /* disfavored supplements, do not install */ + queue_push(dqs, i); + } + } + + /* filter out disfavored recommended packages */ + if (dq->count && solv->isdisfavormap.size) + prune_disfavored(solv, dq); + + /* filter out all packages obsoleted by installed packages */ + /* this is no longer needed if we have (and trust) reverse obsoletes */ + if ((dqs->count || dq->count) && solv->installed) + { + Map obsmap; + Id obs, *obsp, po, ppo; + + map_init(&obsmap, pool->nsolvables); + for (p = solv->installed->start; p < solv->installed->end; p++) + { + s = pool->solvables + p; + if (s->repo != solv->installed || !s->obsoletes) + continue; + if (solv->decisionmap[p] <= 0) + continue; + if (!solv->keepexplicitobsoletes && solv->multiversion.size && MAPTST(&solv->multiversion, p)) + continue; + obsp = s->repo->idarraydata + s->obsoletes; + /* foreach obsoletes */ + while ((obs = *obsp++) != 0) + FOR_PROVIDES(po, ppo, obs) + { + Solvable *pos = pool->solvables + po; + if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, pos, obs)) + continue; + if (pool->obsoleteusescolors && !pool_colormatch(pool, s, pos)) + continue; + MAPSET(&obsmap, po); + } + } + for (i = j = 0; i < dqs->count; i++) + if (!MAPTST(&obsmap, dqs->elements[i])) + dqs->elements[j++] = dqs->elements[i]; + dqs->count = j; + for (i = j = 0; i < dq->count; i++) + if (!MAPTST(&obsmap, dq->elements[i])) + dq->elements[j++] = dq->elements[i]; + dq->count = j; + map_free(&obsmap); + } + + /* filter out all already supplemented packages if requested */ + if (!solv->addalreadyrecommended && dqs->count) + { + /* filter out old supplements */ + for (i = j = 0; i < dqs->count; i++) + { + p = dqs->elements[i]; + s = pool->solvables + p; + if (s->supplements && solver_is_supplementing_alreadyinstalled(solv, s)) + dqs->elements[j++] = p; + } + dqs->count = j; + } + + /* multiversion doesn't mix well with supplements. + * filter supplemented packages where we already decided + * to install a different version (see bnc#501088) */ + if (dqs->count && solv->multiversion.size) + { + for (i = j = 0; i < dqs->count; i++) + { + p = dqs->elements[i]; + if (MAPTST(&solv->multiversion, p)) + { + Id p2, pp2; + s = pool->solvables + p; + FOR_PROVIDES(p2, pp2, s->name) + if (solv->decisionmap[p2] > 0 && pool->solvables[p2].name == s->name) + break; + if (p2) + continue; /* ignore this package */ + } + dqs->elements[j++] = p; + } + dqs->count = j; + } + + /* implicitobsoleteusescolors doesn't mix well with supplements. + * filter supplemented packages where we already decided + * to install a different architecture */ + if (dqs->count && pool->implicitobsoleteusescolors) + { + for (i = j = 0; i < dqs->count; i++) + { + Id p2, pp2; + p = dqs->elements[i]; + s = pool->solvables + p; + FOR_PROVIDES(p2, pp2, s->name) + if (solv->decisionmap[p2] > 0 && pool->solvables[p2].name == s->name && pool->solvables[p2].arch != s->arch) + break; + if (p2) + continue; /* ignore this package */ + dqs->elements[j++] = p; + } + dqs->count = j; + } + + /* make dq contain both recommended and supplemented pkgs */ + if (dqs->count) + { + for (i = 0; i < dqs->count; i++) + queue_pushunique(dq, dqs->elements[i]); + } + + if (!dq->count) + return level; + *rerunp = 1; + + if (dq->count == 1) + { + /* simple case, just one package. no need to choose to best version */ + p = dq->elements[0]; + if (dqs->count) + POOL_DEBUG(SOLV_DEBUG_POLICY, "installing supplemented %s\n", pool_solvid2str(pool, p)); + else + POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended %s\n", pool_solvid2str(pool, p)); + return setpropagatelearn(solv, level, p, 0, 0, SOLVER_REASON_WEAKDEP); + } + + /* filter packages, this gives us the best versions */ + policy_filter_unwanted(solv, dq, POLICY_MODE_RECOMMEND); + + /* create map of result */ + map_init(&dqmap, pool->nsolvables); + for (i = 0; i < dq->count; i++) + MAPSET(&dqmap, dq->elements[i]); + + /* prune dqs so that it only contains the best versions */ + for (i = j = 0; i < dqs->count; i++) + { + p = dqs->elements[i]; + if (MAPTST(&dqmap, p)) + dqs->elements[j++] = p; + } + dqs->count = j; + + /* install all supplemented packages, but order first */ + if (dqs->count > 1) + policy_filter_unwanted(solv, dqs, POLICY_MODE_SUPPLEMENT); + decisioncount = solv->decisionq.count; + for (i = 0; i < dqs->count; i++) + { + p = dqs->elements[i]; + if (solv->decisionmap[p]) + continue; + POOL_DEBUG(SOLV_DEBUG_POLICY, "installing supplemented %s\n", pool_solvid2str(pool, p)); + olevel = level; + level = setpropagatelearn(solv, level, p, 0, 0, SOLVER_REASON_WEAKDEP); + if (level <= olevel) + break; + } + if (i < dqs->count || solv->decisionq.count < decisioncount) + { + map_free(&dqmap); + return level; + } + + /* install all recommended packages */ + /* more work as we want to created branches if multiple + * choices are valid */ + for (i = 0; i < decisioncount; i++) + { + Id rec, *recp, pp; + p = solv->decisionq.elements[i]; + if (p < 0) + continue; + s = pool->solvables + p; + if (!s->repo || (!solv->addalreadyrecommended && s->repo == solv->installed)) + continue; + if (!s->recommends) + continue; + recp = s->repo->idarraydata + s->recommends; + while ((rec = *recp++) != 0) + { + queue_empty(dq); +#ifdef ENABLE_COMPLEX_DEPS + if (pool_is_complex_dep(pool, rec)) + add_complex_recommends(solv, rec, dq, &dqmap); + else +#endif + FOR_PROVIDES(p, pp, rec) + { + if (solv->decisionmap[p] > 0) + { + dq->count = 0; + break; + } + else if (solv->decisionmap[p] == 0 && MAPTST(&dqmap, p)) + queue_push(dq, p); + } + if (!dq->count) + continue; + if (dq->count > 1) + policy_filter_unwanted(solv, dq, POLICY_MODE_CHOOSE); + /* if we have multiple candidates we open a branch */ + if (dq->count > 1) + createbranch(solv, level, dq, s - pool->solvables, rec); + p = dq->elements[0]; + POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended %s\n", pool_solvid2str(pool, p)); + olevel = level; + level = setpropagatelearn(solv, level, p, 0, 0, SOLVER_REASON_WEAKDEP); + if (level <= olevel || solv->decisionq.count < decisioncount) + break; /* we had to revert some decisions */ + } + if (rec) + break; /* had a problem above, quit loop */ + } + map_free(&dqmap); + return level; +} + + +static int +resolve_orphaned(Solver *solv, int level, int disablerules, Queue *dq, int *rerunp) +{ + Pool *pool = solv->pool; + int i; + Id p; + int installedone = 0; + int olevel; + + /* let's see if we can install some unsupported package */ + POOL_DEBUG(SOLV_DEBUG_SOLVER, "deciding orphaned packages\n"); + for (i = 0; i < solv->orphaned.count; i++) + { + p = solv->orphaned.elements[i]; + if (solv->decisionmap[p]) + continue; /* already decided */ + if (solv->droporphanedmap_all) + continue; + if (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start)) + continue; + POOL_DEBUG(SOLV_DEBUG_SOLVER, "keeping orphaned %s\n", pool_solvid2str(pool, p)); + olevel = level; + level = setpropagatelearn(solv, level, p, 0, 0, SOLVER_REASON_RESOLVE_ORPHAN); + installedone = 1; + if (level < olevel) + break; + } + if (installedone || i < solv->orphaned.count) + { + *rerunp = 1; + return level; + } + for (i = 0; i < solv->orphaned.count; i++) + { + p = solv->orphaned.elements[i]; + if (solv->decisionmap[p]) + continue; /* already decided */ + POOL_DEBUG(SOLV_DEBUG_SOLVER, "removing orphaned %s\n", pool_solvid2str(pool, p)); + olevel = level; + level = setpropagatelearn(solv, level, -p, 0, 0, SOLVER_REASON_RESOLVE_ORPHAN); + if (level < olevel) + { + *rerunp = 1; + return level; + } + } + if (solv->brokenorphanrules) + { + solver_check_brokenorphanrules(solv, dq); + if (dq->count) + { + policy_filter_unwanted(solv, dq, POLICY_MODE_CHOOSE); + for (i = 0; i < dq->count; i++) + { + p = dq->elements[i]; + POOL_DEBUG(SOLV_DEBUG_POLICY, "installing orphaned dep %s\n", pool_solvid2str(pool, p)); + olevel = level; + level = setpropagatelearn(solv, level, p, 0, 0, SOLVER_REASON_RESOLVE_ORPHAN); + if (level < olevel) + break; + } + *rerunp = 1; + } + } + return level; +} + /*------------------------------------------------------------------- * * solver_run_sat @@ -2068,12 +2760,11 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) int systemlevel; int level, olevel; Rule *r; - int i, j, n; + int i; Solvable *s; Pool *pool = solv->pool; - Id p, pp, *dp, postponed; + Id p; int minimizationsteps; - int installedpos = solv->installed ? solv->installed->start : 0; IF_POOLDEBUG (SOLV_DEBUG_RULE_CREATION) { @@ -2089,6 +2780,8 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) queue_init(&dq); queue_init(&dqs); + solv->installedpos = 0; + solv->do_extra_reordering = 0; /* * here's the main loop: @@ -2125,652 +2818,106 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) level = analyze_unsolvable(solv, r, disablerules); continue; } - systemlevel = level + 1; - } - - /* - * resolve jobs first (unless focus_installed is set) - */ - if (level < systemlevel && !solv->focus_installed) - { - olevel = level; - level = resolve_jobrules(solv, level, disablerules, &dq); - if (level < olevel) - continue; - systemlevel = level + 1; - } - - - /* - * installed packages - */ - if (!solv->decisioncnt_update) - solv->decisioncnt_update = solv->decisionq.count; - if (level < systemlevel && solv->installed && solv->installed->nsolvables && !solv->installed->disabled) - { - Repo *installed = solv->installed; - int pass; - - POOL_DEBUG(SOLV_DEBUG_SOLVER, "resolving installed packages\n"); - /* we use two passes if we need to update packages - * to create a better user experience */ - for (pass = solv->updatemap.size ? 0 : 1; pass < 2; pass++) - { - int passlevel = level; - Id *specialupdaters = solv->specialupdaters; - if (pass == 1 && !solv->decisioncnt_keep) - solv->decisioncnt_keep = solv->decisionq.count; - /* start with installedpos, the position that gave us problems the last time */ - for (i = installedpos, n = installed->start; n < installed->end; i++, n++) - { - Rule *rr; - Id d; - - if (i == installed->end) - i = installed->start; - s = pool->solvables + i; - if (s->repo != installed) - continue; - - if (solv->decisionmap[i] > 0 && (!specialupdaters || !specialupdaters[i - installed->start])) - continue; /* already decided */ - if (!pass && solv->updatemap.size && !MAPTST(&solv->updatemap, i - installed->start)) - continue; /* updates first */ - 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 && !(specialupdaters && specialupdaters[i - installed->start])) - continue; /* orpaned package */ - - /* check if we should update this package to the latest version - * noupdate is set for erase jobs, in that case we want to deinstall - * the installed package and not replace it with a newer version - * rr->p != i is for dup jobs where the installed package cannot be kept */ - queue_empty(&dq); - if (!MAPTST(&solv->noupdate, i - installed->start) && (solv->decisionmap[i] < 0 || solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, i - installed->start)) || (rr->p && rr->p != i))) - { - if (!rr->p) - { - /* specialupdater with no update/feature rule */ - for (d = specialupdaters[i - installed->start]; (p = pool->whatprovidesdata[d++]) != 0; ) - { - if (solv->decisionmap[p] > 0) - { - dq.count = 0; - break; - } - if (!solv->decisionmap[p]) - queue_push(&dq, p); - } - } - else if (specialupdaters && (d = specialupdaters[i - installed->start]) != 0) - { - /* special multiversion handling, make sure best version is chosen */ - if (rr->p == i && solv->decisionmap[i] >= 0) - queue_push(&dq, i); - while ((p = pool->whatprovidesdata[d++]) != 0) - if (solv->decisionmap[p] >= 0) - queue_push(&dq, p); - if (dq.count && solv->update_targets && solv->update_targets->elements[i - installed->start]) - prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[i - installed->start], &dq); - if (dq.count) - { - policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE); - p = dq.elements[0]; - if (p != i && solv->decisionmap[p] == 0) - { - 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; - } - else - dq.count = 0; - } - } - else - { - /* update to best package of the update rule */ - FOR_RULELITERALS(p, pp, rr) - { - if (solv->decisionmap[p] > 0) - { - dq.count = 0; /* already fulfilled */ - break; - } - if (!solv->decisionmap[p]) - queue_push(&dq, p); - } - } - } - if (dq.count && solv->update_targets && solv->update_targets->elements[i - installed->start]) - prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[i - installed->start], &dq); - /* install best version */ - if (dq.count) - { - olevel = level; - level = selectandinstall(solv, level, &dq, disablerules, rr - solv->rules); - if (level <= olevel) - { - if (level < passlevel) - break; /* trouble */ - if (level < olevel) - n = installed->start; /* redo all */ - i--; - n--; - continue; - } - } - /* if still undecided keep package */ - if (solv->decisionmap[i] == 0) - { - olevel = level; - if (solv->cleandepsmap.size && MAPTST(&solv->cleandepsmap, i - installed->start)) - { -#if 0 - POOL_DEBUG(SOLV_DEBUG_POLICY, "cleandeps erasing %s\n", pool_solvid2str(pool, i)); - level = setpropagatelearn(solv, level, -i, disablerules, 0); -#else - continue; -#endif - } - else - { - POOL_DEBUG(SOLV_DEBUG_POLICY, "keeping %s\n", pool_solvid2str(pool, i)); - level = setpropagatelearn(solv, level, i, disablerules, r - solv->rules); - } - if (level <= olevel) - { - if (level < passlevel) - break; /* trouble */ - if (level < olevel) - n = installed->start; /* redo all */ - i--; - n--; - continue; /* retry with learnt rule */ - } - } - } - if (n < installed->end) - { - installedpos = i; /* retry problem solvable next time */ - break; /* ran into trouble */ - } - installedpos = installed->start; /* reset installedpos */ - } - systemlevel = level + 1; - if (pass < 2) - continue; /* had trouble, retry */ - } - if (!solv->decisioncnt_keep) - solv->decisioncnt_keep = solv->decisionq.count; - - if (level < systemlevel && solv->focus_installed) - { - olevel = level; - level = resolve_jobrules(solv, level, disablerules, &dq); - if (level < olevel) - continue; - systemlevel = level + 1; - } - - if (level < systemlevel) - systemlevel = level; - - /* - * decide - */ - if (!solv->decisioncnt_resolve) - solv->decisioncnt_resolve = solv->decisionq.count; - POOL_DEBUG(SOLV_DEBUG_POLICY, "deciding unresolved rules\n"); - postponed = 0; - for (i = 1, n = 1; ; i++, n++) - { - if (n >= solv->nrules) - { - if (postponed <= 0) - break; - i = postponed; - postponed = -1; - n = 1; - } - if (i == solv->nrules) - i = 1; - r = solv->rules + i; - if (r->d < 0) /* ignore disabled rules */ - continue; - if (r->p < 0) /* most common cases first */ - { - if (r->d == 0 || solv->decisionmap[-r->p] <= 0) - continue; - } - if (dq.count) - queue_empty(&dq); - if (r->d == 0) - { - /* binary or unary rule */ - /* need two positive undecided literals, r->p already checked above */ - if (r->w2 <= 0) - continue; - if (solv->decisionmap[r->p] || solv->decisionmap[r->w2]) - continue; - queue_push(&dq, r->p); - queue_push(&dq, r->w2); - } - else - { - /* make sure that - * all negative literals are installed - * no positive literal is installed - * i.e. the rule is not fulfilled and we - * just need to decide on the positive literals - * (decisionmap[-r->p] for the r->p < 0 case is already checked above) - */ - if (r->p >= 0) - { - if (solv->decisionmap[r->p] > 0) - continue; - if (solv->decisionmap[r->p] == 0) - queue_push(&dq, r->p); - } - dp = pool->whatprovidesdata + r->d; - while ((p = *dp++) != 0) - { - if (p < 0) - { - if (solv->decisionmap[-p] <= 0) - break; - } - else - { - if (solv->decisionmap[p] > 0) - break; - if (solv->decisionmap[p] == 0) - queue_push(&dq, p); - } - } - if (p) - continue; - } - IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE) - { - POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "unfulfilled "); - solver_printruleclass(solv, SOLV_DEBUG_PROPAGATE, r); - } - /* dq.count < 2 cannot happen as this means that - * the rule is unit */ - assert(dq.count > 1); - - /* prune to cleandeps packages */ - if (solv->cleandepsmap.size && solv->installed) - { - Repo *installed = solv->installed; - for (j = 0; j < dq.count; j++) - if (pool->solvables[dq.elements[j]].repo == installed && MAPTST(&solv->cleandepsmap, dq.elements[j] - installed->start)) - break; - if (j < dq.count) - { - dq.elements[0] = dq.elements[j]; - queue_truncate(&dq, 1); - } - } - - if (dq.count > 1 && postponed >= 0) - { - policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE_NOREORDER); - if (dq.count > 1) - { - if (!postponed) - postponed = i; - continue; - } - } + systemlevel = level + 1; + } + /* + * resolve jobs first (unless focus_installed is set) + */ + if (level < systemlevel && !solv->focus_installed) + { + if (solv->installed && solv->installed->nsolvables && !solv->installed->disabled) + solv->do_extra_reordering = 1; olevel = level; - level = selectandinstall(solv, level, &dq, disablerules, r - solv->rules); - if (level < systemlevel) - break; /* trouble */ - /* something changed, so look at all rules again */ - n = 0; + level = resolve_jobrules(solv, level, disablerules, &dq); + solv->do_extra_reordering = 0; + if (level < olevel) + continue; + systemlevel = level + 1; } - if (n < solv->nrules) /* ran into trouble? */ - continue; /* start over */ + /* resolve job dependencies in the focus_best case */ + if (level < systemlevel && solv->focus_best && !solv->focus_installed && solv->installed && solv->installed->nsolvables && !solv->installed->disabled) + { + solv->do_extra_reordering = 1; + olevel = level; + level = resolve_dependencies(solv, level, disablerules, &dq); + solv->do_extra_reordering = 0; + if (level < olevel) + continue; /* start over */ + systemlevel = level + 1; + } - /* decide leftover cleandeps packages */ - if (solv->cleandepsmap.size && solv->installed) + /* + * installed packages + */ + if (level < systemlevel && solv->installed && solv->installed->nsolvables && !solv->installed->disabled) { - 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); - if (level < olevel) - break; - } - } - if (p < solv->installed->end) + olevel = level; + level = resolve_installed(solv, level, disablerules, &dq); + if (level < olevel) continue; + systemlevel = level + 1; } - /* at this point we have a consistent system. now do the extras... */ - - if (!solv->decisioncnt_weak) - solv->decisioncnt_weak = solv->decisionq.count; - if (doweak) + /* resolve jobs in focus_installed case */ + if (level < systemlevel && solv->focus_installed) { - int qcount; - - POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended packages\n"); - queue_empty(&dq); /* recommended packages */ - queue_empty(&dqs); /* supplemented packages */ - for (i = 1; i < pool->nsolvables; i++) - { - if (solv->decisionmap[i] < 0) - continue; - if (solv->decisionmap[i] > 0) - { - /* installed, check for recommends */ - Id *recp, rec, pp, p; - s = pool->solvables + i; - if (!solv->addalreadyrecommended && s->repo == solv->installed) - continue; - /* XXX need to special case AND ? */ - if (s->recommends) - { - recp = s->repo->idarraydata + s->recommends; - while ((rec = *recp++) != 0) - { -#ifdef ENABLE_COMPLEX_DEPS - if (pool_is_complex_dep(pool, rec)) - { - add_complex_recommends(solv, rec, &dq, 0); - continue; - } -#endif - qcount = dq.count; - FOR_PROVIDES(p, pp, rec) - { - if (solv->decisionmap[p] > 0) - { - dq.count = qcount; - break; - } - 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)))) - continue; - queue_pushunique(&dq, p); - } - } - } - } - } - else - { - s = pool->solvables + i; - if (!s->supplements) - continue; - if (!pool_installable(pool, s)) - 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)))) - continue; - queue_push(&dqs, i); - } - } - - /* filter out all packages obsoleted by installed packages */ - /* this is no longer needed if we have reverse obsoletes */ - if ((dqs.count || dq.count) && solv->installed) - { - Map obsmap; - Id obs, *obsp, po, ppo; - - map_init(&obsmap, pool->nsolvables); - for (p = solv->installed->start; p < solv->installed->end; p++) - { - s = pool->solvables + p; - if (s->repo != solv->installed || !s->obsoletes) - continue; - if (solv->decisionmap[p] <= 0) - continue; - if (!solv->keepexplicitobsoletes && solv->multiversion.size && MAPTST(&solv->multiversion, p)) - continue; - obsp = s->repo->idarraydata + s->obsoletes; - /* foreach obsoletes */ - while ((obs = *obsp++) != 0) - FOR_PROVIDES(po, ppo, obs) - { - Solvable *pos = pool->solvables + po; - if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, pos, obs)) - continue; - if (pool->obsoleteusescolors && !pool_colormatch(pool, s, pos)) - continue; - MAPSET(&obsmap, po); - } - } - for (i = j = 0; i < dqs.count; i++) - if (!MAPTST(&obsmap, dqs.elements[i])) - dqs.elements[j++] = dqs.elements[i]; - dqs.count = j; - for (i = j = 0; i < dq.count; i++) - if (!MAPTST(&obsmap, dq.elements[i])) - dq.elements[j++] = dq.elements[i]; - dq.count = j; - map_free(&obsmap); - } - - /* filter out all already supplemented packages if requested */ - if (!solv->addalreadyrecommended && dqs.count) - { - /* filter out old supplements */ - for (i = j = 0; i < dqs.count; i++) - { - p = dqs.elements[i]; - s = pool->solvables + p; - if (s->supplements && solver_is_supplementing_alreadyinstalled(solv, s)) - dqs.elements[j++] = p; - } - dqs.count = j; - } - - /* multiversion doesn't mix well with supplements. - * filter supplemented packages where we already decided - * to install a different version (see bnc#501088) */ - if (dqs.count && solv->multiversion.size) - { - for (i = j = 0; i < dqs.count; i++) - { - p = dqs.elements[i]; - if (MAPTST(&solv->multiversion, p)) - { - Id p2, pp2; - s = pool->solvables + p; - FOR_PROVIDES(p2, pp2, s->name) - if (solv->decisionmap[p2] > 0 && pool->solvables[p2].name == s->name) - break; - if (p2) - continue; /* ignore this package */ - } - dqs.elements[j++] = p; - } - dqs.count = j; - } - - /* make dq contain both recommended and supplemented pkgs */ - if (dqs.count) - { - for (i = 0; i < dqs.count; i++) - queue_pushunique(&dq, dqs.elements[i]); - } - - if (dq.count) - { - Map dqmap; - int decisioncount = solv->decisionq.count; + olevel = level; + level = resolve_jobrules(solv, level, disablerules, &dq); + if (level < olevel) + continue; + systemlevel = level + 1; + } - if (dq.count == 1) - { - /* simple case, just one package. no need to choose to best version */ - p = dq.elements[0]; - if (dqs.count) - POOL_DEBUG(SOLV_DEBUG_POLICY, "installing supplemented %s\n", pool_solvid2str(pool, p)); - else - POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended %s\n", pool_solvid2str(pool, p)); - level = setpropagatelearn(solv, level, p, 0, 0); - continue; /* back to main loop */ - } + if (level < systemlevel) + systemlevel = level; - /* filter packages, this gives us the best versions */ - policy_filter_unwanted(solv, &dq, POLICY_MODE_RECOMMEND); + /* resolve all dependencies */ + olevel = level; + level = resolve_dependencies(solv, level, disablerules, &dq); + if (level < olevel) + continue; /* start over */ - /* create map of result */ - map_init(&dqmap, pool->nsolvables); - for (i = 0; i < dq.count; i++) - MAPSET(&dqmap, dq.elements[i]); + /* 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; + } - /* install all supplemented packages */ - for (i = 0; i < dqs.count; i++) - { - p = dqs.elements[i]; - if (solv->decisionmap[p] || !MAPTST(&dqmap, p)) - continue; - POOL_DEBUG(SOLV_DEBUG_POLICY, "installing supplemented %s\n", pool_solvid2str(pool, p)); - olevel = level; - level = setpropagatelearn(solv, level, p, 0, 0); - if (level <= olevel) - break; - } - if (i < dqs.count || solv->decisionq.count < decisioncount) - { - map_free(&dqmap); - continue; - } + /* at this point we have a consistent system. now do the extras... */ - /* install all recommended packages */ - /* more work as we want to created branches if multiple - * choices are valid */ - for (i = 0; i < decisioncount; i++) - { - Id rec, *recp, pp; - p = solv->decisionq.elements[i]; - if (p < 0) - continue; - s = pool->solvables + p; - if (!s->repo || (!solv->addalreadyrecommended && s->repo == solv->installed)) - continue; - if (!s->recommends) - continue; - recp = s->repo->idarraydata + s->recommends; - while ((rec = *recp++) != 0) - { - queue_empty(&dq); -#ifdef ENABLE_COMPLEX_DEPS - if (pool_is_complex_dep(pool, rec)) - add_complex_recommends(solv, rec, &dq, &dqmap); - else -#endif - FOR_PROVIDES(p, pp, rec) - { - if (solv->decisionmap[p] > 0) - { - dq.count = 0; - break; - } - else if (solv->decisionmap[p] == 0 && MAPTST(&dqmap, p)) - queue_push(&dq, p); - } - if (!dq.count) - continue; - if (dq.count > 1) - policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE); - /* if we have multiple candidates we open a branch */ - if (dq.count > 1) - createbranch(solv, level, &dq, s - pool->solvables, rec); - p = dq.elements[0]; - POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended %s\n", pool_solvid2str(pool, p)); - olevel = level; - level = setpropagatelearn(solv, level, p, 0, 0); - if (level <= olevel || solv->decisionq.count < decisioncount) - break; /* we had to revert some decisions */ - } - if (rec) - break; /* had a problem above, quit loop */ - } - map_free(&dqmap); - continue; /* back to main loop so that all deps are checked */ - } + if (doweak) + { + int rerun = 0; + level = resolve_weak(solv, level, disablerules, &dq, &dqs, &rerun); + if (rerun) + continue; } - if (!solv->decisioncnt_orphan) - solv->decisioncnt_orphan = solv->decisionq.count; - if (solv->dupmap_all && solv->installed) + if (solv->installed && (solv->orphaned.count || solv->brokenorphanrules)) { - int installedone = 0; - - /* let's see if we can install some unsupported package */ - POOL_DEBUG(SOLV_DEBUG_SOLVER, "deciding orphaned packages\n"); - for (i = 0; i < solv->orphaned.count; i++) - { - p = solv->orphaned.elements[i]; - if (solv->decisionmap[p]) - continue; /* already decided */ - if (solv->droporphanedmap_all) - continue; - if (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start)) - continue; - POOL_DEBUG(SOLV_DEBUG_SOLVER, "keeping orphaned %s\n", pool_solvid2str(pool, p)); - olevel = level; - level = setpropagatelearn(solv, level, p, 0, 0); - installedone = 1; - if (level < olevel) - break; - } - if (installedone || i < solv->orphaned.count) - continue; /* back to main loop */ - for (i = 0; i < solv->orphaned.count; i++) - { - p = solv->orphaned.elements[i]; - if (solv->decisionmap[p]) - continue; /* already decided */ - POOL_DEBUG(SOLV_DEBUG_SOLVER, "removing orphaned %s\n", pool_solvid2str(pool, p)); - olevel = level; - level = setpropagatelearn(solv, level, -p, 0, 0); - if (level < olevel) - break; - } - if (i < solv->orphaned.count) - continue; /* back to main loop */ - if (solv->brokenorphanrules) - { - solver_check_brokenorphanrules(solv, &dq); - if (dq.count) - { - policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE); - for (i = 0; i < dq.count; i++) - { - p = dq.elements[i]; - POOL_DEBUG(SOLV_DEBUG_POLICY, "installing orphaned dep %s\n", pool_solvid2str(pool, p)); - olevel = level; - level = setpropagatelearn(solv, level, p, 0, 0); - if (level < olevel) - break; - } - continue; - } - } + int rerun = 0; + level = resolve_orphaned(solv, level, disablerules, &dq, &rerun); + if (rerun) + continue; } - + /* one final pass to make sure we decided all installed packages */ if (solv->installed) { @@ -2783,7 +2930,7 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) continue; POOL_DEBUG(SOLV_DEBUG_SOLVER, "removing unwanted %s\n", pool_solvid2str(pool, p)); olevel = level; - level = setpropagatelearn(solv, level, -p, 0, 0); + level = setpropagatelearn(solv, level, -p, 0, 0, SOLVER_REASON_CLEANDEPS_ERASE); if (level < olevel) break; } @@ -2853,6 +3000,8 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) lastsi = -1; break; } + if (solv->isdisfavormap.size && MAPTST(&solv->isdisfavormap, p)) + continue; if (lastsi < 0 && (MAPTST(&solv->recommendsmap, p) || solver_is_supplementing(solv, pool->solvables + p))) lastsi = i; } @@ -2865,6 +3014,9 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) p = -solv->branches.elements[i]; if (p <= 0 || solv->decisionmap[p] != l + 1) continue; + if (solv->favormap.size && MAPTST(&solv->favormap, p)) + if (!(solv->isdisfavormap.size && MAPTST(&solv->isdisfavormap, p))) + continue; /* current selection is favored */ if (!(MAPTST(&solv->recommendsmap, p) || solver_is_supplementing(solv, pool->solvables + p))) { lasti = lastsi; @@ -2885,22 +3037,13 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) /* no minimization found, we're finally finished! */ break; } + assert(level == -1 || level + 1 == solv->decisionq_reason.count); POOL_DEBUG(SOLV_DEBUG_STATS, "solver statistics: %d learned rules, %d unsolvable, %d minimization steps\n", solv->stats_learned, solv->stats_unsolvable, minimizationsteps); POOL_DEBUG(SOLV_DEBUG_STATS, "done solving.\n\n"); queue_free(&dq); queue_free(&dqs); - if (level < 0) - { - /* unsolvable */ - solv->decisioncnt_jobs = solv->decisionq.count; - solv->decisioncnt_update = solv->decisionq.count; - solv->decisioncnt_keep = solv->decisionq.count; - solv->decisioncnt_resolve = solv->decisionq.count; - solv->decisioncnt_weak = solv->decisionq.count; - solv->decisioncnt_orphan = solv->decisionq.count; - } #if 0 solver_printdecisionq(solv, SOLV_DEBUG_RESULT); #endif @@ -3076,8 +3219,10 @@ solver_calculate_multiversionmap(Pool *pool, Queue *job, Map *multiversionmap) Solvable *s; Repo *repo = pool_id2repo(pool, what); if (repo) - FOR_REPO_SOLVABLES(repo, p, s) - MAPSET(multiversionmap, p); + { + FOR_REPO_SOLVABLES(repo, p, s) + MAPSET(multiversionmap, p); + } } FOR_JOB_SELECT(p, pp, select, what) MAPSET(multiversionmap, p); @@ -3330,6 +3475,42 @@ add_complex_jobrules(Solver *solv, Id dep, int flags, int jobidx, int weak) } #endif +/* sort by package id, last entry wins */ +static int +setup_favormaps_cmp(const void *ap, const void *bp, void *dp) +{ + const Id *a = ap, *b = bp; + if ((*a - *b) != 0) + return *a - *b; + return (b[1] < 0 ? -b[1] : b[1]) - (a[1] < 0 ? -a[1] : a[1]); +} + +static void +setup_favormaps(Solver *solv) +{ + Queue *q = solv->favorq; + Pool *pool = solv->pool; + int i; + Id oldp = 0; + if (q->count > 2) + solv_sort(q->elements, q->count / 2, 2 * sizeof(Id), setup_favormaps_cmp, solv); + map_grow(&solv->favormap, pool->nsolvables); + for (i = 0; i < q->count; i += 2) + { + Id p = q->elements[i]; + if (p == oldp) + continue; + oldp = p; + MAPSET(&solv->favormap, p); + if (q->elements[i + 1] < 0) + { + if (!solv->isdisfavormap.size) + map_grow(&solv->isdisfavormap, pool->nsolvables); + MAPSET(&solv->isdisfavormap, p); + } + } +} + /* * * solve job queue @@ -3350,7 +3531,7 @@ solver_solve(Solver *solv, Queue *job) Solvable *s; Rule *r; int now, solve_start; - int hasdupjob = 0; + int needduprules = 0; int hasbestinstalljob = 0; solve_start = solv_timems(0); @@ -3403,6 +3584,8 @@ solver_solve(Solver *solv, Queue *job) map_zerosize(&solv->allowuninstallmap); map_zerosize(&solv->cleandepsmap); map_zerosize(&solv->weakrulemap); + map_zerosize(&solv->favormap); + map_zerosize(&solv->isdisfavormap); queue_empty(&solv->weakruleq); solv->watches = solv_free(solv->watches); queue_empty(&solv->ruletojob); @@ -3410,7 +3593,7 @@ solver_solve(Solver *solv, Queue *job) memset(solv->decisionmap, 0, pool->nsolvables * sizeof(Id)); queue_empty(&solv->decisionq); queue_empty(&solv->decisionq_why); - solv->decisioncnt_jobs = solv->decisioncnt_update = solv->decisioncnt_keep = solv->decisioncnt_resolve = solv->decisioncnt_weak = solv->decisioncnt_orphan = 0; + queue_empty(&solv->decisionq_reason); queue_empty(&solv->learnt_why); queue_empty(&solv->learnt_pool); queue_empty(&solv->branches); @@ -3457,6 +3640,7 @@ solver_solve(Solver *solv, Queue *job) if (solv->nrules != initialnrules) solver_shrinkrules(solv, initialnrules); solv->nrules = initialnrules; + solv->lastpkgrule = 0; solv->pkgrules_end = 0; if (installed) @@ -3561,6 +3745,19 @@ solver_solve(Solver *solv, Queue *job) MAPSET(&solv->droporphanedmap, p - installed->start); } break; + case SOLVER_ALLOWUNINSTALL: + if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && installed && what == installed->repoid)) + solv->allowuninstall_all = 1; + FOR_JOB_SELECT(p, pp, select, what) + { + s = pool->solvables + p; + if (s->repo != installed) + continue; + if (!solv->allowuninstallmap.size) + map_grow(&solv->allowuninstallmap, installed->end - installed->start); + MAPSET(&solv->allowuninstallmap, p - installed->start); + } + break; default: break; } @@ -3608,8 +3805,10 @@ solver_solve(Solver *solv, Queue *job) if (how & SOLVER_FORCEBEST) solv->bestupdatemap_all = 1; } - if (!solv->dupmap_all || solv->allowuninstall) - hasdupjob = 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; break; default: break; @@ -3655,6 +3854,7 @@ solver_solve(Solver *solv, Queue *job) if (solv->nrules > initialnrules) solver_unifyrules(solv); /* remove duplicate pkg rules */ solv->pkgrules_end = solv->nrules; /* mark end of pkg rules */ + solv->lastpkgrule = 0; if (solv->nrules > initialnrules) addedmap2deduceq(solv, &addedmap); /* so that we can recreate the addedmap */ @@ -3664,7 +3864,7 @@ solver_solve(Solver *solv, Queue *job) /* create dup maps if needed. We need the maps early to create our * update rules */ - if (hasdupjob) + if (needduprules) solver_createdupmaps(solv); /* @@ -3690,7 +3890,7 @@ solver_solve(Solver *solv, Queue *job) solver_addrule(solv, 0, 0, 0); /* create dummy rule */ continue; } - solver_addupdaterule(solv, s, 1); /* allow s to be updated */ + solver_addfeaturerule(solv, s); } /* make sure we accounted for all rules */ assert(solv->nrules - solv->featurerules == installed->end - installed->start); @@ -3718,20 +3918,25 @@ solver_solve(Solver *solv, Queue *job) solver_addrule(solv, 0, 0, 0); /* create dummy rule */ continue; } - solver_addupdaterule(solv, s, 0); /* allowall = 0: downgrades not allowed */ + solver_addupdaterule(solv, s); /* * check for and remove duplicate */ r = solv->rules + solv->nrules - 1; /* r: update rule */ - if (!r->p) - continue; sr = r - (installed->end - installed->start); /* sr: feature rule */ + if (!r->p) + { + if (sr->p) + memset(sr, 0, sizeof(*sr)); /* no feature rules without update rules */ + 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) queue_push(&solv->orphaned, i); + if (!solver_rulecmp(solv, r, sr)) memset(sr, 0, sizeof(*sr)); /* delete unneeded feature rule */ - else + else if (sr->p) solver_disablerule(solv, sr); /* disable feature rule for now */ } /* consistency check: we added a rule for _every_ installed solvable */ @@ -3824,8 +4029,10 @@ solver_solve(Solver *solv, Queue *job) { Repo *repo = pool_id2repo(pool, what); if (repo) - FOR_REPO_SOLVABLES(repo, p, s) - solver_addjobrule(solv, -p, 0, 0, i, weak); + { + FOR_REPO_SOLVABLES(repo, p, s) + solver_addjobrule(solv, -p, 0, 0, i, weak); + } } #ifdef ENABLE_COMPLEX_DEPS else if ((select == SOLVER_SOLVABLE_PROVIDES || select == SOLVER_SOLVABLE_NAME) && pool_is_complex_dep(pool, what)) @@ -3900,8 +4107,10 @@ solver_solve(Solver *solv, Queue *job) { Repo *repo = pool_id2repo(pool, what); if (repo) - FOR_REPO_SOLVABLES(repo, p, s) - solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, 0, i, weak); + { + FOR_REPO_SOLVABLES(repo, p, s) + solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, 0, i, weak); + } } FOR_JOB_SELECT(p, pp, select, what) solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, 0, i, weak); @@ -3917,16 +4126,20 @@ solver_solve(Solver *solv, Queue *job) break; case SOLVER_ALLOWUNINSTALL: POOL_DEBUG(SOLV_DEBUG_JOB, "job: allowuninstall %s\n", solver_select2str(pool, select, what)); - if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && installed && what == installed->repoid)) - solv->allowuninstall_all = 1; + break; + case SOLVER_FAVOR: + case SOLVER_DISFAVOR: + POOL_DEBUG(SOLV_DEBUG_JOB, "job: %s %s\n", (how & SOLVER_JOBMASK) == SOLVER_FAVOR ? "favor" : "disfavor", solver_select2str(pool, select, what)); FOR_JOB_SELECT(p, pp, select, what) { - s = pool->solvables + p; - if (s->repo != installed) - continue; - if (!solv->allowuninstallmap.size) - map_grow(&solv->allowuninstallmap, installed->end - installed->start); - MAPSET(&solv->allowuninstallmap, p - installed->start); + int j; + if (!solv->favorq) + { + solv->favorq = solv_calloc(1, sizeof(Queue)); + queue_init(solv->favorq); + } + j = solv->favorq->count + 1; + queue_push2(solv->favorq, p, (how & SOLVER_JOBMASK) == SOLVER_FAVOR ? j : -j); } break; default: @@ -3949,6 +4162,10 @@ solver_solve(Solver *solv, Queue *job) assert(solv->ruletojob.count == solv->nrules - solv->jobrules); solv->jobrules_end = solv->nrules; + /* transform favorq into two maps */ + if (solv->favorq) + setup_favormaps(solv); + /* now create infarch and dup rules */ if (!solv->noinfarchcheck) { @@ -3966,17 +4183,22 @@ solver_solve(Solver *solv, Queue *job) else solv->infarchrules = solv->infarchrules_end = solv->nrules; - if (hasdupjob) + if (needduprules) solver_addduprules(solv, &addedmap); else solv->duprules = solv->duprules_end = solv->nrules; +#ifdef ENABLE_LINKED_PKGS + if (solv->instbuddy && solv->updatemap.size) + extend_updatemap_to_buddies(solv); +#endif + if (solv->bestupdatemap_all || solv->bestupdatemap.size || hasbestinstalljob) solver_addbestrules(solv, hasbestinstalljob); else solv->bestrules = solv->bestrules_end = solv->nrules; - if (hasdupjob) + if (needduprules) solver_freedupmaps(solv); /* no longer needed */ if (solv->do_yum_obsoletes) @@ -4008,7 +4230,7 @@ solver_solve(Solver *solv, Queue *job) POOL_DEBUG(SOLV_DEBUG_STATS, "overall rule memory used: %d K\n", solv->nrules * (int)sizeof(Rule) / 1024); /* create weak map */ - if (solv->weakruleq.count) + if (solv->weakruleq.count || solv->recommendsruleq) { map_grow(&solv->weakrulemap, solv->nrules); for (i = 0; i < solv->weakruleq.count; i++) @@ -4016,6 +4238,14 @@ solver_solve(Solver *solv, Queue *job) p = solv->weakruleq.elements[i]; MAPSET(&solv->weakrulemap, p); } + if (solv->recommendsruleq) + { + for (i = 0; i < solv->recommendsruleq->count; i++) + { + p = solv->recommendsruleq->elements[i]; + MAPSET(&solv->weakrulemap, p); + } + } } /* enable cleandepsmap creation if we have updatepkgs */ @@ -4148,20 +4378,12 @@ void solver_get_recommendations(Solver *solv, Queue *recommendationsq, Queue *su MAPZERO(&solv->recommendsmap); /* put all packages the solver already chose in the map */ - if (solv->decisioncnt_weak) - { - for (i = solv->decisioncnt_weak; i < solv->decisioncnt_orphan; i++) - { - Id why; - why = solv->decisionq_why.elements[i]; - if (why) - continue; /* forced by unit rule or dep resolving */ - p = solv->decisionq.elements[i]; - if (p < 0) - continue; + for (i = 1; i < solv->decisionq.count; i++) + if ((p = solv->decisionq.elements[i]) > 0 && solv->decisionq_why.elements[i] == 0) + { + if (solv->decisionq_reason.elements[solv->decisionmap[p]] == SOLVER_REASON_WEAKDEP) MAPSET(&solv->recommendsmap, p); - } - } + } for (i = 0; i < solv->decisionq.count; i++) { @@ -4349,24 +4571,6 @@ solver_create_state_maps(Solver *solv, Map *installedmap, Map *conflictsmap) pool_create_state_maps(solv->pool, &solv->decisionq, installedmap, conflictsmap); } -void -solver_trivial_installable(Solver *solv, Queue *pkgs, Queue *res) -{ - Pool *pool = solv->pool; - Map installedmap; - int i; - pool_create_state_maps(pool, &solv->decisionq, &installedmap, 0); - pool_trivial_installable_multiversionmap(pool, &installedmap, pkgs, res, solv->multiversion.size ? &solv->multiversion : 0); - for (i = 0; i < res->count; i++) - if (res->elements[i] != -1) - { - Solvable *s = pool->solvables + pkgs->elements[i]; - if (!strncmp("patch:", pool_id2str(pool, s->name), 6) && solvable_is_irrelevant_patch(s, &installedmap)) - res->elements[i] = -1; - } - map_free(&installedmap); -} - /*------------------------------------------------------------------- * * decision introspection @@ -4447,31 +4651,8 @@ solver_describe_decision(Solver *solv, Id p, Id *infop) *infop = why > 0 ? why : -why; if (why > 0) return SOLVER_REASON_UNIT_RULE; - why = -why; - if (i == 0) - return SOLVER_REASON_KEEP_INSTALLED; /* the systemsolvable */ - if (i < solv->decisioncnt_update) - return SOLVER_REASON_RESOLVE_JOB; - if (i < solv->decisioncnt_keep) - { - if (why == 0 && pp < 0) - return SOLVER_REASON_CLEANDEPS_ERASE; - return SOLVER_REASON_UPDATE_INSTALLED; - } - if (i < solv->decisioncnt_resolve) - { - if (solv->focus_installed && i >= solv->decisioncnt_jobs) - return SOLVER_REASON_RESOLVE_JOB; - if (why == 0 && pp < 0) - return SOLVER_REASON_CLEANDEPS_ERASE; - return SOLVER_REASON_KEEP_INSTALLED; - } - if (why > 0) - return SOLVER_REASON_RESOLVE; - /* weak or orphaned */ - if (i < solv->decisioncnt_orphan) - return SOLVER_REASON_WEAKDEP; - return SOLVER_REASON_RESOLVE_ORPHAN; + i = solv->decisionmap[p] >= 0 ? solv->decisionmap[p] : -solv->decisionmap[p]; + return solv->decisionq_reason.elements[i]; } @@ -4492,7 +4673,8 @@ solver_describe_weakdep_decision(Solver *solv, Id p, Queue *whyq) break; if (decisionno == solv->decisionq.count) return; /* huh? */ - if (decisionno < solv->decisioncnt_weak || decisionno >= solv->decisioncnt_orphan) + i = solv->decisionmap[p] >= 0 ? solv->decisionmap[p] : -solv->decisionmap[p]; + if (solv->decisionq_reason.elements[i] != SOLVER_REASON_WEAKDEP) return; /* huh? */ /* 1) list all packages that recommend us */ @@ -4593,8 +4775,10 @@ pool_job2solvables(Pool *pool, Queue *pkgs, Id how, Id what) Repo *repo = pool_id2repo(pool, what); Solvable *s; if (repo) - FOR_REPO_SOLVABLES(repo, p, s) - queue_push(pkgs, p); + { + FOR_REPO_SOLVABLES(repo, p, s) + queue_push(pkgs, p); + } } else { @@ -4750,8 +4934,10 @@ solver_get_userinstalled(Solver *solv, Queue *q, int flags) what = solv->job.elements[i + 1]; select = how & SOLVER_SELECTMASK; if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid)) - FOR_REPO_SOLVABLES(installed, p, s) - MAPSET(&userinstalled, p - installed->start); + { + FOR_REPO_SOLVABLES(installed, p, s) + MAPSET(&userinstalled, p - installed->start); + } FOR_JOB_SELECT(p, pp, select, what) if (pool->solvables[p].repo == installed) MAPSET(&userinstalled, p - installed->start); @@ -5141,6 +5327,12 @@ pool_job2str(Pool *pool, Id how, Id what, Id flagmask) case SOLVER_ALLOWUNINSTALL: strstart = "allow deinstallation of "; break; + case SOLVER_FAVOR: + strstart = "favor "; + break; + case SOLVER_DISFAVOR: + strstart = "disfavor "; + break; default: strstart = "unknown job "; break;