Fix build error about binding python 2.7 path
[platform/upstream/libsolv.git] / src / solver.c
index a80090d..bdce9a9 100644 (file)
@@ -151,11 +151,11 @@ makeruledecisions(Solver *solv, int disablerules)
              solv->decisionmap[vv] = v > 0 ? 1 : -1;
              IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
                {
-                 Solvable *s = solv->pool->solvables + vv;
+                 Solvable *s = pool->solvables + vv;
                  if (v < 0)
-                   POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "conflicting %s (assertion)\n", pool_solvable2str(solv->pool, s));
+                   POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "conflicting %s (assertion)\n", pool_solvable2str(pool, s));
                  else
-                   POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "installing  %s (assertion)\n", pool_solvable2str(solv->pool, s));
+                   POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "installing  %s (assertion)\n", pool_solvable2str(pool, s));
                }
              continue;
            }
@@ -311,11 +311,11 @@ makeruledecisions(Solver *solv, int disablerules)
              solv->decisionmap[vv] = v > 0 ? 1 : -1;
              IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
                {
-                 Solvable *s = solv->pool->solvables + vv;
+                 Solvable *s = pool->solvables + vv;
                  if (v < 0)
-                   POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "conflicting %s (weak assertion)\n", pool_solvable2str(solv->pool, s));
+                   POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "conflicting %s (weak assertion)\n", pool_solvable2str(pool, s));
                  else
-                   POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "installing  %s (weak assertion)\n", pool_solvable2str(solv->pool, s));
+                   POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "installing  %s (weak assertion)\n", pool_solvable2str(pool, s));
                }
              continue;
            }
@@ -431,7 +431,7 @@ propagate(Solver *solv, int level)
   Id *decisionmap = solv->decisionmap;
   Id *watches = solv->watches + pool->nsolvables;   /* place ptr in middle */
 
-  POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "----- propagate -----\n");
+  POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "----- propagate level %d -----\n", level);
 
   /* foreach non-propagated decision */
   while (solv->propagate_index < solv->decisionq.count)
@@ -444,7 +444,7 @@ propagate(Solver *solv, int level)
        
       IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
         {
-         POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "propagate for decision %d level %d\n", -pkg, level);
+         POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "propagate decision %d:", -pkg);
          solver_printruleelement(solv, SOLV_DEBUG_PROPAGATE, 0, -pkg);
         }
 
@@ -462,10 +462,10 @@ propagate(Solver *solv, int level)
              continue;
            }
 
-         IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
+         IF_POOLDEBUG (SOLV_DEBUG_WATCHES)
            {
-             POOL_DEBUG(SOLV_DEBUG_PROPAGATE,"  watch triggered ");
-             solver_printrule(solv, SOLV_DEBUG_PROPAGATE, r);
+             POOL_DEBUG(SOLV_DEBUG_WATCHES, "  watch triggered ");
+             solver_printrule(solv, SOLV_DEBUG_WATCHES, r);
            }
 
          /*
@@ -532,12 +532,12 @@ propagate(Solver *solv, int level)
                   * if we found some p that is UNDEF or TRUE, move
                   * watch to it
                   */
-                 IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
+                 IF_POOLDEBUG (SOLV_DEBUG_WATCHES)
                    {
                      if (p > 0)
-                       POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "    -> move w%d to %s\n", (pkg == r->w1 ? 1 : 2), pool_solvid2str(pool, p));
+                       POOL_DEBUG(SOLV_DEBUG_WATCHES, "    -> move w%d to %s\n", (pkg == r->w1 ? 1 : 2), pool_solvid2str(pool, p));
                      else
-                       POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "    -> move w%d to !%s\n", (pkg == r->w1 ? 1 : 2), pool_solvid2str(pool, -p));
+                       POOL_DEBUG(SOLV_DEBUG_WATCHES, "    -> move w%d to !%s\n", (pkg == r->w1 ? 1 : 2), pool_solvid2str(pool, -p));
                    }
 
                  *rp = *next_rp;
@@ -593,7 +593,7 @@ propagate(Solver *solv, int level)
        
     } /* while we have non-decided decisions */
 
-  POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "----- propagate end-----\n");
+  POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "----- propagate end -----\n");
 
   return 0;    /* all is well */
 }
@@ -986,7 +986,7 @@ analyze_unsolvable(Solver *solv, Rule *cr, int disablerules)
   FOR_RULELITERALS(v, pp, r)
     {
       if (DECISIONMAP_TRUE(v)) /* the one true literal */
-         continue;
+         abort();
       vv = v > 0 ? v : -v;
       MAPSET(&involved, vv);
     }
@@ -1005,8 +1005,12 @@ analyze_unsolvable(Solver *solv, Rule *cr, int disablerules)
       analyze_unsolvable_rule(solv, r, &weakq, &rseen);
       FOR_RULELITERALS(v, pp, r)
        {
-         if (DECISIONMAP_TRUE(v))      /* the one true literal */
+         if (DECISIONMAP_TRUE(v))      /* the one true literal, i.e. our decision */
+           {
+             if (v != solv->decisionq.elements[idx])
+               abort();
              continue;
+           }
          vv = v > 0 ? v : -v;
          MAPSET(&involved, vv);
        }
@@ -1117,10 +1121,77 @@ setpropagatelearn(Solver *solv, int level, Id decision, int disablerules, Id rul
 }
 
 static void
