From 6d567daed91cd8c0ca20e3d680f0b94012fa8df3 Mon Sep 17 00:00:00 2001 From: Michael Schroeder Date: Mon, 10 Dec 2012 19:18:31 +0100 Subject: [PATCH] implement special install/erase namespace provides hack --- bindings/solv.i | 1 + examples/solv.c | 17 +++++++ src/rules.c | 138 +++++++++++++++++++++++++++++++++++++++++++++++---- src/rules.h | 1 + src/solver.c | 80 +++++++++++++++++++++++++++++ src/solver.h | 2 + src/solverdebug.c | 5 ++ tools/installcheck.c | 1 + tools/patchcheck.c | 1 + 9 files changed, 235 insertions(+), 11 deletions(-) diff --git a/bindings/solv.i b/bindings/solv.i index 654ea86..3273b34 100644 --- a/bindings/solv.i +++ b/bindings/solv.i @@ -2459,6 +2459,7 @@ typedef struct { static const int SOLVER_RULE_FEATURE = SOLVER_RULE_FEATURE; static const int SOLVER_RULE_JOB = SOLVER_RULE_JOB; static const int SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP = SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP; + static const int SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM = SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM; static const int SOLVER_RULE_DISTUPGRADE = SOLVER_RULE_DISTUPGRADE; static const int SOLVER_RULE_INFARCH = SOLVER_RULE_INFARCH; static const int SOLVER_RULE_CHOICE = SOLVER_RULE_CHOICE; diff --git a/examples/solv.c b/examples/solv.c index 3d690f1..6218e64 100644 --- a/examples/solv.c +++ b/examples/solv.c @@ -2214,6 +2214,19 @@ nscallback(Pool *pool, void *data, Id name, Id evr) } return bestp; } +#if 0 + if (name == NAMESPACE_LANGUAGE) + { + if (!strcmp(pool_id2str(pool, evr), "ja")) + return 1; + if (!strcmp(pool_id2str(pool, evr), "de")) + return 1; + if (!strcmp(pool_id2str(pool, evr), "en")) + return 1; + if (!strcmp(pool_id2str(pool, evr), "en_US")) + return 1; + } +#endif return 0; } @@ -2808,6 +2821,10 @@ main(int argc, char **argv) // queue_push2(&job, SOLVER_NOOBSOLETES|SOLVER_SOLVABLE_NAME, pool_str2id(pool, "kernel-pae", 1)); // queue_push2(&job, SOLVER_NOOBSOLETES|SOLVER_SOLVABLE_NAME, pool_str2id(pool, "kernel-pae-base", 1)); // queue_push2(&job, SOLVER_NOOBSOLETES|SOLVER_SOLVABLE_NAME, pool_str2id(pool, "kernel-pae-extra", 1)); +#if 0 + queue_push2(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES, pool_rel2id(pool, NAMESPACE_LANGUAGE, 0, REL_NAMESPACE, 1)); + queue_push2(&job, SOLVER_ERASE|SOLVER_CLEANDEPS|SOLVER_SOLVABLE_PROVIDES, pool_rel2id(pool, NAMESPACE_LANGUAGE, 0, REL_NAMESPACE, 1)); +#endif #ifdef SOFTLOCKS_PATH addsoftlocks(pool, &job); diff --git a/src/rules.c b/src/rules.c index 4a9459d..9b9b8aa 100644 --- a/src/rules.c +++ b/src/rules.c @@ -35,8 +35,8 @@ static void solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unnee /*------------------------------------------------------------------- * Check if dependency is possible * - * mirrors solver_dep_fulfilled but uses map m instead of the decisionmap - * used in solver_addrpmrulesforweak and solver_createcleandepsmap + * mirrors solver_dep_fulfilled but uses map m instead of the decisionmap. + * used in solver_addrpmrulesforweak and solver_createcleandepsmap. */ static inline int @@ -2132,10 +2132,14 @@ solver_ruleinfo(Solver *solv, Id rid, Id *fromp, Id *top, Id *depp) *depp = solv->job.elements[jidx + 1]; if ((r->d == 0 || r->d == -1) && r->w2 == 0 && r->p == -SYSTEMSOLVABLE) { - if ((solv->job.elements[jidx] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_NAME) + if ((solv->job.elements[jidx] & (SOLVER_JOBMASK|SOLVER_SELECTMASK)) == (SOLVER_INSTALL|SOLVER_SOLVABLE_NAME)) return SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP; - if ((solv->job.elements[jidx] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_PROVIDES) + if ((solv->job.elements[jidx] & (SOLVER_JOBMASK|SOLVER_SELECTMASK)) == (SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES)) return SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP; + if ((solv->job.elements[jidx] & (SOLVER_JOBMASK|SOLVER_SELECTMASK)) == (SOLVER_ERASE|SOLVER_SOLVABLE_NAME)) + return SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM; + if ((solv->job.elements[jidx] & (SOLVER_JOBMASK|SOLVER_SELECTMASK)) == (SOLVER_ERASE|SOLVER_SOLVABLE_PROVIDES)) + return SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM; } return SOLVER_RULE_JOB; } @@ -2671,6 +2675,59 @@ dep_pkgcheck(Solver *solv, Id dep, Map *m, Queue *q) queue_push(q, p); } +static int +check_xsupp(Solver *solv, Queue *depq, Id dep) +{ + Pool *pool = solv->pool; + Id p, pp; + + if (ISRELDEP(dep)) + { + Reldep *rd = GETRELDEP(pool, dep); + if (rd->flags >= 8) + { + if (rd->flags == REL_AND) + { + if (!check_xsupp(solv, depq, rd->name)) + return 0; + return check_xsupp(solv, depq, rd->evr); + } + if (rd->flags == REL_OR) + { + if (check_xsupp(solv, depq, rd->name)) + return 1; + return check_xsupp(solv, depq, rd->evr); + } + if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES) + return solver_splitprovides(solv, rd->evr); + if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_INSTALLED) + return solver_dep_installed(solv, rd->evr); + } + if (depq && rd->flags == REL_NAMESPACE) + { + int i; + for (i = 0; i < depq->count; i++) + if (depq->elements[i] == dep || depq->elements[i] == rd->name) + return 1; + } + } + FOR_PROVIDES(p, pp, dep) + if (p == SYSTEMSOLVABLE || pool->solvables[p].repo == solv->installed) + return 1; + return 0; +} + +static inline int +queue_contains(Queue *q, Id id) +{ + int i; + for (i = 0; i < q->count; i++) + if (q->elements[i] == id) + return 1; + return 0; +} + + /* * Find all installed packages that are no longer * needed regarding the current solver job. @@ -2707,7 +2764,7 @@ solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded) Id p, pp, ip, jp; Id req, *reqp, sup, *supp; Solvable *s; - Queue iq, iqcopy; + Queue iq, iqcopy, xsuppq; int i; map_empty(cleandepsmap); @@ -2717,6 +2774,7 @@ solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded) map_init(&im, pool->nsolvables); map_init(&installedm, pool->nsolvables); queue_init(&iq); + queue_init(&xsuppq); for (i = 0; i < job->count; i += 2) { @@ -2732,6 +2790,50 @@ solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded) if (pool->solvables[p].repo == installed) MAPSET(&userinstalled, p - installed->start); } + if ((how & (SOLVER_JOBMASK | SOLVER_SELECTMASK)) == (SOLVER_ERASE | SOLVER_SOLVABLE_PROVIDES)) + { + what = job->elements[i + 1]; + if (ISRELDEP(what)) + { + Reldep *rd = GETRELDEP(pool, what); + if (rd->flags != REL_NAMESPACE) + continue; + if (rd->evr == 0) + { + queue_pushunique(&iq, rd->name); + continue; + } + FOR_PROVIDES(p, pp, what) + if (p) + break; + if (p) + continue; + queue_pushunique(&iq, what); + } + } + } + + /* have special namespace cleandeps erases */ + if (iq.count) + { + for (ip = solv->installed->start; ip < solv->installed->end; ip++) + { + s = pool->solvables + ip; + if (s->repo != installed) + continue; + if (!s->supplements) + continue; + supp = s->repo->idarraydata + s->supplements; + while ((sup = *supp++) != 0) + if (check_xsupp(solv, &iq, sup) && !check_xsupp(solv, 0, sup)) + { +#ifdef CLEANDEPSDEBUG + printf("xsupp %s from %s\n", pool_dep2str(pool, sup), pool_solvid2str(pool, ip)); +#endif + queue_pushunique(&xsuppq, sup); + } + } + queue_empty(&iq); } /* also add visible patterns to userinstalled for openSUSE */ @@ -2904,6 +3006,8 @@ solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded) continue; MAPSET(&im, p); } + MAPSET(&installedm, SYSTEMSOLVABLE); + MAPSET(&im, SYSTEMSOLVABLE); #ifdef CLEANDEPSDEBUG printf("REMOVE PASS\n"); @@ -2916,7 +3020,7 @@ solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded) if (unneeded) break; /* supplements pass */ - for (ip = solv->installed->start; ip < solv->installed->end; ip++) + for (ip = installed->start; ip < installed->end; ip++) { if (!MAPTST(&installedm, ip)) continue; @@ -2935,7 +3039,7 @@ solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded) { supp = s->repo->idarraydata + s->supplements; while ((sup = *supp++) != 0) - if (dep_possible(solv, sup, &installedm)) + if (dep_possible(solv, sup, &installedm) || (xsuppq.count && queue_contains(&xsuppq, sup))) { /* no longer supplemented, also erase */ int iqcount = iq.count; @@ -2949,14 +3053,14 @@ solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded) } queue_truncate(&iq, iqcount); #ifdef CLEANDEPSDEBUG - printf("%s supplemented\n", pool_solvid2str(pool, ip)); + printf("%s supplemented [%s]\n", pool_solvid2str(pool, ip), pool_dep2str(pool, sup)); #endif queue_push(&iq, ip); } } } if (!iq.count) - break; + break; /* no supplementing package found, we're done */ } ip = queue_shift(&iq); s = pool->solvables + ip; @@ -2988,7 +3092,7 @@ solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded) #endif FOR_PROVIDES(p, pp, req) { - if (MAPTST(&im, p)) + if (p != SYSTEMSOLVABLE && MAPTST(&im, p)) { #ifdef CLEANDEPSDEBUG printf("%s requires %s\n", pool_solvid2str(pool, ip), pool_solvid2str(pool, p)); @@ -3013,7 +3117,7 @@ solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded) #endif FOR_PROVIDES(p, pp, req) { - if (MAPTST(&im, p)) + if (p != SYSTEMSOLVABLE && MAPTST(&im, p)) { #ifdef CLEANDEPSDEBUG printf("%s recommends %s\n", pool_solvid2str(pool, ip), pool_solvid2str(pool, p)); @@ -3037,6 +3141,7 @@ solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded) if (pool->solvables[p].repo == installed) MAPSET(&userinstalled, p - installed->start); } + MAPSET(&im, SYSTEMSOLVABLE); /* in case we cleared it above */ for (p = installed->start; p < installed->end; p++) if (MAPTST(&im, p)) queue_push(&iq, p); @@ -3109,6 +3214,11 @@ solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded) while ((req = *reqp++) != 0) { FOR_PROVIDES(p, pp, req) + if (MAPTST(&im, p)) + break; + if (p) + continue; + FOR_PROVIDES(p, pp, req) { if (!MAPTST(&im, p) && MAPTST(&installedm, p)) { @@ -3131,6 +3241,11 @@ solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded) while ((req = *reqp++) != 0) { FOR_PROVIDES(p, pp, req) + if (MAPTST(&im, p)) + break; + if (p) + continue; + FOR_PROVIDES(p, pp, req) { if (!MAPTST(&im, p) && MAPTST(&installedm, p)) { @@ -3171,6 +3286,7 @@ solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded) map_free(&im); map_free(&installedm); map_free(&userinstalled); + queue_free(&xsuppq); #ifdef CLEANDEPSDEBUG printf("=== final cleandeps map:\n"); for (p = installed->start; p < installed->end; p++) diff --git a/src/rules.h b/src/rules.h index d42b22b..144b683 100644 --- a/src/rules.h +++ b/src/rules.h @@ -62,6 +62,7 @@ typedef enum { SOLVER_RULE_FEATURE = 0x300, SOLVER_RULE_JOB = 0x400, SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP, + SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM, SOLVER_RULE_DISTUPGRADE = 0x500, SOLVER_RULE_INFARCH = 0x600, SOLVER_RULE_CHOICE = 0x700, diff --git a/src/solver.c b/src/solver.c index 8b6140c..76680ce 100644 --- a/src/solver.c +++ b/src/solver.c @@ -103,6 +103,64 @@ solver_dep_installed(Solver *solv, Id dep) return 0; } +/* mirrors solver_dep_installed, but returns 2 if a + * dependency listed in solv->installsuppdepq was involved */ +static int +solver_check_installsuppdepq_dep(Solver *solv, Id dep) +{ + Pool *pool = solv->pool; + Id p, pp; + Queue *q; + + if (ISRELDEP(dep)) + { + Reldep *rd = GETRELDEP(pool, dep); + if (rd->flags == REL_AND) + { + int r2, r1 = solver_check_installsuppdepq_dep(solv, rd->name); + if (!r1) + return 0; + r2 = solver_check_installsuppdepq_dep(solv, rd->evr); + if (!r2) + return 0; + return r1 == 2 || r2 == 2 ? 2 : 1; + } + if (rd->flags == REL_OR) + { + int r2, r1 = solver_check_installsuppdepq_dep(solv, rd->name); + r2 = solver_check_installsuppdepq_dep(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); + if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_INSTALLED) + return solver_dep_installed(solv, rd->evr); + if (rd->flags == REL_NAMESPACE && (q = solv->installsuppdepq) != 0) + { + int i; + for (i = 0; i < q->count; i++) + if (q->elements[i] == dep || q->elements[i] == rd->name) + return 2; + } + } + FOR_PROVIDES(p, pp, dep) + if (solv->decisionmap[p] > 0) + return 1; + return 0; +} + +static int +solver_check_installsuppdepq(Solver *solv, Solvable *s) +{ + Id sup, *supp; + supp = s->repo->idarraydata + s->supplements; + while ((sup = *supp++) != 0) + if (solver_check_installsuppdepq_dep(solv, sup) == 2) + return 1; + return 0; +} static Id autouninstall(Solver *solv, Id *problem) @@ -1430,6 +1488,11 @@ solver_free(Solver *solv) queue_free(solv->update_targets); solv->update_targets = solv_free(solv->update_targets); } + if (solv->installsuppdepq) + { + queue_free(solv->installsuppdepq); + solv->installsuppdepq = solv_free(solv->installsuppdepq); + } map_free(&solv->recommendsmap); map_free(&solv->suggestsmap); @@ -2151,6 +2214,8 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) continue; if (!solver_is_supplementing(solv, s)) dqs.elements[j++] = p; + else if (s->supplements && solv->installsuppdepq && solver_check_installsuppdepq(solv, s)) + dqs.elements[j++] = p; } dqs.count = j; /* undo turning off */ @@ -3140,6 +3205,21 @@ solver_solve(Solver *solv, Queue *job) p = queue_shift(&q); /* get first candidate */ d = !q.count ? 0 : pool_queuetowhatprovides(pool, &q); /* internalize */ } + /* force install of namespace supplements hack */ + if (select == SOLVER_SOLVABLE_PROVIDES && !d && (p == SYSTEMSOLVABLE || p == -SYSTEMSOLVABLE) && ISRELDEP(what)) + { + Reldep *rd = GETRELDEP(pool, what); + if (rd->flags == REL_NAMESPACE) + { + p = SYSTEMSOLVABLE; + if (!solv->installsuppdepq) + { + solv->installsuppdepq = solv_calloc(1, sizeof(Queue)); + queue_init(solv->installsuppdepq); + } + queue_pushunique(solv->installsuppdepq, rd->evr == 0 ? rd->name : what); + } + } solver_addjobrule(solv, p, d, i, weak); if (how & SOLVER_FORCEBEST) hasbestinstalljob = 1; diff --git a/src/solver.h b/src/solver.h index fac1a17..dc7377f 100644 --- a/src/solver.h +++ b/src/solver.h @@ -225,6 +225,8 @@ struct _Solver { Queue *cleandeps_mistakes; /* mistakes we made */ Queue *update_targets; /* update to specific packages */ + + Queue *installsuppdepq; /* deps from the install namespace provides hack */ #endif /* LIBSOLV_INTERNAL */ }; diff --git a/src/solverdebug.c b/src/solverdebug.c index a755da3..58785f7 100644 --- a/src/solverdebug.c +++ b/src/solverdebug.c @@ -569,6 +569,9 @@ solver_printproblemruleinfo(Solver *solv, Id probr) case SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP: POOL_DEBUG(SOLV_DEBUG_RESULT, "nothing provides requested %s\n", pool_dep2str(pool, dep)); return; + case SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM: + POOL_DEBUG(SOLV_DEBUG_RESULT, "%s is provided by the system\n", pool_dep2str(pool, dep)); + return; case SOLVER_RULE_RPM: POOL_DEBUG(SOLV_DEBUG_RESULT, "some dependency problem\n"); return; @@ -996,6 +999,8 @@ solver_problemruleinfo2str(Solver *solv, SolverRuleinfo type, Id source, Id targ return "conflicting requests"; case SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP: return pool_tmpjoin(pool, "nothing provides requested ", pool_dep2str(pool, dep), 0); + case SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM: + 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_RPM_NOT_INSTALLABLE: diff --git a/tools/installcheck.c b/tools/installcheck.c index 3721682..4859bc2 100644 --- a/tools/installcheck.c +++ b/tools/installcheck.c @@ -379,6 +379,7 @@ main(int argc, char **argv) printf(" %s can not be updated\n", pool_solvable2str(pool, s)); break; case SOLVER_RULE_JOB: + case SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM: break; case SOLVER_RULE_RPM: printf(" some dependency problem\n"); diff --git a/tools/patchcheck.c b/tools/patchcheck.c index 7c91974..6edc51f 100644 --- a/tools/patchcheck.c +++ b/tools/patchcheck.c @@ -93,6 +93,7 @@ showproblems(Solver *solv, Solvable *s, Queue *cand, Queue *badguys) } break; case SOLVER_RULE_JOB: + case SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM: break; case SOLVER_RULE_RPM: printf(" some dependency problem\n"); -- 2.7.4