add the SOLVER_FLAG_FOCUS_INSTALLED solver flag
authorMichael Schroeder <mls@suse.de>
Thu, 15 May 2014 12:48:30 +0000 (14:48 +0200)
committerMichael Schroeder <mls@suse.de>
Thu, 15 May 2014 12:48:30 +0000 (14:48 +0200)
Setting this flag means that the solver will prefer picking
a package version that fits the other installed packages
over updating installed packages.

bindings/solv.i
doc/libsolv-bindings.txt
ext/testcase.c
src/solver.c
src/solver.h

index 3f88a8b..6816183 100644 (file)
@@ -2758,6 +2758,9 @@ rb_eval_string(
   static const int SOLVER_FLAG_DUP_ALLOW_ARCHCHANGE = SOLVER_FLAG_DUP_ALLOW_ARCHCHANGE;
   static const int SOLVER_FLAG_DUP_ALLOW_VENDORCHANGE = SOLVER_FLAG_DUP_ALLOW_VENDORCHANGE;
   static const int SOLVER_FLAG_DUP_ALLOW_NAMECHANGE = SOLVER_FLAG_DUP_ALLOW_NAMECHANGE;
+  static const int SOLVER_FLAG_KEEP_ORPHANS = SOLVER_FLAG_KEEP_ORPHANS;
+  static const int SOLVER_FLAG_BREAK_ORPHANS = SOLVER_FLAG_BREAK_ORPHANS;
+  static const int SOLVER_FLAG_FOCUS_INSTALLED = SOLVER_FLAG_FOCUS_INSTALLED;
 
   static const int SOLVER_REASON_UNRELATED = SOLVER_REASON_UNRELATED;
   static const int SOLVER_REASON_UNIT_RULE = SOLVER_REASON_UNIT_RULE;
index 5a65235..b4f5609 100644 (file)
@@ -2081,6 +2081,21 @@ installed packages, which may conflict with the set policy.
 Do not enable auto-targeting up update and distupgrade jobs. See
 the section on targeted updates for more information.
 
+*SOLVER_FLAG_KEEP_ORPHANS*::
+Do not allow orphaned packages to be deinstalled if they get
+in the way of resolving other packages.
+
+*SOLVER_FLAG_BREAK_ORPHANS*::
+Ignore dependencies of orphaned packages that get in the way
+of resolving non-orphaned ones. Setting the flag might result
+in no longer working packages in case they are orphaned.
+
+*SOLVER_FLAG_FOCUS_INSTALLED*::
+Resolve installed packages before resolving the given job.
+Setting this flag means that the solver will prefer picking
+a package version that fits the other installed packages
+over updating installed packages.
+
 Basic rule types:
 
 *SOLVER_RULE_UNKNOWN*::
index 32547c8..3da7aff 100644 (file)
@@ -104,6 +104,7 @@ static struct solverflags2str {
   { SOLVER_FLAG_DUP_ALLOW_NAMECHANGE,       "dupallownamechange", 1 },
   { SOLVER_FLAG_KEEP_ORPHANS,               "keeporphans", 0 },
   { SOLVER_FLAG_BREAK_ORPHANS,              "breakorphans", 0 },
+  { SOLVER_FLAG_FOCUS_INSTALLED,            "focusinstalled", 0 },
   { 0, 0, 0 }
 };
 
index 065cb7f..c519bea 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
@@ -1644,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;
   }
@@ -1713,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;
   }
@@ -1992,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;
@@ -2232,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;
 
@@ -2828,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;
@@ -3307,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);
@@ -4310,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)
@@ -4324,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;
index c8f51fc..3d63b6f 100644 (file)
@@ -109,6 +109,7 @@ struct _Solver {
                                         * > 0: level of decision when installed,
                                         * < 0: level of decision when conflict */
 
+  int decisioncnt_jobs;
   int decisioncnt_update;
   int decisioncnt_keep;
   int decisioncnt_resolve;
@@ -159,7 +160,7 @@ struct _Solver {
   int keepexplicitobsoletes;           /* true: honor obsoletes during multiinstall */
   int bestobeypolicy;                  /* true: stay in policy with the best rules */
   int noautotarget;                    /* true: do not assume targeted for up/dup jobs that contain no installed solvable */
-
+  int focus_installed;                 /* true: resolve update rules first */
 
   Map dupmap;                          /* dup these packages*/
   int dupmap_all;                      /* dup all packages */
@@ -287,6 +288,7 @@ typedef struct _Solver Solver;
 #define SOLVER_FLAG_DUP_ALLOW_NAMECHANGE       17
 #define SOLVER_FLAG_KEEP_ORPHANS               18
 #define SOLVER_FLAG_BREAK_ORPHANS              19
+#define SOLVER_FLAG_FOCUS_INSTALLED            20
 
 #define GET_USERINSTALLED_NAMES                        (1 << 0)        /* package names instead if ids */
 #define GET_USERINSTALLED_INVERTED             (1 << 1)        /* autoinstalled */