implement SOLVER_FORCRBEST for install/up/dup
authorMichael Schroeder <mls@suse.de>
Mon, 19 Nov 2012 16:18:51 +0000 (17:18 +0100)
committerMichael Schroeder <mls@suse.de>
Mon, 19 Nov 2012 16:18:51 +0000 (17:18 +0100)
src/problems.c
src/problems.h
src/rules.c
src/rules.h
src/solver.c
src/solver.h
src/solverdebug.c

index 5a2ae60..5cf42a3 100644 (file)
@@ -434,14 +434,11 @@ convertsolution(Solver *solv, Id why, Queue *solutionq)
       Id p, *dp, rp = 0;
       Rule *rr;
 
-      assert(why >= solv->updaterules && why < solv->updaterules_end);
       /* check if this is a false positive, i.e. the update rule is fulfilled */
       rr = solv->rules + why;
       FOR_RULELITERALS(p, dp, rr)
        if (p > 0 && solv->decisionmap[p] > 0)
-         break;
-      if (p)
-       return;         /* false alarm */
+         return;       /* false alarm */
 
       p = solv->installed->start + (why - solv->updaterules);
       rr = solv->rules + solv->featurerules + (why - solv->updaterules);
@@ -480,6 +477,51 @@ convertsolution(Solver *solv, Id why, Queue *solutionq)
       queue_push(solutionq, rp);
       return;
     }
+  if (why >= solv->bestrules && why < solv->bestrules_end)
+    {
+      int mvrp;
+      Id p, *dp, rp = 0;
+      Rule *rr;
+      /* check false positive */
+      rr = solv->rules + why;
+      FOR_RULELITERALS(p, dp, rr)
+       if (p > 0 && solv->decisionmap[p] > 0)
+         return;       /* false alarm */
+      /* check update/feature rule */
+      p = solv->bestrules_pkg[why - solv->bestrules];
+      if (p < 0)
+       {
+         /* install job */
+         queue_push(solutionq, 0);
+         queue_push(solutionq, solv->ruletojob.elements[-p - solv->jobrules] + 1);
+         return;
+       }
+      rr = solv->rules + solv->featurerules + (p - solv->installed->start);
+      if (!rr->p)
+       rr = solv->rules + solv->updaterules + (p - solv->installed->start);
+      mvrp = 0;                /* multi-version replacement */
+      FOR_RULELITERALS(rp, dp, rr)
+       if (rp > 0 && solv->decisionmap[rp] > 0)
+         {
+           mvrp = rp;
+           if (!(solv->noobsoletes.size && MAPTST(&solv->noobsoletes, rp)))
+             break;
+         }
+      if (!rp && mvrp)
+       {
+         queue_push(solutionq, SOLVER_SOLUTION_BEST);  /* split, see above */
+         queue_push(solutionq, mvrp);
+         queue_push(solutionq, p);
+         queue_push(solutionq, 0);
+         return;
+       }
+      if (rp)
+       {
+         queue_push(solutionq, SOLVER_SOLUTION_BEST);
+         queue_push(solutionq, rp);
+       }
+      return;
+    }
 }
 
 /*
@@ -722,6 +764,8 @@ solver_solutionelement_extrajobflags(Solver *solv, Id problem, Id solution)
  *    -> add (SOLVER_INSTALL|SOLVER_SOLVABLE, rp) to the job
  *    SOLVER_SOLUTION_DISTUPGRADE   pkgid
  *    -> add (SOLVER_INSTALL|SOLVER_SOLVABLE, rp) to the job
+ *    SOLVER_SOLUTION_BEST          pkgid
+ *    -> add (SOLVER_INSTALL|SOLVER_SOLVABLE, rp) to the job
  *    SOLVER_SOLUTION_JOB           jobidx
  *    -> remove job (jobidx - 1, jobidx) from job queue
  *    pkgid (> 0)                   0
@@ -823,7 +867,7 @@ findproblemrule_internal(Solver *solv, Id idx, Id *reqrp, Id *conrp, Id *sysrp,
       assert(rid > 0);
       if (rid >= solv->learntrules)
        findproblemrule_internal(solv, solv->learnt_why.elements[rid - solv->learntrules], &lreqr, &lconr, &lsysr, &ljobr);
-      else if ((rid >= solv->jobrules && rid < solv->jobrules_end) || (rid >= solv->infarchrules && rid < solv->infarchrules_end) || (rid >= solv->duprules && rid < solv->duprules_end))
+      else if ((rid >= solv->jobrules && rid < solv->jobrules_end) || (rid >= solv->infarchrules && rid < solv->infarchrules_end) || (rid >= solv->duprules && rid < solv->duprules_end) || (rid >= solv->bestrules && rid < solv->bestrules_end))
        {
          if (!*jobrp)
            *jobrp = rid;
index d01f2fa..cb37139 100644 (file)
@@ -23,6 +23,7 @@ struct _Solver;
 #define SOLVER_SOLUTION_JOB             (0)
 #define SOLVER_SOLUTION_DISTUPGRADE     (-1)
 #define SOLVER_SOLUTION_INFARCH         (-2)
+#define SOLVER_SOLUTION_BEST            (-3)
 
 void solver_disableproblem(struct _Solver *solv, Id v);
 void solver_enableproblem(struct _Solver *solv, Id v);
index c5b6917..9e292d7 100644 (file)
@@ -958,6 +958,13 @@ solver_addupdaterule(Solver *solv, Solvable *s, int allow_all)
            }
          qs.count = j;
        }
+      else if (p != -SYSTEMSOLVABLE)
+       {
+         /* could fallthrough, but then we would do pool_queuetowhatprovides twice */
+         queue_free(&qs);
+         solver_addrule(solv, p, d);   /* allow update of s */
+         return;
+       }
     }
   if (qs.count && p == -SYSTEMSOLVABLE)
     p = queue_shift(&qs);