+queue_prunezeros(Queue *q)
+{
+  int i, j;
+  for (i = 0; i < q->count; i++)
+    if (q->elements[i] == 0)
+      break;
+  if (i == q->count)
+    return;
+  for (j = i++; i < q->count; i++)
+    if (q->elements[i])
+      q->elements[j++] = q->elements[i];
+  queue_truncate(q, j);
+}
+
+static int
+replaces_installed_package(Pool *pool, Id p, Map *noupdate)
+{
+  Repo *installed = pool->installed;
+  Solvable *s = pool->solvables + p, *s2;
+  Id p2, pp2;
+  Id obs, *obsp;
+
+  if (s->repo == installed && !(noupdate && MAPTST(noupdate, p - installed->start)))
+    return 1;
+  FOR_PROVIDES(p2, pp2, s->name)
+    {
+      s2 = pool->solvables + p2;
+      if (s2->repo == installed && s2->name == s->name && !(noupdate && MAPTST(noupdate, p - installed->start)))
+       return 1;
+    }
+  if (!s->obsoletes)
+    return 0;
+  obsp = s->repo->idarraydata + s->obsoletes;
+  while ((obs = *obsp++) != 0)
+    {
+      FOR_PROVIDES(p2, pp2, obs)
+       {
+         s2 = pool->solvables + p2;
+         if (s2->repo != pool->installed || (noupdate && MAPTST(noupdate, p - installed->start)))
+           continue;
+         if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, s2, obs))
+           continue;
+         if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2))
+           continue;
+         return 1;
+       }
+    }
+  return 0;
+}
+
+static void
+prune_dq_for_future_installed(Solver *solv, Queue *dq)
+{
+  Pool *pool = solv->pool;
+  int i, j;
+  for (i = j = 0; i < dq->count; i++)
+    {
+      Id p = dq->elements[i];
+      if (replaces_installed_package(pool, p, &solv->noupdate))
+        dq->elements[j++] = p;
+    }
+  if (j)
+    queue_truncate(dq, j);
+}
+
+
+static void
 reorder_dq_for_future_installed(Solver *solv, int level, Queue *dq)
 {
   Pool *pool = solv->pool;
-  int i, j, haveone = 0, dqcount = dq->count;
+  int i, haveone = 0, dqcount = dq->count;
   int decisionqcount = solv->decisionq.count;
   Id p;
   Solvable *s;
@@ -1161,10 +1232,7 @@ reorder_dq_for_future_installed(Solver *solv, int level, Queue *dq)
          dq->elements[i] = 0;
         }
     }
-  for (i = j = 0; i < dq->count; i++)
-    if (dq->elements[i])
-      dq->elements[j++] = dq->elements[i];
-  queue_truncate(dq, j);
+  queue_prunezeros(dq);
   FOR_REPO_SOLVABLES(solv->installed, p, s)
     if (solv->decisionmap[p] == level + 1)
       solv->decisionmap[p] = 0;
@@ -1198,7 +1266,7 @@ createbranch(Solver *solv, int level, Queue *dq, Id p, Id data)
   int i;
   IF_POOLDEBUG (SOLV_DEBUG_POLICY)
     {
-      POOL_DEBUG (SOLV_DEBUG_POLICY, "creating a branch:\n");
+      POOL_DEBUG (SOLV_DEBUG_POLICY, "creating a branch [data=%d]:\n", data);
       for (i = 0; i < dq->count; i++)
        POOL_DEBUG (SOLV_DEBUG_POLICY, "  - %s\n", pool_solvid2str(pool, dq->elements[i]));
     }
@@ -1218,7 +1286,7 @@ takebranch(Solver *solv, int pos, int end, const char *msg, int disablerules)
 #if 0
   {
     int i;
-    printf("branch group level %d [%d-%d] %d %d:\n", solv->branches.elements[end - 1], start, end, solv->branches.elements[end - 4], solv->branches.elements[end - 3]);
+    printf("branch group level %d [%d-%d] %d %d:\n", solv->branches.elements[end - 1], end - solv->branches.elements[end - 2], end, solv->branches.elements[end - 4], solv->branches.elements[end - 3]);
     for (i = end - solv->branches.elements[end - 2]; i < end - 4; i++)
       printf("%c %c%s\n", i == pos ? 'x' : ' ', solv->branches.elements[i] >= 0 ? ' ' : '-', pool_solvid2str(pool, solv->branches.elements[i] >= 0 ? solv->branches.elements[i] : -solv->branches.elements[i]));
   }
@@ -1238,6 +1306,46 @@ takebranch(Solver *solv, int pos, int end, const char *msg, int disablerules)
   return setpropagatelearn(solv, level, p, disablerules, why, reason);
 }
 
+static void
+prune_yumobs(Solver *solv, Queue *dq, Id ruleid)
+{
+  Pool *pool = solv->pool;
+  Rule *r;
+  Map m;
+  int i, j, rid;
+
+  map_init(&m, 0);
+  for (i = 0; i < dq->count - 1; i++)
+    {
+      Id p2, pp, p = dq->elements[i];
+      if (!p || !pool->solvables[p].obsoletes)
+        continue;
+      for (rid = solv->yumobsrules, r = solv->rules + rid; rid < solv->yumobsrules_end; rid++, r++)
+       if (r->p == -p)
+         break;
+      if (rid == solv->yumobsrules_end)
+       continue;
+      if (!m.size)
+       map_grow(&m, pool->nsolvables);
+      else
+       MAPZERO(&m);
+      for (; rid < solv->yumobsrules_end; rid++, r++)
+       {
+         if (r->p != -p)
+           continue;
+         FOR_RULELITERALS(p2, pp, r)
+           if (p2 > 0)
+             MAPSET(&m, p2);
+       }
+      for (j = i + 1; j < dq->count; j++)
+       if (MAPTST(&m, dq->elements[j]))
+         dq->elements[j] = 0;
+    }
+  map_free(&m);
+  queue_prunezeros(dq);
+}
+
+
 /*-------------------------------------------------------------------
  *
  * select and install
@@ -1258,9 +1366,16 @@ selectandinstall(Solver *solv, int level, Queue *dq, int disablerules, Id ruleid
   if (dq->count > 1)
     policy_filter_unwanted(solv, dq, POLICY_MODE_CHOOSE);
   /* if we're resolving rules and didn't resolve the installed packages yet,
-   * do some special supplements ordering */
+   * do some special pruning and supplements ordering */
   if (dq->count > 1 && solv->do_extra_reordering)
-    reorder_dq_for_future_installed(solv, level, dq);
+    {
+      prune_dq_for_future_installed(solv, dq);
+      if (dq->count > 1)
+       reorder_dq_for_future_installed(solv, level, dq);
+    }
+  /* check if the candidates are all connected via yumobs rules */
+  if (dq->count > 1 && solv->yumobsrules_end > solv->yumobsrules)
+    prune_yumobs(solv, dq, ruleid);
   /* if we have multiple candidates we open a branch */
   if (dq->count > 1)
     createbranch(solv, level, dq, 0, ruleid);
@@ -1382,7 +1497,6 @@ solver_free(Solver *solv)
   queuep_free(&solv->recommendscplxq);
   queuep_free(&solv->suggestscplxq);
   queuep_free(&solv->brokenorphanrules);
-  queuep_free(&solv->favorq);
   queuep_free(&solv->recommendsruleq);
 
   map_free(&solv->recommendsmap);
@@ -1399,6 +1513,8 @@ solver_free(Solver *solv)
   map_free(&solv->droporphanedmap);
   map_free(&solv->cleandepsmap);
   map_free(&solv->allowuninstallmap);
