Imported Upstream version 0.6.30
[platform/upstream/libsolv.git] / src / solver.c
index 5d1052d..037b33d 100644 (file)
 #define RULES_BLOCK 63
 
 
-/********************************************************************
- *
- * dependency check helpers
- *
- */
-
-/*-------------------------------------------------------------------
- * handle split provides
- *
- * a splitprovides dep looks like
- *     namespace:splitprovides(pkg REL_WITH path)
- * and is only true if pkg is installed and contains the specified path.
- * we also make sure that pkg is selected for an update, otherwise the
- * update would always be forced onto the user.
- * Map m is the map used when called from dep_possible.
- */
-
-static int
-solver_is_updating(Solver *solv, Id p)
-{
-  /* check if the update rule is true */
-  Pool *pool = solv->pool;
-  Rule *r;
-  Id l, pp;
-  if (solv->decisionmap[p] >= 0)
-    return 0;  /* old package stayed */
-  r = solv->rules + solv->updaterules + (p - solv->installed->start);
-  FOR_RULELITERALS(l, pp, r)
-    if (l > 0 && l != p && solv->decisionmap[l] > 0)
-      return 1;
-  return 0;
-}
-
-int
-solver_splitprovides(Solver *solv, Id dep, Map *m)
-{
-  Pool *pool = solv->pool;
-  Id p, pp;
-  Reldep *rd;
-  Solvable *s;
-
-  if (!solv->dosplitprovides || !solv->installed)
-    return 0;
-  if (!ISRELDEP(dep))
-    return 0;
-  rd = GETRELDEP(pool, dep);
-  if (rd->flags != REL_WITH)
-    return 0;
-  /*
-   * things are a bit tricky here if pool->addedprovides == 1, because most split-provides are in
-   * a non-standard location. If we simply call pool_whatprovides, we'll drag in the complete
-   * file list. Instead we rely on pool_addfileprovides ignoring the addfileprovidesfiltered flag
-   * for installed packages and check the lazywhatprovidesq (ignoring the REL_WITH part, but
-   * we filter the package name further down anyway).
-   */
-  if (pool->addedfileprovides == 1 && !ISRELDEP(rd->evr) && !pool->whatprovides[rd->evr])
-    pp = pool_searchlazywhatprovidesq(pool, rd->evr);
-  else
-    pp = pool_whatprovides(pool, dep);
-  while ((p = pool->whatprovidesdata[pp++]) != 0)
-    {
-      /* here we have packages that provide the correct name and contain the path,
-       * now do extra filtering */
-      s = pool->solvables + p;
-      if (s->repo != solv->installed || s->name != rd->name)
-       continue;
-      /* check if the package is updated. if m is set, we're called from dep_possible */
-      if (m || solver_is_updating(solv, p))
-       return 1;
-    }
-  return 0;
-}
-
-int
-solver_dep_fulfilled_cplx(Solver *solv, Reldep *rd)
-{
-  Pool *pool = solv->pool;
-  if (rd->flags == REL_COND)
-    {
-      if (ISRELDEP(rd->evr))
-       {
-         Reldep *rd2 = GETRELDEP(pool, rd->evr);
-         if (rd2->flags == REL_ELSE)
-           {
-             if (solver_dep_fulfilled(solv, rd2->name))
-               return solver_dep_fulfilled(solv, rd->name);
-             return solver_dep_fulfilled(solv, rd2->evr);
-           }
-       }
-      if (solver_dep_fulfilled(solv, rd->name))
-       return 1;
-      return !solver_dep_fulfilled(solv, rd->evr);
-    }
-  if (rd->flags == REL_UNLESS)
-    {
-      if (ISRELDEP(rd->evr))
-       {
-         Reldep *rd2 = GETRELDEP(pool, rd->evr);
-         if (rd2->flags == REL_ELSE)
-           {
-             if (!solver_dep_fulfilled(solv, rd2->name))
-               return solver_dep_fulfilled(solv, rd->name);
-             return solver_dep_fulfilled(solv, rd2->evr);
-           }
-       }
-      if (!solver_dep_fulfilled(solv, rd->name))
-       return 0;
-      return !solver_dep_fulfilled(solv, rd->evr);
-    }
-  if (rd->flags == REL_AND)
-    {
-      if (!solver_dep_fulfilled(solv, rd->name))
-       return 0;
-      return solver_dep_fulfilled(solv, rd->evr);
-    }
-  if (rd->flags == REL_OR)
-    {
-      if (solver_dep_fulfilled(solv, rd->name))
-       return 1;
-      return solver_dep_fulfilled(solv, rd->evr);
-    }
-  return 0;
-}
-
-
-/* mirrors solver_dep_fulfilled, but returns 2 if a new package
- * was involved */
-static int
-solver_dep_fulfilled_alreadyinstalled(Solver *solv, Id dep)
-{
-  Pool *pool = solv->pool;
-  Id p, pp;
-  int r;
-
-  if (ISRELDEP(dep))
-    {
-      Reldep *rd = GETRELDEP(pool, dep);
-      if (rd->flags == REL_COND)
-       {
-         int r1, r2;
-         if (ISRELDEP(rd->evr))
-           {
-             Reldep *rd2 = GETRELDEP(pool, rd->evr);
-             if (rd2->flags == REL_ELSE)
-               {
-                 r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd2->name);
-                 if (r1)
-                   {
-                     r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
-                     return r2 && r1 == 2 ? 2 : r2;
-                   }
-                 return solver_dep_fulfilled_alreadyinstalled(solv, rd2->evr);
-               }
-           }
-         r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
-         r2 = !solver_dep_fulfilled_alreadyinstalled(solv, rd->evr);
-         if (!r1 && !r2)
-           return 0;
-          return r1 == 2 ? 2 : 1;
-       }
-      if (rd->flags == REL_UNLESS)
-       {
-         int r1, r2;
-         if (ISRELDEP(rd->evr))
-           {
-             Reldep *rd2 = GETRELDEP(pool, rd->evr);
-             if (rd2->flags == REL_ELSE)
-               {
-                 r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd2->name);
-                 if (r1)
-                   {
-                     r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd2->evr);
-                     return r2 && r1 == 2 ? 2 : r2;
-                   }
-                 return solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
-               }
-           }
-         /* A AND NOT(B) */
-         r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
-         r2 = !solver_dep_fulfilled_alreadyinstalled(solv, rd->evr);
-         if (!r1 || !r2)
-           return 0;
-          return r1 == 2 ? 2 : 1;
-       }
-      if (rd->flags == REL_AND)
-        {
-         int r2, r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
-          if (!r1)
-            return 0;
-         r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd->evr);
-         if (!r2)
-           return 0;
-          return r1 == 2 || r2 == 2 ? 2 : 1;
-        }
-      if (rd->flags == REL_OR)
-       {
-         int r2, r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
-         r2 = solver_dep_fulfilled_alreadyinstalled(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, 0);
-      if (rd->flags == REL_NAMESPACE && solv->installsuppdepq)
-       {
-         Queue *q = solv->installsuppdepq;
-         int i;
-         for (i = 0; i < q->count; i++)
-           if (q->elements[i] == dep || q->elements[i] == rd->name)
-             return 2;
-       }
-    }
-  r = 0;
-  FOR_PROVIDES(p, pp, dep)
-    if (solv->decisionmap[p] > 0)
-      {
-       Solvable *s = pool->solvables + p;
-       if (s->repo && s->repo != solv->installed)
-         return 2;
-        r = 1;
-      }
-  return r;
-}
-
-static int
-solver_is_supplementing_alreadyinstalled(Solver *solv, Solvable *s)
-{
-  Id sup, *supp;
-  supp = s->repo->idarraydata + s->supplements;
-  while ((sup = *supp++) != 0)
-    if (solver_dep_fulfilled_alreadyinstalled(solv, sup) == 2)
-      return 1;
-  return 0;
-}
-
 static Id
 autouninstall(Solver *solv, Id *problem)
 {
@@ -495,6 +259,10 @@ makeruledecisions(Solver *solv)
              continue;
            }
 