@@ -978,6 +985,14 @@ disableupdaterule(Solver *solv, Id p)
   r = solv->rules + solv->featurerules + (p - solv->installed->start);
   if (r->p && r->d >= 0)
     solver_disablerule(solv, r);
+  if (solv->bestrules_pkg)
+    {
+      int i, ni;
+      ni = solv->bestrules_end - solv->bestrules;
+      for (i = 0; i < ni; i++)
+       if (solv->bestrules_pkg[i] == p)
+         solver_disablerule(solv, solv->rules + solv->bestrules + i);
+    }
 }
 
 static inline void 
@@ -990,26 +1005,37 @@ reenableupdaterule(Solver *solv, Id p)
   r = solv->rules + solv->updaterules + (p - solv->installed->start);
   if (r->p)
     {    
-      if (r->d >= 0)
-       return;
-      solver_enablerule(solv, r);
-      IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
+      if (r->d > 0)
        {
-         POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "@@@ re-enabling ");
-         solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r);
+         solver_enablerule(solv, r);
+         IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
+           {
+             POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "@@@ re-enabling ");
+             solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r);
+           }
        }
-      return;
     }
-  r = solv->rules + solv->featurerules + (p - solv->installed->start);
-  if (r->p && r->d < 0)
+  else
     {
-      solver_enablerule(solv, r);
-      IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
+      r = solv->rules + solv->featurerules + (p - solv->installed->start);
+      if (r->p && r->d < 0)
        {
-         POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "@@@ re-enabling ");
-         solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r);
+         solver_enablerule(solv, r);
+         IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
+           {
+             POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "@@@ re-enabling ");
+             solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r);
+           }
        }
     }
+  if (solv->bestrules_pkg)
+    {
+      int i, ni;
+      ni = solv->bestrules_end - solv->bestrules;
+      for (i = 0; i < ni; i++)
+       if (solv->bestrules_pkg[i] == p)
+         solver_enablerule(solv, solv->rules + solv->bestrules + i);
+    }
 }
 
 
@@ -1159,6 +1185,7 @@ solver_createdupmaps(Solver *solv)
   Queue *job = &solv->job;
   Pool *pool = solv->pool;
   Repo *repo;
