From: Michael Schroeder Date: Wed, 4 Oct 2017 11:48:27 +0000 (+0200) Subject: Add new solver_util.c file for helper functions X-Git-Tag: 0.6.30~22 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b414e484df71c6d1ebba62ab6b851030a1fef9f2;p=thirdparty%2Flibsolv.git Add new solver_util.c file for helper functions No need to clutter up the solver.c and rules.c with those functions. --- diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 76ea9f16..9f19efa3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -19,7 +19,7 @@ SET (libsolv_SRCS queue.c repo.c repodata.c repopage.c util.c policy.c solvable.c transaction.c order.c rules.c problems.c linkedpkg.c cplxdeps.c chksum.c md5.c sha1.c sha2.c solvversion.c selection.c - fileprovides.c diskusage.c suse.c) + fileprovides.c diskusage.c suse.c solver_util.c) SET (libsolv_HEADERS bitmap.h evr.h hash.h policy.h poolarch.h poolvendor.h pool.h diff --git a/src/rules.c b/src/rules.c index 7206ebbd..71bb4f14 100644 --- a/src/rules.c +++ b/src/rules.c @@ -34,50 +34,6 @@ static void addpkgruleinfo(Solver *solv, Id p, Id p2, Id d, int type, Id dep); static void solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded); -/*------------------------------------------------------------------- - * Check if dependency is possible - * - * mirrors solver_dep_fulfilled but uses map m instead of the decisionmap. - * used in solver_addpkgrulesforweak and solver_createcleandepsmap. - */ - -static inline int -dep_possible(Solver *solv, Id dep, Map *m) -{ - Pool *pool = solv->pool; - Id p, pp; - - if (ISRELDEP(dep)) - { - Reldep *rd = GETRELDEP(pool, dep); - if (rd->flags >= 8) - { - if (rd->flags == REL_COND || rd->flags == REL_UNLESS) - return 1; - if (rd->flags == REL_AND) - { - if (!dep_possible(solv, rd->name, m)) - return 0; - return dep_possible(solv, rd->evr, m); - } - if (rd->flags == REL_OR) - { - if (dep_possible(solv, rd->name, m)) - return 1; - return dep_possible(solv, rd->evr, m); - } - if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES) - return solver_splitprovides(solv, rd->evr, m); - } - } - FOR_PROVIDES(p, pp, dep) - { - if (MAPTST(m, p)) - return 1; - } - return 0; -} - static inline int is_otherproviders_dep(Pool *pool, Id dep) { @@ -1205,7 +1161,7 @@ solver_addpkgrulesforweak(Solver *solv, Map *m) /* find possible supplements */ supp = s->repo->idarraydata + s->supplements; while ((sup = *supp++) != 0) - if (dep_possible(solv, sup, m)) + if (solver_dep_possible(solv, sup, m)) break; } @@ -1214,7 +1170,7 @@ solver_addpkgrulesforweak(Solver *solv, Map *m) { supp = s->repo->idarraydata + s->enhances; while ((sup = *supp++) != 0) - if (dep_possible(solv, sup, m)) + if (solver_dep_possible(solv, sup, m)) break; } /* if nothing found, goto next solvables */ @@ -2137,120 +2093,6 @@ reenableduprule(Solver *solv, Id name) #define DISABLE_INFARCH 2 #define DISABLE_DUP 3 -/* - * add all installed packages that package p obsoletes to Queue q. - * Package p is not installed. Also, we know that if - * solv->keepexplicitobsoletes is not set, p is not in the multiversion map. - * Entries may get added multiple times. - */ -static void -add_obsoletes(Solver *solv, Id p, Queue *q) -{ - Pool *pool = solv->pool; - Repo *installed = solv->installed; - Id p2, pp2; - Solvable *s = pool->solvables + p; - Id obs, *obsp; - Id lastp2 = 0; - - if (!solv->keepexplicitobsoletes || !(solv->multiversion.size && MAPTST(&solv->multiversion, p))) - { - FOR_PROVIDES(p2, pp2, s->name) - { - Solvable *ps = pool->solvables + p2; - if (ps->repo != installed) - continue; - if (!pool->implicitobsoleteusesprovides && ps->name != s->name) - continue; - if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps)) - continue; - queue_push(q, p2); - lastp2 = p2; - } - } - if (!s->obsoletes) - return; - obsp = s->repo->idarraydata + s->obsoletes; - while ((obs = *obsp++) != 0) - FOR_PROVIDES(p2, pp2, obs) - { - Solvable *ps = pool->solvables + p2; - if (ps->repo != installed) - continue; - if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs)) - continue; - if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps)) - continue; - if (p2 == lastp2) - continue; - queue_push(q, p2); - lastp2 = p2; - } -} - -/* - * Call add_obsoletes and intersect the result with the - * elements in Queue q starting at qstart. - * Assumes that it's the first call if qstart == q->count. - * May use auxillary map m for the intersection process, all - * elements of q starting at qstart must have their bit cleared. - * (This is also true after the function returns.) - */ -static void -intersect_obsoletes(Solver *solv, Id p, Queue *q, int qstart, Map *m) -{ - int i, j; - int qcount = q->count; - - add_obsoletes(solv, p, q); - if (qcount == qstart) - return; /* first call */ - if (qcount == q->count) - j = qstart; - else if (qcount == qstart + 1) - { - /* easy if there's just one element */ - j = qstart; - for (i = qcount; i < q->count; i++) - if (q->elements[i] == q->elements[qstart]) - { - j++; /* keep the element */ - break; - } - } - else if (!m->size && q->count - qstart <= 8) - { - /* faster than a map most of the time */ - int k; - for (i = j = qstart; i < qcount; i++) - { - Id ip = q->elements[i]; - for (k = qcount; k < q->count; k++) - if (q->elements[k] == ip) - { - q->elements[j++] = ip; - break; - } - } - } - else - { - /* for the really pathologic cases we use the map */ - Repo *installed = solv->installed; - if (!m->size) - map_init(m, installed->end - installed->start); - for (i = qcount; i < q->count; i++) - MAPSET(m, q->elements[i] - installed->start); - for (i = j = qstart; i < qcount; i++) - if (MAPTST(m, q->elements[i] - installed->start)) - { - MAPCLR(m, q->elements[i] - installed->start); - q->elements[j++] = q->elements[i]; - } - } - queue_truncate(q, j); -} - static void jobtodisablelist(Solver *solv, Id how, Id what, Queue *q) { @@ -2366,7 +2208,7 @@ jobtodisablelist(Solver *solv, Id how, Id what, Queue *q) qstart = q->count; FOR_JOB_SELECT(p, pp, select, what) { - intersect_obsoletes(solv, p, q, qstart, &omap); + solver_intersect_obsoleted(solv, p, q, qstart, &omap); if (q->count == qstart) break; } @@ -4243,7 +4085,7 @@ solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded) } } else - intersect_obsoletes(solv, p, &iq, iqstart, &om); + solver_intersect_obsoleted(solv, p, &iq, iqstart, &om); if (iq.count == iqstart) break; } @@ -4311,13 +4153,13 @@ solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded) continue; supp = s->repo->idarraydata + s->supplements; while ((sup = *supp++) != 0) - if (dep_possible(solv, sup, &im)) + if (solver_dep_possible(solv, sup, &im)) break; if (!sup) { supp = s->repo->idarraydata + s->supplements; while ((sup = *supp++) != 0) - if (dep_possible(solv, sup, &installedm) || (xsuppq.count && queue_contains(&xsuppq, sup))) + if (solver_dep_possible(solv, sup, &installedm) || (xsuppq.count && queue_contains(&xsuppq, sup))) { /* no longer supplemented, also erase */ int iqcount = iq.count; @@ -4473,7 +4315,7 @@ solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded) continue; supp = s->repo->idarraydata + s->supplements; while ((sup = *supp++) != 0) - if (dep_possible(solv, sup, &im)) + if (solver_dep_possible(solv, sup, &im)) break; if (sup) { @@ -4832,7 +4674,7 @@ solver_get_unneeded(Solver *solv, Queue *unneededq, int filtered) Id *dp; int k; for (dp = s->repo->idarraydata + s->supplements; *dp; dp++) - if (dep_possible(solv, *dp, &installedm)) + if (solver_dep_possible(solv, *dp, &installedm)) { Queue iq; Id iqbuf[16]; diff --git a/src/solver.c b/src/solver.c index 4aa92901..25969ec8 100644 --- a/src/solver.c +++ b/src/solver.c @@ -31,242 +31,6 @@ #define RULES_BLOCK 63 -/******************************************************************** - * - * dependency check helpers - * - */ - -/*------------------------------------------------------------------- - * handle split provides - * - * a splitprovides dep looks like - * namespace:splitprovides(pkg REL_WITH path) - * and is only true if pkg is installed and contains the specified path. - * we also make sure that pkg is selected for an update, otherwise the - * update would always be forced onto the user. - * Map m is the map used when called from dep_possible. - */ - -static int -solver_is_updating(Solver *solv, Id p) -{ - /* check if the update rule is true */ - Pool *pool = solv->pool; - Rule *r; - Id l, pp; - if (solv->decisionmap[p] >= 0) - return 0; /* old package stayed */ - r = solv->rules + solv->updaterules + (p - solv->installed->start); - FOR_RULELITERALS(l, pp, r) - if (l > 0 && l != p && solv->decisionmap[l] > 0) - return 1; - return 0; -} - -int -solver_splitprovides(Solver *solv, Id dep, Map *m) -{ - Pool *pool = solv->pool; - Id p, pp; - Reldep *rd; - Solvable *s; - - if (!solv->dosplitprovides || !solv->installed) - return 0; - if (!ISRELDEP(dep)) - return 0; - rd = GETRELDEP(pool, dep); - if (rd->flags != REL_WITH) - return 0; - /* - * things are a bit tricky here if pool->addedprovides == 1, because most split-provides are in - * a non-standard location. If we simply call pool_whatprovides, we'll drag in the complete - * file list. Instead we rely on pool_addfileprovides ignoring the addfileprovidesfiltered flag - * for installed packages and check the lazywhatprovidesq (ignoring the REL_WITH part, but - * we filter the package name further down anyway). - */ - if (pool->addedfileprovides == 1 && !ISRELDEP(rd->evr) && !pool->whatprovides[rd->evr]) - pp = pool_searchlazywhatprovidesq(pool, rd->evr); - else - pp = pool_whatprovides(pool, dep); - while ((p = pool->whatprovidesdata[pp++]) != 0) - { - /* here we have packages that provide the correct name and contain the path, - * now do extra filtering */ - s = pool->solvables + p; - if (s->repo != solv->installed || s->name != rd->name) - continue; - /* check if the package is updated. if m is set, we're called from dep_possible */ - if (m || solver_is_updating(solv, p)) - return 1; - } - return 0; -} - -int -solver_dep_fulfilled_cplx(Solver *solv, Reldep *rd) -{ - Pool *pool = solv->pool; - if (rd->flags == REL_COND) - { - if (ISRELDEP(rd->evr)) - { - Reldep *rd2 = GETRELDEP(pool, rd->evr); - if (rd2->flags == REL_ELSE) - { - if (solver_dep_fulfilled(solv, rd2->name)) - return solver_dep_fulfilled(solv, rd->name); - return solver_dep_fulfilled(solv, rd2->evr); - } - } - if (solver_dep_fulfilled(solv, rd->name)) - return 1; - return !solver_dep_fulfilled(solv, rd->evr); - } - if (rd->flags == REL_UNLESS) - { - if (ISRELDEP(rd->evr)) - { - Reldep *rd2 = GETRELDEP(pool, rd->evr); - if (rd2->flags == REL_ELSE) - { - if (!solver_dep_fulfilled(solv, rd2->name)) - return solver_dep_fulfilled(solv, rd->name); - return solver_dep_fulfilled(solv, rd2->evr); - } - } - if (!solver_dep_fulfilled(solv, rd->name)) - return 0; - return !solver_dep_fulfilled(solv, rd->evr); - } - if (rd->flags == REL_AND) - { - if (!solver_dep_fulfilled(solv, rd->name)) - return 0; - return solver_dep_fulfilled(solv, rd->evr); - } - if (rd->flags == REL_OR) - { - if (solver_dep_fulfilled(solv, rd->name)) - return 1; - return solver_dep_fulfilled(solv, rd->evr); - } - return 0; -} - - -/* mirrors solver_dep_fulfilled, but returns 2 if a new package - * was involved */ -static int -solver_dep_fulfilled_alreadyinstalled(Solver *solv, Id dep) -{ - Pool *pool = solv->pool; - Id p, pp; - int r; - - if (ISRELDEP(dep)) - { - Reldep *rd = GETRELDEP(pool, dep); - if (rd->flags == REL_COND) - { - int r1, r2; - if (ISRELDEP(rd->evr)) - { - Reldep *rd2 = GETRELDEP(pool, rd->evr); - if (rd2->flags == REL_ELSE) - { - r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd2->name); - if (r1) - { - r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name); - return r2 && r1 == 2 ? 2 : r2; - } - return solver_dep_fulfilled_alreadyinstalled(solv, rd2->evr); - } - } - r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name); - r2 = !solver_dep_fulfilled_alreadyinstalled(solv, rd->evr); - if (!r1 && !r2) - return 0; - return r1 == 2 ? 2 : 1; - } - if (rd->flags == REL_UNLESS) - { - int r1, r2; - if (ISRELDEP(rd->evr)) - { - Reldep *rd2 = GETRELDEP(pool, rd->evr); - if (rd2->flags == REL_ELSE) - { - r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd2->name); - if (r1) - { - r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd2->evr); - return r2 && r1 == 2 ? 2 : r2; - } - return solver_dep_fulfilled_alreadyinstalled(solv, rd->name); - } - } - /* A AND NOT(B) */ - r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name); - r2 = !solver_dep_fulfilled_alreadyinstalled(solv, rd->evr); - if (!r1 || !r2) - return 0; - return r1 == 2 ? 2 : 1; - } - if (rd->flags == REL_AND) - { - int r2, r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name); - if (!r1) - return 0; - r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd->evr); - if (!r2) - return 0; - return r1 == 2 || r2 == 2 ? 2 : 1; - } - if (rd->flags == REL_OR) - { - int r2, r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name); - r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd->evr); - if (!r1 && !r2) - return 0; - return r1 == 2 || r2 == 2 ? 2 : 1; - } - if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES) - return solver_splitprovides(solv, rd->evr, 0) ? 2 : 0; - if (rd->flags == REL_NAMESPACE && solv->installsuppdepq) - { - Queue *q = solv->installsuppdepq; - int i; - for (i = 0; i < q->count; i++) - if (q->elements[i] == dep || q->elements[i] == rd->name) - return 2; - } - } - r = 0; - FOR_PROVIDES(p, pp, dep) - if (solv->decisionmap[p] > 0) - { - Solvable *s = pool->solvables + p; - if (s->repo && s->repo != solv->installed) - return 2; - r = 1; - } - return r; -} - -static int -solver_is_supplementing_alreadyinstalled(Solver *solv, Solvable *s) -{ - Id sup, *supp; - supp = s->repo->idarraydata + s->supplements; - while ((sup = *supp++) != 0) - if (solver_dep_fulfilled_alreadyinstalled(solv, sup) == 2) - return 1; - return 0; -} - static Id autouninstall(Solver *solv, Id *problem) { diff --git a/src/solver_private.h b/src/solver_private.h index a2342238..50cf2932 100644 --- a/src/solver_private.h +++ b/src/solver_private.h @@ -17,7 +17,29 @@ extern void solver_run_sat(Solver *solv, int disablerules, int doweak); extern void solver_reset(Solver *solv); extern int solver_splitprovides(Solver *solv, Id dep, Map *m); +extern int solver_dep_possible_slow(Solver *solv, Id dep, Map *m); extern int solver_dep_fulfilled_cplx(Solver *solv, Reldep *rd); +extern int solver_is_supplementing_alreadyinstalled(Solver *solv, Solvable *s); +extern void solver_intersect_obsoleted(Solver *solv, Id p, Queue *q, int qstart, Map *m); + + +#define ISSIMPLEDEP(pool, dep) (!ISRELDEP(dep) || GETRELDEP(pool, dep)->flags < 8) + +static inline int +solver_dep_possible(Solver *solv, Id dep, Map *m) +{ + Pool *pool = solv->pool; + Id p, pp; + + if (!ISSIMPLEDEP(pool, dep)) + return solver_dep_possible_slow(solv, dep, m); + FOR_PROVIDES(p, pp, dep) + { + if (MAPTST(m, p)) + return 1; + } + return 0; +} static inline int solver_dep_fulfilled(Solver *solv, Id dep) diff --git a/src/solver_util.c b/src/solver_util.c new file mode 100644 index 00000000..d5096acb --- /dev/null +++ b/src/solver_util.c @@ -0,0 +1,409 @@ +/* + * Copyright (c) 2017, SUSE Inc. + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +/* + * solver_util.c + * + * Dependency solver helper functions + */ + +#include +#include +#include +#include + +#include "solver.h" +#include "solver_private.h" +#include "bitmap.h" +#include "pool.h" +#include "poolarch.h" +#include "util.h" + + +/*------------------------------------------------------------------- + * check if a installed package p is being updated + */ +static int +solver_is_updating(Solver *solv, Id p) +{ + /* check if the update rule is true */ + Pool *pool = solv->pool; + Rule *r; + Id l, pp; + if (solv->decisionmap[p] >= 0) + return 0; /* old package stayed */ + r = solv->rules + solv->updaterules + (p - solv->installed->start); + FOR_RULELITERALS(l, pp, r) + if (l > 0 && l != p && solv->decisionmap[l] > 0) + return 1; + return 0; +} + +/*------------------------------------------------------------------- + * handle split provides + * + * a splitprovides dep looks like + * namespace:splitprovides(pkg REL_WITH path) + * and is only true if pkg is installed and contains the specified path. + * we also make sure that pkg is selected for an update, otherwise the + * update would always be forced onto the user. + * Map m is the map used when called from dep_possible. + */ +int +solver_splitprovides(Solver *solv, Id dep, Map *m) +{ + Pool *pool = solv->pool; + Id p, pp; + Reldep *rd; + Solvable *s; + + if (!solv->dosplitprovides || !solv->installed) + return 0; + if (!ISRELDEP(dep)) + return 0; + rd = GETRELDEP(pool, dep); + if (rd->flags != REL_WITH) + return 0; + /* + * things are a bit tricky here if pool->addedprovides == 1, because most split-provides are in + * a non-standard location. If we simply call pool_whatprovides, we'll drag in the complete + * file list. Instead we rely on pool_addfileprovides ignoring the addfileprovidesfiltered flag + * for installed packages and check the lazywhatprovidesq (ignoring the REL_WITH part, but + * we filter the package name further down anyway). + */ + if (pool->addedfileprovides == 1 && !ISRELDEP(rd->evr) && !pool->whatprovides[rd->evr]) + pp = pool_searchlazywhatprovidesq(pool, rd->evr); + else + pp = pool_whatprovides(pool, dep); + while ((p = pool->whatprovidesdata[pp++]) != 0) + { + /* here we have packages that provide the correct name and contain the path, + * now do extra filtering */ + s = pool->solvables + p; + if (s->repo != solv->installed || s->name != rd->name) + continue; + /* check if the package is updated. if m is set, we're called from dep_possible */ + if (m || solver_is_updating(solv, p)) + return 1; + } + return 0; +} + +int +solver_dep_possible_slow(Solver *solv, Id dep, Map *m) +{ + Pool *pool = solv->pool; + Id p, pp; + + if (ISRELDEP(dep)) + { + Reldep *rd = GETRELDEP(pool, dep); + if (rd->flags >= 8) + { + if (rd->flags == REL_COND || rd->flags == REL_UNLESS) + return 1; + if (rd->flags == REL_AND) + { + if (!solver_dep_possible_slow(solv, rd->name, m)) + return 0; + return solver_dep_possible_slow(solv, rd->evr, m); + } + if (rd->flags == REL_OR) + { + if (solver_dep_possible_slow(solv, rd->name, m)) + return 1; + return solver_dep_possible_slow(solv, rd->evr, m); + } + if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES) + return solver_splitprovides(solv, rd->evr, m); + } + } + FOR_PROVIDES(p, pp, dep) + { + if (MAPTST(m, p)) + return 1; + } + return 0; +} + +int +solver_dep_fulfilled_cplx(Solver *solv, Reldep *rd) +{ + Pool *pool = solv->pool; + if (rd->flags == REL_COND) + { + if (ISRELDEP(rd->evr)) + { + Reldep *rd2 = GETRELDEP(pool, rd->evr); + if (rd2->flags == REL_ELSE) + { + if (solver_dep_fulfilled(solv, rd2->name)) + return solver_dep_fulfilled(solv, rd->name); + return solver_dep_fulfilled(solv, rd2->evr); + } + } + if (solver_dep_fulfilled(solv, rd->name)) + return 1; + return !solver_dep_fulfilled(solv, rd->evr); + } + if (rd->flags == REL_UNLESS) + { + if (ISRELDEP(rd->evr)) + { + Reldep *rd2 = GETRELDEP(pool, rd->evr); + if (rd2->flags == REL_ELSE) + { + if (!solver_dep_fulfilled(solv, rd2->name)) + return solver_dep_fulfilled(solv, rd->name); + return solver_dep_fulfilled(solv, rd2->evr); + } + } + if (!solver_dep_fulfilled(solv, rd->name)) + return 0; + return !solver_dep_fulfilled(solv, rd->evr); + } + if (rd->flags == REL_AND) + { + if (!solver_dep_fulfilled(solv, rd->name)) + return 0; + return solver_dep_fulfilled(solv, rd->evr); + } + if (rd->flags == REL_OR) + { + if (solver_dep_fulfilled(solv, rd->name)) + return 1; + return solver_dep_fulfilled(solv, rd->evr); + } + return 0; +} + + +/* mirrors solver_dep_fulfilled, but returns 2 if a new package + * was involved */ +static int +solver_dep_fulfilled_alreadyinstalled(Solver *solv, Id dep) +{ + Pool *pool = solv->pool; + Id p, pp; + int r; + + if (ISRELDEP(dep)) + { + Reldep *rd = GETRELDEP(pool, dep); + if (rd->flags == REL_COND) + { + int r1, r2; + if (ISRELDEP(rd->evr)) + { + Reldep *rd2 = GETRELDEP(pool, rd->evr); + if (rd2->flags == REL_ELSE) + { + r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd2->name); + if (r1) + { + r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name); + return r2 && r1 == 2 ? 2 : r2; + } + return solver_dep_fulfilled_alreadyinstalled(solv, rd2->evr); + } + } + r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name); + r2 = !solver_dep_fulfilled_alreadyinstalled(solv, rd->evr); + if (!r1 && !r2) + return 0; + return r1 == 2 ? 2 : 1; + } + if (rd->flags == REL_UNLESS) + { + int r1, r2; + if (ISRELDEP(rd->evr)) + { + Reldep *rd2 = GETRELDEP(pool, rd->evr); + if (rd2->flags == REL_ELSE) + { + r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd2->name); + if (r1) + { + r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd2->evr); + return r2 && r1 == 2 ? 2 : r2; + } + return solver_dep_fulfilled_alreadyinstalled(solv, rd->name); + } + } + /* A AND NOT(B) */ + r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name); + r2 = !solver_dep_fulfilled_alreadyinstalled(solv, rd->evr); + if (!r1 || !r2) + return 0; + return r1 == 2 ? 2 : 1; + } + if (rd->flags == REL_AND) + { + int r2, r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name); + if (!r1) + return 0; + r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd->evr); + if (!r2) + return 0; + return r1 == 2 || r2 == 2 ? 2 : 1; + } + if (rd->flags == REL_OR) + { + int r2, r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name); + r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd->evr); + if (!r1 && !r2) + return 0; + return r1 == 2 || r2 == 2 ? 2 : 1; + } + if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES) + return solver_splitprovides(solv, rd->evr, 0) ? 2 : 0; + if (rd->flags == REL_NAMESPACE && solv->installsuppdepq) + { + Queue *q = solv->installsuppdepq; + int i; + for (i = 0; i < q->count; i++) + if (q->elements[i] == dep || q->elements[i] == rd->name) + return 2; + } + } + r = 0; + FOR_PROVIDES(p, pp, dep) + if (solv->decisionmap[p] > 0) + { + Solvable *s = pool->solvables + p; + if (s->repo && s->repo != solv->installed) + return 2; + r = 1; + } + return r; +} + +int +solver_is_supplementing_alreadyinstalled(Solver *solv, Solvable *s) +{ + Id sup, *supp; + supp = s->repo->idarraydata + s->supplements; + while ((sup = *supp++) != 0) + if (solver_dep_fulfilled_alreadyinstalled(solv, sup) == 2) + return 1; + return 0; +} +/* + * add all installed packages that package p obsoletes to Queue q. + * Package p is not installed. Also, we know that if + * solv->keepexplicitobsoletes is not set, p is not in the multiversion map. + * Entries may get added multiple times. + */ +static void +solver_add_obsoleted(Solver *solv, Id p, Queue *q) +{ + Pool *pool = solv->pool; + Repo *installed = solv->installed; + Id p2, pp2; + Solvable *s = pool->solvables + p; + Id obs, *obsp; + Id lastp2 = 0; + + if (!solv->keepexplicitobsoletes || !(solv->multiversion.size && MAPTST(&solv->multiversion, p))) + { + FOR_PROVIDES(p2, pp2, s->name) + { + Solvable *ps = pool->solvables + p2; + if (ps->repo != installed) + continue; + if (!pool->implicitobsoleteusesprovides && ps->name != s->name) + continue; + if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps)) + continue; + queue_push(q, p2); + lastp2 = p2; + } + } + if (!s->obsoletes) + return; + obsp = s->repo->idarraydata + s->obsoletes; + while ((obs = *obsp++) != 0) + FOR_PROVIDES(p2, pp2, obs) + { + Solvable *ps = pool->solvables + p2; + if (ps->repo != installed) + continue; + if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs)) + continue; + if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps)) + continue; + if (p2 == lastp2) + continue; + queue_push(q, p2); + lastp2 = p2; + } +} + +/* + * Call solver_add_obsoleted and intersect the result with the + * elements in Queue q starting at qstart. + * Assumes that it's the first call if qstart == q->count. + * May use auxillary map m for the intersection process, all + * elements of q starting at qstart must have their bit cleared. + * (This is also true after the function returns.) + * (See solver_add_obsoleted for limitations of the package p) + */ +void +solver_intersect_obsoleted(Solver *solv, Id p, Queue *q, int qstart, Map *m) +{ + int i, j; + int qcount = q->count; + + solver_add_obsoleted(solv, p, q); + if (qcount == qstart) + return; /* first call */ + if (qcount == q->count) + j = qstart; + else if (qcount == qstart + 1) + { + /* easy if there's just one element */ + j = qstart; + for (i = qcount; i < q->count; i++) + if (q->elements[i] == q->elements[qstart]) + { + j++; /* keep the element */ + break; + } + } + else if (!m->size && q->count - qstart <= 8) + { + /* faster than a map most of the time */ + int k; + for (i = j = qstart; i < qcount; i++) + { + Id ip = q->elements[i]; + for (k = qcount; k < q->count; k++) + if (q->elements[k] == ip) + { + q->elements[j++] = ip; + break; + } + } + } + else + { + /* for the really pathologic cases we use the map */ + Repo *installed = solv->installed; + if (!m->size) + map_init(m, installed->end - installed->start); + for (i = qcount; i < q->count; i++) + MAPSET(m, q->elements[i] - installed->start); + for (i = j = qstart; i < qcount; i++) + if (MAPTST(m, q->elements[i] - installed->start)) + { + MAPCLR(m, q->elements[i] - installed->start); + q->elements[j++] = q->elements[i]; + } + } + queue_truncate(q, j); +} +