From: Michael Schroeder Date: Fri, 25 Jul 2014 16:22:43 +0000 (+0200) Subject: support yum style obsolete handling for package splits X-Git-Tag: 0.6.5~9 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=99e2d6786a2f18126932170eccd5da139eb5f438;p=thirdparty%2Flibsolv.git support yum style obsolete handling for package splits Actually slightly modified: we insist that the dependencies in the split group are exactly identical. Let's see how this works out in practice... --- diff --git a/bindings/solv.i b/bindings/solv.i index 2d8f7752..124bdca6 100644 --- a/bindings/solv.i +++ b/bindings/solv.i @@ -2769,6 +2769,7 @@ rb_eval_string( static const int SOLVER_FLAG_KEEP_ORPHANS = SOLVER_FLAG_KEEP_ORPHANS; static const int SOLVER_FLAG_BREAK_ORPHANS = SOLVER_FLAG_BREAK_ORPHANS; static const int SOLVER_FLAG_FOCUS_INSTALLED = SOLVER_FLAG_FOCUS_INSTALLED; + static const int SOLVER_FLAG_YUM_OBSOLETES = SOLVER_FLAG_YUM_OBSOLETES; static const int SOLVER_REASON_UNRELATED = SOLVER_REASON_UNRELATED; static const int SOLVER_REASON_UNIT_RULE = SOLVER_REASON_UNIT_RULE; diff --git a/ext/testcase.c b/ext/testcase.c index 3da7affe..6f1c5b46 100644 --- a/ext/testcase.c +++ b/ext/testcase.c @@ -105,6 +105,7 @@ static struct solverflags2str { { SOLVER_FLAG_KEEP_ORPHANS, "keeporphans", 0 }, { SOLVER_FLAG_BREAK_ORPHANS, "breakorphans", 0 }, { SOLVER_FLAG_FOCUS_INSTALLED, "focusinstalled", 0 }, + { SOLVER_FLAG_YUM_OBSOLETES, "yumobsoletes", 0 }, { 0, 0, 0 } }; diff --git a/src/policy.c b/src/policy.c index 5b72517a..9e5a934d 100644 --- a/src/policy.c +++ b/src/policy.c @@ -776,7 +776,7 @@ 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; diff --git a/src/policy.h b/src/policy.h index d034f0de..a4dd4c42 100644 --- a/src/policy.h +++ b/src/policy.h @@ -36,6 +36,9 @@ extern void policy_update_recommendsmap(Solver *solv); extern void policy_create_obsolete_index(Solver *solv); +/* internal, do not use */ +extern void prune_to_best_version(Pool *pool, Queue *plist); + #ifdef __cplusplus } diff --git a/src/problems.c b/src/problems.c index bb00aa6a..b2063a5d 100644 --- a/src/problems.c +++ b/src/problems.c @@ -918,7 +918,7 @@ findproblemrule_internal(Solver *solv, Id idx, Id *reqrp, Id *conrp, Id *sysrp, MAPSET(rseen, rid - solv->learntrules); findproblemrule_internal(solv, solv->learnt_why.elements[rid - solv->learntrules], &lreqr, &lconr, &lsysr, &ljobr, rseen); } - else if ((rid >= solv->jobrules && rid < solv->jobrules_end) || (rid >= solv->infarchrules && rid < solv->infarchrules_end) || (rid >= solv->duprules && rid < solv->duprules_end) || (rid >= solv->bestrules && rid < solv->bestrules_end)) + else if ((rid >= solv->jobrules && rid < solv->jobrules_end) || (rid >= solv->infarchrules && rid < solv->infarchrules_end) || (rid >= solv->duprules && rid < solv->duprules_end) || (rid >= solv->bestrules && rid < solv->bestrules_end) || (rid >= solv->yumobsrules && rid <= solv->yumobsrules_end)) { if (!*jobrp) *jobrp = rid; @@ -1105,6 +1105,10 @@ solver_problemruleinfo2str(Solver *solv, SolverRuleinfo type, Id source, Id targ return pool_tmpjoin(pool, pool_dep2str(pool, dep), " is provided by the system", 0); case SOLVER_RULE_RPM: return "some dependency problem"; + case SOLVER_RULE_BEST: + if (source > 0) + return pool_tmpjoin(pool, "cannot install the best update candidate for package ", pool_solvid2str(pool, source), 0); + return "cannot install the best candidate for the job"; case SOLVER_RULE_RPM_NOT_INSTALLABLE: return pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), " is not installable"); case SOLVER_RULE_RPM_NOTHING_PROVIDES_DEP: @@ -1135,6 +1139,10 @@ solver_problemruleinfo2str(Solver *solv, SolverRuleinfo type, Id source, Id targ case SOLVER_RULE_RPM_SELF_CONFLICT: s = pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), " conflicts with "); return pool_tmpappend(pool, s, pool_dep2str(pool, dep), " provided by itself"); + case SOLVER_RULE_YUMOBS: + s = pool_tmpjoin(pool, "both package ", pool_solvid2str(pool, source), " and "); + s = pool_tmpjoin(pool, s, pool_solvid2str(pool, target), " obsolete "); + return pool_tmpappend(pool, s, pool_dep2str(pool, dep), 0); default: return "bad problem rule type"; } diff --git a/src/rules.c b/src/rules.c index f245533c..8f07bab6 100644 --- a/src/rules.c +++ b/src/rules.c @@ -2652,8 +2652,26 @@ 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]; return SOLVER_RULE_BEST; } + if (rid >= solv->yumobsrules && rid < solv->yumobsrules_end) + { + if (fromp) + *fromp = -r->p; + if (top) + { + /* first solvable is enough, we just need it for the name */ + if (!r->d || r->d == -1) + *top = r->w2; + else + *top = pool->whatprovidesdata[r->d < 0 ? -r->d : r->d]; + } + if (depp) + *depp = solv->yumobsrules_info[rid - solv->yumobsrules]; + return SOLVER_RULE_YUMOBS; + } if (rid >= solv->choicerules && rid < solv->choicerules_end) { return SOLVER_RULE_CHOICE; @@ -2684,6 +2702,8 @@ solver_ruleclass(Solver *solv, Id rid) return SOLVER_RULE_INFARCH; if (rid >= solv->bestrules && rid < solv->bestrules_end) return SOLVER_RULE_BEST; + if (rid >= solv->yumobsrules && rid < solv->yumobsrules_end) + return SOLVER_RULE_YUMOBS; if (rid >= solv->choicerules && rid < solv->choicerules_end) return SOLVER_RULE_CHOICE; if (rid >= solv->learntrules) @@ -3251,6 +3271,228 @@ solver_addbestrules(Solver *solv, int havebestinstalljobs) queue_free(&r2pkg); } + + + +/* yumobs rule handling */ + +static void +find_obsolete_group(Solver *solv, Id obs, Queue *q) +{ + Pool *pool = solv->pool; + Queue qn; + Id p2, pp2, op, *opp, opp2; + int i, j, qnc, ncnt; + + queue_empty(q); + FOR_PROVIDES(p2, pp2, obs) + { + Solvable *s2 = pool->solvables + p2; + if (s2->repo != pool->installed) + continue; + if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p2, obs)) + continue; + /* we obsolete installed package s2 with obs. now find all other packages that have the same dep */ + for (opp = solv->obsoletes_data + solv->obsoletes[p2 - solv->installed->start]; (op = *opp++) != 0;) + { + Solvable *os = pool->solvables + op; + Id obs2, *obsp2; + if (!os->obsoletes) + continue; + if (pool->obsoleteusescolors && !pool_colormatch(pool, s2, os)) + continue; + obsp2 = os->repo->idarraydata + os->obsoletes; + while ((obs2 = *obsp2++) != 0) + if (obs2 == obs) + break; + if (obs2) + queue_pushunique(q, op); + } + /* also search packages with the same name */ + FOR_PROVIDES(op, opp2, s2->name) + { + Solvable *os = pool->solvables + op; + Id obs2, *obsp2; + if (os->name != s2->name) + continue; + if (!os->obsoletes) + continue; + if (pool->obsoleteusescolors && !pool_colormatch(pool, s2, os)) + continue; + obsp2 = os->repo->idarraydata + os->obsoletes; + while ((obs2 = *obsp2++) != 0) + if (obs2 == obs) + break; + if (obs2) + queue_pushunique(q, op); + } + } + /* find names so that we can build groups */ + queue_init_clone(&qn, q); + prune_to_best_version(solv->pool, &qn); +#if 0 +{ + for (i = 0; i < qn.count; i++) + printf(" + %s\n", pool_solvid2str(pool, qn.elements[i])); +} +#endif + /* filter into name groups */ + qnc = qn.count; + if (qnc == 1) + { + queue_free(&qn); + queue_empty(q); + return; + } + ncnt = 0; + for (i = 0; i < qnc; i++) + { + Id n = pool->solvables[qn.elements[i]].name; + int got = 0; + for (j = 0; j < q->count; j++) + { + Id p = q->elements[j]; + if (pool->solvables[p].name == n) + { + queue_push(&qn, p); + got = 1; + } + } + if (got) + { + queue_push(&qn, 0); + ncnt++; + } + } + if (ncnt <= 1) + { + queue_empty(q); + } + else + { + queue_empty(q); + queue_insertn(q, 0, qn.count - qnc, qn.elements + qnc); + } + queue_free(&qn); +} + +void +solver_addyumobsrules(Solver *solv) +{ + Pool *pool = solv->pool; + Repo *installed = solv->installed; + Id p, op, *opp; + Solvable *s; + Queue qo, qq, yumobsinfoq; + int i, j, k; + unsigned int now; + + solv->yumobsrules = solv->nrules; + if (!installed || !solv->obsoletes) + { + solv->yumobsrules_end = solv->nrules; + return; + } + now = solv_timems(0); + queue_init(&qo); + FOR_REPO_SOLVABLES(installed, p, s) + { + if (!solv->obsoletes[p - installed->start]) + continue; +#if 0 +printf("checking yumobs for %s\n", pool_solvable2str(pool, s)); +#endif + queue_empty(&qo); + for (opp = solv->obsoletes_data + solv->obsoletes[p - installed->start]; (op = *opp++) != 0;) + { + Solvable *os = pool->solvables + op; + Id obs, *obsp = os->repo->idarraydata + os->obsoletes; + Id p2, pp2; + while ((obs = *obsp++) != 0) + { + FOR_PROVIDES(p2, pp2, obs) + { + Solvable *s2 = pool->solvables + p2; + if (s2->repo != installed) + continue; + if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p2, obs)) + continue; + if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2)) + continue; + queue_pushunique(&qo, obs); + break; + } + } + } + } + if (!qo.count) + { + queue_free(&qo); + return; + } + queue_init(&yumobsinfoq); + queue_init(&qq); + for (i = 0; i < qo.count; i++) + { + int group, groupk, groupstart; + queue_empty(&qq); +#if 0 +printf("investigating %s\n", pool_dep2str(pool, qo.elements[i])); +#endif + find_obsolete_group(solv, qo.elements[i], &qq); +#if 0 +printf("result:\n"); +for (j = 0; j < qq.count; j++) + if (qq.elements[j] == 0) + printf("---\n"); + else + printf("%s\n", pool_solvid2str(pool, qq.elements[j])); +#endif + + if (!qq.count) + continue; + /* at least two goups, build rules */ + group = 0; + for (j = 0; j < qq.count; j++) + { + p = qq.elements[j]; + if (!p) + { + group++; + continue; + } + if (pool->solvables[p].repo == installed) + continue; + groupk = 0; + groupstart = 0; + for (k = 0; k < qq.count; k++) + { + Id pk = qq.elements[k]; + if (pk) + continue; + if (group != groupk && k > groupstart) + { + /* add the rule */ + Queue qhelper; + memset(&qhelper, 0, sizeof(qhelper)); + qhelper.count = k - groupstart; + qhelper.elements = qq.elements + groupstart; + solver_addrule(solv, -p, pool_queuetowhatprovides(pool, &qhelper)); + queue_push(&yumobsinfoq, qo.elements[i]); + } + groupstart = k + 1; + groupk++; + } + } + } + if (yumobsinfoq.count) + solv->yumobsrules_info = solv_memdup2(yumobsinfoq.elements, yumobsinfoq.count, sizeof(Id)); + queue_free(&yumobsinfoq); + queue_free(&qq); + solv->yumobsrules_end = solv->nrules; + POOL_DEBUG(SOLV_DEBUG_STATS, "yumobs rule creation took %d ms\n", solv_timems(now)); +} + #undef CLEANDEPSDEBUG /* diff --git a/src/rules.h b/src/rules.h index 06048e43..3be3ea1e 100644 --- a/src/rules.h +++ b/src/rules.h @@ -69,7 +69,8 @@ typedef enum { SOLVER_RULE_INFARCH = 0x600, SOLVER_RULE_CHOICE = 0x700, SOLVER_RULE_LEARNT = 0x800, - SOLVER_RULE_BEST = 0x900 + SOLVER_RULE_BEST = 0x900, + SOLVER_RULE_YUMOBS = 0xa00 } SolverRuleinfo; #define SOLVER_RULE_TYPEMASK 0xff00 @@ -127,6 +128,9 @@ extern void solver_disablechoicerules(struct _Solver *solv, Rule *r); /* best rules */ extern void solver_addbestrules(struct _Solver *solv, int havebestinstalljobs); +/* yumobs rules */ +extern void solver_addyumobsrules(struct _Solver *solv); + /* policy rule disabling/reenabling */ extern void solver_disablepolicyrules(struct _Solver *solv); extern void solver_reenablepolicyrules(struct _Solver *solv, int jobidx); diff --git a/src/solver.c b/src/solver.c index b0f1bce7..48b3aaac 100644 --- a/src/solver.c +++ b/src/solver.c @@ -1681,6 +1681,7 @@ solver_free(Solver *solv) solv_free(solv->specialupdaters); solv_free(solv->choicerules_ref); solv_free(solv->bestrules_pkg); + solv_free(solv->yumobsrules_info); solv_free(solv->instbuddy); solv_free(solv); } @@ -1730,6 +1731,8 @@ solver_get_flag(Solver *solv, int flag) return solv->break_orphans; case SOLVER_FLAG_FOCUS_INSTALLED: return solv->focus_installed; + case SOLVER_FLAG_YUM_OBSOLETES: + return solv->do_yum_obsoletes; default: break; } @@ -1802,6 +1805,9 @@ solver_set_flag(Solver *solv, int flag, int value) case SOLVER_FLAG_FOCUS_INSTALLED: solv->focus_installed = value; break; + case SOLVER_FLAG_YUM_OBSOLETES: + solv->do_yum_obsoletes = value; + break; default: break; } @@ -3401,6 +3407,7 @@ solver_solve(Solver *solv, Queue *job) queuep_free(&solv->cleandeps_updatepkgs); queue_empty(&solv->ruleassertions); solv->bestrules_pkg = solv_free(solv->bestrules_pkg); + solv->yumobsrules_info = solv_free(solv->yumobsrules_info); solv->choicerules_ref = solv_free(solv->choicerules_ref); if (solv->noupdate.size) map_empty(&solv->noupdate); @@ -3963,6 +3970,11 @@ solver_solve(Solver *solv, Queue *job) if (hasdupjob) solver_freedupmaps(solv); /* no longer needed */ + if (solv->do_yum_obsoletes) + solver_addyumobsrules(solv); + else + solv->yumobsrules = solv->yumobsrules_end = solv->nrules; + if (1) solver_addchoicerules(solv); else diff --git a/src/solver.h b/src/solver.h index 3d63b6fe..49ccec8b 100644 --- a/src/solver.h +++ b/src/solver.h @@ -70,6 +70,10 @@ struct _Solver { Id bestrules_end; Id *bestrules_pkg; + Id yumobsrules; /* rules from yum obsoletes handling */ + Id yumobsrules_end; + Id *yumobsrules_info; /* the dependency for each rule */ + Id choicerules; /* choice rules (always weak) */ Id choicerules_end; Id *choicerules_ref; @@ -161,6 +165,7 @@ struct _Solver { int bestobeypolicy; /* true: stay in policy with the best rules */ int noautotarget; /* true: do not assume targeted for up/dup jobs that contain no installed solvable */ int focus_installed; /* true: resolve update rules first */ + int do_yum_obsoletes; /* true: add special yumobs rules */ Map dupmap; /* dup these packages*/ int dupmap_all; /* dup all packages */ @@ -289,6 +294,7 @@ typedef struct _Solver Solver; #define SOLVER_FLAG_KEEP_ORPHANS 18 #define SOLVER_FLAG_BREAK_ORPHANS 19 #define SOLVER_FLAG_FOCUS_INSTALLED 20 +#define SOLVER_FLAG_YUM_OBSOLETES 21 #define GET_USERINSTALLED_NAMES (1 << 0) /* package names instead if ids */ #define GET_USERINSTALLED_INVERTED (1 << 1) /* autoinstalled */ diff --git a/src/solverdebug.c b/src/solverdebug.c index afec8c5a..3e840462 100644 --- a/src/solverdebug.c +++ b/src/solverdebug.c @@ -126,6 +126,8 @@ solver_printruleclass(Solver *solv, int type, Rule *r) POOL_DEBUG(type, "UPDATE "); else if (p >= solv->featurerules && p < solv->featurerules_end) POOL_DEBUG(type, "FEATURE "); + else if (p >= solv->yumobsrules && p < solv->yumobsrules_end) + POOL_DEBUG(type, "YUMOBS "); solver_printrule(solv, type, r); }