From c2767065ade1ce6f494125078b27d5b279d6fc5b Mon Sep 17 00:00:00 2001 From: Michael Schroeder Date: Thu, 29 Nov 2007 09:32:47 +0000 Subject: [PATCH] - make schubi's job much easier by providing nice helper functions that find and analyze a problem rule --- src/policy.c | 1 + src/solver.c | 431 ++++++++++++++++++++++++++++++++++++++--------------------- src/solver.h | 15 +++ 3 files changed, 293 insertions(+), 154 deletions(-) diff --git a/src/policy.c b/src/policy.c index 26a0524..121c8a6 100644 --- a/src/policy.c +++ b/src/policy.c @@ -297,6 +297,7 @@ prune_to_best_version(Pool *pool, Queue *plist) plist->count = j; } +/* legacy, do not use anymore! */ void prune_best_version_arch(Pool *pool, Queue *plist) { diff --git a/src/solver.c b/src/solver.c index c2fcbd8..1f80483 100644 --- a/src/solver.c +++ b/src/solver.c @@ -2742,198 +2742,321 @@ printdecisions(Solver *solv) } } -int -printconflicts(Solver *solv, Solvable *s, Id pc) +/* this is basically the reverse of addrpmrulesforsolvable */ +SolverProbleminfo +solver_problemruleinfo(Solver *solv, Queue *job, Id rid, Id *depp, Id *sourcep, Id *targetp) { Pool *pool = solv->pool; - Solvable *sc = pool->solvables + pc; - Id p, *pp, con, *conp, obs, *obsp; - int numc = 0; - - if (s->conflicts) - { - conp = s->repo->idarraydata + s->conflicts; - while ((con = *conp++) != 0) - { - FOR_PROVIDES(p, pp, con) - { - if (p != pc) - continue; - POOL_DEBUG(SAT_DEBUG_RESULT, "packags %s conflicts with %s, which is provided by %s\n", solvable2str(pool, s), dep2str(pool, con), solvable2str(pool, sc)); - numc++; - } - } - } - if (s->obsoletes && (!solv->installed || s->repo != solv->installed)) - { - obsp = s->repo->idarraydata + s->obsoletes; - while ((obs = *obsp++) != 0) + Repo *installed = solv->installed; + Rule *r; + Solvable *s; + int dontfix = 0; + Id p, *pp, req, *reqp, con, *conp, obs, *obsp, *dp; + + if (rid >= solv->weakrules) + abort(); + if (rid >= solv->systemrules) + { + *depp = 0; + *sourcep = solv->installed->start + (rid - solv->systemrules); + *targetp = 0; + return SOLVER_PROBLEM_UPDATE_RULE; + } + if (rid >= solv->jobrules) + { + + r = solv->rules + rid; + p = solv->ruletojob.elements[rid - solv->jobrules]; + *depp = job->elements[p + 1]; + *sourcep = p; + *targetp = job->elements[p]; + if (r->d == 0 && r->w2 == 0 && r->p == -SYSTEMSOLVABLE) + return SOLVER_PROBLEM_JOB_NOTHING_PROVIDES_DEP; + return SOLVER_PROBLEM_JOB_RULE; + } + if (rid < 0) + { + /* a rpm rule assertion */ + if (rid == -SYSTEMSOLVABLE) + abort(); /* can happen only for job rules */ + s = pool->solvables - rid; + if (installed && !solv->fixsystem && s->repo == installed) + dontfix = 1; + if (dontfix) /* dontfix packages never have a neg assertion */ + abort(); + /* see why the package is not installable */ + if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC && !pool_installable(pool, s)) + return SOLVER_PROBLEM_NOT_INSTALLABLE; + /* check requires */ + if (!s->requires) + abort(); + reqp = s->repo->idarraydata + s->requires; + while ((req = *reqp++) != 0) { - FOR_PROVIDES(p, pp, obs) + if (req == SOLVABLE_PREREQMARKER) + continue; + dp = pool_whatprovides(pool, req); + if (*dp == 0) { - if (p != pc) - continue; - POOL_DEBUG(SAT_DEBUG_RESULT, "packags %s obsolets %s, which is provided by %s\n", solvable2str(pool, s), dep2str(pool, obs), solvable2str(pool, sc)); - numc++; + *depp = req; + *sourcep = -rid; + *targetp = 0; + return SOLVER_PROBLEM_NOTHING_PROVIDES_DEP; } } + abort(); } - return numc; -} - -void -printprobleminfo(Solver *solv, Queue *job, Id problem) -{ - Pool *pool = solv->pool; - Rule *r; - Solvable *s; - Id p, d, rn; - Id idx = solv->problems.elements[problem - 1]; - - rn = solv->learnt_pool.elements[idx]; - if (rn < 0) + r = solv->rules + rid; + if (r->p >= 0) + abort(); /* not a rpm rule */ + if (r->d == 0 && r->w2 == 0) { - p = rn; /* fake a negative assertion rule */ - r = 0; + /* an assertion. we don't store them as rpm rules, so + * can't happen */ + abort(); } - else + s = pool->solvables - r->p; + if (installed && !solv->fixsystem && s->repo == installed) + dontfix = 1; + if (r->d == 0 && r->w2 < 0) { - r = solv->rules + rn; - p = r->p; - } + /* a package conflict */ + Solvable *s2 = pool->solvables - r->w2; + int dontfix2 = 0; - if (!r || r->w2 == 0) - { - Id req, *reqp, *dp; - int count = 0; + if (installed && !solv->fixsystem && s2->repo == installed) + dontfix2 = 1; - /* assertions */ - if (p == -SYSTEMSOLVABLE) + /* if both packages have the same name and at least one of them + * is not installed, they conflict */ + if (s->name == s2->name && (!installed || (s->repo != installed || s2->repo != installed))) { - Id ji, what; + *depp = 0; + *sourcep = -r->p; + *targetp = -r->w2; + return SOLVER_PROBLEM_SAME_NAME; + } - /* we tried to deinstall the system solvable. must be a job. */ - if (rn < solv->jobrules || rn >= solv->systemrules) - abort(); - ji = solv->ruletojob.elements[rn - solv->jobrules]; - what = job->elements[ji + 1]; - switch (job->elements[ji]) - { - case SOLVER_INSTALL_SOLVABLE_NAME: - POOL_DEBUG(SAT_DEBUG_RESULT, "no solvable exists with name %s\n", dep2str(pool, what)); - break; - case SOLVER_INSTALL_SOLVABLE_PROVIDES: - POOL_DEBUG(SAT_DEBUG_RESULT, "no solvable provides %s\n", dep2str(pool, what)); - break; - default: - pool_debug(pool, SAT_FATAL, "unknown job\n"); - abort(); + /* check conflicts in both directions */ + if (s->conflicts) + { + conp = s->repo->idarraydata + s->conflicts; + while ((con = *conp++) != 0) + { + FOR_PROVIDES(p, pp, con) + { + if (dontfix && pool->solvables[p].repo == installed) + continue; + if (p != -r->w2) + continue; + *depp = con; + *sourcep = -r->p; + *targetp = p; + return SOLVER_PROBLEM_PACKAGE_CONFLICT; + } } - return; } - if (p > 0 && solv->learnt_pool.elements[idx + 1] == -p) + if (s2->conflicts) { - /* we conflicted with a direct rpm assertion */ - /* print other rule */ - p = -p; - rn = 0; + conp = s2->repo->idarraydata + s2->conflicts; + while ((con = *conp++) != 0) + { + FOR_PROVIDES(p, pp, con) + { + if (dontfix2 && pool->solvables[p].repo == installed) + continue; + if (p != -r->p) + continue; + *depp = con; + *sourcep = -r->w2; + *targetp = p; + return SOLVER_PROBLEM_PACKAGE_CONFLICT; + } + } } - if (rn >= solv->jobrules) + /* check obsoletes in both directions */ + if ((!installed || s->repo != installed) && s->obsoletes) { - POOL_DEBUG(SAT_DEBUG_RESULT, "some job/system/learnt rule\n"); - printrule(solv, SAT_DEBUG_RESULT, r); - return; + obsp = s->repo->idarraydata + s->obsoletes; + while ((obs = *obsp++) != 0) + { + FOR_PROVIDES(p, pp, obs) + { + if (p != -r->w2) + continue; + *depp = obs; + *sourcep = -r->p; + *targetp = p; + return SOLVER_PROBLEM_PACKAGE_OBSOLETES; + } + } } - if (p >= 0) - abort(); - /* negative assertion, i.e. package is not installable */ - s = pool->solvables + (-p); - if (s->requires) + if ((!installed || s2->repo != installed) && s2->obsoletes) { - reqp = s->repo->idarraydata + s->requires; - while ((req = *reqp++) != 0) + obsp = s2->repo->idarraydata + s2->obsoletes; + while ((obs = *obsp++) != 0) { - if (req == SOLVABLE_PREREQMARKER) - continue; - dp = pool_whatprovides(pool, req); - if (*dp) - continue; - POOL_DEBUG(SAT_DEBUG_RESULT, "package %s requires %s, but no package provides it\n", solvable2str(pool, s), dep2str(pool, req)); - count++; + FOR_PROVIDES(p, pp, obs) + { + if (p != -r->p) + continue; + *depp = obs; + *sourcep = -r->w2; + *targetp = p; + return SOLVER_PROBLEM_PACKAGE_OBSOLETES; + } } } - if (!count) - POOL_DEBUG(SAT_DEBUG_RESULT, "package %s is not installable\n", solvable2str(pool, s)); - return; - } - - if (rn >= solv->learntrules) - { - /* learnt rule, ignore for now */ - POOL_DEBUG(SAT_DEBUG_RESULT, "some learnt rule...\n"); - printrule(solv, SAT_DEBUG_RESULT, r); - return; + /* all cases checked, can't happen */ + abort(); } - if (rn >= solv->systemrules) - { - /* system rule, ignore for now */ - POOL_DEBUG(SAT_DEBUG_RESULT, "some system rule...\n"); - printrule(solv, SAT_DEBUG_RESULT, r); - return; - } - if (rn >= solv->jobrules) + /* simple requires */ + if (!s->requires) + abort(); + reqp = s->repo->idarraydata + s->requires; + while ((req = *reqp++) != 0) { - /* job rule, ignore for now */ - POOL_DEBUG(SAT_DEBUG_RESULT, "some job rule...\n"); - printrule(solv, SAT_DEBUG_RESULT, r); - return; + if (req == SOLVABLE_PREREQMARKER) + continue; + dp = pool_whatprovides(pool, req); + if (r->d == 0) + { + if (*dp == r->w2 && dp[1] == 0) + break; + } + else if (dp - pool->whatprovidesdata == r->d) + break; } - /* only rpm rules left... */ - p = r->p; - d = r->d; - if (p >= 0) + if (!req) abort(); - if (d == 0 && r->w2 < 0) + *depp = req; + *sourcep = -r->p; + *targetp = 0; + return SOLVER_PROBLEM_DEP_PROVIDERS_NOT_INSTALLABLE; +} + +static void +findproblemrule_internal(Solver *solv, Id idx, Id *reqrp, Id *conrp, Id *sysrp, Id *jobrp) +{ + Id rid; + Id lreqr, lconr, lsysr, ljobr; + Rule *r; + + lreqr = lconr = lsysr = ljobr = 0; + while ((rid = solv->learnt_pool.elements[idx++]) != 0) { - Solvable *sp, *sd; - d = r->w2; - sp = pool->solvables + (-p); - sd = pool->solvables + (-d); - if (sp->name == sd->name) + if (rid >= solv->learntrules) + findproblemrule_internal(solv, solv->learnt_why.elements[rid - solv->learntrules], &lreqr, &lconr, &lsysr, &ljobr); + else if (rid >= solv->systemrules) { - POOL_DEBUG(SAT_DEBUG_RESULT, "cannot install both %s and %s\n", solvable2str(pool, sp), solvable2str(pool, sd)); + if (!*sysrp) + *sysrp = rid; } - else + else if (rid >= solv->jobrules) { - printconflicts(solv, pool->solvables + (-p), -d); - printconflicts(solv, pool->solvables + (-d), -p); + if (!*jobrp) + *jobrp = rid; } - } - else - { - /* find requires of p that corresponds with our rule */ - Id req, *reqp, *dp; - s = pool->solvables + (-p); - reqp = s->repo->idarraydata + s->requires; - while ((req = *reqp++) != 0) + else if (rid >= 0) { - if (req == SOLVABLE_PREREQMARKER) - continue; - dp = pool_whatprovides(pool, req); - if (d == 0) + r = solv->rules + rid; + if (!r->d && r->w2 < 0) { - if (*dp == r->w2 && dp[1] == 0) - break; + if (!*conrp) + *conrp = rid; + } + else + { + if (!*reqrp) + *reqrp = rid; } - else if (dp - pool->whatprovidesdata == d) - break; } - if (!req) + else { - pool_debug(pool, SAT_FATAL, "req not found\n"); - abort(); - } - POOL_DEBUG(SAT_DEBUG_RESULT, "package %s requires %s, but none of its providers can be installed\n", solvable2str(pool, s), dep2str(pool, req)); + /* assertion, counts as require rule */ + /* system solvable doesn't count, as this is useful information */ + if (rid == -SYSTEMSOLVABLE) + continue; + if (!*reqrp) + *reqrp = rid; + } + } + if (!*reqrp && lreqr) + *reqrp = lreqr; + if (!*conrp && lconr) + *conrp = lconr; + if (!*jobrp && ljobr) + *jobrp = ljobr; + if (!*sysrp && lsysr) + *sysrp = lsysr; +} + +Id +findproblemrule(Solver *solv, Id problem) +{ + Id reqr, conr, sysr, jobr; + Id idx = solv->problems.elements[problem - 1]; + reqr = conr = sysr = jobr = 0; + findproblemrule_internal(solv, idx, &reqr, &conr, &sysr, &jobr); + if (reqr) + return reqr; + if (conr) + return conr; + if (sysr) + return sysr; + if (jobr) + return jobr; + abort(); +} + +void +printprobleminfo(Solver *solv, Queue *job, Id problem) +{ + Pool *pool = solv->pool; + Id probr; + Id dep, source, target; + Solvable *s, *s2; + + probr = findproblemrule(solv, problem); + switch (solver_problemruleinfo(solv, job, probr, &dep, &source, &target)) + { + case SOLVER_PROBLEM_UPDATE_RULE: + s = pool_id2solvable(pool, source); + POOL_DEBUG(SAT_DEBUG_RESULT, "problem with installed package %s\n", solvable2str(pool, s)); + return; + case SOLVER_PROBLEM_JOB_RULE: + POOL_DEBUG(SAT_DEBUG_RESULT, "conflicting requests\n"); + return; + case SOLVER_PROBLEM_JOB_NOTHING_PROVIDES_DEP: + POOL_DEBUG(SAT_DEBUG_RESULT, "nothing provides requested %s\n", dep2str(pool, dep)); + return; + case SOLVER_PROBLEM_NOT_INSTALLABLE: + s = pool_id2solvable(pool, source); + POOL_DEBUG(SAT_DEBUG_RESULT, "package %s is not installable\n", solvable2str(pool, s)); + return; + case SOLVER_PROBLEM_NOTHING_PROVIDES_DEP: + s = pool_id2solvable(pool, source); + POOL_DEBUG(SAT_DEBUG_RESULT, "nothing provides %s needed by %s\n", dep2str(pool, dep), solvable2str(pool, s)); + return; + case SOLVER_PROBLEM_SAME_NAME: + s = pool_id2solvable(pool, source); + s2 = pool_id2solvable(pool, target); + POOL_DEBUG(SAT_DEBUG_RESULT, "cannot install both %s and %s\n", solvable2str(pool, s), solvable2str(pool, s2)); + return; + case SOLVER_PROBLEM_PACKAGE_CONFLICT: + s = pool_id2solvable(pool, source); + s2 = pool_id2solvable(pool, target); + POOL_DEBUG(SAT_DEBUG_RESULT, "package %s conflicts with %s provided by %s\n", solvable2str(pool, s), dep2str(pool, dep), solvable2str(pool, s2)); + return; + case SOLVER_PROBLEM_PACKAGE_OBSOLETES: + s = pool_id2solvable(pool, source); + s2 = pool_id2solvable(pool, target); + POOL_DEBUG(SAT_DEBUG_RESULT, "package %s obsoletes %s provided by %s\n", solvable2str(pool, s), dep2str(pool, dep), solvable2str(pool, s2)); + return; + case SOLVER_PROBLEM_DEP_PROVIDERS_NOT_INSTALLABLE: + s = pool_id2solvable(pool, source); + POOL_DEBUG(SAT_DEBUG_RESULT, "package %s requires %s, but none of the providers can be installed\n", solvable2str(pool, s), dep2str(pool, dep)); + return; } } diff --git a/src/solver.h b/src/solver.h index a55e423..341faee 100644 --- a/src/solver.h +++ b/src/solver.h @@ -121,6 +121,19 @@ typedef enum { SOLVER_INSTALL_SOLVABLE_UPDATE } SolverCmd; +typedef enum { + SOLVER_PROBLEM_UPDATE_RULE, + SOLVER_PROBLEM_JOB_RULE, + SOLVER_PROBLEM_JOB_NOTHING_PROVIDES_DEP, + SOLVER_PROBLEM_NOT_INSTALLABLE, + SOLVER_PROBLEM_NOTHING_PROVIDES_DEP, + SOLVER_PROBLEM_SAME_NAME, + SOLVER_PROBLEM_PACKAGE_CONFLICT, + SOLVER_PROBLEM_PACKAGE_OBSOLETES, + SOLVER_PROBLEM_DEP_PROVIDERS_NOT_INSTALLABLE +} SolverProbleminfo; + + extern Solver *solver_create(Pool *pool, Repo *installed); extern void solver_free(Solver *solv); extern void solver_solve(Solver *solv, Queue *job); @@ -129,6 +142,8 @@ extern int solver_dep_installed(Solver *solv, Id dep); extern Id solver_next_problem(Solver *solv, Id problem); extern Id solver_next_solution(Solver *solv, Id problem, Id solution); extern Id solver_next_solutionelement(Solver *solv, Id problem, Id solution, Id element, Id *p, Id *rp); +extern SolverProbleminfo solver_problemruleinfo(Solver *solv, Queue *job, Id rid, Id *depp, Id *sourcep, Id *targetp); +extern Id findproblemrule(Solver *solv, Id problem); /* debug functions, do not use */ void printdecisions(Solver *solv); -- 2.7.4