X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fsolver.c;h=403d9f8556b5a9413ca1b14b1bf5350e2b9d2a65;hb=a52836206e91b14de83ffa1f9cce7194066f314f;hp=538b786ab1da0fc202952cd1126089cf44e273b8;hpb=1c1cd3cd70b42fa97022b5817f6f051e15e6b148;p=platform%2Fupstream%2Flibsolv.git diff --git a/src/solver.c b/src/solver.c index 538b786..403d9f8 100644 --- a/src/solver.c +++ b/src/solver.c @@ -26,6 +26,7 @@ #include "poolarch.h" #include "solverdebug.h" #include "cplxdeps.h" +#include "linkedpkg.h" #define RULES_BLOCK 63 @@ -1133,7 +1134,7 @@ analyze_unsolvable(Solver *solv, Rule *cr, int disablerules) { v = solv->decisionq.elements[--idx]; vv = v > 0 ? v : -v; - if (!MAPTST(&seen, vv)) + if (!MAPTST(&seen, vv) || vv == SYSTEMSOLVABLE) continue; why = solv->decisionq_why.elements[idx]; assert(why > 0); @@ -1249,6 +1250,8 @@ revert(Solver *solv, int level) } 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) @@ -1447,7 +1450,9 @@ selectandinstall(Solver *solv, int level, Queue *dq, int disablerules, Id ruleid break; } } - if (dq->count > 1 && ruleid >= solv->jobrules && ruleid < solv->jobrules_end && solv->installed) + /* if we're resolving job 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) { @@ -1526,6 +1531,83 @@ 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 == 0) + return 0; /* unsolvable */ + 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; +} + /*------------------------------------------------------------------- * * solver_free @@ -1572,6 +1654,7 @@ solver_free(Solver *solv) queuep_free(&solv->installsuppdepq); queuep_free(&solv->recommendscplxq); queuep_free(&solv->suggestscplxq); + queuep_free(&solv->brokenorphanrules); map_free(&solv->recommendsmap); map_free(&solv->suggestsmap); @@ -1630,6 +1713,20 @@ solver_get_flag(Solver *solv, int flag) return solv->bestobeypolicy; case SOLVER_FLAG_NO_AUTOTARGET: return solv->noautotarget; + case SOLVER_FLAG_DUP_ALLOW_DOWNGRADE: + return solv->dup_allowdowngrade; + case SOLVER_FLAG_DUP_ALLOW_NAMECHANGE: + return solv->dup_allownamechange; + case SOLVER_FLAG_DUP_ALLOW_ARCHCHANGE: + return solv->dup_allowarchchange; + case SOLVER_FLAG_DUP_ALLOW_VENDORCHANGE: + return solv->dup_allowvendorchange; + case SOLVER_FLAG_KEEP_ORPHANS: + return solv->keep_orphans; + case SOLVER_FLAG_BREAK_ORPHANS: + return solv->break_orphans; + case SOLVER_FLAG_FOCUS_INSTALLED: + return solv->focus_installed; default: break; } @@ -1681,6 +1778,27 @@ solver_set_flag(Solver *solv, int flag, int value) case SOLVER_FLAG_NO_AUTOTARGET: solv->noautotarget = value; break; + case SOLVER_FLAG_DUP_ALLOW_DOWNGRADE: + solv->dup_allowdowngrade = value; + break; + case SOLVER_FLAG_DUP_ALLOW_NAMECHANGE: + solv->dup_allownamechange = value; + break; + case SOLVER_FLAG_DUP_ALLOW_ARCHCHANGE: + solv->dup_allowarchchange = value; + break; + case SOLVER_FLAG_DUP_ALLOW_VENDORCHANGE: + solv->dup_allowvendorchange = value; + break; + case SOLVER_FLAG_KEEP_ORPHANS: + solv->keep_orphans = value; + break; + case SOLVER_FLAG_BREAK_ORPHANS: + solv->break_orphans = value; + break; + case SOLVER_FLAG_FOCUS_INSTALLED: + solv->focus_installed = value; + break; default: break; } @@ -1960,74 +2078,27 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) } /* - * resolve jobs first + * resolve jobs first (unless focus_installed is set) */ - if (level < systemlevel) + if (level < systemlevel && !solv->focus_installed) { - POOL_DEBUG(SOLV_DEBUG_SOLVER, "resolving job rules\n"); - for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++) + olevel = level; + level = resolve_jobrules(solv, level, disablerules, &dq); + if (level < olevel) { - Id l; - 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 == 0) - break; - if (level <= olevel) - break; + break; /* unsolvable */ + continue; } - if (level == 0) - break; /* unsolvable */ systemlevel = level + 1; - if (i < solv->jobrules_end) - continue; - if (!solv->decisioncnt_update) - solv->decisioncnt_update = solv->decisionq.count; } + /* * 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; @@ -2064,7 +2135,7 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) rr -= solv->installed->end - solv->installed->start; if (!rr->p) /* identical to update rule? */ rr = r; - if (!rr->p && (!specialupdaters || !specialupdaters[i - installed->start])) + if (!rr->p && !(specialupdaters && specialupdaters[i - installed->start])) continue; /* orpaned package */ /* check if we should update this package to the latest version @@ -2074,7 +2145,21 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) 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) + 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) @@ -2084,7 +2169,7 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) 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 && rr->p) + if (dq.count) { policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE); p = dq.elements[0]; @@ -2186,6 +2271,19 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) 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) + { + if (level == 0) + break; /* unsolvable */ + continue; + } + systemlevel = level + 1; + } + if (level < systemlevel) systemlevel = level; @@ -2642,6 +2740,26 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) break; 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; + } + if (level == 0) + break; + continue; + } + } } /* one final pass to make sure we decided all installed packages */ @@ -2762,6 +2880,7 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) 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; @@ -3241,7 +3360,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_update = solv->decisioncnt_keep = solv->decisioncnt_resolve = solv->decisioncnt_weak = solv->decisioncnt_orphan = 0; + solv->decisioncnt_jobs = solv->decisioncnt_update = solv->decisioncnt_keep = solv->decisioncnt_resolve = solv->decisioncnt_weak = solv->decisioncnt_orphan = 0; queue_empty(&solv->learnt_why); queue_empty(&solv->learnt_pool); queue_empty(&solv->branches); @@ -3258,6 +3377,7 @@ solver_solve(Solver *solv, Queue *job) queuep_free(&solv->suggestscplxq); solv->recommends_index = 0; } + queuep_free(&solv->brokenorphanrules); solv->specialupdaters = solv_free(solv->specialupdaters); @@ -3292,6 +3412,7 @@ solver_solve(Solver *solv, Queue *job) if (installed) { /* check for update/verify jobs as they need to be known early */ + /* also setup the droporphaned map, we need it when creating update rules */ for (i = 0; i < job->count; i += 2) { how = job->elements[i]; @@ -3377,6 +3498,19 @@ solver_solve(Solver *solv, Queue *job) add_update_target(solv, p, how); } break; + case SOLVER_DROP_ORPHANED: + if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid)) + solv->droporphanedmap_all = 1; + FOR_JOB_SELECT(p, pp, select, what) + { + s = pool->solvables + p; + if (s->repo != installed) + continue; + if (!solv->droporphanedmap.size) + map_grow(&solv->droporphanedmap, installed->end - installed->start); + MAPSET(&solv->droporphanedmap, p - installed->start); + } + break; default: break; } @@ -3539,20 +3673,16 @@ solver_solve(Solver *solv, Queue *job) * 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 */ - /* it's orphaned if there is no feature rule or the feature rule - * consists just of the installed package */ - if (!sr->p || (sr->p == i && !sr->d && !sr->w2)) + /* 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 (!r->p) - { - /* assert(solv->dupmap_all && !sr->p); */ - continue; - } if (!solver_rulecmp(solv, r, sr)) memset(sr, 0, sizeof(*sr)); /* delete unneeded feature rule */ else - solver_disablerule(solv, sr); /* disable feature rule */ + solver_disablerule(solv, sr); /* disable feature rule for now */ } /* consistency check: we added a rule for _every_ installed solvable */ assert(solv->nrules - solv->updaterules == installed->end - installed->start); @@ -3714,17 +3844,6 @@ solver_solve(Solver *solv, Queue *job) break; case SOLVER_DROP_ORPHANED: POOL_DEBUG(SOLV_DEBUG_JOB, "job: drop orphaned %s\n", solver_select2str(pool, select, what)); - if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && installed && what == installed->repoid)) - solv->droporphanedmap_all = 1; - FOR_JOB_SELECT(p, pp, select, what) - { - s = pool->solvables + p; - if (!installed || s->repo != installed) - continue; - if (!solv->droporphanedmap.size) - map_grow(&solv->droporphanedmap, installed->end - installed->start); - MAPSET(&solv->droporphanedmap, p - installed->start); - } break; case SOLVER_USERINSTALLED: POOL_DEBUG(SOLV_DEBUG_JOB, "job: user installed %s\n", solver_select2str(pool, select, what)); @@ -3734,10 +3853,6 @@ solver_solve(Solver *solv, Queue *job) break; } - /* - * debug - */ - IF_POOLDEBUG (SOLV_DEBUG_JOB) { int j; @@ -3839,6 +3954,10 @@ solver_solve(Solver *solv, Queue *job) /* disable update rules that conflict with our job */ solver_disablepolicyrules(solv); + /* break orphans if requested */ + if (solv->dupmap_all && solv->orphaned.count && solv->break_orphans) + solver_breakorphans(solv); + /* make initial decisions based on assertion rules */ makeruledecisions(solv); POOL_DEBUG(SOLV_DEBUG_SOLVER, "problems so far: %d\n", solv->problems.count); @@ -4244,12 +4363,10 @@ solver_describe_decision(Solver *solv, Id p, Id *infop) 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) - { - if (i == 0) - return SOLVER_REASON_KEEP_INSTALLED; - return SOLVER_REASON_RESOLVE_JOB; - } + return SOLVER_REASON_RESOLVE_JOB; if (i < solv->decisioncnt_keep) { if (why == 0 && pp < 0) @@ -4258,6 +4375,8 @@ solver_describe_decision(Solver *solv, Id p, Id *infop) } 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; @@ -4265,7 +4384,7 @@ solver_describe_decision(Solver *solv, Id p, Id *infop) if (why > 0) return SOLVER_REASON_RESOLVE; /* weak or orphaned */ - if (solv->decisionq.count < solv->decisioncnt_orphan) + if (i < solv->decisioncnt_orphan) return SOLVER_REASON_WEAKDEP; return SOLVER_REASON_RESOLVE_ORPHAN; } @@ -4320,7 +4439,7 @@ solver_describe_weakdep_decision(Solver *solv, Id p, Queue *whyq) if (!p2 && found) { queue_push(whyq, SOLVER_REASON_RECOMMENDED); - queue_push2(whyq, p2, rec); + queue_push2(whyq, i, rec); } } } @@ -4446,6 +4565,250 @@ pool_isemptyupdatejob(Pool *pool, Id how, Id what) return 1; } +static int +get_userinstalled_cmp(const void *ap, const void *bp, void *dp) +{ + return *(Id *)ap - *(Id *)bp; +} + +static int +get_userinstalled_cmp_names(const void *ap, const void *bp, void *dp) +{ + Pool *pool = dp; + return strcmp(pool_id2str(pool, *(Id *)ap), pool_id2str(pool, *(Id *)bp)); +} + +static void +get_userinstalled_sort_uniq(Pool *pool, Queue *q, int flags) +{ + Id lastp = -1; + int i, j; + if ((flags & GET_USERINSTALLED_NAMES) != 0) + solv_sort(q->elements, q->count, sizeof(Id), get_userinstalled_cmp_names, pool); + else + solv_sort(q->elements, q->count, sizeof(Id), get_userinstalled_cmp, 0); + for (i = j = 0; i < q->count; i++) + if (q->elements[i] != lastp) + q->elements[j++] = lastp = q->elements[i]; + queue_truncate(q, j); +} + +void +solver_get_userinstalled(Solver *solv, Queue *q, int flags) +{ + Pool *pool = solv->pool; + Id p, p2, pp; + Solvable *s; + Repo *installed = solv->installed; + int i, j; + Map userinstalled; + + map_init(&userinstalled, 0); + queue_empty(q); + /* first process jobs */ + for (i = 0; i < solv->job.count; i += 2) + { + Id how = solv->job.elements[i]; + Id what, select; + if (installed && (how & SOLVER_JOBMASK) == SOLVER_USERINSTALLED) + { + if (!userinstalled.size) + map_grow(&userinstalled, installed->end - installed->start); + 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_JOB_SELECT(p, pp, select, what) + if (pool->solvables[p].repo == installed) + MAPSET(&userinstalled, p - installed->start); + continue; + } + if ((how & SOLVER_JOBMASK) != SOLVER_INSTALL) + continue; + if ((how & SOLVER_NOTBYUSER) != 0) + continue; + what = solv->job.elements[i + 1]; + select = how & SOLVER_SELECTMASK; + FOR_JOB_SELECT(p, pp, select, what) + if (solv->decisionmap[p] > 0) + { + queue_push(q, p); +#ifdef ENABLE_LINKED_PKGS + if (has_package_link(pool, pool->solvables + p)) + { + int j; + Queue lq; + queue_init(&lq); + find_package_link(pool, pool->solvables + p, 0, &lq, 0, 0); + for (j = 0; j < lq.count; j++) + if (solv->decisionmap[lq.elements[j]] > 0) + queue_push(q, lq.elements[j]); + } +#endif + } + } + /* now process updates of userinstalled packages */ + if (installed && userinstalled.size) + { + for (i = 1; i < solv->decisionq.count; i++) + { + p = solv->decisionq.elements[i]; + if (p <= 0) + continue; + s = pool->solvables + p; + if (!s->repo) + continue; + if (s->repo == installed) + { + if (MAPTST(&userinstalled, p - installed->start)) + queue_push(q, p); + continue; + } + /* new package, check if we replace a userinstalled one */ + FOR_PROVIDES(p2, pp, s->name) + { + Solvable *ps = pool->solvables + p2; + if (p2 == p || ps->repo != installed || !MAPTST(&userinstalled, p2 - installed->start)) + continue; + if (!pool->implicitobsoleteusesprovides && s->name != ps->name) + continue; + if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps)) + continue; + queue_push(q, p); + break; + } + if (!p2 && s->repo != installed && s->obsoletes) + { + Id obs, *obsp = s->repo->idarraydata + s->obsoletes; + while ((obs = *obsp++) != 0) + { + FOR_PROVIDES(p2, pp, obs) + { + Solvable *ps = pool->solvables + p2; + if (p2 == p || ps->repo != installed || !MAPTST(&userinstalled, p2 - installed->start)) + continue; + if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs)) + continue; + if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps)) + continue; + queue_push(q, p); + break; + } + if (p2) + break; + } + } + } + } + map_free(&userinstalled); + /* convert to names if asked */ + if ((flags & GET_USERINSTALLED_NAMES) != 0) + { + for (i = 0; i < q->count; i++) + { + s = pool->solvables + q->elements[i]; + q->elements[i] = s->name; + } + } + /* sort and unify */ + if (q->count > 1) + get_userinstalled_sort_uniq(pool, q, flags); + /* invert if asked */ + if ((flags & GET_USERINSTALLED_INVERTED) != 0) + { + /* first generate queue with all installed packages */ + Queue invq; + queue_init(&invq); + for (i = 1; i < solv->decisionq.count; i++) + { + p = solv->decisionq.elements[i]; + if (p <= 0) + continue; + s = pool->solvables + p; + if (!s->repo) + continue; + if ((flags & GET_USERINSTALLED_NAMES) != 0) + queue_push(&invq, s->name); + else + queue_push(&invq, p); + } + /* push q on invq, just in case... */ + queue_insertn(&invq, invq.count, q->count, q->elements); + if (invq.count > 1) + get_userinstalled_sort_uniq(pool, &invq, flags); + /* subtract queues (easy as they are sorted and invq is a superset of q) */ + if (q->count) + { + for (i = j = 0; i < invq.count; i++) + if (invq.elements[i] == q->elements[j]) + { + invq.elements[i] = 0; + if (++j >= q->count) + break; + } + queue_empty(q); + } + for (i = j = 0; i < invq.count; i++) + if (invq.elements[i]) + queue_push(q, invq.elements[i]); + queue_free(&invq); + } +} + +void +pool_add_userinstalled_jobs(Pool *pool, Queue *q, Queue *job, int flags) +{ + int i; + + if (flags & GET_USERINSTALLED_INVERTED) + { + Queue invq; + Id p, lastid; + Solvable *s; + int bad; + if (!pool->installed) + return; + queue_init(&invq); + FOR_REPO_SOLVABLES(pool->installed, p, s) + queue_push(&invq, flags & GET_USERINSTALLED_NAMES ? s->name : p); + queue_insertn(&invq, invq.count, q->count, q->elements); + if (invq.count > 1) + get_userinstalled_sort_uniq(pool, &invq, flags); + /* now the fun part, add q again, sort, and remove all dups */ + queue_insertn(&invq, invq.count, q->count, q->elements); + if (invq.count > 1) + { + if ((flags & GET_USERINSTALLED_NAMES) != 0) + solv_sort(invq.elements, invq.count, sizeof(Id), get_userinstalled_cmp_names, pool); + else + solv_sort(invq.elements, invq.count, sizeof(Id), get_userinstalled_cmp, 0); + } + lastid = -1; + bad = 1; + for (i = 0; i < invq.count; i++) + { + if (invq.elements[i] == lastid) + { + bad = 1; + continue; + } + if (!bad) + queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), lastid); + bad = 0; + lastid = invq.elements[i]; + } + if (!bad) + queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), lastid); + queue_free(&invq); + } + else + { + for (i = 0; i < q->count; i++) + queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), q->elements[i]); + } +} + const char * solver_select2str(Pool *pool, Id select, Id what) { @@ -4529,7 +4892,7 @@ pool_job2str(Pool *pool, Id how, Id what, Id flagmask) strstart = "multi version "; break; case SOLVER_LOCK: - strstart = "update "; + strstart = "lock "; break; case SOLVER_DISTUPGRADE: strstart = "dist upgrade ";