- make schubi's job much easier by providing nice helper functions
authorMichael Schroeder <mls@suse.de>
Thu, 29 Nov 2007 09:32:47 +0000 (09:32 +0000)
committerMichael Schroeder <mls@suse.de>
Thu, 29 Nov 2007 09:32:47 +0000 (09:32 +0000)
  that find and analyze a problem rule

src/policy.c
src/solver.c
src/solver.h

index 26a0524..121c8a6 100644 (file)
@@ -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)
 {
index c2fcbd8..1f80483 100644 (file)
@@ -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;
     }
 }
 
index a55e423..341faee 100644 (file)
@@ -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);