Imported Upstream version 0.6.15
[platform/upstream/libsolv.git] / src / rules.c
index b941986..248b1cd 100644 (file)
@@ -1157,17 +1157,19 @@ finddistupgradepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all)
   if (!qs->count)
     {
       if (allow_all)
-        return 0;      /* orphaned, don't create feature rule */
+        return 0;              /* orphaned, don't create feature rule */
       /* check if this is an orphaned package */
       policy_findupdatepackages(solv, s, qs, 1);
       if (!qs->count)
-       return 0;       /* orphaned, don't create update rule */
+       return 0;               /* orphaned, don't create update rule */
       qs->count = 0;
       return -SYSTEMSOLVABLE;  /* supported but not installable */
     }
   if (allow_all)
     return s - pool->solvables;
   /* check if it is ok to keep the installed package */
+  if (solv->dupmap.size && MAPTST(&solv->dupmap,  s - pool->solvables))
+    return s - pool->solvables;
   for (i = 0; i < qs->count; i++)
     {
       Solvable *ns = pool->solvables + qs->elements[i];
@@ -1178,6 +1180,7 @@ finddistupgradepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all)
   return -SYSTEMSOLVABLE;
 }
 
+#if 0
 /* add packages from the dup repositories to the update candidates
  * this isn't needed for the global dup mode as all packages are
  * from dup repos in that case */
@@ -1201,6 +1204,7 @@ addduppackages(Solver *solv, Solvable *s, Queue *qs)
     }
   queue_free(&dupqs);
 }
+#endif
 
 /*-------------------------------------------------------------------
  *
@@ -1218,18 +1222,15 @@ solver_addupdaterule(Solver *solv, Solvable *s, int allow_all)
   Id p, d;
   Queue qs;
   Id qsbuf[64];
+  int isorphaned = 0;
 
   queue_init_buffer(&qs, qsbuf, sizeof(qsbuf)/sizeof(*qsbuf));
   p = s - pool->solvables;
   /* find update candidates for 's' */
-  if (solv->dupmap_all)
+  if (solv->dupmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p)))
     p = finddistupgradepackages(solv, s, &qs, allow_all);
   else
-    {
-      policy_findupdatepackages(solv, s, &qs, allow_all);
-      if (!allow_all && solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))
-        addduppackages(solv, s, &qs);
-    }
+    policy_findupdatepackages(solv, s, &qs, allow_all);
 
 #ifdef ENABLE_LINKED_PKGS
   if (solv->instbuddy && solv->instbuddy[s - pool->solvables - solv->installed->start])
@@ -1237,7 +1238,7 @@ solver_addupdaterule(Solver *solv, Solvable *s, int allow_all)
       const char *name = pool_id2str(pool, s->name);
       if (strncmp(name, "pattern:", 8) == 0 || strncmp(name, "application:", 12) == 0)
        {
-         /* a linked pseudo package. As it is linked, we do not need an update rule */
+         /* a linked pseudo package. As it is linked, we do not need an update/feature rule */
          /* nevertheless we set specialupdaters so we can update */
          solver_addrule(solv, 0, 0, 0);
          if (!allow_all && qs.count)
@@ -1254,11 +1255,14 @@ solver_addupdaterule(Solver *solv, Solvable *s, int allow_all)
     }
 #endif
 
-  if (!allow_all && !p && solv->dupmap_all)
+  if (!allow_all && !p)                /* !p implies qs.count == 0 */
     {
       queue_push(&solv->orphaned, s - pool->solvables);                /* an orphaned package */
       if (solv->keep_orphans && !(solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, s - pool->solvables - solv->installed->start))))
        p = s - pool->solvables;        /* keep this orphaned package installed */
+      queue_free(&qs);
+      solver_addrule(solv, p, 0, 0);
+      return;
     }
 
   if (!allow_all && qs.count && solv->multiversion.size)
@@ -1271,7 +1275,7 @@ solver_addupdaterule(Solver *solv, Solvable *s, int allow_all)
       if (i < qs.count)
        {
          /* filter out all multiversion packages as they don't update */
-         d = pool_queuetowhatprovides(pool, &qs);
+         d = pool_queuetowhatprovides(pool, &qs);      /* save qs away */
          for (j = i; i < qs.count; i++)
             {
              if (MAPTST(&solv->multiversion, qs.elements[i]))
@@ -1290,19 +1294,25 @@ solver_addupdaterule(Solver *solv, Solvable *s, int allow_all)
                }
              qs.elements[j++] = qs.elements[i];
            }
