#include "poolarch.h"
#include "solverdebug.h"
#include "cplxdeps.h"
+#include "linkedpkg.h"
#define RULES_BLOCK 63
queuep_free(&solv->installsuppdepq);
queuep_free(&solv->recommendscplxq);
queuep_free(&solv->suggestscplxq);
+ queuep_free(&solv->brokenorphanrules);
map_free(&solv->recommendsmap);
map_free(&solv->suggestsmap);
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;
default:
break;
}
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;
default:
break;
}
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 */
queuep_free(&solv->suggestscplxq);
solv->recommends_index = 0;
}
+ queuep_free(&solv->brokenorphanrules);
solv->specialupdaters = solv_free(solv->specialupdaters);
* 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);
/* 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);
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)
{
strstart = "multi version ";
break;
case SOLVER_LOCK:
- strstart = "update ";
+ strstart = "lock ";
break;
case SOLVER_DISTUPGRADE:
strstart = "dist upgrade ";