+  map_free(&solv->excludefromweakmap);
+
 
   solv_free(solv->favormap);
   solv_free(solv->decisionmap);
@@ -1474,6 +1590,8 @@ solver_get_flag(Solver *solv, int flag)
     return solv->install_also_updates;
   case SOLVER_FLAG_ONLY_NAMESPACE_RECOMMENDED:
     return solv->only_namespace_recommended;
+  case SOLVER_FLAG_STRICT_REPO_PRIORITY:
+    return solv->strict_repo_priority;
   default:
     break;
   }
@@ -1567,6 +1685,9 @@ solver_set_flag(Solver *solv, int flag, int value)
   case SOLVER_FLAG_ONLY_NAMESPACE_RECOMMENDED:
     solv->only_namespace_recommended = value;
     break;
+  case SOLVER_FLAG_STRICT_REPO_PRIORITY:
+    solv->strict_repo_priority = value;
+    break;
   default:
     break;
   }
@@ -1630,6 +1751,7 @@ resolve_jobrules(Solver *solv, int level, int disablerules, Queue *dq)
        }
       olevel = level;
       level = selectandinstall(solv, level, dq, disablerules, i, SOLVER_REASON_RESOLVE_JOB);
+      r = solv->rules + i;    /* selectandinstall may have added more rules */
       if (level <= olevel)
        {
          if (level == olevel)
@@ -1721,12 +1843,27 @@ resolve_installed(Solver *solv, int level, int disablerules, Queue *dq)
            {
              if (specialupdaters && (d = specialupdaters[i - installed->start]) != 0)
                {
+                 int j;
                  /* special multiversion handling, make sure best version is chosen */
                  if (rr->p == i && solv->decisionmap[i] >= 0)
                    queue_push(dq, i);
                  while ((p = pool->whatprovidesdata[d++]) != 0)
                    if (solv->decisionmap[p] >= 0)
                      queue_push(dq, p);
+                 for (j = 0; j < dq->count; j++)
+                   {
+                     Id p2 = dq->elements[j];
+                     if (pool->solvables[p2].repo != installed)
+                       continue;
+                     d = specialupdaters[i - installed->start];
+                     while ((p = pool->whatprovidesdata[d++]) != 0)
+                       {
+                         if (solv->decisionmap[p] >= 0 || pool->solvables[p].repo == installed)
+                           continue;
+                         if (solvable_identical(pool->solvables + p, pool->solvables + p2))
+                           queue_push(dq, p);  /* identical to installed, put it on the list so we have a repo prio */
+                       }
+                   }
                  if (dq->count && solv->update_targets && solv->update_targets->elements[i - installed->start])
                    prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[i - installed->start], dq);
                  if (dq->count)
@@ -1824,6 +1961,69 @@ resolve_installed(Solver *solv, int level, int disablerules, Queue *dq)
   return level;
 }
 
+/* one or more installed cleandeps packages in dq that are to be updated */
+/* we need to emulate the code in resolve_installed */
+static void
+do_cleandeps_update_filter(Solver *solv, Queue *dq)
+{
+  Pool *pool = solv->pool;
+  Repo *installed = solv->installed;
+  Id *specialupdaters = solv->specialupdaters;
+  Id p, p2, pp, d;
+  Queue q;
+  int i, j, k;
+
+  queue_init(&q);
+  for (i = 0; i < dq->count; i++)
+    {
+      Id p = dq->elements[i];
+      if (p < 0)
+       p = -p;
+      if (pool->solvables[p].repo != installed || !MAPTST(&solv->cleandepsmap, p - installed->start))
+       continue;
+      queue_empty(&q);
+      /* find updaters */
+      if (specialupdaters && (d = specialupdaters[p - installed->start]) != 0)
+       {
+         while ((p2 = pool->whatprovidesdata[d++]) != 0)
+           if (solv->decisionmap[p2] >= 0)
+             queue_push(&q, p2);
+       }
+      else
+       {
+         Rule *r = solv->rules + solv->updaterules + (p - installed->start);
+         if (r->p)
+           {
+             FOR_RULELITERALS(p2, pp, r)
+               if (solv->decisionmap[p2] >= 0)
+                 queue_push(&q, p2);
+           }
+       }
+      if (q.count && solv->update_targets && solv->update_targets->elements[p - installed->start])
+        prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[p - installed->start], &q);
+      /* mark all elements in dq that are in the updaters list */
+      dq->elements[i] = -p;
+      for (j = 0; j < dq->count; j++)
+       {
+          p = dq->elements[j];
+         if (p < 0)
+           continue;
+         for (k = 0; k < q.count; k++)
+           if (q.elements[k] == p)
+             {
+               dq->elements[j] = -p;
+               break;
+             }
+       }
+    }
+  /* now prune to marked elements */
+  for (i = j = 0; i < dq->count; i++)
+    if ((p = dq->elements[i]) < 0)
+      dq->elements[j++] = -p;
+  dq->count = j;
+  queue_free(&q);
+}
+
 static int
 resolve_dependencies(Solver *solv, int level, int disablerules, Queue *dq)
 {
@@ -1833,6 +2033,8 @@ resolve_dependencies(Solver *solv, int level, int disablerules, Queue *dq)
   Rule *r;
   int origlevel = level;
   Id p, *dp;
+  int focusbest = solv->focus_best && solv->do_extra_reordering;
+  Repo *installed = solv->installed;
 
   /*
    * decide
@@ -1851,6 +2053,8 @@ resolve_dependencies(Solver *solv, int level, int disablerules, Queue *dq)
        }
       if (i == solv->nrules)
        i = 1;
+      if (focusbest && i >= solv->featurerules)
+       continue;
       r = solv->rules + i;
       if (r->d < 0)            /* ignore disabled rules */
        continue;
@@ -1859,6 +2063,19 @@ resolve_dependencies(Solver *solv, int level, int disablerules, Queue *dq)
          if (r->d == 0 || solv->decisionmap[-r->p] <= 0)
            continue;
        }
+      if (focusbest && r->d != 0 && installed)
+       {
+         /* make sure at least one negative literal is from a new package */
+         if (!(r->p < 0 && pool->solvables[-r->p].repo != installed))
+           {
+             dp = pool->whatprovidesdata + r->d;
+             while ((p = *dp++) != 0)
+               if (p < 0 && solv->decisionmap[-p] > 0 && pool->solvables[-p].repo != installed)
+                 break;
+             if (!p)
+               continue;               /* sorry */
+           }
+       }
       if (dq->count)
        queue_empty(dq);
       if (r->d == 0)