+  Repo *installed = solv->installed;
   Id select, how, what, p, pi, pp, pip, obs, *obsp;
   Solvable *s, *ps;
   int i;
@@ -1177,10 +1204,10 @@ solver_createdupmaps(Solver *solv)
            {
              int haveinstalled;
              p = 0;
-             if (solv->installed)
+             if (installed)
                {
                  FOR_JOB_SELECT(p, pp, select, what)
-                   if (pool->solvables[p].repo == solv->installed)
+                   if (pool->solvables[p].repo == installed)
                      break;
                }
              haveinstalled = p != 0;
@@ -1189,9 +1216,9 @@ solver_createdupmaps(Solver *solv)
                  Solvable *s = pool->solvables + p;
                  if (!s->repo)
                    continue;
-                 if (haveinstalled && s->repo != solv->installed)
+                 if (haveinstalled && s->repo != installed)
                    continue;
-                 if (s->repo != solv->installed && !pool_installable(pool, s))
+                 if (s->repo != installed && !pool_installable(pool, s))
                    continue;
                  MAPSET(&solv->dupinvolvedmap, p);
                  if (!haveinstalled)
@@ -1202,18 +1229,24 @@ solver_createdupmaps(Solver *solv)
                      if (ps->name != s->name)
                        continue;
                      MAPSET(&solv->dupinvolvedmap, pi);
-                     if (haveinstalled && ps->repo != solv->installed)
+                     if (ps->repo == installed && (how & SOLVER_FORCEBEST) != 0)
+                       {
+                         if (!solv->bestupdatemap.size)
+                           map_grow(&solv->bestupdatemap, installed->end - installed->start);
+                         MAPSET(&solv->bestupdatemap, pi - installed->start);
+                       }
+                     if (haveinstalled && ps->repo != installed)
                        MAPSET(&solv->dupmap, pi);
                    }
                  if (haveinstalled)
                    {
-                     if (solv->obsoletes && solv->obsoletes[p - solv->installed->start])
+                     if (solv->obsoletes && solv->obsoletes[p - installed->start])
                        {
                          Id *opp;
-                         for (opp = solv->obsoletes_data + solv->obsoletes[p - solv->installed->start]; (pi = *opp++) != 0;)
+                         for (opp = solv->obsoletes_data + solv->obsoletes[p - installed->start]; (pi = *opp++) != 0;)
                            {
                              ps = pool->solvables + pi;
-                             if (ps->repo == solv->installed)
+                             if (ps->repo == installed)
                                continue;
                              MAPSET(&solv->dupinvolvedmap, pi);
                              MAPSET(&solv->dupmap, pi);
@@ -1228,12 +1261,18 @@ solver_createdupmaps(Solver *solv)
                        {
                          FOR_PROVIDES(pi, pp, obs)
                            {
-                             Solvable *pis = pool->solvables + pi;
-                             if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, pis, obs))
+                             Solvable *ps = pool->solvables + pi;
+                             if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
                                continue;
-                             if (pool->obsoleteusescolors && !pool_colormatch(pool, s, pis))
+                             if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
                                continue;
                              MAPSET(&solv->dupinvolvedmap, pi);
+                             if (ps->repo == installed && (how & SOLVER_FORCEBEST) != 0)
+                               {
+                                 if (!solv->bestupdatemap.size)
+                                   map_grow(&solv->bestupdatemap, installed->end - installed->start);
+                                 MAPSET(&solv->bestupdatemap, pi - installed->start);
+                               }
                            }
                        }
                    }