-         if (j < qs.count)
+         if (j < qs.count)             /* filtered at least one package? */
            {
-             if (d && solv->installed && s->repo == solv->installed &&
-                 (solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, s - pool->solvables - solv->installed->start))))
+             if (j == 0 && p == -SYSTEMSOLVABLE)
                {
+                 /* this is a multiversion orphan */
+                 queue_push(&solv->orphaned, s - pool->solvables);
                  if (!solv->specialupdaters)
                    solv->specialupdaters = solv_calloc(solv->installed->end - solv->installed->start, sizeof(Id));
                  solv->specialupdaters[s - pool->solvables - solv->installed->start] = d;
-               }
-             if (j == 0 && p == -SYSTEMSOLVABLE && solv->dupmap_all)
-               {
-                 queue_push(&solv->orphaned, s - pool->solvables);     /* also treat as orphaned */
-                 j = qs.count;
+                 if (solv->keep_orphans && !(solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, s - pool->solvables - solv->installed->start))))
+                   {
+                     /* we need to keep the orphan */
+                     queue_free(&qs);
+                     solver_addrule(solv, s - pool->solvables, 0, 0);
+                     return;
+                   }
+                 /* we can drop it as long as we update */
+                 isorphaned = 1;
+                 j = qs.count;         /* force the update */
                }
              qs.count = j;
            }
@@ -1310,11 +1320,13 @@ solver_addupdaterule(Solver *solv, Solvable *s, int allow_all)
            {
              /* could fallthrough, but then we would do pool_queuetowhatprovides twice */
              queue_free(&qs);
-             solver_addrule(solv, p, 0, d);    /* allow update of s */
+             solver_addrule(solv, s - pool->solvables, 0, d);  /* allow update of s */
              return;
            }
        }
     }
+  if (!isorphaned && p == -SYSTEMSOLVABLE && solv->dupmap.size)
+    p = s - pool->solvables;           /* let the dup rules sort it out */
   if (qs.count && p == -SYSTEMSOLVABLE)
     p = queue_shift(&qs);
   if (qs.count > 1)
@@ -1623,7 +1635,7 @@ add_cleandeps_package(Solver *solv, Id p)
   queue_pushunique(solv->cleandeps_updatepkgs, p);
 }
 