@@ -1919,15 +2136,25 @@ resolve_dependencies(Solver *solv, int level, int disablerules, Queue *dq)
       /* prune to cleandeps packages */
       if (solv->cleandepsmap.size && solv->installed)
        {
+         int cleandeps_update = 0;
          Repo *installed = solv->installed;
          for (j = 0; j < dq->count; j++)
            if (pool->solvables[dq->elements[j]].repo == installed && MAPTST(&solv->cleandepsmap, dq->elements[j] - installed->start))
-             break;
+             {
+               if (solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, dq->elements[j] - installed->start)))
+                 {
+                   cleandeps_update = 1;               /* cleandeps package is marked for update */
+                   continue;
+                 }
+               break;
+             }
          if (j < dq->count)
            {
              dq->elements[0] = dq->elements[j];
              queue_truncate(dq, 1);
            }
+         else if (cleandeps_update)
+           do_cleandeps_update_filter(solv, dq);       /* special update filter */
        }
 
       if (dq->count > 1 && postponed >= 0)
@@ -1985,6 +2212,8 @@ add_complex_recommends(Solver *solv, Id rec, Queue *dq, Map *dqmap)
              queue_truncate(dq, blkcnt);
              break;
            }
+         if (solv->decisionmap[p] < 0)
+           continue;
          if (dqmap)
            {
              if (!MAPTST(dqmap, p))
@@ -1992,8 +2221,6 @@ add_complex_recommends(Solver *solv, Id rec, Queue *dq, Map *dqmap)
            }
          else
            {
-             if (solv->decisionmap[p] < 0)
-               continue;
              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;
            }
@@ -2097,6 +2324,20 @@ prune_disfavored(Solver *solv, Queue *plist)
     queue_truncate(plist, j);
 }
 
+static void
+prune_exclude_from_weak(Solver *solv, Queue *plist)
+{
+  int i, j;
+  for (i = j = 0; i < plist->count; i++)
+    {
+      Id p = plist->elements[i];
+      if (!MAPTST(&solv->excludefromweakmap, p))
+        plist->elements[j++] = p;
+    }
+  if (i != j)
+    queue_truncate(plist, j);
+}
+
 static int
 resolve_weak(Solver *solv, int level, int disablerules, Queue *dq, Queue *dqs, int *rerunp)
 {
@@ -2170,6 +2411,8 @@ resolve_weak(Solver *solv, int level, int disablerules, Queue *dq, Queue *dqs, i
            continue;
          if (solv->havedisfavored && solv->favormap[i] < 0)
            continue;   /* disfavored supplements, do not install */
+         if (solv->excludefromweakmap.size && MAPTST(&solv->excludefromweakmap, i))
+           continue;   /* excluded for weak deps, do not install */
          queue_push(dqs, i);
        }
     }
@@ -2178,6 +2421,10 @@ resolve_weak(Solver *solv, int level, int disablerules, Queue *dq, Queue *dqs, i
   if (dq->count && solv->havedisfavored)
     prune_disfavored(solv, dq);
 
+  /* filter out weak_excluded recommended packages */
+  if (solv->excludefromweakmap.size)
+    prune_exclude_from_weak(solv, dq);
+
   /* filter out all packages obsoleted by installed packages */
   /* this is no longer needed if we have (and trust) reverse obsoletes */
   if ((dqs->count || dq->count) && solv->installed)
@@ -2488,6 +2735,43 @@ resolve_orphaned(Solver *solv, int level, int disablerules, Queue *dq, int *reru
   return level;
 }
 
+int
+solver_check_unneeded_choicerules(Solver *solv)
+{
+  Pool *pool = solv->pool;
+  Rule *r, *or;
+  Id p, pp, p2, pp2;
+  int i;
+  int havedisabled = 0;
+
+  /* check if some choice rules could have been broken */
+  for (i = solv->choicerules, r = solv->rules + i; i < solv->choicerules_end; i++, r++)
+    {
+      if (r->d < 0)
+       continue;
+      or = solv->rules + solv->choicerules_info[i - solv->choicerules];
+      if (or->d < 0)
+       continue;
+      FOR_RULELITERALS(p, pp, or)
+       {
+         if (p < 0 || solv->decisionmap[p] <= 0)
+           continue;
+         FOR_RULELITERALS(p2, pp2, r)
+           if (p2 == p)
+             break;
+         if (!p2)
+           {
+             /* did not find p in choice rule, disable it */
+             POOL_DEBUG(SOLV_DEBUG_SOLVER, "disabling unneeded choice rule #%d\n", i);
+             solver_disablechoicerules(solv, r);
+             havedisabled = 1;
+             break;
+           }
+       }
+    }
+  return havedisabled;
+}
+
 /*-------------------------------------------------------------------
  *
  * solver_run_sat
@@ -2673,6 +2957,14 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
          continue;
        }
 
+      if (solv->choicerules != solv->choicerules_end && solver_check_unneeded_choicerules(solv))
+       {
+         POOL_DEBUG(SOLV_DEBUG_SOLVER, "did choice rule minimization, rerunning solver\n");
+         solver_reset(solv);
+         level = 0;    /* restart from scratch */
+         continue;
+       }
+
       if (solv->solution_callback)
        {
          solv->solution_callback(solv, solv->solution_callback_data);
@@ -2744,6 +3036,8 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
                        continue;
                      if (solv->favormap && solv->favormap[p] > solv->favormap[solv->branches.elements[lastsi]])
                        continue;       /* current selection is more favored */
+                     if (replaces_installed_package(pool, p, &solv->noupdate))
+                       continue;       /* current selection replaces an installed package */
                      if (!(MAPTST(&solv->recommendsmap, p) || solver_is_supplementing(solv, pool->solvables + p)))
                        {
                          lasti = lastsi;
@@ -3002,6 +3296,12 @@ add_update_target(Solver *solv, Id p, Id how)
   if (s->repo == installed)
     {
       queue_push2(solv->update_targets, p, p);
+      FOR_PROVIDES(pi, pip, s->name)
+       {
+         Solvable *si = pool->solvables + pi;
+         if (si->repo == installed && si->name == s->name && pi != p)
+           queue_push2(solv->update_targets, pi, p);
+       }
       return;
     }
   identicalp = 0;
@@ -3130,7 +3430,7 @@ addedmap2deduceq(Solver *solv, Map *addedmap)
       p = -r->p;
       if (!MAPTST(addedmap, p))
        {
-         /* should never happen, but... */
+         /* this can happen with complex dependencies that have more than one pos literal */
          if (!solv->addedmap_deduceq.count || solv->addedmap_deduceq.elements[solv->addedmap_deduceq.count - 1] != -p)
             queue_push(&solv->addedmap_deduceq, -p);
          continue;
@@ -3170,7 +3470,7 @@ deduceq2addedmap(Solver *solv, Map *addedmap)
       if (p > 0)
        MAPSET(addedmap, p);
       else
-       MAPCLR(addedmap, p);
+       MAPCLR(addedmap, -p);
     }
 }
 
@@ -3208,36 +3508,75 @@ add_complex_jobrules(Solver *solv, Id dep, int flags, int jobidx, int weak)
 }
 #endif
 
