support -X option in rpmmd2solv, make add_autopattern available in bindings
[platform/upstream/libsolv.git] / src / solver.c
index 054567e..403d9f8 100644 (file)
@@ -1250,6 +1250,8 @@ revert(Solver *solv, int level)
     }
   if (solv->recommends_index > solv->decisionq.count)
     solv->recommends_index = -1;       /* rebuild recommends/suggests maps */
+  if (solv->decisionq.count < solv->decisioncnt_jobs)
+    solv->decisioncnt_jobs = 0;
   if (solv->decisionq.count < solv->decisioncnt_update)
     solv->decisioncnt_update = 0;
   if (solv->decisionq.count < solv->decisioncnt_keep)
@@ -1448,7 +1450,9 @@ selectandinstall(Solver *solv, int level, Queue *dq, int disablerules, Id ruleid
            break;
          }
     }
-  if (dq->count > 1 && ruleid >= solv->jobrules && ruleid < solv->jobrules_end && solv->installed)
+  /* if we're resolving job rules and didn't resolve the installed packages yet,
+   * do some special supplements ordering */
+  if (dq->count > 1 && ruleid >= solv->jobrules && ruleid < solv->jobrules_end && solv->installed && !solv->focus_installed)
     reorder_dq_for_jobrules(solv, level, dq);
   if (dq->count > 1)
     {
@@ -1527,6 +1531,83 @@ solver_create(Pool *pool)
 }
 
 
+static int
+resolve_jobrules(Solver *solv, int level, int disablerules, Queue *dq)
+{
+  Pool *pool = solv->pool;
+  int oldlevel = level;
+  int i, olevel;
+  Rule *r;
+
+  POOL_DEBUG(SOLV_DEBUG_SOLVER, "resolving job rules\n");
+  if (!solv->decisioncnt_jobs)
+    solv->decisioncnt_jobs = solv->decisionq.count;
+  for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++)
+    {
+      Id l, pp;
+      if (r->d < 0)            /* ignore disabled rules */
+       continue;
+      queue_empty(dq);
+      FOR_RULELITERALS(l, pp, r)
+       {
+         if (l < 0)
+           {
+             if (solv->decisionmap[-l] <= 0)
+               break;
+           }
+         else
+           {
+             if (solv->decisionmap[l] > 0)
+               break;
+             if (solv->decisionmap[l] == 0)
+               queue_push(dq, l);
+           }
+       }
+      if (l || !dq->count)
+       continue;
+      /* prune to installed if not updating */
+      if (dq->count > 1 && solv->installed && !solv->updatemap_all &&
+         !(solv->job.elements[solv->ruletojob.elements[i - solv->jobrules]] & SOLVER_ORUPDATE))
+       {
+         int j, k;
+         for (j = k = 0; j < dq->count; j++)
+           {
+             Solvable *s = pool->solvables + dq->elements[j];
+             if (s->repo == solv->installed)
+               {
+                 dq->elements[k++] = dq->elements[j];
+                 if (solv->updatemap.size && MAPTST(&solv->updatemap, dq->elements[j] - solv->installed->start))
+                   {
+                     k = 0;    /* package wants to be updated, do not prune */
+                     break;
+                   }
+               }
+           }
+         if (k)
+           dq->count = k;
+       }
+      olevel = level;
+      level = selectandinstall(solv, level, dq, disablerules, i);
+      if (level <= olevel)
+       {
+         if (level == 0)
+           return 0;   /* unsolvable */
+         if (level == olevel)
+           {
+             i--;
+             r--;
+             continue; /* try something else */
+           }
+         if (level < oldlevel)
+           return level;
+         /* redo from start of jobrules */
+         i = solv->jobrules - 1;
+         r = solv->rules + i;
+       }
+    }
+  return level;
+}
+
 /*-------------------------------------------------------------------
  *
  * solver_free
@@ -1573,6 +1654,7 @@ solver_free(Solver *solv)
   queuep_free(&solv->installsuppdepq);
   queuep_free(&solv->recommendscplxq);
   queuep_free(&solv->suggestscplxq);
+  queuep_free(&solv->brokenorphanrules);
 
   map_free(&solv->recommendsmap);
   map_free(&solv->suggestsmap);
@@ -1643,6 +1725,8 @@ solver_get_flag(Solver *solv, int flag)
     return solv->keep_orphans;
   case SOLVER_FLAG_BREAK_ORPHANS:
     return solv->break_orphans;
+  case SOLVER_FLAG_FOCUS_INSTALLED:
+    return solv->focus_installed;
   default:
     break;
   }
@@ -1712,6 +1796,9 @@ solver_set_flag(Solver *solv, int flag, int value)
   case SOLVER_FLAG_BREAK_ORPHANS:
     solv->break_orphans = value;
     break;
+  case SOLVER_FLAG_FOCUS_INSTALLED:
+    solv->focus_installed = value;
+    break;
   default:
     break;
   }
@@ -1991,74 +2078,27 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
        }
 
       /*
-       * resolve jobs first
+       * resolve jobs first (unless focus_installed is set)
        */