@@ -1245,7 +1284,7 @@ solver_createdupmaps(Solver *solv)
          repo = pool_id2repo(pool, what);
          FOR_REPO_SOLVABLES(repo, p, s)
            {
-             if (repo != solv->installed && !pool_installable(pool, s))
+             if (repo != installed && !pool_installable(pool, s))
                continue;
              MAPSET(&solv->dupmap, p);
              FOR_PROVIDES(pi, pip, s->name)
@@ -1254,6 +1293,12 @@ solver_createdupmaps(Solver *solv)
                  if (ps->name != s->name)
                    continue;
                  MAPSET(&solv->dupinvolvedmap, pi);
+                 if (ps->repo == installed && (how & SOLVER_FORCEBEST) != 0)
+                   {
+                     if (!solv->bestupdatemap.size)
+                       map_grow(&solv->bestupdatemap, installed->end - installed->start);
+                     MAPSET(&solv->bestupdatemap, pi - installed->start);
+                   }
                }
              if (s->obsoletes)
                {
@@ -1263,12 +1308,18 @@ solver_createdupmaps(Solver *solv)
                    {
                      FOR_PROVIDES(pi, pp, obs)
                        {
-                         Solvable *pis = pool->solvables + pi;
-                         if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, pis, obs))
+                         Solvable *ps = pool->solvables + pi;
+                         if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
                            continue;
-                         if (pool->obsoleteusescolors && !pool_colormatch(pool, s, pis))
+                         if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
                            continue;
                          MAPSET(&solv->dupinvolvedmap, pi);
+                         if (ps->repo == installed && (how & SOLVER_FORCEBEST) != 0)
+                           {
+                             if (!solv->bestupdatemap.size)
+                               map_grow(&solv->bestupdatemap, installed->end - installed->start);
+                             MAPSET(&solv->bestupdatemap, pi - installed->start);
+                           }
                        }
                    }
                }
@@ -2102,6 +2153,10 @@ solver_ruleinfo(Solver *solv, Id rid, Id *fromp, Id *top, Id *depp)
        *depp = pool->solvables[-r->p].name;
       return SOLVER_RULE_INFARCH;
     }
+  if (rid >= solv->bestrules && rid < solv->bestrules_end)
+    {
+      return SOLVER_RULE_BEST;
+    }
   if (rid >= solv->choicerules && rid < solv->choicerules_end)
     {
       return SOLVER_RULE_CHOICE;
@@ -2130,6 +2185,8 @@ solver_ruleclass(Solver *solv, Id rid)
     return SOLVER_RULE_DISTUPGRADE;
   if (rid >= solv->infarchrules && rid < solv->infarchrules_end)
     return SOLVER_RULE_INFARCH;
+  if (rid >= solv->bestrules && rid < solv->bestrules_end)
+    return SOLVER_RULE_BEST;
   if (rid >= solv->choicerules && rid < solv->choicerules_end)
     return SOLVER_RULE_CHOICE;
   if (rid >= solv->learntrules)
@@ -2375,6 +2432,129 @@ solver_disablechoicerules(Solver *solv, Rule *r)
     }
 }
 