-/* sort by package id, last entry wins */
-static int
-setup_favormap_cmp(const void *ap, const void *bp, void *dp)
+static void
+solver_add_exclude_from_weak(Solver *solv)
 {
-  const Id *a = ap, *b = bp;
-  if ((*a - *b) != 0)
-    return *a - *b;
-  return (b[1] < 0 ? -b[1] : b[1]) - (a[1] < 0 ? -a[1] : a[1]);
+  Queue *job = &solv->job;
+  Pool *pool = solv->pool;
+  int i;
+  Id p, pp, how, what, select;
+for (i = 0; i < job->count; i += 2)
+  {
+    how = job->elements[i];
+    if ((how & SOLVER_JOBMASK) != SOLVER_EXCLUDEFROMWEAK)
+       continue;
+    if (!solv->excludefromweakmap.size)
+       map_grow(&solv->excludefromweakmap, pool->nsolvables);
+    what = job->elements[i + 1];
+    select = how & SOLVER_SELECTMASK;
+    if (select == SOLVER_SOLVABLE_REPO)
+      {
+       Repo *repo = pool_id2repo(pool, what);
+         if (repo)
+           {
+             Solvable *s;
+             FOR_REPO_SOLVABLES(repo, p, s)
+               MAPSET(&solv->excludefromweakmap, p);
+           }
+       }
+      FOR_JOB_SELECT(p, pp, select, what)
+       MAPSET(&solv->excludefromweakmap, p);
+    }
 }
 
 static void
 setup_favormap(Solver *solv)
 {
-  Queue *q = solv->favorq;
+  Queue *job = &solv->job;
   Pool *pool = solv->pool;
-  int i;
-  Id oldp = 0;
-  if (q->count > 2)
-    solv_sort(q->elements, q->count / 2, 2 * sizeof(Id), setup_favormap_cmp, solv);
+  int i, idx;
+  Id p, pp, how, what, select;
+
+  solv_free(solv->favormap);
   solv->favormap = solv_calloc(pool->nsolvables, sizeof(Id));
-  solv->havedisfavored = 0;
-  for (i = 0; i < q->count; i += 2)
+  for (i = 0; i < job->count; i += 2)
     {
-      Id p = q->elements[i];
-      if (p == oldp)
+      how = job->elements[i];
+      if ((how & SOLVER_JOBMASK) != SOLVER_FAVOR && (how & SOLVER_JOBMASK) != SOLVER_DISFAVOR)
        continue;
-      oldp = p;
-      solv->favormap[p] = q->elements[i + 1];
-      if (q->elements[i + 1] < 0)
-       solv->havedisfavored = 1;
+      what = job->elements[i + 1];
+      select = how & SOLVER_SELECTMASK;
+      idx = (how & SOLVER_JOBMASK) == SOLVER_FAVOR ? i + 1 : -(i + 1);
+      if (select == SOLVER_SOLVABLE_REPO)
+       {
+         Repo *repo = pool_id2repo(pool, what);
+         if (repo)
+           {
+             Solvable *s;
+             FOR_REPO_SOLVABLES(repo, p, s)
+               {
+                 solv->favormap[p] = idx;
+                 if (idx < 0)
+                   solv->havedisfavored = 1;
+               }
+           }
+       }
+      FOR_JOB_SELECT(p, pp, select, what)
+       {
+         solv->favormap[p] = idx;
+         if (idx < 0)
+           solv->havedisfavored = 1;
+       }
     }
 }
 
@@ -3263,6 +3602,10 @@ solver_solve(Solver *solv, Queue *job)
   int now, solve_start;
   int needduprules = 0;
   int hasbestinstalljob = 0;
+  int hasfavorjob = 0;
+  int haslockjob = 0;
+  int hasblacklistjob = 0;
+  int hasexcludefromweakjob = 0;
 
   solve_start = solv_timems(0);
 
@@ -3270,6 +3613,7 @@ solver_solve(Solver *solv, Queue *job)
   POOL_DEBUG(SOLV_DEBUG_STATS, "solver started\n");
   POOL_DEBUG(SOLV_DEBUG_STATS, "dosplitprovides=%d, noupdateprovide=%d, noinfarchcheck=%d\n", solv->dosplitprovides, solv->noupdateprovide, solv->noinfarchcheck);
   POOL_DEBUG(SOLV_DEBUG_STATS, "allowuninstall=%d, allowdowngrade=%d, allownamechange=%d, allowarchchange=%d, allowvendorchange=%d\n", solv->allowuninstall, solv->allowdowngrade, solv->allownamechange, solv->allowarchchange, solv->allowvendorchange);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "dupallowdowngrade=%d, dupallownamechange=%d, dupallowarchchange=%d, dupallowvendorchange=%d\n", solv->dup_allowdowngrade, solv->dup_allownamechange, solv->dup_allowarchchange, solv->dup_allowvendorchange);
   POOL_DEBUG(SOLV_DEBUG_STATS, "promoteepoch=%d, forbidselfconflicts=%d\n", pool->promoteepoch, pool->forbidselfconflicts);
   POOL_DEBUG(SOLV_DEBUG_STATS, "obsoleteusesprovides=%d, implicitobsoleteusesprovides=%d, obsoleteusescolors=%d, implicitobsoleteusescolors=%d\n", pool->obsoleteusesprovides, pool->implicitobsoleteusesprovides, pool->obsoleteusescolors, pool->implicitobsoleteusescolors);
   POOL_DEBUG(SOLV_DEBUG_STATS, "dontinstallrecommended=%d, addalreadyrecommended=%d onlynamespacerecommended=%d\n", solv->dontinstallrecommended, solv->addalreadyrecommended, solv->only_namespace_recommended);
