X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fpolicy.c;h=6f06101ff6c4b63fe8e6ac88ad28049fd9919c35;hb=refs%2Ftags%2Fupstream%2F0.6.30;hp=915c865e84fb05438adac5816661caa1ae3a0368;hpb=4b5801decc6940c8a4d14fa0ca54df24456977eb;p=platform%2Fupstream%2Flibsolv.git diff --git a/src/policy.c b/src/policy.c index 915c865..6f06101 100644 --- a/src/policy.c +++ b/src/policy.c @@ -21,6 +21,9 @@ #include "policy.h" #include "poolvendor.h" #include "poolarch.h" +#include "linkedpkg.h" +#include "cplxdeps.h" + /*-----------------------------------------------------------------*/ @@ -51,6 +54,15 @@ prune_to_best_version_sortcmp(const void *ap, const void *bp, void *dp) nb = pool_id2str(pool, sb->name); return strcmp(na, nb); } + if (sa->arch != sb->arch) + { + int aa, ab; + aa = (sa->arch <= pool->lastarch) ? pool->id2arch[sa->arch] : 0; + ab = (sb->arch <= pool->lastarch) ? pool->id2arch[sb->arch] : 0; + if (aa != ab && aa > 1 && ab > 1) + return aa - ab; /* lowest score first */ + } + /* the same name, bring installed solvables to the front */ if (pool->installed) { @@ -106,9 +118,78 @@ prune_to_highest_prio(Pool *pool, Queue *plist) plist->count = j; } + +/* installed packages involed in a dup operation can only be kept + * if they are identical to a non-installed one */ static void -prune_to_highest_prio_per_name(Pool *pool, Queue *plist) +solver_prune_installed_dup_packages(Solver *solv, Queue *plist) { + Pool *pool = solv->pool; + int i, j, bestprio = 0; + + /* find bestprio (again) */ + for (i = 0; i < plist->count; i++) + { + Solvable *s = pool->solvables + plist->elements[i]; + if (s->repo != pool->installed) + { + bestprio = s->repo->priority; + break; + } + } + if (i == plist->count) + return; /* only installed packages, could not find prio */ + for (i = j = 0; i < plist->count; i++) + { + Id p = plist->elements[i]; + Solvable *s = pool->solvables + p; + if (s->repo != pool->installed && s->repo->priority < bestprio) + continue; + if (s->repo == pool->installed && (solv->dupinvolvedmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p)))) + { + Id p2, pp2; + int keepit = 0; + FOR_PROVIDES(p2, pp2, s->name) + { + Solvable *s2 = pool->solvables + p2; + if (s2->repo == pool->installed || s2->evr != s->evr || s2->repo->priority < bestprio) + continue; + if (!solvable_identical(s, s2)) + continue; + keepit = 1; + if (s2->repo->priority > bestprio) + { + /* new max prio! */ + bestprio = s2->repo->priority; + j = 0; + } + } + if (!keepit) + continue; /* no identical package found, ignore installed package */ + } + plist->elements[j++] = p; + } + if (j) + plist->count = j; +} + +/* + * like prune_to_highest_prio, but calls solver prune_installed_dup_packages + * when there are dup packages + */ +static inline void +solver_prune_to_highest_prio(Solver *solv, Queue *plist) +{ + prune_to_highest_prio(solv->pool, plist); + if (plist->count > 1 && solv->pool->installed && (solv->dupinvolvedmap_all || solv->dupinvolvedmap.size)) + solver_prune_installed_dup_packages(solv, plist); +} + + +static void +solver_prune_to_highest_prio_per_name(Solver *solv, Queue *plist) +{ + Pool *pool = solv->pool; Queue pq; int i, j, k; Id name; @@ -121,17 +202,17 @@ prune_to_highest_prio_per_name(Pool *pool, Queue *plist) { if (pool->solvables[plist->elements[i]].name != name) { + name = pool->solvables[plist->elements[i]].name; if (pq.count > 2) - prune_to_highest_prio(pool, &pq); + solver_prune_to_highest_prio(solv, &pq); for (k = 0; k < pq.count; k++) plist->elements[j++] = pq.elements[k]; queue_empty(&pq); - queue_push(&pq, plist->elements[i]); - name = pool->solvables[pq.elements[0]].name; } + queue_push(&pq, plist->elements[i]); } if (pq.count > 2) - prune_to_highest_prio(pool, &pq); + solver_prune_to_highest_prio(solv, &pq); for (k = 0; k < pq.count; k++) plist->elements[j++] = pq.elements[k]; queue_free(&pq); @@ -139,38 +220,158 @@ prune_to_highest_prio_per_name(Pool *pool, Queue *plist) } -/* - * prune to recommended/suggested packages. - * does not prune installed packages (they are also somewhat recommended). - */ +#ifdef ENABLE_COMPLEX_DEPS + +/* simple fixed-size hash for package ids */ +#define CPLXDEPHASH_EMPTY(elements) (memset(elements, 0, sizeof(Id) * 256)) +#define CPLXDEPHASH_SET(elements, p) (elements[(p) & 255] |= (1 << ((p) >> 8 & 31))) +#define CPLXDEPHASH_TST(elements, p) (elements[(p) & 255] && (elements[(p) & 255] & (1 << ((p) >> 8 & 31)))) static void -prune_to_recommended(Solver *solv, Queue *plist) +check_complex_dep(Solver *solv, Id dep, Map *m, Queue **cqp) { Pool *pool = solv->pool; - int i, j, k, ninst; - Solvable *s; - Id p, pp, rec, *recp, sug, *sugp; - - ninst = 0; - if (pool->installed) + Queue q; + queue_init(&q); + Id p; + int i, qcnt; + +#if 0 + printf("check_complex_dep %s\n", pool_dep2str(pool, dep)); +#endif + i = pool_normalize_complex_dep(pool, dep, &q, CPLXDEPS_EXPAND); + if (i == 0 || i == 1) { - for (i = 0; i < plist->count; i++) + queue_free(&q); + return; + } + qcnt = q.count; + for (i = 0; i < qcnt; i++) + { + /* we rely on the fact that blocks are ordered here. + * if we reach a positive element, we know that we + * saw all negative ones */ + for (; (p = q.elements[i]) < 0; i++) { - p = plist->elements[i]; - s = pool->solvables + p; - if (pool->installed && s->repo == pool->installed) - ninst++; + if (solv->decisionmap[-p] < 0) + break; + if (solv->decisionmap[-p] == 0) + queue_push(&q, -p); /* undecided negative literal */ + } + if (p <= 0) + { +#if 0 + printf("complex dep block cannot be true or no pos literals\n"); +#endif + while (q.elements[i]) + i++; + if (qcnt != q.count) + queue_truncate(&q, qcnt); + continue; + } + if (qcnt == q.count) + { + /* all negative literals installed, add positive literals to map */ + for (; (p = q.elements[i]) != 0; i++) + MAPSET(m, p); + } + else + { + /* at least one undecided negative literal, postpone */ + int j, k; + Queue *cq; +#if 0 + printf("add new complex dep block\n"); + for (j = qcnt; j < q.count; j++) + printf(" - %s\n", pool_solvid2str(pool, q.elements[j])); +#endif + while (q.elements[i]) + i++; + if (!(cq = *cqp)) + { + cq = solv_calloc(1, sizeof(Queue)); + queue_init(cq); + queue_insertn(cq, 0, 256, 0); /* allocate hash area */ + *cqp = cq; + } + for (j = qcnt; j < q.count; j++) + { + p = q.elements[j]; + /* check if we already have this (dep, p) entry */ + for (k = 256; k < cq->count; k += 2) + if (cq->elements[k + 1] == dep && cq->elements[k] == p) + break; + if (k == cq->count) + { + /* a new one. add to cq and hash */ + queue_push2(cq, p, dep); + CPLXDEPHASH_SET(cq->elements, p); + } + } + queue_truncate(&q, qcnt); } } - if (plist->count - ninst < 2) - return; + queue_free(&q); +} + +static void +recheck_complex_deps(Solver *solv, Id p, Map *m, Queue **cqp) +{ + Queue *cq = *cqp; + Id pp; + int i; +#if 0 + printf("recheck_complex_deps for package %s\n", pool_solvid2str(solv->pool, p)); +#endif + /* make sure that we don't have a false hit */ + for (i = 256; i < cq->count; i += 2) + if (cq->elements[i] == p) + break; + if (i == cq->count) + return; /* false alert */ + if (solv->decisionmap[p] <= 0) + return; /* just in case... */ + + /* rebuild the hash, call check_complex_dep for our package */ + CPLXDEPHASH_EMPTY(cq->elements); + for (i = 256; i < cq->count; i += 2) + if ((pp = cq->elements[i]) == p) + { + Id dep = cq->elements[i + 1]; + queue_deleten(cq, i, 2); + i -= 2; + check_complex_dep(solv, dep, m, &cq); + } + else + CPLXDEPHASH_SET(cq->elements, pp); +} + +#endif + + +void +policy_update_recommendsmap(Solver *solv) +{ + Pool *pool = solv->pool; + Solvable *s; + Id p, pp, rec, *recp, sug, *sugp; - /* update our recommendsmap/suggestsmap */ if (solv->recommends_index < 0) { MAPZERO(&solv->recommendsmap); MAPZERO(&solv->suggestsmap); +#ifdef ENABLE_COMPLEX_DEPS + if (solv->recommendscplxq) + { + queue_free(solv->recommendscplxq); + solv->recommendscplxq = solv_free(solv->recommendscplxq); + } + if (solv->suggestscplxq) + { + queue_free(solv->suggestscplxq); + solv->suggestscplxq = solv_free(solv->suggestscplxq); + } +#endif solv->recommends_index = 0; } while (solv->recommends_index < solv->decisionq.count) @@ -179,21 +380,191 @@ prune_to_recommended(Solver *solv, Queue *plist) if (p < 0) continue; s = pool->solvables + p; +#ifdef ENABLE_COMPLEX_DEPS + /* re-check postponed complex blocks */ + if (solv->recommendscplxq && CPLXDEPHASH_TST(solv->recommendscplxq->elements, p)) + recheck_complex_deps(solv, p, &solv->recommendsmap, &solv->recommendscplxq); + if (solv->suggestscplxq && CPLXDEPHASH_TST(solv->suggestscplxq->elements, p)) + recheck_complex_deps(solv, p, &solv->suggestsmap, &solv->suggestscplxq); +#endif if (s->recommends) { recp = s->repo->idarraydata + s->recommends; while ((rec = *recp++) != 0) - FOR_PROVIDES(p, pp, rec) - MAPSET(&solv->recommendsmap, p); + { +#ifdef ENABLE_COMPLEX_DEPS + if (pool_is_complex_dep(pool, rec)) + { + check_complex_dep(solv, rec, &solv->recommendsmap, &solv->recommendscplxq); + continue; + } +#endif + FOR_PROVIDES(p, pp, rec) + MAPSET(&solv->recommendsmap, p); + } } if (s->suggests) { sugp = s->repo->idarraydata + s->suggests; while ((sug = *sugp++) != 0) - FOR_PROVIDES(p, pp, sug) - MAPSET(&solv->suggestsmap, p); + { +#ifdef ENABLE_COMPLEX_DEPS + if (pool_is_complex_dep(pool, sug)) + { + check_complex_dep(solv, sug, &solv->suggestsmap, &solv->suggestscplxq); + continue; + } +#endif + FOR_PROVIDES(p, pp, sug) + MAPSET(&solv->suggestsmap, p); + } + } + } +} + +/* bring suggested/enhanced packages to front + * installed packages count as suggested */ +static void +prefer_suggested(Solver *solv, Queue *plist) +{ + Pool *pool = solv->pool; + int i, count; + + /* update our recommendsmap/suggestsmap */ + if (solv->recommends_index < solv->decisionq.count) + policy_update_recommendsmap(solv); + + for (i = 0, count = plist->count; i < count; i++) + { + Id p = plist->elements[i]; + Solvable *s = pool->solvables + p; + if ((pool->installed && s->repo == pool->installed) || + MAPTST(&solv->suggestsmap, p) || + solver_is_enhancing(solv, s)) + continue; /* good package */ + /* bring to back */ + if (i < plist->count - 1) + { + memmove(plist->elements + i, plist->elements + i + 1, (plist->count - 1 - i) * sizeof(Id)); + plist->elements[plist->count - 1] = p; + } + i--; + count--; + } +} + +static int +sort_by_favorq_cmp(const void *ap, const void *bp, void *dp) +{ + const Id *a = ap, *b = bp, *d = dp; + return d[b[0]] - d[a[0]]; +} + +static void +sort_by_favorq(Queue *favorq, Id *el, int cnt) +{ + int i; + /* map to offsets into favorq */ + for (i = 0; i < cnt; i++) + { + Id p = el[i]; + /* lookup p in sorted favorq */ + int med = 0, low = 0; + int high = favorq->count / 2; + while (low != high) + { + med = (low + high) / 2; + Id pp = favorq->elements[2 * med]; + if (pp < p) + low = med; + else if (pp > p) + high = med; + else + break; + } + while(med && favorq->elements[2 * med - 2] == p) + med--; + if (favorq->elements[2 * med] == p) + el[i] = 2 * med + 1; + else + el[i] = 0; /* hmm */ + } + /* sort by position */ + solv_sort(el, cnt, sizeof(Id), sort_by_favorq_cmp, favorq->elements); + /* map back */ + for (i = 0; i < cnt; i++) + if (el[i]) + el[i] = favorq->elements[el[i] - 1]; +} + +/* bring favored packages to front and disfavored packages to back */ +void +policy_prefer_favored(Solver *solv, Queue *plist) +{ + int i, fav, disfav, count; + if (!solv->favormap.size) + return; + for (i = fav = disfav = 0, count = plist->count; i < count; i++) + { + Id p = plist->elements[i]; + if (!MAPTST(&solv->favormap, p)) + continue; + if (solv->isdisfavormap.size && MAPTST(&solv->isdisfavormap, p)) + { + /* disfavored package. bring to back */ + if (i < plist->count - 1) + { + memmove(plist->elements + i, plist->elements + i + 1, (plist->count - 1 - i) * sizeof(Id)); + plist->elements[plist->count - 1] = p; + } + i--; + count--; + disfav++; + } + else + { + /* favored package. bring to front */ + if (i > fav) + memmove(plist->elements + fav + 1, plist->elements + fav, (i - fav) * sizeof(Id)); + plist->elements[fav++] = p; } } + /* if we have multiple favored/disfavored packages, sort by favorq index */ + if (fav > 1) + sort_by_favorq(solv->favorq, plist->elements, fav); + if (disfav > 1) + sort_by_favorq(solv->favorq, plist->elements + plist->count - disfav, disfav); +} + +/* + * prune to recommended/suggested packages. + * does not prune installed packages (they are also somewhat recommended). + */ +static void +prune_to_recommended(Solver *solv, Queue *plist) +{ + Pool *pool = solv->pool; + int i, j, k, ninst; + Solvable *s; + Id p; + + ninst = 0; + if (pool->installed) + { + for (i = 0; i < plist->count; i++) + { + p = plist->elements[i]; + s = pool->solvables + p; + if (pool->installed && s->repo == pool->installed) + ninst++; + } + } + if (plist->count - ninst < 2) + return; + + /* update our recommendsmap/suggestsmap */ + if (solv->recommends_index < solv->decisionq.count) + policy_update_recommendsmap(solv); /* prune to recommended/supplemented */ ninst = 0; @@ -225,6 +596,7 @@ prune_to_recommended(Solver *solv, Queue *plist) if (j) plist->count = j; +#if 0 /* anything left to prune? */ if (plist->count - ninst < 2) return; @@ -258,6 +630,7 @@ prune_to_recommended(Solver *solv, Queue *plist) } if (j) plist->count = j; +#endif } static void @@ -388,7 +761,7 @@ trj_visit(struct trj_data *trj, Id node) trj->nstack = stackstart; /* empty stack */ } } - + /* * remove entries from plist that are obsoleted by other entries * with different name. @@ -400,7 +773,7 @@ prune_obsoleted(Pool *pool, Queue *plist) struct trj_data trj; int i, j; Solvable *s; - + if (plist->count <= 16) { memset(data_buf, 0, sizeof(data_buf)); @@ -534,10 +907,10 @@ move_installed_to_front(Pool *pool, Queue *plist) * sort list of packages (given through plist) by name and evr * return result through plist */ -static void +void prune_to_best_version(Pool *pool, Queue *plist) { - int i, j; + int i, j, r; Solvable *s, *best; if (plist->count < 2) /* no need to prune for a single entry */ @@ -570,12 +943,13 @@ prune_to_best_version(Pool *pool, Queue *plist) best = s; /* take current as new best */ continue; } - - if (best->evr != s->evr) /* compare evr */ - { - if (pool_evrcmp(pool, best->evr, s->evr, EVRCMP_COMPARE) < 0) - best = s; - } + r = best->evr != s->evr ? pool_evrcmp(pool, best->evr, s->evr, EVRCMP_COMPARE) : 0; +#ifdef ENABLE_LINKED_PKGS + if (r == 0 && has_package_link(pool, s)) + r = pool_link_evrcmp(pool, best, s); +#endif + if (r < 0) + best = s; } plist->elements[j++] = best - pool->solvables; /* finish last group */ plist->count = j; @@ -594,48 +968,341 @@ prune_to_best_version(Pool *pool, Queue *plist) } -/* legacy, do not use anymore! - * (rates arch higher than version, but thats a policy) - */ +static int +sort_by_name_evr_sortcmp(const void *ap, const void *bp, void *dp) +{ + Pool *pool = dp; + Id a, *aa = (Id *)ap; + Id b, *bb = (Id *)bp; + Id r = aa[1] - bb[1]; + if (r) + return r < 0 ? -1 : 1; + if (aa[2] == bb[2]) + return 0; + a = aa[2] < 0 ? -aa[2] : aa[2]; + b = bb[2] < 0 ? -bb[2] : bb[2]; + r = pool_evrcmp(pool, b, a, pool->disttype != DISTTYPE_DEB ? EVRCMP_MATCH_RELEASE : EVRCMP_COMPARE); + if (!r && (aa[2] < 0 || bb[2] < 0)) + { + if (bb[2] >= 0) + return 1; + if (aa[2] >= 0) + return -1; + } + return r; +} +/* common end of sort_by_srcversion and sort_by_common_dep */ static void -prune_best_arch_name_version(const Solver *solv, Pool *pool, Queue *plist) +sort_by_name_evr_array(Pool *pool, Queue *plist, int count, int ent) { - if (plist->count > 1) - prune_to_best_arch(pool, plist); - if (plist->count > 1) - prune_to_best_version(pool, plist); + Id lastname; + int i, j, bad, havebad; + Id *pp, *elements = plist->elements; + + if (ent < 2) + { + queue_truncate(plist, count); + return; + } + solv_sort(elements + count * 2, ent, sizeof(Id) * 3, sort_by_name_evr_sortcmp, pool); + lastname = 0; + bad = havebad = 0; + for (i = 0, pp = elements + count * 2; i < ent; i++, pp += 3) + { + if (lastname && pp[1] == lastname) + { + if (pp[0] != pp[-3] && sort_by_name_evr_sortcmp(pp - 3, pp, pool) == -1) + { +#if 0 + printf("%s - %s: bad %s %s - %s\n", pool_solvid2str(pool, elements[pp[-3]]), pool_solvid2str(pool, elements[pp[0]]), pool_dep2str(pool, lastname), pool_id2str(pool, pp[-1] < 0 ? -pp[-1] : pp[-1]), pool_id2str(pool, pp[2] < 0 ? -pp[2] : pp[2])); +#endif + bad++; + havebad = 1; + } + } + else + { + bad = 0; + lastname = pp[1]; + } + elements[count + pp[0]] += bad; + } + +#if 0 +for (i = 0; i < count; i++) + printf("%s badness %d\n", pool_solvid2str(pool, elements[i]), elements[count + i]); +#endif + + if (havebad) + { + /* simple stable insertion sort */ + if (pool->installed) + for (i = 0; i < count; i++) + if (pool->solvables[elements[i]].repo == pool->installed) + elements[i + count] = 0; + for (i = 1; i < count; i++) + for (j = i, pp = elements + count + j; j > 0; j--, pp--) + if (pp[-1] > pp[0]) + { + Id *pp2 = pp - count; + Id p = pp[-1]; + pp[-1] = pp[0]; + pp[0] = p; + p = pp2[-1]; + pp2[-1] = pp2[0]; + pp2[0] = p; + } + else + break; + } + queue_truncate(plist, count); } -/* installed packages involed in a dup operation can only be kept - * if they are identical to a non-installed one */ +#if 0 static void -prune_installed_dup_packages(Solver *solv, Queue *plist) +sort_by_srcversion(Pool *pool, Queue *plist) { - Pool *pool = solv->pool; - int i, j, k; + int i, count = plist->count, ent = 0; + queue_insertn(plist, count, count, 0); + for (i = 0; i < count; i++) + { + Id name, evr, p = plist->elements[i]; + Solvable *s = pool->solvables + p; + if (solvable_lookup_void(s, SOLVABLE_SOURCENAME)) + name = s->name; + else + name = solvable_lookup_id(s, SOLVABLE_SOURCENAME); + if (solvable_lookup_void(s, SOLVABLE_SOURCEEVR)) + evr = s->evr; + else + evr = solvable_lookup_id(s, SOLVABLE_SOURCEEVR); + if (!name || !evr || ISRELDEP(evr)) + continue; + queue_push(plist, i); + queue_push2(plist, name, evr); + ent++; + } + sort_by_name_evr_array(pool, plist, count, ent); +} +#endif - for (i = j = 0; i < plist->count; i++) +static void +sort_by_common_dep(Pool *pool, Queue *plist) +{ + int i, count = plist->count, ent = 0; + Id id, *dp; + queue_insertn(plist, count, count, 0); + for (i = 0; i < count; i++) { Id p = plist->elements[i]; Solvable *s = pool->solvables + p; - if (s->repo == pool->installed && (solv->dupmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p)))) + if (!s->provides) + continue; + for (dp = s->repo->idarraydata + s->provides; (id = *dp++) != 0; ) { - for (k = 0; k < plist->count; k++) + Reldep *rd; + if (!ISRELDEP(id)) + continue; + rd = GETRELDEP(pool, id); + if ((rd->flags == REL_EQ || rd->flags == (REL_EQ | REL_LT) || rd->flags == REL_LT) && !ISRELDEP(rd->evr)) { - Solvable *s2 = pool->solvables + plist->elements[k]; - if (s2->repo != pool->installed && solvable_identical(s, s2)) - break; + if (rd->flags == REL_EQ) + { + /* ignore hashes */ + const char *s = pool_id2str(pool, rd->evr); + if (strlen(s) >= 4) + { + while ((*s >= 'a' && *s <= 'f') || (*s >= '0' && *s <= '9')) + s++; + if (!*s) + continue; + } + } + queue_push(plist, i); + queue_push2(plist, rd->name, rd->flags == REL_LT ? -rd->evr : rd->evr); + ent++; } - if (k == plist->count) - continue; /* no identical package found, ignore installed package */ } - plist->elements[j++] = p; } - if (j) - plist->count = j; + sort_by_name_evr_array(pool, plist, count, ent); +} + +/* check if we have an update candidate */ +static void +dislike_old_versions(Pool *pool, Queue *plist) +{ + int i, count; + + for (i = 0, count = plist->count; i < count; i++) + { + Id p = plist->elements[i]; + Solvable *s = pool->solvables + p; + Repo *repo = s->repo; + Id q, qq; + int bad = 0; + + if (!repo || repo == pool->installed) + continue; + FOR_PROVIDES(q, qq, s->name) + { + Solvable *qs = pool->solvables + q; + if (q == p) + continue; + if (s->name != qs->name || s->arch != qs->arch) + continue; + if (repo->priority != qs->repo->priority) + { + if (repo->priority > qs->repo->priority) + continue; + bad = 1; + break; + } + if (pool_evrcmp(pool, qs->evr, s->evr, EVRCMP_COMPARE) > 0) + { + bad = 1; + break; + } + } + if (!bad) + continue; + /* bring to back */ + if (i < plist->count - 1) + { + memmove(plist->elements + i, plist->elements + i + 1, (plist->count - 1 - i) * sizeof(Id)); + plist->elements[plist->count - 1] = p; + } + i--; + count--; + } +} + + +/* special lang package handling for urpm */ +/* see https://bugs.mageia.org/show_bug.cgi?id=18315 */ + +static int +urpm_reorder_cmp(const void *ap, const void *bp, void *dp) +{ + return ((Id *)bp)[1] - ((Id *)ap)[1]; +} + +static void +urpm_reorder(Solver *solv, Queue *plist) +{ + Pool *pool = solv->pool; + int i, count = plist->count; + /* add locale score to packages */ + queue_insertn(plist, count, count, 0); + for (i = count - 1; i >= 0; i--) + { + Solvable *s = pool->solvables + plist->elements[i]; + int score = 1; + const char *sn = pool_id2str(pool, s->name); + + if (!strncmp(sn, "kernel-", 7)) + { + const char *devel = strstr(sn, "-devel-"); + if (devel && strlen(sn) < 256) + { + char kn[256]; + Id p, pp, knid; + memcpy(kn, sn, devel - sn); + strcpy(kn + (devel - sn), devel + 6); + knid = pool_str2id(pool, kn, 0); + if (knid) + { + FOR_PROVIDES(p, pp, knid) + { + if (solv->decisionmap[p] > 0) + { + score = 4; + break; + } + else if (pool->installed && pool->solvables[p].repo == pool->installed) + score = 3; + } + } + } + } + else if ((sn = strstr(sn, "-kernel-")) != 0) + { + sn += 8; + if (strlen(sn) < 256 - 8 && *sn >= '0' && *sn <= '9' && sn[1] == '.') + { + const char *flavor = strchr(sn, '-'); + if (flavor) + { + const char *release = strchr(flavor + 1, '-'); + if (release) + { + char kn[256]; + Id p, pp, knid; + memcpy(kn, "kernel", 8); + memcpy(kn + 6, flavor, release - flavor + 1); + memcpy(kn + 6 + (release - flavor) + 1, sn, flavor - sn); + strcpy(kn + 6 + (release + 1 - sn), release); + knid = pool_str2id(pool, kn, 0); + if (knid) + { + FOR_PROVIDES(p, pp, knid) + { + if (solv->decisionmap[p] > 0) + { + score = 4; + break; + } + if (pool->installed && pool->solvables[p].repo == pool->installed) + score = 3; + } + } + } + } + } + } + if (score == 1 && s->requires) + { + Id id, *idp, p, pp; + const char *deps; + for (idp = s->repo->idarraydata + s->requires; (id = *idp) != 0; idp++) + { + while (ISRELDEP(id)) + { + Reldep *rd = GETRELDEP(pool, id); + id = rd->name; + } + deps = strstr(pool_id2str(pool, id), "locales-"); + if (!deps) + continue; + if (!strncmp(deps + 8, "en", 2)) + score = 2; + else + { + score = 0; + FOR_PROVIDES(p, pp, id) + { + if (solv->decisionmap[p] > 0) + { + score = 4; + break; + } + if (pool->installed && pool->solvables[p].repo == pool->installed) + score = 3; + } + break; + } + } + } + plist->elements[i * 2] = plist->elements[i]; + plist->elements[i * 2 + 1] = score; + } + solv_sort(plist->elements, count, sizeof(Id) * 2, urpm_reorder_cmp, pool); + for (i = 0; i < count; i++) + plist->elements[i] = plist->elements[2 * i]; + queue_truncate(plist, count); } + /* * POLICY_MODE_CHOOSE: default, do all pruning steps * POLICY_MODE_RECOMMEND: leave out prune_to_recommended @@ -645,20 +1312,61 @@ void policy_filter_unwanted(Solver *solv, Queue *plist, int mode) { Pool *pool = solv->pool; + if (mode == POLICY_MODE_SUPPLEMENT) + { + /* reorder only */ + dislike_old_versions(pool, plist); + sort_by_common_dep(pool, plist); + if (solv->urpmreorder) + urpm_reorder(solv, plist); + prefer_suggested(solv, plist); + policy_prefer_favored(solv, plist); + return; + } if (plist->count > 1) { if (mode != POLICY_MODE_SUGGEST) - prune_to_highest_prio(pool, plist); + solver_prune_to_highest_prio(solv, plist); else - prune_to_highest_prio_per_name(pool, plist); - /* installed dup packages need special treatment as prio pruning - * does not prune installed packages */ - if (plist->count > 1 && pool->installed && (solv->dupmap_all || solv->dupinvolvedmap.size)) - prune_installed_dup_packages(solv, plist); + solver_prune_to_highest_prio_per_name(solv, plist); + } + if (plist->count > 1) + prune_to_best_arch(pool, plist); + if (plist->count > 1) + prune_to_best_version(pool, plist); + if (plist->count > 1 && (mode == POLICY_MODE_CHOOSE || mode == POLICY_MODE_CHOOSE_NOREORDER)) + { + prune_to_recommended(solv, plist); + if (plist->count > 1 && mode != POLICY_MODE_CHOOSE_NOREORDER) + { + /* do some fancy reordering */ +#if 0 + sort_by_srcversion(pool, plist); +#endif + dislike_old_versions(pool, plist); + sort_by_common_dep(pool, plist); + if (solv->urpmreorder) + urpm_reorder(solv, plist); + prefer_suggested(solv, plist); + policy_prefer_favored(solv, plist); + } + } +} + +void +pool_best_solvables(Pool *pool, Queue *plist, int flags) +{ + if (plist->count > 1) + prune_to_highest_prio(pool, plist); + if (plist->count > 1) + prune_to_best_arch(pool, plist); + if (plist->count > 1) + prune_to_best_version(pool, plist); + if (plist->count > 1) + { + dislike_old_versions(pool, plist); + sort_by_common_dep(pool, plist); } - if (plist->count > 1 && mode == POLICY_MODE_CHOOSE) - prune_to_recommended(solv, plist); - prune_best_arch_name_version(solv, pool, plist); } @@ -716,7 +1424,7 @@ policy_is_illegal(Solver *solv, Solvable *is, Solvable *s, int ignore) { Pool *pool = solv->pool; int ret = 0; - int duppkg = solv->dupmap_all ? 1 : 0; + int duppkg = solv->dupinvolvedmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, is - pool->solvables)); if (!(ignore & POLICY_ILLEGAL_DOWNGRADE) && !(duppkg ? solv->dup_allowdowngrade : solv->allowdowngrade)) { if (is->name == s->name && pool_evrcmp(pool, is->evr, s->evr, EVRCMP_COMPARE) > 0) @@ -741,7 +1449,7 @@ policy_is_illegal(Solver *solv, Solvable *is, Solvable *s, int ignore) } /*------------------------------------------------------------------- - * + * * create reverse obsoletes map for installed solvables * * For each installed solvable find which packages with *different* names @@ -828,12 +1536,12 @@ policy_create_obsolete_index(Solver *solv) /* * find update candidates - * + * * s: installed solvable to be updated * qs: [out] queue to hold Ids of candidates * allow_all: 0 = dont allow downgrades, 1 = allow all candidates * 2 = dup mode - * + * */ void policy_findupdatepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all) @@ -871,13 +1579,20 @@ policy_findupdatepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all) ps = pool->solvables + p; if (s->name == ps->name) /* name match */ { + if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps)) + continue; if (!allowdowngrade && pool_evrcmp(pool, s->evr, ps->evr, EVRCMP_COMPARE) > 0) continue; } else if (!allownamechange) continue; - else if (!solv->noupdateprovide && ps->obsoletes) /* provides/obsoletes combination ? */ + else if ((!solv->noupdateprovide || solv->needupdateprovide) && ps->obsoletes) /* provides/obsoletes combination ? */ { + /* check if package ps obsoletes installed package s */ + /* implicitobsoleteusescolors is somewhat wrong here, but we nevertheless + * use it to limit our update candidates */ + if ((pool->obsoleteusescolors || pool->implicitobsoleteusescolors) && !pool_colormatch(pool, s, ps)) + continue; obsp = ps->repo->idarraydata + ps->obsoletes; while ((obs = *obsp++) != 0) /* for all obsoletes */ { @@ -886,8 +1601,6 @@ policy_findupdatepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all) Solvable *ps2 = pool->solvables + p2; if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps2, obs)) continue; - if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps2)) - continue; if (p2 == n) /* match ! */ break; } @@ -913,7 +1626,7 @@ policy_findupdatepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all) return; /* if we have found some valid candidates and noupdateprovide is not set, we're done. otherwise we fallback to all obsoletes */ - if (!solv->noupdateprovide && haveprovobs) + if (solv->needupdateprovide || (!solv->noupdateprovide && haveprovobs)) return; if (solv->obsoletes && solv->obsoletes[n - solv->installed->start]) { @@ -925,6 +1638,10 @@ policy_findupdatepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all) continue; if (!allowvendorchange && s->vendor != ps->vendor && policy_illegal_vendorchange(solv, s, ps)) continue; + /* implicitobsoleteusescolors is somewhat wrong here, but we nevertheless + * use it to limit our update candidates */ + if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps)) + continue; queue_push(qs, p); } }