+         POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "ANALYZE UNSOLVABLE ASSERTION ----------------------\n");
+         IF_POOLDEBUG (SOLV_DEBUG_UNSOLVABLE)
+           solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + ri);
+
          /*
           * find the decision which is the "opposite" of the rule
           */
@@ -540,6 +308,8 @@ makeruledecisions(Solver *solv)
            }
 
          assert(solv->decisionq_why.elements[i] > 0);
+         IF_POOLDEBUG (SOLV_DEBUG_UNSOLVABLE)
+           solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + solv->decisionq_why.elements[i]);
 
          /*
           * conflict with a pkg rule ?
@@ -2002,56 +1772,6 @@ resolve_jobrules(Solver *solv, int level, int disablerules, Queue *dq)
   return level;
 }
 
-static int
-cleandeps_check_mistakes(Solver *solv)
-{
-  Pool *pool = solv->pool;
-  Rule *r;
-  Id p, pp;
-  int i;
-  int mademistake = 0;
-
-  if (!solv->cleandepsmap.size)
-    return 0;
-  /* check for mistakes */
-  for (i = solv->installed->start; i < solv->installed->end; i++)
-    {
-      if (!MAPTST(&solv->cleandepsmap, i - solv->installed->start))
-       continue;
-      r = solv->rules + solv->featurerules + (i - solv->installed->start);
-      /* a mistake is when the featurerule is true but the updaterule is false */
-      if (!r->p)
-       continue;
-      FOR_RULELITERALS(p, pp, r)
-       if (p > 0 && solv->decisionmap[p] > 0)
-         break;
-      if (!p)
-       continue;       /* feature rule is not true */
-      r = solv->rules + solv->updaterules + (i - solv->installed->start);
-      if (!r->p)
-       continue;
-      FOR_RULELITERALS(p, pp, r)
-       if (p > 0 && solv->decisionmap[p] > 0)
-         break;
-      if (p)
-       continue;       /* update rule is true */
-      POOL_DEBUG(SOLV_DEBUG_SOLVER, "cleandeps mistake: ");
-      solver_printruleclass(solv, SOLV_DEBUG_SOLVER, r);
-      POOL_DEBUG(SOLV_DEBUG_SOLVER, "feature rule: ");
-      solver_printruleclass(solv, SOLV_DEBUG_SOLVER, solv->rules + solv->featurerules + (i - solv->installed->start));
-      if (!solv->cleandeps_mistakes)
-       {
-         solv->cleandeps_mistakes = solv_calloc(1, sizeof(Queue));
-         queue_init(solv->cleandeps_mistakes);
-       }
-      queue_push(solv->cleandeps_mistakes, i);
-      MAPCLR(&solv->cleandepsmap, i - solv->installed->start);
-      solver_reenablepolicyrules_cleandeps(solv, i);
-      mademistake = 1;
-    }
-  return mademistake;
-}
-
 static void
 prune_to_update_targets(Solver *solv, Id *cp, Queue *q)
 {
@@ -2398,7 +2118,7 @@ add_complex_recommends(Solver *solv, Id rec, Queue *dq, Map *dqmap)
            {
              if (solv->decisionmap[p] < 0)
                continue;
-             if (solv->dupmap_all && solv->installed && pool->solvables[p].repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start))))
+             if (solv->process_orphans && solv->installed && pool->solvables[p].repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start))))
                continue;
            }
          queue_push(dq, p);
