X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Frules.c;h=6b1432f4fa2eedc34e5f45fc9a5b11fd2cfed3dc;hb=6a68988035ea989055076d81b7ab53c7015c8c32;hp=b5f3e3e1c66e763c04856157da8b0e086ef8c68a;hpb=593cf72349c7de430751446480779582c63902f5;p=platform%2Fupstream%2Flibsolv.git diff --git a/src/rules.c b/src/rules.c index b5f3e3e..6b1432f 100644 --- a/src/rules.c +++ b/src/rules.c @@ -498,6 +498,16 @@ add_package_link(Solver *solv, Solvable *s, Map *m, Queue *workq) #ifdef ENABLE_COMPLEX_DEPS +#ifdef SUSE +static inline int +suse_isptf(Pool *pool, Solvable *s) +{ + if (!strncmp("ptf-", pool_id2str(pool, s->name), 4)) + return 1; + return 0; +} +#endif + static void add_complex_deprules(Solver *solv, Id p, Id dep, int type, int dontfix, Queue *workq, Map *m) { @@ -511,6 +521,10 @@ add_complex_deprules(Solver *solv, Id p, Id dep, int type, int dontfix, Queue *w /* CNF expansion for requires, DNF + INVERT expansion for conflicts */ if (type == SOLVER_RULE_PKG_CONFLICTS) flags |= CPLXDEPS_TODNF | CPLXDEPS_EXPAND | CPLXDEPS_INVERT; +#ifdef SUSE + if (type == SOLVER_RULE_PKG_REQUIRES && suse_isptf(pool, pool->solvables + p)) + flags |= CPLXDEPS_NAME; /* do not match provides */ +#endif i = pool_normalize_complex_dep(pool, dep, &bq, flags); /* handle special cases */ @@ -599,7 +613,7 @@ add_complex_deprules(Solver *solv, Id p, Id dep, int type, int dontfix, Queue *w } else { - Id *qele; + Id *qele, d; int qcnt; qele = bq.elements + i; @@ -639,7 +653,17 @@ add_complex_deprules(Solver *solv, Id p, Id dep, int type, int dontfix, Queue *w break; if (j < qcnt) continue; - addpkgrule(solv, qele[0], 0, pool_ids2whatprovides(pool, qele + 1, qcnt - 1), type, dep); + d = pool_ids2whatprovides(pool, qele + 1, qcnt - 1); + if (solv->ruleinfoq && qele[0] != p) + { + int oldcount = solv->ruleinfoq->count; + addpkgrule(solv, qele[0], 0, d, type, dep); + /* fixup from element of ruleinfo */ + if (solv->ruleinfoq->count > oldcount) + solv->ruleinfoq->elements[oldcount + 1] = p; + } + else + addpkgrule(solv, qele[0], 0, d, type, dep); if (m) for (j = 0; j < qcnt; j++) if (qele[j] > 0 && !MAPTST(m, qele[j])) @@ -651,6 +675,34 @@ add_complex_deprules(Solver *solv, Id p, Id dep, int type, int dontfix, Queue *w #endif +#ifdef ENABLE_CONDA +void +add_conda_constrains_rule(Solver *solv, Id n, Id dep, int dontfix) +{ + Pool *pool = solv->pool; + Reldep *rd; + Id p, pp, pdep; + if (!ISRELDEP(dep)) + return; + rd = GETRELDEP(pool, dep); + pdep = pool_whatprovides(pool, dep); + FOR_PROVIDES(p, pp, rd->name) + { + Id p2; + if (p == n) + continue; + if (dontfix && pool->solvables[p].repo == solv->installed) + continue; + while ((p2 = pool->whatprovidesdata[pdep]) != 0 && p2 < p) + pdep++; + if (p == p2) + pdep++; + else + addpkgrule(solv, -n, -p, 0, SOLVER_RULE_PKG_CONSTRAINS, dep); + } +} +#endif + /*------------------------------------------------------------------- * * add dependency rules for solvable @@ -679,8 +731,8 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m) Queue workq; /* list of solvables we still have to work on */ Id workqbuf[64]; - Queue prereqq; /* list of pre-req ids to ignore */ - Id prereqbuf[16]; + Queue depq; /* list of pre-req ids to ignore */ + Id depqbuf[16]; int i; int dontfix; /* ignore dependency errors for installed solvables */ @@ -696,7 +748,7 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m) queue_init_buffer(&workq, workqbuf, sizeof(workqbuf)/sizeof(*workqbuf)); queue_push(&workq, s - pool->solvables); /* push solvable Id to work queue */ - queue_init_buffer(&prereqq, prereqbuf, sizeof(prereqbuf)/sizeof(*prereqbuf)); + queue_init_buffer(&depq, depqbuf, sizeof(depqbuf)/sizeof(*depqbuf)); /* loop until there's no more work left */ while (workq.count) @@ -756,20 +808,18 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m) { if (installed && s->repo == installed) { - if (prereqq.count) - queue_empty(&prereqq); - solvable_lookup_idarray(s, SOLVABLE_PREREQ_IGNOREINST, &prereqq); - filterpre = prereqq.count; + solvable_lookup_idarray(s, SOLVABLE_PREREQ_IGNOREINST, &depq); + filterpre = depq.count; } continue; } if (filterpre) { - /* check if this id is filtered. assumes that prereqq.count is small */ - for (i = 0; i < prereqq.count; i++) - if (req == prereqq.elements[i]) + /* check if this id is filtered. assumes that depq.count is small */ + for (i = 0; i < depq.count; i++) + if (req == depq.elements[i]) break; - if (i < prereqq.count) + if (i < depq.count) { POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "package %s: ignoring filtered pre-req dependency %s\n", pool_solvable2str(pool, s), pool_dep2str(pool, req)); continue; @@ -882,6 +932,15 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m) } } +#ifdef ENABLE_CONDA + if (pool->disttype == DISTTYPE_CONDA) + { + solvable_lookup_idarray(s, SOLVABLE_CONSTRAINS, &depq); + for (i = 0; i < depq.count; i++) + add_conda_constrains_rule(solv, n, depq.elements[i], dontfix); + } +#endif + /* that's all we check for src packages */ if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC) continue; @@ -1031,16 +1090,17 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m) } } - if (m && pool->implicitobsoleteusescolors && (s->arch > pool->lastarch || pool->id2arch[s->arch] != 1)) + if (m && pool->implicitobsoleteusescolors && pool_arch2score(pool, s->arch) > 1) { - int a = pool->id2arch[s->arch]; + unsigned int pa, a = pool_arch2score(pool, s->arch); /* check lock-step candidates */ FOR_PROVIDES(p, pp, s->name) { Solvable *ps = pool->solvables + p; if (s->name != ps->name || s->evr != ps->evr || MAPTST(m, p)) continue; - if (ps->arch > pool->lastarch || pool->id2arch[ps->arch] == 1 || pool->id2arch[ps->arch] >= a) + pa = pool_arch2score(pool, ps->arch); + if (!pa || pa == 1 || pa >= a) continue; queue_push(&workq, p); } @@ -1058,7 +1118,7 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m) if (pool_is_complex_dep(pool, rec)) { pool_add_pos_literals_complex_dep(pool, rec, &workq, m, 0); - continue; + continue; } #endif FOR_PROVIDES(p, pp, rec) @@ -1075,7 +1135,7 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m) if (pool_is_complex_dep(pool, sug)) { pool_add_pos_literals_complex_dep(pool, sug, &workq, m, 0); - continue; + continue; } #endif FOR_PROVIDES(p, pp, sug) @@ -1084,7 +1144,7 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m) } } } - queue_free(&prereqq); + queue_free(&depq); queue_free(&workq); } @@ -1327,6 +1387,31 @@ solver_addfeaturerule(Solver *solv, Solvable *s) } } +/* check if multiversion solvable s2 has an obsoletes for installed solvable s */ +static int +is_multiversion_obsoleteed(Pool *pool, Solvable *s, Solvable *s2) +{ + Id *wp, obs, *obsp; + + if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2)) + return 0; + obsp = s2->repo->idarraydata + s2->obsoletes; + if (!pool->obsoleteusesprovides) + { + while ((obs = *obsp++) != 0) + if (pool_match_nevr(pool, s, obs)) + return 1; + } + else + { + while ((obs = *obsp++) != 0) + for (wp = pool_whatprovides_ptr(pool, obs); *wp; wp++) + if (pool->solvables + *wp == s) + return 1; + } + return 0; +} + /*------------------------------------------------------------------- * * add rule for update @@ -1347,6 +1432,14 @@ solver_addupdaterule(Solver *solv, Solvable *s) int dupinvolved = 0; p = s - pool->solvables; + + if (pool->considered && pool_disabled_solvable(pool, s)) + { + /* disabled installed solvables must stay installed */ + solver_addrule(solv, p, 0, 0); + return; + } + /* Orphan detection. We cheat by looking at the feature rule, which * we already calculated */ r = solv->rules + solv->featurerules + (p - solv->installed->start); @@ -1388,9 +1481,8 @@ solver_addupdaterule(Solver *solv, Solvable *s) if (MAPTST(&solv->multiversion, qs.elements[i])) { Solvable *ps = pool->solvables + qs.elements[i]; - /* if keepexplicitobsoletes is set and the name is different, - * we assume that there is an obsoletes. XXX: not 100% correct */ - if (solv->keepexplicitobsoletes && ps->name != s->name) + /* check if there is an explicit obsoletes */ + if (solv->keepexplicitobsoletes && ps->obsoletes && is_multiversion_obsoleteed(pool, s, ps)) { qs.elements[j++] = qs.elements[i]; continue; @@ -1462,12 +1554,12 @@ disableupdaterule(Solver *solv, Id p) r = solv->rules + solv->featurerules + (p - solv->installed->start); if (r->p && r->d >= 0) solver_disablerule(solv, r); - if (solv->bestrules_pkg) + if (solv->bestrules_info) { int i, ni; ni = solv->bestrules_end - solv->bestrules; - for (i = 0; i < ni; i++) - if (solv->bestrules_pkg[i] == p) + for (i = solv->bestrules_up - solv->bestrules; i < ni; i++) + if (solv->bestrules_info[i] == p) solver_disablerule(solv, solv->rules + solv->bestrules + i); } } @@ -1505,12 +1597,12 @@ reenableupdaterule(Solver *solv, Id p) } } } - if (solv->bestrules_pkg) + if (solv->bestrules_info) { int i, ni; ni = solv->bestrules_end - solv->bestrules; - for (i = 0; i < ni; i++) - if (solv->bestrules_pkg[i] == p) + for (i = solv->bestrules_up - solv->bestrules; i < ni; i++) + if (solv->bestrules_info[i] == p) solver_enablerule(solv, solv->rules + solv->bestrules + i); } } @@ -1531,7 +1623,8 @@ solver_addinfarchrules(Solver *solv, Map *addedmap) Pool *pool = solv->pool; Repo *installed = pool->installed; int first, i, j; - Id p, pp, a, aa, bestarch; + Id p, pp, aa; + unsigned int a, bestscore; Solvable *s, *ps, *bests; Queue badq, allowedarchs; Queue lsq; @@ -1546,7 +1639,7 @@ solver_addinfarchrules(Solver *solv, Map *addedmap) continue; s = pool->solvables + i; first = i; - bestarch = 0; + bestscore = 0; bests = 0; queue_empty(&allowedarchs); FOR_PROVIDES(p, pp, s->name) @@ -1558,8 +1651,7 @@ solver_addinfarchrules(Solver *solv, Map *addedmap) first = 0; if (first) break; - a = ps->arch; - a = (a <= pool->lastarch) ? pool->id2arch[a] : 0; + a = pool_arch2score(pool, ps->arch); if (a != 1 && installed && ps->repo == installed) { if (solv->dupinvolvedmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))) @@ -1567,20 +1659,23 @@ solver_addinfarchrules(Solver *solv, Map *addedmap) queue_pushunique(&allowedarchs, ps->arch); /* also ok to keep this architecture */ continue; /* but ignore installed solvables when calculating the best arch */ } - if (a && a != 1 && (!bestarch || a < bestarch)) + if (a && a != 1 && (!bestscore || a < bestscore)) { - bestarch = a; + bestscore = a; bests = ps; } } if (first) - continue; + continue; /* not the first in the group */ + + if (!bestscore) + continue; /* did not find a score for this group */ /* speed up common case where installed package already has best arch */ if (allowedarchs.count == 1 && bests && allowedarchs.elements[0] == bests->arch) allowedarchs.count--; /* installed arch is best */ - if (allowedarchs.count && pool->implicitobsoleteusescolors && installed && bestarch) + if (allowedarchs.count && pool->implicitobsoleteusescolors && installed) { /* need an extra pass for lockstep checking: we only allow to keep an inferior arch * if the corresponding installed package is not lock-stepped */ @@ -1593,25 +1688,23 @@ solver_addinfarchrules(Solver *solv, Map *addedmap) continue; if (solv->dupinvolvedmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))) continue; - a = ps->arch; - a = (a <= pool->lastarch) ? pool->id2arch[a] : 0; + a = pool_arch2score(pool, ps->arch); if (!a) { queue_pushunique(&allowedarchs, ps->arch); /* strange arch, allow */ continue; } - if (a == 1 || ((a ^ bestarch) & 0xffff0000) == 0) + if (a == 1 || ((a ^ bestscore) & 0xffff0000) == 0) continue; /* have installed package with inferior arch, check if lock-stepped */ FOR_PROVIDES(p2, pp2, s->name) { Solvable *s2 = pool->solvables + p2; - Id a2; + unsigned int a2; if (p2 == p || s2->name != s->name || s2->evr != pool->solvables[p].evr || s2->arch == pool->solvables[p].arch) continue; - a2 = s2->arch; - a2 = (a2 <= pool->lastarch) ? pool->id2arch[a2] : 0; - if (a2 && (a2 == 1 || ((a2 ^ bestarch) & 0xffff0000) == 0)) + a2 = pool_arch2score(pool, s2->arch); + if (a2 && (a2 == 1 || ((a2 ^ bestscore) & 0xffff0000) == 0)) break; } if (!p2) @@ -1626,9 +1719,8 @@ solver_addinfarchrules(Solver *solv, Map *addedmap) ps = pool->solvables + p; if (ps->name != s->name || !MAPTST(addedmap, p)) continue; - a = ps->arch; - a = (a <= pool->lastarch) ? pool->id2arch[a] : 0; - if (a != 1 && bestarch && ((a ^ bestarch) & 0xffff0000) != 0) + a = pool_arch2score(pool, ps->arch); + if (a != 1 && ((a ^ bestscore) & 0xffff0000) != 0) { if (installed && ps->repo == installed) { @@ -1638,11 +1730,12 @@ solver_addinfarchrules(Solver *solv, Map *addedmap) } for (j = 0; j < allowedarchs.count; j++) { + unsigned int aas; aa = allowedarchs.elements[j]; if (ps->arch == aa) break; - aa = (aa <= pool->lastarch) ? pool->id2arch[aa] : 0; - if (aa && ((a ^ aa) & 0xffff0000) == 0) + aas = pool_arch2score(pool, aa); + if (aas && ((a ^ aas) & 0xffff0000) == 0) break; /* compatible */ } if (j == allowedarchs.count) @@ -1654,7 +1747,7 @@ solver_addinfarchrules(Solver *solv, Map *addedmap) for (j = 0; j < badq.count; j++) { p = badq.elements[j]; - /* lock-step */ + /* special lock-step handling */ if (pool->implicitobsoleteusescolors) { Id p2; @@ -1665,9 +1758,8 @@ solver_addinfarchrules(Solver *solv, Map *addedmap) Solvable *s2 = pool->solvables + p2; if (p2 == p || s2->name != s->name || s2->evr != pool->solvables[p].evr || s2->arch == pool->solvables[p].arch) continue; - a = s2->arch; - a = (a <= pool->lastarch) ? pool->id2arch[a] : 0; - if (a && (a == 1 || ((a ^ bestarch) & 0xffff000) == 0)) + a = pool_arch2score(pool, s2->arch); + if (a && (a == 1 || ((a ^ bestscore) & 0xffff000) == 0)) { queue_push(&lsq, p2); if (installed && s2->repo == installed) @@ -1676,11 +1768,15 @@ solver_addinfarchrules(Solver *solv, Map *addedmap) } if (installed && pool->solvables[p].repo == installed && !haveinstalled) continue; /* installed package not in lock-step */ + if (lsq.count < 2) + solver_addrule(solv, -p, lsq.count ? lsq.elements[0] : 0, 0); + else + solver_addrule(solv, -p, 0, pool_queuetowhatprovides(pool, &lsq)); } - if (lsq.count < 2) - solver_addrule(solv, -p, lsq.count ? lsq.elements[0] : 0, 0); else - solver_addrule(solv, -p, 0, pool_queuetowhatprovides(pool, &lsq)); + { + solver_addrule(solv, -p, 0, 0); + } } } queue_free(&lsq); @@ -1922,6 +2018,21 @@ solver_createdupmaps(Solver *solv) } if (solv->dupinvolvedmap.size) MAPCLR(&solv->dupinvolvedmap, SYSTEMSOLVABLE); + /* set update for all involved installed packages. We need to do + * this before creating the update rules */ + if (solv->dupinvolvedmap_all) + solv->updatemap_all = 1; + else if (installed && !solv->updatemap_all && solv->dupinvolvedmap.size) + { + FOR_REPO_SOLVABLES(installed, p, s) + { + if (!MAPTST(&solv->dupinvolvedmap, p)) + continue; + if (!solv->updatemap.size) + map_grow(&solv->updatemap, installed->end - installed->start); + MAPSET(&solv->updatemap, p - installed->start); + } + } } void @@ -1943,8 +2054,6 @@ solver_addduprules(Solver *solv, Map *addedmap) Rule *r; solv->duprules = solv->nrules; - if (solv->dupinvolvedmap_all) - solv->updatemap_all = 1; for (i = 1; i < pool->nsolvables; i++) { if (i == SYSTEMSOLVABLE || !MAPTST(addedmap, i)) @@ -1964,12 +2073,8 @@ solver_addduprules(Solver *solv, Map *addedmap) continue; if (installed && ps->repo == installed) { - if (!solv->updatemap_all) - { - if (!solv->updatemap.size) - map_grow(&solv->updatemap, installed->end - installed->start); - MAPSET(&solv->updatemap, p - installed->start); - } + if (pool->considered && pool_disabled_solvable(pool, ps)) + continue; /* always keep disabled installed packages */ if (!MAPTST(&solv->dupmap, p)) { Id ip, ipp; @@ -2058,6 +2163,97 @@ reenableduprule(Solver *solv, Id name) } } +/*********************************************************************** + *** + *** Black rule part + ***/ + +static inline void +disableblackrule(Solver *solv, Id p) +{ + Rule *r; + int i; + for (i = solv->blackrules, r = solv->rules + i; i < solv->blackrules_end; i++, r++) + if (r->p == -p) + solver_disablerule(solv, r); +} + +static inline void +reenableblackrule(Solver *solv, Id p) +{ + Pool *pool = solv->pool; + Rule *r; + int i; + for (i = solv->blackrules, r = solv->rules + i; i < solv->blackrules_end; i++, r++) + if (r->p == -p) + { + solver_enablerule(solv, r); + IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS) + { + POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "@@@ re-enabling "); + solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r); + } + } +} + +void +solver_addblackrules(Solver *solv) +{ + int i; + Id how, select, what, p, pp; + Queue *job = &solv->job; + Pool *pool = solv->pool; + Repo *installed = solv->installed; + Map updatemap; + + map_init(&updatemap, 0); + solv->blackrules = solv->nrules; + if (installed) + { + for (i = 0; i < job->count; i += 2) + { + how = job->elements[i]; + select = job->elements[i] & SOLVER_SELECTMASK; + what = job->elements[i + 1]; + switch (how & SOLVER_JOBMASK) + { + case SOLVER_BLACKLIST: + FOR_JOB_SELECT(p, pp, select, what) + { + Solvable *s = pool->solvables + p; + if (s->repo != installed) + continue; + if (!updatemap.size) + map_grow(&updatemap, pool->ss.nstrings); + if (s->name > 0 && s->name < pool->ss.nstrings) + MAPSET(&updatemap, s->name); + } + } + } + } + for (i = 0; i < job->count; i += 2) + { + how = job->elements[i]; + select = job->elements[i] & SOLVER_SELECTMASK; + what = job->elements[i + 1]; + switch (how & SOLVER_JOBMASK) + { + case SOLVER_BLACKLIST: + FOR_JOB_SELECT(p, pp, select, what) + { + Solvable *s = pool->solvables + p; + if (s->repo == installed) + continue; + if (updatemap.size && s->name > 0 && s->name < pool->ss.nstrings && MAPTST(&updatemap, s->name)) + continue; /* installed package with same name is already blacklisted */ + solver_addrule(solv, -p, 0, 0); + } + break; + } + } + map_free(&updatemap); + solv->blackrules_end = solv->nrules; +} /*********************************************************************** *** @@ -2071,6 +2267,7 @@ reenableduprule(Solver *solv, Id name) #define DISABLE_UPDATE 1 #define DISABLE_INFARCH 2 #define DISABLE_DUP 3 +#define DISABLE_BLACK 4 static void jobtodisablelist(Solver *solv, Id how, Id what, Queue *q) @@ -2121,7 +2318,13 @@ jobtodisablelist(Solver *solv, Id how, Id what, Queue *q) if ((set & SOLVER_SETARCH) != 0 && solv->infarchrules != solv->infarchrules_end) { if (select == SOLVER_SOLVABLE) - queue_push2(q, DISABLE_INFARCH, pool->solvables[what].name); + { + for (i = solv->infarchrules; i < solv->infarchrules_end; i++) + if (solv->rules[i].p == -what) + break; + if (i < solv->infarchrules_end) + queue_push2(q, DISABLE_INFARCH, pool->solvables[what].name); + } else { int qcnt = q->count; @@ -2135,8 +2338,12 @@ jobtodisablelist(Solver *solv, Id how, Id what, Queue *q) if (q->elements[i + 1] == s->name) break; if (i < q->count) - continue; - queue_push2(q, DISABLE_INFARCH, s->name); + continue; /* already have that DISABLE_INFARCH element */ + for (i = solv->infarchrules; i < solv->infarchrules_end; i++) + if (solv->rules[i].p == -p) + break; + if (i < solv->infarchrules_end) + queue_push2(q, DISABLE_INFARCH, s->name); } } } @@ -2160,6 +2367,16 @@ jobtodisablelist(Solver *solv, Id how, Id what, Queue *q) } } } + if ((set & SOLVER_SETEVR) != 0 && solv->blackrules != solv->blackrules_end) + { + if (select == SOLVER_SOLVABLE) + queue_push2(q, DISABLE_BLACK, what); + else + { + FOR_JOB_SELECT(p, pp, select, what) + queue_push2(q, DISABLE_BLACK, p); + } + } if (!installed || installed->end == installed->start) return; /* now the hard part: disable some update rules */ @@ -2170,7 +2387,7 @@ jobtodisablelist(Solver *solv, Id how, Id what, Queue *q) if (pool->solvables[p].repo == installed) return; if (solv->multiversion.size && MAPTST(&solv->multiversion, p) && !solv->keepexplicitobsoletes) - return; + return; /* will not obsolete anything, so just return */ } omap.size = 0; qstart = q->count; @@ -2254,6 +2471,34 @@ jobtodisablelist(Solver *solv, Id how, Id what, Queue *q) #endif } return; + + case SOLVER_LOCK: + if (!installed) + break; + qstart = q->count; + if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid)) + { + FOR_REPO_SOLVABLES(installed, p, s) + { + for (i = qstart; i < q->count; i += 2) + if (q->elements[i] == DISABLE_DUP && q->elements[i + 1] == pool->solvables[p].name) + break; + if (i == q->count) + queue_push2(q, DISABLE_DUP, pool->solvables[p].name); + } + } + FOR_JOB_SELECT(p, pp, select, what) + { + if (pool->solvables[p].repo != installed) + continue; + for (i = qstart; i < q->count; i += 2) + if (q->elements[i] == DISABLE_DUP && q->elements[i + 1] == pool->solvables[p].name) + break; + if (i == q->count) + queue_push2(q, DISABLE_DUP, pool->solvables[p].name); + } + break; + default: return; } @@ -2305,6 +2550,9 @@ solver_disablepolicyrules(Solver *solv) case DISABLE_DUP: disableduprule(solv, arg); break; + case DISABLE_BLACK: + disableblackrule(solv, arg); + break; default: break; } @@ -2408,6 +2656,9 @@ solver_reenablepolicyrules(Solver *solv, int jobidx) case DISABLE_DUP: reenableduprule(solv, arg); break; + case DISABLE_BLACK: + reenableblackrule(solv, arg); + break; } } queue_free(&q); @@ -2488,7 +2739,8 @@ addpkgruleinfo(Solver *solv, Id p, Id p2, Id d, int type, Id dep) if (*odp) return; } - if (p < 0 && pool->whatprovidesdata[d] < 0 && type == SOLVER_RULE_PKG_CONFLICTS) + /* set p2 for multiversion conflicts */ + if (p < 0 && pool->whatprovidesdata[d] < 0 && pool->whatprovidesdata[d + 1] >= 0 && type == SOLVER_RULE_PKG_CONFLICTS) p2 = pool->whatprovidesdata[d]; } else @@ -2714,8 +2966,8 @@ solver_ruleinfo(Solver *solv, Id rid, Id *fromp, Id *top, Id *depp) } if (rid >= solv->bestrules && rid < solv->bestrules_end) { - if (fromp && solv->bestrules_pkg[rid - solv->bestrules] > 0) - *fromp = solv->bestrules_pkg[rid - solv->bestrules]; + if (fromp && solv->bestrules_info[rid - solv->bestrules] > 0) + *fromp = solv->bestrules_info[rid - solv->bestrules]; return SOLVER_RULE_BEST; } if (rid >= solv->yumobsrules && rid < solv->yumobsrules_end) @@ -2734,14 +2986,18 @@ solver_ruleinfo(Solver *solv, Id rid, Id *fromp, Id *top, Id *depp) *depp = solv->yumobsrules_info[rid - solv->yumobsrules]; return SOLVER_RULE_YUMOBS; } - if (rid >= solv->choicerules && rid < solv->choicerules_end) + if (rid >= solv->blackrules && rid < solv->blackrules_end) { - return SOLVER_RULE_CHOICE; + if (fromp) + *fromp = -r->p; + return SOLVER_RULE_BLACK; } + if (rid >= solv->choicerules && rid < solv->choicerules_end) + return SOLVER_RULE_CHOICE; + if (rid >= solv->recommendsrules && rid < solv->recommendsrules_end) + return SOLVER_RULE_RECOMMENDS; if (rid >= solv->learntrules) - { - return SOLVER_RULE_LEARNT; - } + return SOLVER_RULE_LEARNT; return SOLVER_RULE_UNKNOWN; } @@ -2766,8 +3022,14 @@ solver_ruleclass(Solver *solv, Id rid) return SOLVER_RULE_BEST; if (rid >= solv->yumobsrules && rid < solv->yumobsrules_end) return SOLVER_RULE_YUMOBS; + if (rid >= solv->blackrules && rid < solv->blackrules_end) + return SOLVER_RULE_BLACK; if (rid >= solv->choicerules && rid < solv->choicerules_end) return SOLVER_RULE_CHOICE; + if (rid >= solv->recommendsrules && rid < solv->recommendsrules_end) + return SOLVER_RULE_RECOMMENDS; + if (rid >= solv->blackrules && rid < solv->blackrules_end) + return SOLVER_RULE_BLACK; if (rid >= solv->learntrules && rid < solv->nrules) return SOLVER_RULE_LEARNT; return SOLVER_RULE_UNKNOWN; @@ -2829,7 +3091,9 @@ Id solver_rule2pkgrule(Solver *solv, Id rid) { if (rid >= solv->choicerules && rid < solv->choicerules_end) - return solv->choicerules_ref[rid - solv->choicerules]; + return solv->choicerules_info[rid - solv->choicerules]; + if (rid >= solv->recommendsrules && rid < solv->recommendsrules_end) + return solv->recommendsrules_info[rid - solv->recommendsrules]; return 0; } @@ -2945,7 +3209,7 @@ solver_addchoicerules(Solver *solv) Pool *pool = solv->pool; Map m, mneg; Rule *r; - Queue q, qi, qcheck; + Queue q, qi, qcheck, infoq; int i, j, rid, havechoice; Id p, d, pp; Id p2, pp2; @@ -2961,10 +3225,11 @@ solver_addchoicerules(Solver *solv) return; } now = solv_timems(0); - solv->choicerules_ref = solv_calloc(solv->pkgrules_end, sizeof(Id)); + solv->choicerules_info = solv_calloc(solv->pkgrules_end, sizeof(Id)); queue_init(&q); queue_init(&qi); queue_init(&qcheck); + queue_init(&infoq); map_init(&m, pool->nsolvables); map_init(&mneg, pool->nsolvables); /* set up negative assertion map from infarch and dup rules */ @@ -3153,7 +3418,7 @@ solver_addchoicerules(Solver *solv) solver_addrule(solv, r->p, 0, d); queue_push(&solv->weakruleq, solv->nrules - 1); - solv->choicerules_ref[solv->nrules - 1 - solv->choicerules] = rid; + queue_push(&infoq, rid); #if 0 printf("OLD "); solver_printrule(solv, SOLV_DEBUG_RESULT, solv->rules + rid); @@ -3161,20 +3426,21 @@ solver_addchoicerules(Solver *solv) solver_printrule(solv, SOLV_DEBUG_RESULT, solv->rules + solv->nrules - 1); #endif } + if (infoq.count) + solv->choicerules_info = solv_memdup2(infoq.elements, infoq.count, sizeof(Id)); queue_free(&q); queue_free(&qi); queue_free(&qcheck); + queue_free(&infoq); map_free(&m); map_free(&mneg); solv->choicerules_end = solv->nrules; - /* shrink choicerules_ref */ - solv->choicerules_ref = solv_realloc2(solv->choicerules_ref, solv->choicerules_end - solv->choicerules, sizeof(Id)); POOL_DEBUG(SOLV_DEBUG_STATS, "choice rule creation took %d ms\n", solv_timems(now)); } -/* called when a choice rule is disabled by analyze_unsolvable. We also - * have to disable all other choice rules so that the best packages get - * picked */ +/* called when a choice rule needs to be disabled by analyze_unsolvable. + * We also have to disable all other choice rules so that the best packages + * get picked */ void solver_disablechoicerules(Solver *solv, Rule *r) { @@ -3183,7 +3449,8 @@ solver_disablechoicerules(Solver *solv, Rule *r) Map m; Rule *or; - or = solv->rules + solv->choicerules_ref[(r - solv->rules) - solv->choicerules]; + solver_disablerule(solv, r); + or = solv->rules + solv->choicerules_info[(r - solv->rules) - solv->choicerules]; map_init(&m, pool->nsolvables); FOR_RULELITERALS(p, pp, or) if (p > 0) @@ -3196,7 +3463,7 @@ solver_disablechoicerules(Solver *solv, Rule *r) r = solv->rules + rid; if (r->d < 0) continue; - or = solv->rules + solv->choicerules_ref[(r - solv->rules) - solv->choicerules]; + or = solv->rules + solv->choicerules_info[rid - solv->choicerules]; FOR_RULELITERALS(p, pp, or) if (p > 0 && MAPTST(&m, p)) break; @@ -3236,8 +3503,34 @@ prune_to_dup_packages(Solver *solv, Id p, Queue *q) queue_truncate(q, j); } +static void +prune_best_update(Solver *solv, Id p, Queue *q) +{ + if (solv->update_targets && solv->update_targets->elements[p - solv->installed->start]) + prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[p - solv->installed->start], q); + if (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p)) + prune_to_dup_packages(solv, p, q); + /* select best packages, just look at prio and version */ + policy_filter_unwanted(solv, q, POLICY_MODE_RECOMMEND); +} + +static void +prune_disabled(Pool *pool, Queue *q) +{ + int i, j; + for (i = j = 0; i < q->count; i++) + { + Id p = q->elements[i]; + Solvable *s = pool->solvables + p; + if (s->repo && s->repo != pool->installed && !MAPTST(pool->considered, p)) + continue; + q->elements[j++] = p; + } + queue_truncate(q, j); +} + void -solver_addbestrules(Solver *solv, int havebestinstalljobs) +solver_addbestrules(Solver *solv, int havebestinstalljobs, int haslockjob) { Pool *pool = solv->pool; Id p; @@ -3245,48 +3538,99 @@ solver_addbestrules(Solver *solv, int havebestinstalljobs) Repo *installed = solv->installed; Queue q, q2; Rule *r; - Queue r2pkg; + Queue infoq; int i, oldcnt; + Map *lockedmap = 0; solv->bestrules = solv->nrules; queue_init(&q); queue_init(&q2); - queue_init(&r2pkg); + queue_init(&infoq); + if (haslockjob) + { + int i; + lockedmap = solv_calloc(1, sizeof(Map)); + map_init(lockedmap, pool->nsolvables); + for (i = 0, r = solv->rules + solv->jobrules; i < solv->ruletojob.count; i++, r++) + { + if (r->w2 || (solv->job.elements[solv->ruletojob.elements[i]] & SOLVER_JOBMASK) != SOLVER_LOCK) + continue; + p = r->p > 0 ? r->p : -r->p; + MAPSET(lockedmap, p); + } + } if (havebestinstalljobs) { for (i = 0; i < solv->job.count; i += 2) { - if ((solv->job.elements[i] & (SOLVER_JOBMASK | SOLVER_FORCEBEST)) == (SOLVER_INSTALL | SOLVER_FORCEBEST)) + Id how = solv->job.elements[i]; + if ((how & (SOLVER_JOBMASK | SOLVER_FORCEBEST)) == (SOLVER_INSTALL | SOLVER_FORCEBEST)) { - int j; + int j, k; Id p2, pp2; for (j = 0; j < solv->ruletojob.count; j++) - if (solv->ruletojob.elements[j] == i) - break; - if (j == solv->ruletojob.count) - continue; - r = solv->rules + solv->jobrules + j; - queue_empty(&q); - FOR_RULELITERALS(p2, pp2, r) - if (p2 > 0) - queue_push(&q, p2); - if (!q.count) - continue; /* orphaned */ - /* select best packages, just look at prio and version */ - oldcnt = q.count; - policy_filter_unwanted(solv, &q, POLICY_MODE_RECOMMEND); - if (q.count == oldcnt) - continue; /* nothing filtered */ - p2 = queue_shift(&q); - if (q.count < 2) - solver_addrule(solv, p2, q.count ? q.elements[0] : 0, 0); - else - solver_addrule(solv, p2, 0, pool_queuetowhatprovides(pool, &q)); - queue_push(&r2pkg, -(solv->jobrules + j)); + { + if (solv->ruletojob.elements[j] != i) + continue; + r = solv->rules + solv->jobrules + j; + queue_empty(&q); + queue_empty(&q2); + FOR_RULELITERALS(p2, pp2, r) + { + if (p2 > 0) + queue_push(&q, p2); + else if (p2 < 0) + queue_push(&q2, p2); + } + if (pool->considered && pool->whatprovideswithdisabled) + prune_disabled(pool, &q); + if (!q.count) + continue; /* orphaned */ + /* select best packages, just look at prio and version */ + oldcnt = q.count; + policy_filter_unwanted(solv, &q, POLICY_MODE_RECOMMEND); + if (q.count == oldcnt) + continue; /* nothing filtered */ + if (lockedmap) + { + queue_insertn(&q, 0, q2.count, q2.elements); + queue_empty(&q2); + FOR_RULELITERALS(p2, pp2, r) + { + if (p2 <= 0) + continue; + if (installed && pool->solvables[p2].repo == installed) + { + if (MAPTST(lockedmap, p2)) + queue_pushunique(&q, p2); /* we always want that package */ + } + else if (MAPTST(lockedmap, p2)) + continue; + queue_push(&q2, p2); + } + if (pool->considered && pool->whatprovideswithdisabled) + prune_disabled(pool, &q2); + policy_filter_unwanted(solv, &q2, POLICY_MODE_RECOMMEND); + for (k = 0; k < q2.count; k++) + queue_pushunique(&q, q2.elements[k]); + queue_empty(&q2); + } + if (q2.count) + queue_insertn(&q, 0, q2.count, q2.elements); + p2 = queue_shift(&q); + if (q.count < 2) + solver_addrule(solv, p2, q.count ? q.elements[0] : 0, 0); + else + solver_addrule(solv, p2, 0, pool_queuetowhatprovides(pool, &q)); + if ((how & SOLVER_WEAK) != 0) + queue_push(&solv->weakruleq, solv->nrules - 1); + queue_push(&infoq, -(solv->jobrules + j)); + } } } } + solv->bestrules_up = solv->nrules; if (installed && (solv->bestupdatemap_all || solv->bestupdatemap.size)) { @@ -3326,14 +3670,38 @@ solver_addbestrules(Solver *solv, int havebestinstalljobs) if (p2 > 0) queue_push(&q, p2); } - if (solv->update_targets && solv->update_targets->elements[p - installed->start]) - prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[p - installed->start], &q); - if (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p)) - prune_to_dup_packages(solv, p, &q); - /* select best packages, just look at prio and version */ - policy_filter_unwanted(solv, &q, POLICY_MODE_RECOMMEND); + if (lockedmap) + { + queue_empty(&q2); + queue_insertn(&q2, 0, q.count, q.elements); + } + prune_best_update(solv, p, &q); if (!q.count) continue; /* orphaned */ + if (lockedmap) + { + int j; + /* always ok to keep installed locked packages */ + if (MAPTST(lockedmap, p)) + queue_pushunique(&q2, p); + for (j = 0; j < q2.count; j++) + { + Id p2 = q2.elements[j]; + if (pool->solvables[p2].repo == installed && MAPTST(lockedmap, p2)) + queue_pushunique(&q, p2); + } + /* filter out locked packages */ + for (i = j = 0; j < q2.count; j++) + { + Id p2 = q2.elements[j]; + if (pool->solvables[p2].repo == installed || !MAPTST(lockedmap, p2)) + q2.elements[i++] = p2; + } + queue_truncate(&q2, i); + prune_best_update(solv, p, &q2); + for (j = 0; j < q2.count; j++) + queue_pushunique(&q, q2.elements[j]); + } if (solv->bestobeypolicy) { /* also filter the best of the feature rule packages and add them */ @@ -3345,13 +3713,20 @@ solver_addbestrules(Solver *solv, int havebestinstalljobs) FOR_RULELITERALS(p2, pp2, r) if (p2 > 0) queue_push(&q2, p2); - if (solv->update_targets && solv->update_targets->elements[p - installed->start]) - prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[p - installed->start], &q2); - if (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p)) - prune_to_dup_packages(solv, p, &q2); - policy_filter_unwanted(solv, &q2, POLICY_MODE_RECOMMEND); + prune_best_update(solv, p, &q2); for (j = 0; j < q2.count; j++) queue_pushunique(&q, q2.elements[j]); + if (lockedmap) + { + queue_empty(&q2); + FOR_RULELITERALS(p2, pp2, r) + if (p2 > 0) + if (pool->solvables[p2].repo == installed || !MAPTST(lockedmap, p2)) + queue_push(&q2, p2); + prune_best_update(solv, p, &q2); + for (j = 0; j < q2.count; j++) + queue_pushunique(&q, q2.elements[j]); + } } } if (solv->allowuninstall || solv->allowuninstall_all || (solv->allowuninstallmap.size && MAPTST(&solv->allowuninstallmap, p - installed->start))) @@ -3371,7 +3746,7 @@ solver_addbestrules(Solver *solv, int havebestinstalljobs) solver_addrule(solv, -p2, d, 0); else solver_addrule(solv, -p2, 0, -d); - queue_push(&r2pkg, p); + queue_push(&infoq, p); } for (i = 0; i < q.count; i++) MAPCLR(&m, q.elements[i]); @@ -3382,22 +3757,29 @@ solver_addbestrules(Solver *solv, int havebestinstalljobs) solver_addrule(solv, p2, q.count ? q.elements[0] : 0, 0); else solver_addrule(solv, p2, 0, pool_queuetowhatprovides(pool, &q)); - queue_push(&r2pkg, p); + queue_push(&infoq, p); } map_free(&m); } - if (r2pkg.count) - solv->bestrules_pkg = solv_memdup2(r2pkg.elements, r2pkg.count, sizeof(Id)); + if (infoq.count) + solv->bestrules_info = solv_memdup2(infoq.elements, infoq.count, sizeof(Id)); solv->bestrules_end = solv->nrules; queue_free(&q); queue_free(&q2); - queue_free(&r2pkg); + queue_free(&infoq); + if (lockedmap) + { + map_free(lockedmap); + solv_free(lockedmap); + } } /* yumobs rule handling */ +/* note that we use pool->obsoleteusescolors || pool->implicitobsoleteusescolors + * like in policy_findupdatepackages */ static void find_obsolete_group(Solver *solv, Id obs, Queue *q) @@ -3422,9 +3804,9 @@ find_obsolete_group(Solver *solv, Id obs, Queue *q) Id obs2, *obsp2; if (!os->obsoletes) continue; - if (pool->obsoleteusescolors && !pool_colormatch(pool, s2, os)) + if ((pool->obsoleteusescolors || pool->implicitobsoleteusescolors) && !pool_colormatch(pool, s2, os)) continue; - obsp2 = os->repo->idarraydata + os->obsoletes; + obsp2 = os->repo->idarraydata + os->obsoletes; while ((obs2 = *obsp2++) != 0) if (obs2 == obs) break; @@ -3440,9 +3822,9 @@ find_obsolete_group(Solver *solv, Id obs, Queue *q) continue; if (!os->obsoletes) continue; - if (pool->obsoleteusescolors && !pool_colormatch(pool, s2, os)) + if ((pool->obsoleteusescolors || pool->implicitobsoleteusescolors) && !pool_colormatch(pool, s2, os)) continue; - obsp2 = os->repo->idarraydata + os->obsoletes; + obsp2 = os->repo->idarraydata + os->obsoletes; while ((obs2 = *obsp2++) != 0) if (obs2 == obs) break; @@ -3506,7 +3888,7 @@ solver_addyumobsrules(Solver *solv) Repo *installed = solv->installed; Id p, op, *opp; Solvable *s; - Queue qo, qq, yumobsinfoq; + Queue qo, qq, infoq; int i, j, k; unsigned int now; @@ -3539,7 +3921,7 @@ printf("checking yumobs for %s\n", pool_solvable2str(pool, s)); continue; if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p2, obs)) continue; - if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2)) + if ((pool->obsoleteusescolors || pool->implicitobsoleteusescolors) && !pool_colormatch(pool, s, s2)) continue; queue_pushunique(&qo, obs); break; @@ -3552,7 +3934,7 @@ printf("checking yumobs for %s\n", pool_solvable2str(pool, s)); queue_free(&qo); return; } - queue_init(&yumobsinfoq); + queue_init(&infoq); queue_init(&qq); for (i = 0; i < qo.count; i++) { @@ -3570,7 +3952,7 @@ for (j = 0; j < qq.count; j++) else printf("%s\n", pool_solvid2str(pool, qq.elements[j])); #endif - + if (!qq.count) continue; /* at least two goups, build rules */ @@ -3599,22 +3981,70 @@ for (j = 0; j < qq.count; j++) solver_addrule(solv, -p, qq.elements[groupstart], 0); else solver_addrule(solv, -p, 0, pool_ids2whatprovides(pool, qq.elements + groupstart, k - groupstart)); - queue_push(&yumobsinfoq, qo.elements[i]); + queue_push(&infoq, qo.elements[i]); } groupstart = k + 1; groupk++; } } } - if (yumobsinfoq.count) - solv->yumobsrules_info = solv_memdup2(yumobsinfoq.elements, yumobsinfoq.count, sizeof(Id)); - queue_free(&yumobsinfoq); + if (infoq.count) + solv->yumobsrules_info = solv_memdup2(infoq.elements, infoq.count, sizeof(Id)); + queue_free(&infoq); queue_free(&qq); queue_free(&qo); solv->yumobsrules_end = solv->nrules; POOL_DEBUG(SOLV_DEBUG_STATS, "yumobs rule creation took %d ms\n", solv_timems(now)); } +/* recommendsrules are a copy of some recommends package rule but + * with some disfavored literals removed */ +void +solver_addrecommendsrules(Solver *solv) +{ + Pool *pool = solv->pool; + int i, havedis, havepos; + Id p, pp; + Queue q, infoq; + + solv->recommendsrules = solv->nrules; + queue_init(&q); + queue_init(&infoq); + for (i = 0; i < solv->recommendsruleq->count; i++) + { + int rid = solv->recommendsruleq->elements[i]; + Rule *r = solv->rules + rid; + queue_empty(&q); + havedis = havepos = 0; + FOR_RULELITERALS(p, pp, r) + { + if (p > 0 && solv->favormap[p] < 0) + havedis = 1; + else + { + if (p > 0) + havepos = 1; + queue_push(&q, p); + } + } + if (!havedis) + continue; + solver_disablerule(solv, r); + if (!havepos || q.count < 2) + continue; + if (q.count == 2) + solver_addrule(solv, q.elements[0], q.elements[1], 0); + else + solver_addrule(solv, q.elements[0], 0, pool_ids2whatprovides(pool, q.elements + 1, q.count - 1)); + queue_push(&infoq, rid); + } + if (infoq.count) + solv->recommendsrules_info = solv_memdup2(infoq.elements, infoq.count, sizeof(Id)); + queue_free(&infoq); + queue_free(&q); + solv->recommendsrules_end = solv->nrules; +} + void solver_breakorphans(Solver *solv) { @@ -3678,7 +4108,7 @@ solver_check_brokenorphanrules(Solver *solv, Queue *dq) Pool *pool = solv->pool; int i; Id l, pp; - + queue_empty(dq); if (!solv->brokenorphanrules) return;