@@ -3306,6 +3650,7 @@ solver_solve(Solver *solv, Queue *job)
   map_zerosize(&solv->bestupdatemap);
   solv->fixmap_all = 0;
   map_zerosize(&solv->fixmap);
+  solv->dupinvolvedmap_all = 0;
   map_zerosize(&solv->dupmap);
   map_zerosize(&solv->dupinvolvedmap);
   solv->process_orphans = 0;
@@ -3313,6 +3658,7 @@ solver_solve(Solver *solv, Queue *job)
   map_zerosize(&solv->droporphanedmap);
   solv->allowuninstall_all = 0;
   map_zerosize(&solv->allowuninstallmap);
+  map_zerosize(&solv->excludefromweakmap);
   map_zerosize(&solv->cleandepsmap);
   map_zerosize(&solv->weakrulemap);
   solv->favormap = solv_free(solv->favormap);
@@ -3773,6 +4119,10 @@ solver_solve(Solver *solv, Queue *job)
                  name_s = s;
                }
              solver_addjobrule(solv, -p, 0, 0, i, weak);
+#ifdef ENABLE_LINKED_PKGS
+             if (solv->instbuddy && installed && s->repo == installed && solv->instbuddy[p - installed->start] > 1)
+               solver_addjobrule(solv, -solv->instbuddy[p - installed->start], 0, 0, i, weak);
+#endif
            }
          /* special case for "erase a specific solvable": we also
           * erase all other solvables with that name, so that they
@@ -3840,7 +4190,16 @@ solver_solve(Solver *solv, Queue *job)
                }
            }
          FOR_JOB_SELECT(p, pp, select, what)
-           solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, 0, i, weak);
+           {
+             s = pool->solvables + p;
+             solver_addjobrule(solv, installed && s->repo == installed ? p : -p, 0, 0, i, weak);
+#ifdef ENABLE_LINKED_PKGS
+             if (solv->instbuddy && installed && s->repo == installed && solv->instbuddy[p - installed->start] > 1)
+               solver_addjobrule(solv, solv->instbuddy[p - installed->start], 0, 0, i, weak);
+#endif
+           }
+         if (solv->nrules != oldnrules)
+           haslockjob = 1;
          break;
        case SOLVER_DISTUPGRADE:
          POOL_DEBUG(SOLV_DEBUG_JOB, "job: distupgrade %s\n", solver_select2str(pool, select, what));
@@ -3857,15 +4216,15 @@ solver_solve(Solver *solv, Queue *job)
        case SOLVER_FAVOR:
        case SOLVER_DISFAVOR:
          POOL_DEBUG(SOLV_DEBUG_JOB, "job: %s %s\n", (how & SOLVER_JOBMASK) == SOLVER_FAVOR ? "favor" : "disfavor", solver_select2str(pool, select, what));
-         FOR_JOB_SELECT(p, pp, select, what)
-           {
-             if (!solv->favorq)
-               {
-                 solv->favorq = solv_calloc(1, sizeof(Queue));
-                 queue_init(solv->favorq);
-               }
-             queue_push2(solv->favorq, p, (how & SOLVER_JOBMASK) == SOLVER_FAVOR ? i + 1 : -(i + 1));
-           }
+         hasfavorjob = 1;
+         break;
+       case SOLVER_BLACKLIST:
+         POOL_DEBUG(SOLV_DEBUG_JOB, "job: blacklist %s\n", solver_select2str(pool, select, what));
+         hasblacklistjob = 1;
+         break;
+        case SOLVER_EXCLUDEFROMWEAK:
+         POOL_DEBUG(SOLV_DEBUG_JOB, "job: excludefromweak %s\n", solver_select2str(pool, select, what));
+         hasexcludefromweakjob = 1;
          break;
        default:
          POOL_DEBUG(SOLV_DEBUG_JOB, "job: unknown job\n");
@@ -3887,8 +4246,8 @@ solver_solve(Solver *solv, Queue *job)
   assert(solv->ruletojob.count == solv->nrules - solv->jobrules);
   solv->jobrules_end = solv->nrules;
 
-  /* sort favorq and transform it into two maps */
-  if (solv->favorq)
+  /* create favormap if we have favor jobs */
+  if (hasfavorjob)
     setup_favormap(solv);
 
   /* now create infarch and dup rules */
@@ -3908,7 +4267,7 @@ solver_solve(Solver *solv, Queue *job)
 #endif
 
   if (solv->bestupdatemap_all || solv->bestupdatemap.size || hasbestinstalljob)
-    solver_addbestrules(solv, hasbestinstalljob);
+    solver_addbestrules(solv, hasbestinstalljob, haslockjob);
   else
     solv->bestrules = solv->bestrules_end = solv->bestrules_up = solv->nrules;
 
@@ -3920,11 +4279,24 @@ solver_solve(Solver *solv, Queue *job)
   else
     solv->yumobsrules = solv->yumobsrules_end = solv->nrules;
 
-  if (solv->havedisfavored && solv->strongrecommends)
+  if (hasblacklistjob)
+    solver_addblackrules(solv);
+  else
+    solv->blackrules = solv->blackrules_end = solv->nrules;
+
+  if (hasexcludefromweakjob)
+    solver_add_exclude_from_weak(solv);
+
+  if (solv->havedisfavored && solv->strongrecommends && solv->recommendsruleq)
     solver_addrecommendsrules(solv);
   else
     solv->recommendsrules = solv->recommendsrules_end = solv->nrules;
 
+  if (solv->strict_repo_priority)
+    solver_addstrictrepopriorules(solv, &addedmap);
+  else
+    solv->strictrepopriorules = solv->strictrepopriorules_end = solv->nrules;
+
   if (1)
     solver_addchoicerules(solv);
   else
@@ -3940,7 +4312,19 @@ solver_solve(Solver *solv, Queue *job)
   map_free(&installcandidatemap);
   queue_free(&q);
 