@@ -2553,7 +2273,7 @@ resolve_weak(Solver *solv, int level, int disablerules, Queue *dq, Queue *dqs, i
                        }
                      else if (solv->decisionmap[p] == 0)
                        {
-                         if (solv->dupmap_all && solv->installed && pool->solvables[p].repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start))))
+                         if (solv->process_orphans && solv->installed && pool->solvables[p].repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start))))
                            continue;
                          queue_pushunique(dq, p);
                        }
@@ -2570,7 +2290,7 @@ resolve_weak(Solver *solv, int level, int disablerules, Queue *dq, Queue *dqs, i
            continue;
          if (!solver_is_supplementing(solv, s))
            continue;
-         if (solv->dupmap_all && solv->installed && s->repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, i - solv->installed->start))))
+         if (solv->process_orphans && solv->installed && s->repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, i - solv->installed->start))))
            continue;
          if (solv->isdisfavormap.size && MAPTST(&solv->isdisfavormap, i))
            continue;   /* disfavored supplements, do not install */
@@ -2794,6 +2514,35 @@ resolve_weak(Solver *solv, int level, int disablerules, Queue *dq, Queue *dqs, i
   return level;
 }
 
+static int
+resolve_cleandeps(Solver *solv, int level, int disablerules, int *rerunp)
+{
+  Pool *pool = solv->pool;
+  Repo *installed = solv->installed;
+  int olevel;
+  Id p;
+  Solvable *s;
+
+  if (!installed || !solv->cleandepsmap.size)
+    return level;
+  POOL_DEBUG(SOLV_DEBUG_SOLVER, "deciding cleandeps packages\n");
+  for (p = installed->start; p < installed->end; p++)
+    {
+      s = pool->solvables + p;
+      if (s->repo != installed)
+       continue;
+      if (solv->decisionmap[p] != 0 || !MAPTST(&solv->cleandepsmap, p - installed->start))
+       continue;
+      POOL_DEBUG(SOLV_DEBUG_POLICY, "cleandeps erasing %s\n", pool_solvid2str(pool, p));
+      olevel = level;
+      level = setpropagatelearn(solv, level, -p, 0, 0, SOLVER_REASON_CLEANDEPS_ERASE);
+      if (level < olevel)
+       break;
+    }
+  if (p < installed->end)
+    *rerunp = 1;
+  return level;
+}
 
 static int
 resolve_orphaned(Solver *solv, int level, int disablerules, Queue *dq, int *rerunp)