+void
+solver_addbestrules(Solver *solv, int havebestinstalljobs)
+{
+  Pool *pool = solv->pool;
+  Id p;
+  Solvable *s;
+  Repo *installed = solv->installed;
+  Queue q, q2;
+  Rule *r;
+  Queue r2pkg;
+  int i, oldcnt;
+
+  solv->bestrules = solv->nrules;
+  if (!installed)
+    {
+      solv->bestrules_end = solv->nrules;
+      return;
+    }
+  queue_init(&q);
+  queue_init(&q2);
+  queue_init(&r2pkg);
+
+  if (havebestinstalljobs)
+    {
+      for (i = 0; i < solv->job.count; i += 2)
+       {
+         if ((solv->job.elements[i] & (SOLVER_JOBMASK | SOLVER_FORCEBEST)) == (SOLVER_INSTALL | SOLVER_FORCEBEST))
+           {
+             int j;
+             Id p2, *pp2;
+             for (j = 0; j < solv->ruletojob.count; j++)
+               if (solv->ruletojob.elements[j] == i)
+                 break;
+             if (j == solv->ruletojob.count)
+               continue;
+             r = solv->rules + solv->jobrules + j;
+             queue_empty(&q);
+             FOR_RULELITERALS(p2, pp2, r)
+               if (p2 > 0)
+                 queue_push(&q, p2);
+             if (!q.count)
+               continue;       /* orphaned */
+             /* select best packages, just look at prio and version */
+             oldcnt = q.count;
+             policy_filter_unwanted(solv, &q, POLICY_MODE_RECOMMEND);
+             if (q.count == oldcnt)
+               continue;       /* nothing filtered */
+             p2 = queue_shift(&q);
+             solver_addrule(solv, p2, q.count ? pool_queuetowhatprovides(pool, &q) : 0);
+             queue_push(&r2pkg, -(solv->jobrules + j));
+           }
+       }
+    }
+
+  if (solv->bestupdatemap_all || solv->bestupdatemap.size)
+    {
+      FOR_REPO_SOLVABLES(installed, p, s)
+       {
+         Id d, p2, *pp2;
+         if (!solv->updatemap_all && (!solv->updatemap.size || !MAPTST(&solv->updatemap, p - installed->start)))
+           continue;
+         if (!solv->bestupdatemap_all && (!solv->bestupdatemap.size || !MAPTST(&solv->bestupdatemap, p - installed->start)))
+           continue;
+         queue_empty(&q);
+         if (solv->bestobeypolicy)
+           r = solv->rules + solv->updaterules + (p - installed->start);
+         else
+           {
+             r = solv->rules + solv->featurerules + (p - installed->start);
+             if (!r->p)        /* identical to update rule? */
+               r = solv->rules + solv->updaterules + (p - installed->start);
+           }
+         if (solv->multiversionupdaters && (d = solv->multiversionupdaters[p - installed->start]) != 0 && r == solv->rules + solv->updaterules + (p - installed->start))
+           {
+             /* need to check multiversionupdaters */
+             if (r->p == p)    /* be careful with the dup case */
+               queue_push(&q, p);
+             while ((p2 = pool->whatprovidesdata[d++]) != 0)
+               queue_push(&q, p2);
+           }
+         else
+           {
+             FOR_RULELITERALS(p2, pp2, r)
+               if (p2 > 0)
+                 queue_push(&q, p2);
+           }
+         /* select best packages, just look at prio and version */
+         oldcnt = q.count;
+         policy_filter_unwanted(solv, &q, POLICY_MODE_RECOMMEND);
+         if (!q.count)
+           continue;   /* orphaned */
+         if (solv->bestobeypolicy)
+           {
+             /* also filter the best of the feature rule packages and add them */
+             r = solv->rules + solv->featurerules + (p - installed->start);
+             if (r->p)
+               {
+                 int j;
+                 queue_empty(&q2);
+                 FOR_RULELITERALS(p2, pp2, r)
+                   if (p2 > 0)
+                     queue_push(&q2, p2);
+                 policy_filter_unwanted(solv, &q2, POLICY_MODE_RECOMMEND);
+                 for (j = 0; j < q2.count; j++)
+                   queue_pushunique(&q, q2.elements[j]);
+               }
+           }
+         p2 = queue_shift(&q);
+         solver_addrule(solv, p2, q.count ? pool_queuetowhatprovides(pool, &q) : 0);
+         queue_push(&r2pkg, p);
+       }
+    }
+  if (r2pkg.count)
+    {
+      solv->bestrules_pkg = solv_calloc(r2pkg.count, sizeof(Id));
+      memcpy(solv->bestrules_pkg, r2pkg.elements, r2pkg.count * sizeof(Id));
+    }
+  solv->bestrules_end = solv->nrules;
+  queue_free(&q);
+  queue_free(&q2);
+  queue_free(&r2pkg);
+}
+
 #undef CLEANDEPSDEBUG
 
 /*
index a7ba790..ea56aa7 100644 (file)
@@ -65,7 +65,8 @@ typedef enum {
   SOLVER_RULE_DISTUPGRADE = 0x500,
   SOLVER_RULE_INFARCH = 0x600,
   SOLVER_RULE_CHOICE = 0x700,
-  SOLVER_RULE_LEARNT = 0x800
+  SOLVER_RULE_LEARNT = 0x800,
+  SOLVER_RULE_BEST = 0x900
 } SolverRuleinfo;
 
 #define SOLVER_RULE_TYPEMASK    0xff00
@@ -118,6 +119,9 @@ extern void solver_addduprules(struct _Solver *solv, Map *addedmap);
 extern void solver_addchoicerules(struct _Solver *solv);
 extern void solver_disablechoicerules(struct _Solver *solv, Rule *r);
 
+/* best rules */
+extern void solver_addbestrules(struct _Solver *solv, int havebestinstalljobs);
+
 /* policy rule disabling/reenabling */
 extern void solver_disablepolicyrules(struct _Solver *solv);
 extern void solver_reenablepolicyrules(struct _Solver *solv, int jobidx);