-     if (level < systemlevel)
+     if (level < systemlevel && !solv->focus_installed)
        {
-         POOL_DEBUG(SOLV_DEBUG_SOLVER, "resolving job rules\n");
-         for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++)
+         olevel = level;
+         level = resolve_jobrules(solv, level, disablerules, &dq);
+         if (level < olevel)
            {
-             Id l;
-             if (r->d < 0)             /* ignore disabled rules */
-               continue;
-             queue_empty(&dq);
-             FOR_RULELITERALS(l, pp, r)
-               {
-                 if (l < 0)
-                   {
-                     if (solv->decisionmap[-l] <= 0)
-                       break;
-                   }
-                 else
-                   {
-                     if (solv->decisionmap[l] > 0)
-                       break;
-                     if (solv->decisionmap[l] == 0)
-                       queue_push(&dq, l);
-                   }
-               }
-             if (l || !dq.count)
-               continue;
-             /* prune to installed if not updating */
-             if (dq.count > 1 && solv->installed && !solv->updatemap_all &&
-                 !(solv->job.elements[solv->ruletojob.elements[i - solv->jobrules]] & SOLVER_ORUPDATE))
-               {
-                 int j, k;
-                 for (j = k = 0; j < dq.count; j++)
-                   {
-                     Solvable *s = pool->solvables + dq.elements[j];
-                     if (s->repo == solv->installed)
-                       {
-                         dq.elements[k++] = dq.elements[j];
-                         if (solv->updatemap.size && MAPTST(&solv->updatemap, dq.elements[j] - solv->installed->start))
-                           {
-                             k = 0;    /* package wants to be updated, do not prune */
-                             break;
-                           }
-                       }
-                   }
-                 if (k)
-                   dq.count = k;
-               }
-             olevel = level;
-             level = selectandinstall(solv, level, &dq, disablerules, i);
              if (level == 0)
-               break;
-             if (level <= olevel)
-               break;
+               break;  /* unsolvable */
+             continue;
            }
-          if (level == 0)
-           break;      /* unsolvable */
          systemlevel = level + 1;
-         if (i < solv->jobrules_end)
-           continue;
-          if (!solv->decisioncnt_update)
-            solv->decisioncnt_update = solv->decisionq.count;
        }
 
+
       /*
        * installed packages
        */
+      if (!solv->decisioncnt_update)
+       solv->decisioncnt_update = solv->decisionq.count;
       if (level < systemlevel && solv->installed && solv->installed->nsolvables && !solv->installed->disabled)
        {
          Repo *installed = solv->installed;
@@ -2231,6 +2271,19 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
       if (!solv->decisioncnt_keep)
        solv->decisioncnt_keep = solv->decisionq.count;
 
+     if (level < systemlevel && solv->focus_installed)
+       {
+         olevel = level;
+         level = resolve_jobrules(solv, level, disablerules, &dq);
+         if (level < olevel)
+           {
+             if (level == 0)
+               break;  /* unsolvable */
+             continue;
+           }
+         systemlevel = level + 1;
+       }
+
       if (level < systemlevel)
         systemlevel = level;
 
@@ -2687,6 +2740,26 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
                break;
              continue;         /* back to main loop */
            }
+          if (solv->brokenorphanrules)
+           {
+             solver_check_brokenorphanrules(solv, &dq);
+             if (dq.count)
+               {
+                 policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE);
+                 for (i = 0; i < dq.count; i++)
+                   {
+                     p = dq.elements[i];
+                     POOL_DEBUG(SOLV_DEBUG_POLICY, "installing orphaned dep %s\n", pool_solvid2str(pool, p));
+                     olevel = level;
+                     level = setpropagatelearn(solv, level, p, 0, 0);
+                     if (level < olevel)
+                       break;
+                   }
+                 if (level == 0)
+                   break;
+                 continue;
+               }
+           }
        }
 
      /* one final pass to make sure we decided all installed packages */
@@ -2807,6 +2880,7 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
   if (level == 0)
     {
       /* unsolvable */
+      solv->decisioncnt_jobs = solv->decisionq.count;
       solv->decisioncnt_update = solv->decisionq.count;
       solv->decisioncnt_keep = solv->decisionq.count;
       solv->decisioncnt_resolve = solv->decisionq.count;
@@ -3286,7 +3360,7 @@ solver_solve(Solver *solv, Queue *job)
     memset(solv->decisionmap, 0, pool->nsolvables * sizeof(Id));
   queue_empty(&solv->decisionq);
   queue_empty(&solv->decisionq_why);
-  solv->decisioncnt_update = solv->decisioncnt_keep = solv->decisioncnt_resolve = solv->decisioncnt_weak = solv->decisioncnt_orphan = 0;
+  solv->decisioncnt_jobs = solv->decisioncnt_update = solv->decisioncnt_keep = solv->decisioncnt_resolve = solv->decisioncnt_weak = solv->decisioncnt_orphan = 0;
   queue_empty(&solv->learnt_why);
   queue_empty(&solv->learnt_pool);
   queue_empty(&solv->branches);
@@ -3303,6 +3377,7 @@ solver_solve(Solver *solv, Queue *job)
       queuep_free(&solv->suggestscplxq);
       solv->recommends_index = 0;
     }