@@ -2999,24 +2748,12 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
 
       /* decide leftover cleandeps packages */
       if (solv->cleandepsmap.size && solv->installed)
-       {
-         for (p = solv->installed->start; p < solv->installed->end; p++)
-           {
-             s = pool->solvables + p;
-             if (s->repo != solv->installed)
-               continue;
-             if (solv->decisionmap[p] == 0 && MAPTST(&solv->cleandepsmap, p - solv->installed->start))
-               {
-                 POOL_DEBUG(SOLV_DEBUG_POLICY, "cleandeps erasing %s\n", pool_solvid2str(pool, p));
-                 olevel = level;
-                 level = setpropagatelearn(solv, level, -p, 0, 0, SOLVER_REASON_CLEANDEPS_ERASE);
-                 if (level < olevel)
-                   break;
-               }
-           }
-         if (p < solv->installed->end)
-           continue;
-       }
+       {
+         int rerun = 0;
+         level = resolve_cleandeps(solv, level, disablerules, &rerun);
+         if (rerun)
+           continue;
+       }
 
       /* at this point we have a consistent system. now do the extras... */
 
@@ -3056,7 +2793,7 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
            continue;           /* back to main loop */
        }
 
-      if (solv->installed && solv->cleandepsmap.size && cleandeps_check_mistakes(solv))
+      if (solv->installed && solv->cleandepsmap.size && solver_check_cleandeps_mistakes(solv))
        {
          solver_reset(solv);
          level = 0;    /* restart from scratch */
@@ -3366,7 +3103,7 @@ solver_addjobrule(Solver *solv, Id p, Id p2, Id d, Id job, int weak)
 }
 
 static inline void
-add_cleandeps_package(Solver *solv, Id p)
+add_cleandeps_updatepkg(Solver *solv, Id p)
 {
   if (!solv->cleandeps_updatepkgs)
     {
@@ -3405,7 +3142,7 @@ add_update_target(Solver *solv, Id p, Id how)
          MAPSET(&solv->bestupdatemap, pi - installed->start);
        }
       if (how & SOLVER_CLEANDEPS)
-       add_cleandeps_package(solv, pi);
+       add_cleandeps_updatepkg(solv, pi);
       queue_push2(solv->update_targets, pi, p);
       /* check if it's ok to keep the installed package */
       if (s->evr == si->evr && solvable_identical(s, si))
@@ -3434,7 +3171,7 @@ add_update_target(Solver *solv, Id p, Id how)
                  MAPSET(&solv->bestupdatemap, pi - installed->start);
                }
              if (how & SOLVER_CLEANDEPS)
-               add_cleandeps_package(solv, pi);
+               add_cleandeps_updatepkg(solv, pi);
              queue_push2(solv->update_targets, pi, p);
            }
        }
@@ -3677,7 +3414,7 @@ solver_solve(Solver *solv, Queue *job)
     queue_insertn(&solv->job, 0, pool->pooljobs.count, pool->pooljobs.elements);
   job = &solv->job;
 
-  /* free old stuff in jase we re-run a solver */
+  /* free old stuff in case we re-run a solver */
   queuep_free(&solv->update_targets);
   queuep_free(&solv->cleandeps_updatepkgs);
   queue_empty(&solv->ruleassertions);
@@ -3693,9 +3430,9 @@ solver_solve(Solver *solv, Queue *job)
   map_zerosize(&solv->bestupdatemap);
   solv->fixmap_all = 0;
   map_zerosize(&solv->fixmap);
-  solv->dupmap_all = 0;
   map_zerosize(&solv->dupmap);
   map_zerosize(&solv->dupinvolvedmap);
+  solv->process_orphans = 0;
   solv->droporphanedmap_all = 0;
   map_zerosize(&solv->droporphanedmap);
   solv->allowuninstall_all = 0;
@@ -3794,7 +3531,7 @@ solver_solve(Solver *solv, Queue *job)
                  if (how & SOLVER_CLEANDEPS)
                    {
                      FOR_REPO_SOLVABLES(installed, p, s)
-                       add_cleandeps_package(solv, p);
+                       add_cleandeps_updatepkg(solv, p);
                    }
                }
              else if (select == SOLVER_SOLVABLE_REPO)