index 56c57d2..6e2acba 100644 (file)
@@ -1438,6 +1438,7 @@ solver_free(Solver *solv)
   map_free(&solv->noobsoletes);
 
   map_free(&solv->updatemap);
+  map_free(&solv->bestupdatemap);
   map_free(&solv->fixmap);
   map_free(&solv->dupmap);
   map_free(&solv->dupinvolvedmap);
@@ -1451,6 +1452,7 @@ solver_free(Solver *solv)
   solv_free(solv->obsoletes_data);
   solv_free(solv->multiversionupdaters);
   solv_free(solv->choicerules_ref);
+  solv_free(solv->bestrules_pkg);
   solv_free(solv);
 }
 
@@ -1481,6 +1483,8 @@ solver_get_flag(Solver *solv, int flag)
     return solv->noinfarchcheck;
   case SOLVER_FLAG_KEEP_EXPLICIT_OBSOLETES:
     return solv->keepexplicitobsoletes;
+  case SOLVER_FLAG_BEST_OBEY_POLICY:
+    return solv->bestobeypolicy;
   default:
     break;
   }
@@ -1526,6 +1530,9 @@ solver_set_flag(Solver *solv, int flag, int value)
   case SOLVER_FLAG_KEEP_EXPLICIT_OBSOLETES:
     solv->keepexplicitobsoletes = value;
     break;
+  case SOLVER_FLAG_BEST_OBEY_POLICY:
+    solv->bestobeypolicy = value;
+    break;
   default:
     break;
   }
@@ -2591,7 +2598,7 @@ solver_addjobrule(Solver *solv, Id p, Id d, Id job, int weak)
 }
 
 static void
-add_update_target(Solver *solv, Id p)
+add_update_target(Solver *solv, Id p, Id how)
 {
   Pool *pool = solv->pool;
   Solvable *s = pool->solvables + p;
@@ -2607,6 +2614,12 @@ add_update_target(Solver *solv, Id p)
       Solvable *si = pool->solvables + pi;
       if (si->repo != installed || si->name != s->name)
        continue;
+      if (how & SOLVER_FORCEBEST)
+       {
+         if (!solv->bestupdatemap.size)
+           map_grow(&solv->bestupdatemap, installed->end - installed->start);
+         MAPSET(&solv->bestupdatemap, pi - installed->start);
+       }
       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))
@@ -2628,6 +2641,12 @@ add_update_target(Solver *solv, Id p)
                continue;
              if (pool->obsoleteusescolors && !pool_colormatch(pool, s, si))
                continue;
+             if (how & SOLVER_FORCEBEST)
+               {
+                 if (!solv->bestupdatemap.size)
+                   map_grow(&solv->bestupdatemap, installed->end - installed->start);
+                 MAPSET(&solv->bestupdatemap, pi - installed->start);
+               }
              queue_push2(solv->update_targets, pi, p);
            }
        }
@@ -2706,6 +2725,7 @@ solver_solve(Solver *solv, Queue *job)
   Rule *r;
   int now, solve_start;
   int hasdupjob = 0;
+  int hasbestinstalljob = 0;
 
   solve_start = solv_timems(0);
 
@@ -2778,7 +2798,11 @@ solver_solve(Solver *solv, Queue *job)
              break;
            case SOLVER_UPDATE:
              if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && installed && what == installed->repoid))