+  queuep_free(&solv->brokenorphanrules);
   solv->specialupdaters = solv_free(solv->specialupdaters);
 
 
@@ -3337,6 +3412,7 @@ solver_solve(Solver *solv, Queue *job)
   if (installed)
     {
       /* check for update/verify jobs as they need to be known early */
+      /* also setup the droporphaned map, we need it when creating update rules */
       for (i = 0; i < job->count; i += 2)
        {
          how = job->elements[i];
@@ -3422,6 +3498,19 @@ solver_solve(Solver *solv, Queue *job)
                    add_update_target(solv, p, how);
                }
              break;
+           case SOLVER_DROP_ORPHANED:
+             if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid))
+               solv->droporphanedmap_all = 1;
+             FOR_JOB_SELECT(p, pp, select, what)
+               {
+                 s = pool->solvables + p;
+                 if (s->repo != installed)
+                   continue;
+                 if (!solv->droporphanedmap.size)
+                   map_grow(&solv->droporphanedmap, installed->end - installed->start);
+                 MAPSET(&solv->droporphanedmap, p - installed->start);
+               }
+             break;
            default:
              break;
            }
@@ -3755,17 +3844,6 @@ solver_solve(Solver *solv, Queue *job)
          break;
        case SOLVER_DROP_ORPHANED:
          POOL_DEBUG(SOLV_DEBUG_JOB, "job: drop orphaned %s\n", solver_select2str(pool, select, what));
-         if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && installed && what == installed->repoid))
-           solv->droporphanedmap_all = 1;
-         FOR_JOB_SELECT(p, pp, select, what)
-           {
-             s = pool->solvables + p;
-             if (!installed || s->repo != installed)
-               continue;
-             if (!solv->droporphanedmap.size)
-               map_grow(&solv->droporphanedmap, installed->end - installed->start);
-             MAPSET(&solv->droporphanedmap, p - installed->start);
-           }
          break;
        case SOLVER_USERINSTALLED:
          POOL_DEBUG(SOLV_DEBUG_JOB, "job: user installed %s\n", solver_select2str(pool, select, what));
@@ -3775,10 +3853,6 @@ solver_solve(Solver *solv, Queue *job)
          break;
        }
        
-       /*
-        * debug
-        */
-       
       IF_POOLDEBUG (SOLV_DEBUG_JOB)
        {
          int j;
@@ -3880,6 +3954,10 @@ solver_solve(Solver *solv, Queue *job)
   /* disable update rules that conflict with our job */
   solver_disablepolicyrules(solv);
 
+  /* break orphans if requested */
+  if (solv->dupmap_all && solv->orphaned.count && solv->break_orphans)
+    solver_breakorphans(solv);
+
   /* make initial decisions based on assertion rules */
   makeruledecisions(solv);
   POOL_DEBUG(SOLV_DEBUG_SOLVER, "problems so far: %d\n", solv->problems.count);
@@ -4285,12 +4363,10 @@ solver_describe_decision(Solver *solv, Id p, Id *infop)
   if (why > 0)
     return SOLVER_REASON_UNIT_RULE;
   why = -why;
+  if (i == 0)
+    return SOLVER_REASON_KEEP_INSTALLED;       /* the systemsolvable */
   if (i < solv->decisioncnt_update)
-    {
-      if (i == 0)
-       return SOLVER_REASON_KEEP_INSTALLED;
-      return SOLVER_REASON_RESOLVE_JOB;
-    }
+    return SOLVER_REASON_RESOLVE_JOB;
   if (i < solv->decisioncnt_keep)
     {
       if (why == 0 && pp < 0)
@@ -4299,6 +4375,8 @@ solver_describe_decision(Solver *solv, Id p, Id *infop)
     }
   if (i < solv->decisioncnt_resolve)
     {
+      if (solv->focus_installed && i >= solv->decisioncnt_jobs)
+       return SOLVER_REASON_RESOLVE_JOB;
       if (why == 0 && pp < 0)
        return SOLVER_REASON_CLEANDEPS_ERASE;
       return SOLVER_REASON_KEEP_INSTALLED;
@@ -4306,7 +4384,7 @@ solver_describe_decision(Solver *solv, Id p, Id *infop)
   if (why > 0)
     return SOLVER_REASON_RESOLVE;
   /* weak or orphaned */
-  if (solv->decisionq.count < solv->decisioncnt_orphan)
+  if (i < solv->decisioncnt_orphan)
     return SOLVER_REASON_WEAKDEP;
   return SOLVER_REASON_RESOLVE_ORPHAN;
 }
@@ -4361,7 +4439,7 @@ solver_describe_weakdep_decision(Solver *solv, Id p, Queue *whyq)
          if (!p2 && found)
            {
              queue_push(whyq, SOLVER_REASON_RECOMMENDED);
-             queue_push2(whyq, p2, rec);
+             queue_push2(whyq, i, rec);
            }
        }
     }