@@ -3810,7 +3547,7 @@ solver_solve(Solver *solv, Queue *job)
                      if (how & SOLVER_CLEANDEPS)
                        {
                          FOR_REPO_SOLVABLES(installed, p, s)
-                           add_cleandeps_package(solv, p);
+                           add_cleandeps_updatepkg(solv, p);
                        }
                      break;
                    }
@@ -3840,7 +3577,7 @@ solver_solve(Solver *solv, Queue *job)
                              MAPSET(&solv->bestupdatemap, p - installed->start);
                            }
                          if (how & SOLVER_CLEANDEPS)
-                           add_cleandeps_package(solv, p);
+                           add_cleandeps_updatepkg(solv, p);
                          targeted = 0;
                        }
                      if (!targeted || solv->noautotarget)
@@ -3916,17 +3653,9 @@ solver_solve(Solver *solv, Queue *job)
            }
          break;
        case SOLVER_DISTUPGRADE:
+         needduprules = 1;
          if (select == SOLVER_SOLVABLE_ALL)
-           {
-             solv->dupmap_all = 1;
-             solv->updatemap_all = 1;
-             if (how & SOLVER_FORCEBEST)
-               solv->bestupdatemap_all = 1;
-           }
-         if ((how & SOLVER_TARGETED) != 0)
-           needduprules = 1;
-         if (!solv->dupmap_all || solv->allowuninstall || solv->allowuninstall_all || solv->allowuninstallmap.size || solv->keep_orphans)
-           needduprules = 1;
+           solv->process_orphans = 1;
          break;
        default:
          break;
@@ -4049,7 +3778,7 @@ solver_solve(Solver *solv, Queue *job)
              continue;
            }
          /* it's also orphaned if the feature rule consists just of the installed package */
-         if (!solv->dupmap_all && sr->p == i && !sr->d && !sr->w2)
+         if (!solv->process_orphans && sr->p == i && !sr->d && !sr->w2)
            queue_push(&solv->orphaned, i);
 
          if (!solver_rulecmp(solv, r, sr))
@@ -4307,7 +4036,7 @@ solver_solve(Solver *solv, Queue *job)
   else
     solv->infarchrules = solv->infarchrules_end = solv->nrules;
 
-  if (needduprules)
+  if (solv->dupinvolvedmap_all || solv->dupinvolvedmap.size)
     solver_addduprules(solv, &addedmap);
   else
     solv->duprules = solv->duprules_end = solv->nrules;
@@ -4398,7 +4127,7 @@ solver_solve(Solver *solv, Queue *job)
   solver_disablepolicyrules(solv);
 
   /* break orphans if requested */
-  if (solv->dupmap_all && solv->orphaned.count && solv->break_orphans)
+  if (solv->process_orphans && solv->orphaned.count && solv->break_orphans)
     solver_breakorphans(solv);
 
   /*
@@ -4435,6 +4164,35 @@ void solver_get_orphaned(Solver *solv, Queue *orphanedq)
   queue_init_clone(orphanedq, &solv->orphaned);
 }
 
+void solver_get_cleandeps(Solver *solv, Queue *cleandepsq)
+{
+  Pool *pool = solv->pool;
+  Repo *installed = solv->installed;
+  Solvable *s;
+  Rule *r;
+  Id p, pp, pr;
+
+  queue_empty(cleandepsq);
+  if (!installed || !solv->cleandepsmap.size)
+    return;
+  FOR_REPO_SOLVABLES(installed, p, s)
+    {
+      if (!MAPTST(&solv->cleandepsmap, p - installed->start) || solv->decisionmap[p] >= 0)
+       continue;
+      /* now check the update rule */
+      r = solv->rules + solv->updaterules + (p - solv->installed->start);
+      if (r->p)
+       {
+         FOR_RULELITERALS(pr, pp, r)
+           if (solv->decisionmap[pr] > 0)
+             break;
+         if (pr)
+           continue;
+       }
+      queue_push(cleandepsq, p);
+    }
+}
+
 void solver_get_recommendations(Solver *solv, Queue *recommendationsq, Queue *suggestionsq, int noselected)
 {
   Pool *pool = solv->pool;
@@ -4805,7 +4563,7 @@ solver_describe_weakdep_decision(Solver *solv, Id p, Queue *whyq)
   for (i = 1; i < pool->nsolvables; i++)
     {
       Id *recp, rec, pp2, p2;
-      if (solv->decisionmap[i] < 0 || solv->decisionmap[i] >= level)
+      if (solv->decisionmap[i] <= 0 || solv->decisionmap[i] >= level)
        continue;
       s = pool->solvables + i;
       if (!s->recommends)