-               solv->updatemap_all = 1;
+               {
+                 solv->updatemap_all = 1;
+                 if (how & SOLVER_FORCEBEST)
+                   solv->bestupdatemap_all = 1;
+               }
              else if (select == SOLVER_SOLVABLE_REPO && what != installed->repoid)
                {
                  Repo *repo = pool_id2repo(pool, what);
@@ -2786,7 +2810,7 @@ solver_solve(Solver *solv, Queue *job)
                    break;
                  /* targeted update */
                  FOR_REPO_SOLVABLES(repo, p, s)
-                   add_update_target(solv, p);
+                   add_update_target(solv, p, how);
                }
              else
                {
@@ -2799,12 +2823,18 @@ solver_solve(Solver *solv, Queue *job)
                      if (!solv->updatemap.size)
                        map_grow(&solv->updatemap, installed->end - installed->start);
                      MAPSET(&solv->updatemap, p - installed->start);
+                     if (how & SOLVER_FORCEBEST)
+                       {
+                         if (!solv->bestupdatemap.size)
+                           map_grow(&solv->bestupdatemap, installed->end - installed->start);
+                         MAPSET(&solv->bestupdatemap, p - installed->start);
+                       }
                      targeted = 0;
                    }
                  if (targeted)
                    {
                      FOR_JOB_SELECT(p, pp, select, what)
-                       add_update_target(solv, p);
+                       add_update_target(solv, p, how);
                    }
                }
              break;
@@ -2852,6 +2882,8 @@ solver_solve(Solver *solv, Queue *job)
            {
              solv->dupmap_all = 1;
              solv->updatemap_all = 1;
+             if (how & SOLVER_FORCEBEST)
+               solv->bestupdatemap_all = 1;
            }
          if (!solv->dupmap_all)
            hasdupjob = 1;
@@ -3022,6 +3054,8 @@ solver_solve(Solver *solv, Queue *job)
              d = !q.count ? 0 : pool_queuetowhatprovides(pool, &q);    /* internalize */
            }
          solver_addjobrule(solv, p, d, i, weak);
+          if (how & SOLVER_FORCEBEST)
+           hasbestinstalljob = 1;
          break;
        case SOLVER_ERASE:
          POOL_DEBUG(SOLV_DEBUG_JOB, "job: %s%serase %s\n", weak ? "weak " : "", how & SOLVER_CLEANDEPS ? "clean deps " : "", solver_select2str(pool, select, what));
@@ -3210,11 +3244,21 @@ solver_solve(Solver *solv, Queue *job)
   else
     solv->duprules = solv->duprules_end = solv->nrules;
 
+  if (solv->bestupdatemap_all || solv->bestupdatemap.size || hasbestinstalljob)
+    solver_addbestrules(solv, hasbestinstalljob);
+  else
+    solv->bestrules = solv->bestrules_end = solv->nrules;
+
   if (1)
     solver_addchoicerules(solv);
   else
     solv->choicerules = solv->choicerules_end = solv->nrules;
 
+  if (0)
+    {
+      for (i = solv->featurerules; i < solv->nrules; i++)
+        solver_printruleclass(solv, SOLV_DEBUG_RESULT, solv->rules + i);
+    }
   /* all rules created
    * --------------------------------------------------------------
    * prepare for solving
@@ -3225,7 +3269,7 @@ solver_solve(Solver *solv, Queue *job)
   map_free(&installcandidatemap);
   queue_free(&q);
 
-  POOL_DEBUG(SOLV_DEBUG_STATS, "%d rpm rules, 2 * %d update rules, %d job rules, %d infarch rules, %d dup rules, %d choice rules\n", solv->rpmrules_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);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "%d rpm rules, 2 * %d update rules, %d job rules, %d infarch rules, %d dup rules, %d choice rules, %d best rules\n", solv->rpmrules_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);
   POOL_DEBUG(SOLV_DEBUG_STATS, "overall rule memory used: %d K\n", solv->nrules * (int)sizeof(Rule) / 1024);
 
   /* create weak map */