-  POOL_DEBUG(SOLV_DEBUG_STATS, "%d pkg rules, 2 * %d update rules, %d job rules, %d infarch rules, %d dup rules, %d choice rules, %d best rules, %d yumobs rules\n", solv->pkgrules_end - 1, solv->updaterules_end - solv->updaterules, solv->jobrules_end - solv->jobrules, solv->infarchrules_end - solv->infarchrules, solv->duprules_end - solv->duprules, solv->choicerules_end - solv->choicerules, solv->bestrules_end - solv->bestrules, solv->yumobsrules_end - solv->yumobsrules);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "%d pkg rules, 2 * %d update rules, %d job rules, %d infarch rules, %d dup rules, %d choice rules, %d best rules, %d yumobs rules\n",
+   solv->pkgrules_end - 1, 
+   solv->updaterules_end - solv->updaterules, 
+   solv->jobrules_end - solv->jobrules, 
+   solv->infarchrules_end - solv->infarchrules, 
+   solv->duprules_end - solv->duprules, 
+   solv->choicerules_end - solv->choicerules, 
+   solv->bestrules_end - solv->bestrules, 
+   solv->yumobsrules_end - solv->yumobsrules);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "%d black rules, %d recommends rules, %d repo priority rules\n",
+   solv->blackrules_end - solv->blackrules,
+   solv->recommendsrules_end - solv->recommendsrules,
+   solv->strictrepopriorules_end - solv->strictrepopriorules);
   POOL_DEBUG(SOLV_DEBUG_STATS, "overall rule memory used: %d K\n", solv->nrules * (int)sizeof(Rule) / 1024);
 
   /* create weak map */
@@ -4314,194 +4698,6 @@ solver_create_state_maps(Solver *solv, Map *installedmap, Map *conflictsmap)
   pool_create_state_maps(solv->pool, &solv->decisionq, installedmap, conflictsmap);
 }
 
-/*-------------------------------------------------------------------
- *
- * decision introspection
- */
-
-int
-solver_get_decisionlevel(Solver *solv, Id p)
-{
-  return solv->decisionmap[p];
-}
-
-void
-solver_get_decisionqueue(Solver *solv, Queue *decisionq)
-{
-  queue_free(decisionq);
-  queue_init_clone(decisionq, &solv->decisionq);
-}
-
-int
-solver_get_lastdecisionblocklevel(Solver *solv)
-{
-  Id p;
-  if (solv->decisionq.count == 0)
-    return 0;
-  p = solv->decisionq.elements[solv->decisionq.count - 1];
-  if (p < 0)
-    p = -p;
-  return solv->decisionmap[p] < 0 ? -solv->decisionmap[p] : solv->decisionmap[p];
-}
-
-void
-solver_get_decisionblock(Solver *solv, int level, Queue *decisionq)
-{
-  Id p;
-  int i;
-
-  queue_empty(decisionq);
-  for (i = 0; i < solv->decisionq.count; i++)
-    {
-      p = solv->decisionq.elements[i];
-      if (p < 0)
-       p = -p;
-      if (solv->decisionmap[p] == level || solv->decisionmap[p] == -level)
-        break;
-    }
-  if (i == solv->decisionq.count)
-    return;
-  for (i = 0; i < solv->decisionq.count; i++)
-    {
-      p = solv->decisionq.elements[i];
-      if (p < 0)
-       p = -p;
-      if (solv->decisionmap[p] == level || solv->decisionmap[p] == -level)
-        queue_push(decisionq, p);
-      else
-        break;
-    }
-}
-
-int
-solver_describe_decision(Solver *solv, Id p, Id *infop)
-{
-  int i;
-  Id pp, why;
-
-  if (infop)
-    *infop = 0;
-  if (!solv->decisionmap[p])
-    return SOLVER_REASON_UNRELATED;
-  pp = solv->decisionmap[p] < 0 ? -p : p;
-  for (i = 0; i < solv->decisionq.count; i++)
-    if (solv->decisionq.elements[i] == pp)
-      break;
-  if (i == solv->decisionq.count)      /* just in case... */
-    return SOLVER_REASON_UNRELATED;
-  why = solv->decisionq_why.elements[i];
-  if (infop)
-    *infop = why > 0 ? why : -why;
-  if (why > 0)
-    return SOLVER_REASON_UNIT_RULE;
-  i = solv->decisionmap[p] >= 0 ? solv->decisionmap[p] : -solv->decisionmap[p];
-  return solv->decisionq_reason.elements[i];
-}
-
-
-void
-solver_describe_weakdep_decision(Solver *solv, Id p, Queue *whyq)
-{
-  Pool *pool = solv->pool;
-  int i;
-  int level = solv->decisionmap[p];
-  int decisionno;
-  Solvable *s;
-
-  queue_empty(whyq);
-  if (level < 0)
-    return;    /* huh? */
-  for (decisionno = 0; decisionno < solv->decisionq.count; decisionno++)
-    if (solv->decisionq.elements[decisionno] == p)
-      break;
-  if (decisionno == solv->decisionq.count)
-    return;    /* huh? */
-  i = solv->decisionmap[p] >= 0 ? solv->decisionmap[p] : -solv->decisionmap[p];
-  if (solv->decisionq_reason.elements[i] != SOLVER_REASON_WEAKDEP)
-    return;    /* huh? */
-
-  /* 1) list all packages that recommend us */
-  for (i = 1; i < pool->nsolvables; i++)
-    {
-      Id *recp, rec, pp2, p2;
-      if (solv->decisionmap[i] <= 0 || solv->decisionmap[i] >= level)
-       continue;
-      s = pool->solvables + i;
-      if (!s->recommends)
-       continue;
-      if (!solv->addalreadyrecommended && s->repo == solv->installed)
-       continue;
-      recp = s->repo->idarraydata + s->recommends;
-      while ((rec = *recp++) != 0)
-       {
-         int found = 0;
-         FOR_PROVIDES(p2, pp2, rec)
-           {
-             if (p2 == p)
-               found = 1;
-             else
-               {
-                 /* if p2 is already installed, this recommends is ignored */
-                 if (solv->decisionmap[p2] > 0 && solv->decisionmap[p2] < level)
-                   break;
-               }
-           }
-         if (!p2 && found)
-           {
-             queue_push(whyq, SOLVER_REASON_RECOMMENDED);
-             queue_push2(whyq, i, rec);
-           }
-       }
-    }
-  /* 2) list all supplements */
-  s = pool->solvables + p;
-  if (s->supplements && level > 0)
-    {
-      Id *supp, sup, pp2, p2;
-      /* this is a hack. to use solver_dep_fulfilled we temporarily clear
-       * everything above our level in the decisionmap */
-      for (i = decisionno; i < solv->decisionq.count; i++ )
-       {
-         p2 = solv->decisionq.elements[i];
-         if (p2 > 0)
-           solv->decisionmap[p2] = -solv->decisionmap[p2];
-       }
-      supp = s->repo->idarraydata + s->supplements;
-      while ((sup = *supp++) != 0)
-       if (solver_dep_fulfilled(solv, sup))
-         {
-           int found = 0;
-           /* let's see if this is an easy supp */
-           FOR_PROVIDES(p2, pp2, sup)
-             {
-               if (!solv->addalreadyrecommended && solv->installed)
-                 {
-                   if (pool->solvables[p2].repo == solv->installed)
-                     continue;
-                 }
-               if (solv->decisionmap[p2] > 0 && solv->decisionmap[p2] < level)
-                 {
-                   queue_push(whyq, SOLVER_REASON_SUPPLEMENTED);
-                   queue_push2(whyq, p2, sup);
-                   found = 1;
-                 }
-             }
-           if (!found)
-             {
-               /* hard case, just note dependency with no package */
-               queue_push(whyq, SOLVER_REASON_SUPPLEMENTED);
-               queue_push2(whyq, 0, sup);
-             }
-         }
-      for (i = decisionno; i < solv->decisionq.count; i++)
-       {
-         p2 = solv->decisionq.elements[i];
-         if (p2 > 0)
-           solv->decisionmap[p2] = -solv->decisionmap[p2];
-       }
-    }
-}
-
 void
 pool_job2solvables(Pool *pool, Queue *pkgs, Id how, Id what)
 {
@@ -4533,7 +4729,7 @@ pool_job2solvables(Pool *pool, Queue *pkgs, Id how, Id what)
 int
 pool_isemptyupdatejob(Pool *pool, Id how, Id what)
 {
-  Id p, pp, pi, pip;
+  Id p, pp;
   Id select = how & SOLVER_SELECTMASK;
   if ((how & SOLVER_JOBMASK) != SOLVER_UPDATE)
     return 0;
@@ -4546,85 +4742,11 @@ pool_isemptyupdatejob(Pool *pool, Id how, Id what)
       return 0;
   /* hard work */
   FOR_JOB_SELECT(p, pp, select, what)
-    {
-      Solvable *s = pool->solvables + p;
-      FOR_PROVIDES(pi, pip, s->name)
-       {
-         Solvable *si = pool->solvables + pi;
-         if (si->repo != pool->installed || si->name != s->name)
-           continue;
-         return 0;
-       }
-      if (s->obsoletes)
-       {
-         Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
-         while ((obs = *obsp++) != 0)
-           {
-             FOR_PROVIDES(pi, pip, obs)
-               {
-                 Solvable *si = pool->solvables + pi;
-                 if (si->repo != pool->installed)
-                   continue;
-                 if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, si, obs))
-                   continue;
-                 if (pool->obsoleteusescolors && !pool_colormatch(pool, s, si))
-                   continue;
-                 return 0;
-               }
-           }
-       }
-    }
+    if (replaces_installed_package(pool, p, 0))
+      return 0;
   return 1;
 }
 