-static inline void
+static void
 solver_addtodupmaps(Solver *solv, Id p, Id how, int targeted)
 {
   Pool *pool = solv->pool;
@@ -1796,9 +1808,11 @@ void
 solver_addduprules(Solver *solv, Map *addedmap)
 {
   Pool *pool = solv->pool;
+  Repo *installed = solv->installed;
   Id p, pp;
   Solvable *s, *ps;
   int first, i;
+  Rule *r;
 
   solv->duprules = solv->nrules;
   for (i = 1; i < pool->nsolvables; i++)
@@ -1818,11 +1832,11 @@ solver_addduprules(Solver *solv, Map *addedmap)
            break;
          if (!MAPTST(&solv->dupinvolvedmap, p))
            continue;
-         if (solv->installed && ps->repo == solv->installed)
+         if (installed && ps->repo == installed)
            {
              if (!solv->updatemap.size)
-               map_grow(&solv->updatemap, solv->installed->end - solv->installed->start);
-             MAPSET(&solv->updatemap, p - solv->installed->start);
+               map_grow(&solv->updatemap, installed->end - installed->start);
+             MAPSET(&solv->updatemap, p - installed->start);
              if (!MAPTST(&solv->dupmap, p))
                {
                  Id ip, ipp;
@@ -1835,10 +1849,22 @@ solver_addduprules(Solver *solv, Map *addedmap)
                      if (is->evr == ps->evr && solvable_identical(ps, is))
                        break;
                    }
-                 if (!ip)
-                   solver_addrule(solv, -p, 0, 0);     /* no match, sorry */
-                 else
-                   MAPSET(&solv->dupmap, p);           /* for best rules processing */
+                 if (ip)
+                   {
+                     /* ok, found a good one. we may keep this package. */
+                     MAPSET(&solv->dupmap, p);         /* for best rules processing */
+                     continue;
+                   }
+                 r = solv->rules + solv->updaterules + (p - installed->start);
+                 if (!r->p)
+                     r = solv->rules + solv->featurerules + (p - installed->start);
+                 if (r->p && solv->specialupdaters && solv->specialupdaters[p - installed->start])
+                   {
+                     /* this is a multiversion orphan, we're good if an update is installed */
+                     solver_addrule(solv, -p, 0, solv->specialupdaters[p - installed->start]);
+                     continue;
+                   }
+                 solver_addrule(solv, -p, 0, 0);       /* no match, sorry */
                }
            }
          else if (!MAPTST(&solv->dupmap, p))
@@ -2823,32 +2849,51 @@ solver_rule2rules(Solver *solv, Id rid, Queue *q, int recursive)
 
 /* check if the newest versions of pi still provides the dependency we're looking for */
 static int
-solver_choicerulecheck(Solver *solv, Id pi, Rule *r, Map *m)
+solver_choicerulecheck(Solver *solv, Id pi, Rule *r, Map *m, Queue *q)
 {
   Pool *pool = solv->pool;
   Rule *ur;
-  Queue q;
-  Id p, pp, qbuf[32];
+  Id p, pp;
   int i;
 
-  ur = solv->rules + solv->updaterules + (pi - pool->installed->start);
-  if (!ur->p)
-    ur = solv->rules + solv->featurerules + (pi - pool->installed->start);
-  if (!ur->p)
-    return 0;
-  queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf));
-  FOR_RULELITERALS(p, pp, ur)
-    if (p > 0)
-      queue_push(&q, p);
-  if (q.count > 1)
-    policy_filter_unwanted(solv, &q, POLICY_MODE_CHOOSE);
-  for (i = 0; i < q.count; i++)
-    if (MAPTST(m, q.elements[i]))
-      break;
-  /* 1: none of the newest versions provide it */
-  i = i == q.count ? 1 : 0;
-  queue_free(&q);
-  return i;
+  if (!q->count || q->elements[0] != pi)
+    {
+      if (q->count)
+        queue_empty(q);
+      ur = solv->rules + solv->updaterules + (pi - pool->installed->start);
+      if (!ur->p)
+        ur = solv->rules + solv->featurerules + (pi - pool->installed->start);
+      if (!ur->p)
+       return 0;
+      queue_push2(q, pi, 0);
+      FOR_RULELITERALS(p, pp, ur)
+       if (p > 0)
+         queue_push(q, p);
+    }
+  if (q->count == 2)
+    return 1;
+  if (q->count == 3)
+    {
+      p = q->elements[2];
+      return MAPTST(m, p) ? 0 : 1;
+    }
+  if (!q->elements[1])
+    {
+      for (i = 2; i < q->count; i++)
+       if (!MAPTST(m, q->elements[i]))
+         break;
+      if (i == q->count)
+       return 0;       /* all provide it, no need to filter */
+      /* some don't provide it, have to filter */
+      queue_deleten(q, 0, 2);
+      policy_filter_unwanted(solv, q, POLICY_MODE_CHOOSE);
+      queue_unshift(q, 1);     /* filter mark */
+      queue_unshift(q, pi);
+    }
+  for (i = 2; i < q->count; i++)
+    if (MAPTST(m, q->elements[i]))
+      return 0;                /* at least one provides it */
+  return 1;    /* none of the new packages provided it */
 }
 
 static inline void
@@ -2873,7 +2918,7 @@ solver_addchoicerules(Solver *solv)
   Pool *pool = solv->pool;
   Map m, mneg;
   Rule *r;
-  Queue q, qi;
+  Queue q, qi, qcheck;
   int i, j, rid, havechoice;
   Id p, d, pp;
   Id p2, pp2;
@@ -2892,6 +2937,7 @@ solver_addchoicerules(Solver *solv)
   solv->choicerules_ref = solv_calloc(solv->pkgrules_end, sizeof(Id));
   queue_init(&q);
   queue_init(&qi);
+  queue_init(&qcheck);
   map_init(&m, pool->nsolvables);
   map_init(&mneg, pool->nsolvables);
   /* set up negative assertion map from infarch and dup rules */
@@ -3009,7 +3055,7 @@ solver_addchoicerules(Solver *solv)
          p2 = qi.elements[i];
          if (!p2)
            continue;
-         if (solver_choicerulecheck(solv, p2, r, &m))
+         if (solver_choicerulecheck(solv, p2, r, &m, &qcheck))
            {
              /* oops, remove element p from q */
              queue_removeelement(&q, qi.elements[i + 1]);
@@ -3018,6 +3064,7 @@ solver_addchoicerules(Solver *solv)
          qi.elements[j++] = p2;
        }
       queue_truncate(&qi, j);
+
       if (!q.count || !qi.count)
        {
          FOR_RULELITERALS(p, pp, r)
@@ -3089,6 +3136,7 @@ solver_addchoicerules(Solver *solv)
     }
   queue_free(&q);
   queue_free(&qi);
+  queue_free(&qcheck);
   map_free(&m);
   map_free(&mneg);
   solv->choicerules_end = solv->nrules;