+ Pool *pool = solv->pool;
+ Queue redoq, disabledq;
+ int goterase, i;
+ Solvable *s;
+ Rule *r;
+ Map obsmap;
+
+ if (!recommendationsq && !suggestionsq)
+ return;
+
+ map_init(&obsmap, pool->nsolvables);
+ if (solv->installed)
+ {
+ Id obs, *obsp, p, po, ppo;
+ 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->multiversion.size && MAPTST(&solv->multiversion, p))
+ continue;
+ obsp = s->repo->idarraydata + s->obsoletes;
+ /* foreach obsoletes */
+ while ((obs = *obsp++) != 0)
+ FOR_PROVIDES(po, ppo, obs)
+ MAPSET(&obsmap, po);
+ }
+ }
+
+ queue_init(&redoq);
+ queue_init(&disabledq);
+ goterase = 0;
+ /* disable all erase jobs (including weak "keep uninstalled" rules) */
+ for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++)
+ {
+ if (r->d < 0) /* disabled ? */
+ continue;
+ if (r->p >= 0) /* install job? */
+ continue;
+ queue_push(&disabledq, i);
+ solver_disablerule(solv, r);
+ goterase++;
+ }
+
+ if (goterase)
+ {
+ enabledisablelearntrules(solv);
+ removedisabledconflicts(solv, &redoq);
+ }
+
+ /*
+ * find recommended packages
+ */
+ if (recommendationsq)
+ {
+ Id rec, *recp, p, pp;
+
+ queue_empty(recommendationsq);
+ /* create map of all recommened packages */
+ solv->recommends_index = -1;
+ 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;
+ MAPSET(&solv->recommendsmap, p);
+ }
+ }
+
+ for (i = 0; i < solv->decisionq.count; i++)
+ {
+ p = solv->decisionq.elements[i];
+ if (p < 0)
+ continue;
+ s = pool->solvables + p;
+ if (s->recommends)
+ {
+ recp = s->repo->idarraydata + s->recommends;
+ while ((rec = *recp++) != 0)
+ {
+#ifdef ENABLE_COMPLEX_DEPS
+ if (pool_is_complex_dep(pool, rec))
+ {
+ do_complex_recommendations(solv, rec, &solv->recommendsmap, noselected);
+ continue;
+ }
+#endif
+ FOR_PROVIDES(p, pp, rec)
+ if (solv->decisionmap[p] > 0)
+ break;
+ if (p)
+ {
+ if (!noselected)
+ {
+ FOR_PROVIDES(p, pp, rec)
+ if (solv->decisionmap[p] > 0)
+ MAPSET(&solv->recommendsmap, p);
+ }
+ continue; /* p != 0: already fulfilled */
+ }
+ FOR_PROVIDES(p, pp, rec)
+ MAPSET(&solv->recommendsmap, p);
+ }
+ }
+ }
+ for (i = 1; i < pool->nsolvables; i++)
+ {
+ if (solv->decisionmap[i] < 0)
+ continue;
+ if (solv->decisionmap[i] > 0 && noselected)
+ continue;
+ if (MAPTST(&obsmap, i))
+ continue;
+ s = pool->solvables + i;
+ if (!MAPTST(&solv->recommendsmap, i))
+ {
+ if (!s->supplements)
+ continue;
+ if (!pool_installable(pool, s))
+ continue;
+ if (!solver_is_supplementing(solv, s))
+ continue;
+ }
+ queue_push(recommendationsq, i);
+ }
+ /* we use MODE_SUGGEST here so that repo prio is ignored */
+ policy_filter_unwanted(solv, recommendationsq, POLICY_MODE_SUGGEST);
+ }
+
+ /*
+ * find suggested packages
+ */
+
+ if (suggestionsq)
+ {
+ Id sug, *sugp, p, pp;
+
+ queue_empty(suggestionsq);
+ /* create map of all suggests that are still open */
+ solv->recommends_index = -1;
+ MAPZERO(&solv->suggestsmap);
+ for (i = 0; i < solv->decisionq.count; i++)
+ {
+ p = solv->decisionq.elements[i];
+ if (p < 0)
+ continue;
+ s = pool->solvables + p;
+ if (s->suggests)
+ {
+ sugp = s->repo->idarraydata + s->suggests;
+ while ((sug = *sugp++) != 0)
+ {
+#ifdef ENABLE_COMPLEX_DEPS
+ if (pool_is_complex_dep(pool, sug))
+ {
+ do_complex_recommendations(solv, sug, &solv->suggestsmap, noselected);
+ continue;
+ }
+#endif
+ FOR_PROVIDES(p, pp, sug)
+ if (solv->decisionmap[p] > 0)
+ break;
+ if (p)
+ {
+ if (!noselected)
+ {
+ FOR_PROVIDES(p, pp, sug)
+ if (solv->decisionmap[p] > 0)
+ MAPSET(&solv->suggestsmap, p);
+ }
+ continue; /* already fulfilled */
+ }
+ FOR_PROVIDES(p, pp, sug)
+ MAPSET(&solv->suggestsmap, p);
+ }
+ }
+ }
+ for (i = 1; i < pool->nsolvables; i++)
+ {
+ if (solv->decisionmap[i] < 0)
+ continue;
+ if (solv->decisionmap[i] > 0 && noselected)
+ continue;
+ if (MAPTST(&obsmap, i))
+ continue;
+ s = pool->solvables + i;
+ if (!MAPTST(&solv->suggestsmap, i))
+ {
+ if (!s->enhances)
+ continue;
+ if (!pool_installable(pool, s))
+ continue;
+ if (!solver_is_enhancing(solv, s))
+ continue;
+ }
+ queue_push(suggestionsq, i);
+ }
+ policy_filter_unwanted(solv, suggestionsq, POLICY_MODE_SUGGEST);
+ }
+
+ /* undo removedisabledconflicts */
+ if (redoq.count)
+ undo_removedisabledconflicts(solv, &redoq);
+ queue_free(&redoq);
+
+ /* undo job rule disabling */
+ for (i = 0; i < disabledq.count; i++)
+ solver_enablerule(solv, solv->rules + disabledq.elements[i]);
+ queue_free(&disabledq);
+ map_free(&obsmap);
+}
+
+
+/***********************************************************************/
+/* disk usage computations */
+
+/*-------------------------------------------------------------------
+ *
+ * calculate DU changes
+ */
+
+void
+solver_calc_duchanges(Solver *solv, DUChanges *mps, int nmps)
+{
+ Map installedmap;
+
+ solver_create_state_maps(solv, &installedmap, 0);
+ pool_calc_duchanges(solv->pool, &installedmap, mps, nmps);
+ map_free(&installedmap);
+}
+
+
+/*-------------------------------------------------------------------
+ *
+ * calculate changes in install size
+ */
+
+int
+solver_calc_installsizechange(Solver *solv)
+{
+ Map installedmap;
+ int change;
+
+ solver_create_state_maps(solv, &installedmap, 0);
+ change = pool_calc_installsizechange(solv->pool, &installedmap);
+ map_free(&installedmap);
+ return change;
+}
+
+void
+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
+ */
+
+int
+solver_get_decisionlevel(Solver *solv, Id p)
+{
+ return solv->decisionmap[p];
+}
+
+void
+solver_get_decisionqueue(Solver *solv, Queue *decisionq)
+{
+ queue_free(decisionq);
+ queue_init_clone(decisionq, &solv->decisionq);
+}
+
+int
+solver_get_lastdecisionblocklevel(Solver *solv)
+{
+ Id p;
+ if (solv->decisionq.count == 0)
+ return 0;
+ p = solv->decisionq.elements[solv->decisionq.count - 1];
+ if (p < 0)
+ p = -p;
+ return solv->decisionmap[p] < 0 ? -solv->decisionmap[p] : solv->decisionmap[p];
+}
+
+void
+solver_get_decisionblock(Solver *solv, int level, Queue *decisionq)
+{
+ Id p;
+ int i;
+
+ queue_empty(decisionq);
+ for (i = 0; i < solv->decisionq.count; i++)
+ {
+ p = solv->decisionq.elements[i];
+ if (p < 0)
+ p = -p;
+ if (solv->decisionmap[p] == level || solv->decisionmap[p] == -level)
+ break;
+ }
+ if (i == solv->decisionq.count)
+ return;
+ for (i = 0; i < solv->decisionq.count; i++)
+ {
+ p = solv->decisionq.elements[i];
+ if (p < 0)
+ p = -p;
+ if (solv->decisionmap[p] == level || solv->decisionmap[p] == -level)
+ queue_push(decisionq, p);
+ else
+ break;
+ }
+}
+
+int
+solver_describe_decision(Solver *solv, Id p, Id *infop)
+{
+ int i;
+ Id pp, why;
+
+ if (infop)
+ *infop = 0;
+ if (!solv->decisionmap[p])
+ return SOLVER_REASON_UNRELATED;
+ pp = solv->decisionmap[p] < 0 ? -p : p;
+ for (i = 0; i < solv->decisionq.count; i++)
+ if (solv->decisionq.elements[i] == pp)
+ break;
+ if (i == solv->decisionq.count) /* just in case... */
+ return SOLVER_REASON_UNRELATED;
+ why = solv->decisionq_why.elements[i];
+ if (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;
+}
+
+
+void
+solver_describe_weakdep_decision(Solver *solv, Id p, Queue *whyq)
+{
+ Pool *pool = solv->pool;
+ int i;
+ int level = solv->decisionmap[p];
+ int decisionno;
+ Solvable *s;
+
+ queue_empty(whyq);
+ if (level < 0)
+ return; /* huh? */
+ for (decisionno = 0; decisionno < solv->decisionq.count; decisionno++)
+ if (solv->decisionq.elements[decisionno] == p)
+ break;
+ if (decisionno == solv->decisionq.count)
+ return; /* huh? */
+ if (decisionno < solv->decisioncnt_weak || decisionno >= solv->decisioncnt_orphan)
+ return; /* huh? */
+
+ /* 1) list all packages that recommend us */
+ for (i = 1; i < pool->nsolvables; i++)
+ {
+ Id *recp, rec, pp2, p2;
+ if (solv->decisionmap[i] < 0 || solv->decisionmap[i] >= level)
+ continue;
+ s = pool->solvables + i;
+ if (!s->recommends)
+ continue;
+ if (!solv->addalreadyrecommended && s->repo == solv->installed)
+ continue;
+ recp = s->repo->idarraydata + s->recommends;
+ while ((rec = *recp++) != 0)
+ {
+ int found = 0;
+ FOR_PROVIDES(p2, pp2, rec)
+ {
+ if (p2 == p)
+ found = 1;
+ else
+ {
+ /* if p2 is already installed, this recommends is ignored */
+ if (solv->decisionmap[p2] > 0 && solv->decisionmap[p2] < level)
+ break;
+ }
+ }
+ if (!p2 && found)
+ {
+ queue_push(whyq, SOLVER_REASON_RECOMMENDED);
+ queue_push2(whyq, i, rec);
+ }
+ }
+ }
+ /* 2) list all supplements */
+ s = pool->solvables + p;
+ if (s->supplements && level > 0)
+ {
+ Id *supp, sup, pp2, p2;
+ /* this is a hack. to use solver_dep_fulfilled we temporarily clear
+ * everything above our level in the decisionmap */
+ for (i = decisionno; i < solv->decisionq.count; i++ )
+ {
+ p2 = solv->decisionq.elements[i];
+ if (p2 > 0)
+ solv->decisionmap[p2] = -solv->decisionmap[p2];
+ }
+ supp = s->repo->idarraydata + s->supplements;
+ while ((sup = *supp++) != 0)
+ if (solver_dep_fulfilled(solv, sup))
+ {
+ int found = 0;
+ /* let's see if this is an easy supp */
+ FOR_PROVIDES(p2, pp2, sup)
+ {
+ if (!solv->addalreadyrecommended && solv->installed)
+ {
+ if (pool->solvables[p2].repo == solv->installed)
+ continue;
+ }
+ if (solv->decisionmap[p2] > 0 && solv->decisionmap[p2] < level)
+ {
+ queue_push(whyq, SOLVER_REASON_SUPPLEMENTED);
+ queue_push2(whyq, p2, sup);
+ found = 1;
+ }
+ }
+ if (!found)
+ {
+ /* hard case, just note dependency with no package */
+ queue_push(whyq, SOLVER_REASON_SUPPLEMENTED);
+ queue_push2(whyq, 0, sup);
+ }
+ }
+ for (i = decisionno; i < solv->decisionq.count; i++)
+ {
+ p2 = solv->decisionq.elements[i];
+ if (p2 > 0)
+ solv->decisionmap[p2] = -solv->decisionmap[p2];
+ }
+ }
+}
+
+void
+pool_job2solvables(Pool *pool, Queue *pkgs, Id how, Id what)
+{
+ Id p, pp;
+ how &= SOLVER_SELECTMASK;
+ queue_empty(pkgs);
+ if (how == SOLVER_SOLVABLE_ALL)
+ {
+ FOR_POOL_SOLVABLES(p)
+ queue_push(pkgs, p);
+ }
+ else if (how == SOLVER_SOLVABLE_REPO)
+ {
+ Repo *repo = pool_id2repo(pool, what);
+ Solvable *s;
+ if (repo)
+ FOR_REPO_SOLVABLES(repo, p, s)
+ queue_push(pkgs, p);
+ }
+ else
+ {
+ FOR_JOB_SELECT(p, pp, how, what)
+ queue_push(pkgs, p);
+ }
+}
+
+int
+pool_isemptyupdatejob(Pool *pool, Id how, Id what)
+{
+ Id p, pp, pi, pip;
+ Id select = how & SOLVER_SELECTMASK;
+ if ((how & SOLVER_JOBMASK) != SOLVER_UPDATE)
+ return 0;
+ if (select == SOLVER_SOLVABLE_ALL || select == SOLVER_SOLVABLE_REPO)
+ return 0;
+ if (!pool->installed)
+ return 1;
+ FOR_JOB_SELECT(p, pp, select, what)
+ if (pool->solvables[p].repo == pool->installed)
+ return 0;
+ /* hard work */
+ FOR_JOB_SELECT(p, pp, select, what)
+ {
+ Solvable *s = pool->solvables + p;
+ FOR_PROVIDES(pi, pip, s->name)
+ {
+ Solvable *si = pool->solvables + pi;
+ if (si->repo != pool->installed || si->name != s->name)
+ continue;
+ return 0;
+ }
+ if (s->obsoletes)
+ {
+ Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
+ while ((obs = *obsp++) != 0)
+ {
+ FOR_PROVIDES(pi, pip, obs)
+ {
+ Solvable *si = pool->solvables + pi;
+ if (si->repo != pool->installed)
+ continue;
+ if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, si, obs))
+ continue;
+ if (pool->obsoleteusescolors && !pool_colormatch(pool, s, si))
+ continue;
+ return 0;
+ }
+ }
+ }
+ }
+ 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)
+{
+ const char *s;
+ char *b;
+ select &= SOLVER_SELECTMASK;
+ if (select == SOLVER_SOLVABLE)
+ return pool_solvid2str(pool, what);
+ if (select == SOLVER_SOLVABLE_NAME)
+ return pool_dep2str(pool, what);
+ if (select == SOLVER_SOLVABLE_PROVIDES)
+ {
+ s = pool_dep2str(pool, what);
+ b = pool_alloctmpspace(pool, 11 + strlen(s));
+ sprintf(b, "providing %s", s);
+ return b;
+ }
+ if (select == SOLVER_SOLVABLE_ONE_OF)
+ {
+ Id p;
+ b = 0;
+ while ((p = pool->whatprovidesdata[what++]) != 0)
+ {
+ s = pool_solvid2str(pool, p);
+ if (b)
+ b = pool_tmpappend(pool, b, ", ", s);
+ else
+ b = pool_tmpjoin(pool, s, 0, 0);
+ pool_freetmpspace(pool, s);
+ }
+ return b ? b : "nothing";
+ }
+ if (select == SOLVER_SOLVABLE_REPO)
+ {
+ b = pool_alloctmpspace(pool, 20);
+ sprintf(b, "repo #%d", what);
+ return b;
+ }
+ if (select == SOLVER_SOLVABLE_ALL)
+ return "all packages";
+ return "unknown job select";
+}
+
+const char *
+pool_job2str(Pool *pool, Id how, Id what, Id flagmask)
+{
+ Id select = how & SOLVER_SELECTMASK;
+ const char *strstart = 0, *strend = 0;
+ char *s;
+ int o;
+
+ switch (how & SOLVER_JOBMASK)
+ {
+ case SOLVER_NOOP:
+ return "do nothing";
+ case SOLVER_INSTALL:
+ if (select == SOLVER_SOLVABLE && pool->installed && pool->solvables[what].repo == pool->installed)
+ strstart = "keep ", strend = " installed";
+ else if (select == SOLVER_SOLVABLE || select == SOLVER_SOLVABLE_NAME)
+ strstart = "install ";
+ else if (select == SOLVER_SOLVABLE_PROVIDES)
+ strstart = "install a package ";
+ else
+ strstart = "install one of ";
+ break;
+ case SOLVER_ERASE:
+ if (select == SOLVER_SOLVABLE && !(pool->installed && pool->solvables[what].repo == pool->installed))
+ strstart = "keep ", strend = " uninstalled";
+ else if (select == SOLVER_SOLVABLE_PROVIDES)
+ strstart = "deinstall all packages ";
+ else
+ strstart = "deinstall ";
+ break;
+ case SOLVER_UPDATE:
+ strstart = "update ";
+ break;
+ case SOLVER_WEAKENDEPS:
+ strstart = "weaken deps of ";
+ break;
+ case SOLVER_MULTIVERSION:
+ strstart = "multi version ";
+ break;
+ case SOLVER_LOCK:
+ strstart = "lock ";
+ break;
+ case SOLVER_DISTUPGRADE:
+ strstart = "dist upgrade ";
+ break;
+ case SOLVER_VERIFY:
+ strstart = "verify ";
+ break;
+ case SOLVER_DROP_ORPHANED:
+ strstart = "deinstall ", strend = " if orphaned";
+ break;
+ case SOLVER_USERINSTALLED:
+ strstart = "regard ", strend = " as userinstalled";
+ break;
+ default:
+ strstart = "unknown job ";
+ break;
+ }
+ s = pool_tmpjoin(pool, strstart, solver_select2str(pool, select, what), strend);
+ how &= flagmask;
+ if ((how & ~(SOLVER_SELECTMASK|SOLVER_JOBMASK)) == 0)
+ return s;
+ o = strlen(s);
+ s = pool_tmpappend(pool, s, " ", 0);
+ if (how & SOLVER_WEAK)
+ s = pool_tmpappend(pool, s, ",weak", 0);
+ if (how & SOLVER_ESSENTIAL)
+ s = pool_tmpappend(pool, s, ",essential", 0);
+ if (how & SOLVER_CLEANDEPS)
+ s = pool_tmpappend(pool, s, ",cleandeps", 0);
+ if (how & SOLVER_ORUPDATE)
+ s = pool_tmpappend(pool, s, ",orupdate", 0);
+ if (how & SOLVER_FORCEBEST)
+ s = pool_tmpappend(pool, s, ",forcebest", 0);
+ if (how & SOLVER_TARGETED)
+ s = pool_tmpappend(pool, s, ",targeted", 0);
+ if (how & SOLVER_SETEV)
+ s = pool_tmpappend(pool, s, ",setev", 0);
+ if (how & SOLVER_SETEVR)
+ s = pool_tmpappend(pool, s, ",setevr", 0);
+ if (how & SOLVER_SETARCH)
+ s = pool_tmpappend(pool, s, ",setarch", 0);
+ if (how & SOLVER_SETVENDOR)
+ s = pool_tmpappend(pool, s, ",setvendor", 0);
+ if (how & SOLVER_SETREPO)
+ s = pool_tmpappend(pool, s, ",setrepo", 0);
+ if (how & SOLVER_SETNAME)
+ s = pool_tmpappend(pool, s, ",setname", 0);
+ if (how & SOLVER_NOAUTOSET)
+ s = pool_tmpappend(pool, s, ",noautoset", 0);
+ if (s[o + 1] != ',')
+ s = pool_tmpappend(pool, s, ",?", 0);
+ s[o + 1] = '[';
+ return pool_tmpappend(pool, s, "]", 0);