-int
-solver_alternatives_count(Solver *solv)
-{
-  Id *elements = solv->branches.elements;
-  int res, count;
-  for (res = 0, count = solv->branches.count; count; res++)
-    count -= elements[count - 2];
-  return res;
-}
-
-int
-solver_get_alternative(Solver *solv, Id alternative, Id *idp, Id *fromp, Id *chosenp, Queue *choices, int *levelp)
-{
-  int cnt = solver_alternatives_count(solv);
-  int count = solv->branches.count;
-  Id *elements = solv->branches.elements;
-  if (choices)
-    queue_empty(choices);
-  if (alternative <= 0 || alternative > cnt)
-    return 0;
-  elements += count;
-  for (; cnt > alternative; cnt--)
-    elements -= elements[-2];
-  if (levelp)
-    *levelp = elements[-1];
-  if (fromp)
-    *fromp = elements[-4];
-  if (idp)
-    *idp = elements[-3];
-  if (chosenp)
-    {
-      int i;
-      *chosenp = 0;
-      for (i = elements[-2]; i > 4; i--)
-       {
-         Id p = -elements[-i];
-         if (p > 0 && solv->decisionmap[p] == elements[-1] + 1)
-           {
-             *chosenp = p;
-             break;
-           }
-       }
-    }
-  if (choices)
-    queue_insertn(choices, 0, elements[-2] - 4, elements - elements[-2]);
-  return elements[-4] ? SOLVER_ALTERNATIVE_TYPE_RECOMMENDS : SOLVER_ALTERNATIVE_TYPE_RULE;
-}
-
 const char *
 solver_select2str(Pool *pool, Id select, Id what)
 {
@@ -4731,6 +4853,9 @@ pool_job2str(Pool *pool, Id how, Id what, Id flagmask)
     case SOLVER_DISFAVOR:
       strstart = "disfavor ";
       break;
+    case SOLVER_BLACKLIST:
+      strstart = "blacklist ";
+      break;
     default:
       strstart = "unknown job ";
       break;
@@ -4773,39 +4898,3 @@ pool_job2str(Pool *pool, Id how, Id what, Id flagmask)
   return pool_tmpappend(pool, s, "]", 0);
 }
 
-const char *
-solver_alternative2str(Solver *solv, int type, Id id, Id from)
-{
-  Pool *pool = solv->pool;
-  if (type == SOLVER_ALTERNATIVE_TYPE_RECOMMENDS)
-    {
-      const char *s = pool_dep2str(pool, id);
-      return pool_tmpappend(pool, s, ", recommended by ", pool_solvid2str(pool, from));
-    }
-  if (type == SOLVER_ALTERNATIVE_TYPE_RULE)
-    {
-      int rtype;
-      Id depfrom, depto, dep;
-      char buf[64];
-      if (solver_ruleclass(solv, id) == SOLVER_RULE_CHOICE)
-       id = solver_rule2pkgrule(solv, id);
-      if (solver_ruleclass(solv, id) == SOLVER_RULE_RECOMMENDS)
-       id = solver_rule2pkgrule(solv, id);
-      rtype = solver_ruleinfo(solv, id, &depfrom, &depto, &dep);
-      if ((rtype & SOLVER_RULE_TYPEMASK) == SOLVER_RULE_JOB)
-       {
-         if ((depto & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_PROVIDES)
-           return pool_dep2str(pool, dep);
-         return solver_select2str(pool, depto & SOLVER_SELECTMASK, dep);
-       }
-      if (rtype == SOLVER_RULE_PKG_REQUIRES)
-       {
-         const char *s = pool_dep2str(pool, dep);
-         return pool_tmpappend(pool, s, ", required by ", pool_solvid2str(pool, depfrom));
-       }
-      sprintf(buf, "Rule #%d", id);
-      return pool_tmpjoin(pool, buf, 0, 0);
-    }
-  return "unknown alternative type";
-}
-