index 08fed65..7ba1f51 100644 (file)
@@ -113,6 +113,10 @@ struct _Solver {
   Id duprules;                         /* dist upgrade rules */
   Id duprules_end;
     
+  Id bestrules;                                /* rules from SOLVER_FORCEBEST */
+  Id bestrules_end;
+  Id *bestrules_pkg;
+
   Id choicerules;                      /* choice rules (always weak) */
   Id choicerules_end;
   Id *choicerules_ref;
@@ -126,6 +130,9 @@ struct _Solver {
   Map updatemap;                       /* bring these installed packages to the newest version */
   int updatemap_all;                   /* bring all packages to the newest version */
 
+  Map bestupdatemap;                   /* create best rule for those packages */
+  int bestupdatemap_all;               /* bring all packages to the newest version */
+
   Map fixmap;                          /* fix these packages */
   int fixmap_all;                      /* fix all packages */
 
@@ -195,6 +202,7 @@ struct _Solver {
   
   int noinfarchcheck;                  /* true: do not forbid inferior architectures */
   int keepexplicitobsoletes;           /* true: honor obsoletes during multiinstall */
+  int bestobeypolicy;                  /* true: stay in policy with the best rules */
 
     
   Map dupmap;                          /* dup these packages*/
@@ -296,6 +304,7 @@ typedef struct _Solver Solver;
 #define SOLVER_FLAG_NO_INFARCHCHECK            9
 #define SOLVER_FLAG_ALLOW_NAMECHANGE           10
 #define SOLVER_FLAG_KEEP_EXPLICIT_OBSOLETES    11
+#define SOLVER_FLAG_BEST_OBEY_POLICY           12
 
 extern Solver *solver_create(Pool *pool);
 extern void solver_free(Solver *solv);
index 676c01d..a755da3 100644 (file)
@@ -206,6 +206,8 @@ solver_printruleclass(Solver *solv, int type, Rule *r)
       POOL_DEBUG(type, "WEAK ");
   if (solv->learntrules && p >= solv->learntrules)
     POOL_DEBUG(type, "LEARNT ");
+  else if (p >= solv->bestrules && p < solv->bestrules_end)
+    POOL_DEBUG(type, "BEST ");
   else if (p >= solv->choicerules && p < solv->choicerules_end)
     POOL_DEBUG(type, "CHOICE ");
   else if (p >= solv->infarchrules && p < solv->infarchrules_end)
@@ -601,6 +603,7 @@ solver_printproblemruleinfo(Solver *solv, Id probr)
     case SOLVER_RULE_FEATURE:
     case SOLVER_RULE_LEARNT:
     case SOLVER_RULE_CHOICE:
+    case SOLVER_RULE_BEST:
       POOL_DEBUG(SOLV_DEBUG_RESULT, "bad rule type\n");
       return;
     }
@@ -701,6 +704,14 @@ solver_printsolution(Solver *solv, Id problem, Id solution)
          else
            POOL_DEBUG(SOLV_DEBUG_RESULT, "  - install %s from excluded repository\n", pool_solvable2str(pool, s));
        }
+      else if (p == SOLVER_SOLUTION_BEST)
+       {
+         s = pool->solvables + rp;
+         if (solv->installed && s->repo == solv->installed)
+           POOL_DEBUG(SOLV_DEBUG_RESULT, "  - keep old %s\n", pool_solvable2str(pool, s));
+         else
+           POOL_DEBUG(SOLV_DEBUG_RESULT, "  - install %s despite the old version\n", pool_solvable2str(pool, s));
+       }
       else
        {
          /* policy, replace p with rp */
@@ -1048,6 +1059,14 @@ solver_solutionelement2str(Solver *solv, Id p, Id rp)
       else
         return pool_tmpjoin(pool, "install ", pool_solvable2str(pool, s), " from excluded repository");
     }
+  else if (p == SOLVER_SOLUTION_BEST)
+    {
+      Solvable *s = pool->solvables + rp;
+      if (solv->installed && s->repo == solv->installed)
+        return pool_tmpjoin(pool, "keep old ", pool_solvable2str(pool, s), 0);
+      else
+        return pool_tmpjoin(pool, "install ", pool_solvable2str(pool, s), " despite the old version");
+    }
   else if (p > 0 && rp == 0)
     return pool_tmpjoin(pool, "allow deinstallation of ", pool_solvid2str(pool, p), 0);
   else if (p > 0 && rp > 0)