make sure that the selection only contains installed packages if SELECTION_INSTALLED_...
[platform/upstream/libsolv.git] / src / rules.c
index 6f08612..677807c 100644 (file)
@@ -719,7 +719,7 @@ solver_addrpmrulesforsolvable(Solver *solv, Solvable *s, Map *m)
                    continue;
                  if (!pool->implicitobsoleteusesprovides && s->name != ps->name)
                    continue;
-                 if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
+                 if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps))
                    continue;
                  if (s->name == ps->name)
                    addrpmrule(solv, -n, -p, SOLVER_RULE_RPM_SAME_NAME, 0);
@@ -945,8 +945,15 @@ solver_addupdaterule(Solver *solv, Solvable *s, int allow_all)
        {
          if (MAPTST(&solv->multiversion, qs.elements[i]))
            {
-             /* it's ok if they have same nevra */
              Solvable *ps = pool->solvables + qs.elements[i];
+             /* if keepexplicitobsoletes is set and the name is different,
+              * we assume that there is an obsoletes. XXX: not 100% correct */
+             if (solv->keepexplicitobsoletes && ps->name != s->name)
+               {
+                 qs.elements[j++] = qs.elements[i];
+                 continue;
+               }
+             /* it's ok if they have same nevra */
              if (ps->name != s->name || ps->evr != s->evr || ps->arch != s->arch)
                continue;
            }
@@ -1489,7 +1496,7 @@ add_obsoletes(Solver *solv, Id p, Queue *q)
            continue;
          if (!pool->implicitobsoleteusesprovides && ps->name != s->name)
            continue;
-         if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps)) 
+         if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps)) 
            continue;
          queue_push(q, p2);
          lastp2 = p2;
@@ -1608,11 +1615,8 @@ jobtodisablelist(Solver *solv, Id how, Id what, Queue *q)
                {
                  if (pool->disttype != DISTTYPE_DEB)
                    {
-                     const char *evr = pool_id2str(pool, rd->evr);
-                     if (strchr(evr, '-'))
-                       set |= SOLVER_SETEVR;
-                     else
-                       set |= SOLVER_SETEV;
+                     const char *rel = strrchr(pool_id2str(pool, rd->evr), '-');
+                     set |= rel ? SOLVER_SETEVR : SOLVER_SETEV;
                    }
                  else
                    set |= SOLVER_SETEVR;
@@ -2181,14 +2185,16 @@ solver_ruleinfo(Solver *solv, Id rid, Id *fromp, Id *top, Id *depp)
        *depp = solv->job.elements[jidx + 1];
       if ((r->d == 0 || r->d == -1) && r->w2 == 0 && r->p == -SYSTEMSOLVABLE)
        {
-         if ((solv->job.elements[jidx] & (SOLVER_JOBMASK|SOLVER_SELECTMASK)) == (SOLVER_INSTALL|SOLVER_SOLVABLE_NAME))
+         Id how = solv->job.elements[jidx];
+         if ((how & (SOLVER_JOBMASK|SOLVER_SELECTMASK)) == (SOLVER_INSTALL|SOLVER_SOLVABLE_NAME))
+           return SOLVER_RULE_JOB_UNKNOWN_PACKAGE;
+         if ((how & (SOLVER_JOBMASK|SOLVER_SELECTMASK)) == (SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES))
            return SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP;
-         if ((solv->job.elements[jidx] & (SOLVER_JOBMASK|SOLVER_SELECTMASK)) == (SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES))
-           return SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP;
-         if ((solv->job.elements[jidx] & (SOLVER_JOBMASK|SOLVER_SELECTMASK)) == (SOLVER_ERASE|SOLVER_SOLVABLE_NAME))
+         if ((how & (SOLVER_JOBMASK|SOLVER_SELECTMASK)) == (SOLVER_ERASE|SOLVER_SOLVABLE_NAME))
            return SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM;
-         if ((solv->job.elements[jidx] & (SOLVER_JOBMASK|SOLVER_SELECTMASK)) == (SOLVER_ERASE|SOLVER_SOLVABLE_PROVIDES))
+         if ((how & (SOLVER_JOBMASK|SOLVER_SELECTMASK)) == (SOLVER_ERASE|SOLVER_SOLVABLE_PROVIDES))
            return SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM;
+         return SOLVER_RULE_JOB_UNSUPPORTED;
        }
       return SOLVER_RULE_JOB;
     }
@@ -2301,6 +2307,62 @@ solver_rule2job(Solver *solv, Id rid, Id *whatp)
   return solv->job.elements[idx];
 }
 
+Id
+solver_rule2solvable(Solver *solv, Id rid)
+{
+  if (rid >= solv->updaterules && rid < solv->updaterules_end)
+    return rid - solv->updaterules;
+  if (rid >= solv->featurerules && rid < solv->featurerules_end)
+    return rid - solv->featurerules;
+  return 0;
+}
+
+/* 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)
+{
+  Pool *pool = solv->pool;
+  Rule *ur;
+  Queue q;
+  Id p, pp, qbuf[32];
+  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;
+}
+
+static inline void
+queue_removeelement(Queue *q, Id el)
+{
+  int i, j;
+  for (i = 0; i < q->count; i++)
+    if (q->elements[i] == el)
+      break;
+  if (i < q->count)
+    {
+      for (j = i++; i < q->count; i++)
+       if (q->elements[i] != el)
+         q->elements[j++] = q->elements[i];
+      queue_truncate(q, j);
+    }
+}
+
 void
 solver_addchoicerules(Solver *solv)
 {
@@ -2314,6 +2376,7 @@ solver_addchoicerules(Solver *solv)
   Solvable *s, *s2;
   Id lastaddedp, lastaddedd;
   int lastaddedcnt;
+  unsigned int now;
 
   solv->choicerules = solv->nrules;
   if (!pool->installed)
@@ -2321,6 +2384,7 @@ solver_addchoicerules(Solver *solv)
       solv->choicerules_end = solv->nrules;
       return;
     }
+  now = solv_timems(0);
   solv->choicerules_ref = solv_calloc(solv->rpmrules_end, sizeof(Id));
   queue_init(&q);
   queue_init(&qi);
@@ -2366,7 +2430,7 @@ solver_addchoicerules(Solver *solv)
                continue;
              if (!pool->implicitobsoleteusesprovides && s->name != s2->name)
                continue;
-             if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2))
+             if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, s2))
                continue;
              break;
            }
@@ -2377,7 +2441,13 @@ solver_addchoicerules(Solver *solv)
                continue;
              if (policy_is_illegal(solv, s2, s, 0))
                continue;
+#if 0
+             if (solver_choicerulecheck(solv, p2, r, &m))
+               continue;
              queue_push(&qi, p2);
+#else
+             queue_push2(&qi, p2, p);
+#endif
              queue_push(&q, p);
              continue;
            }
@@ -2408,7 +2478,13 @@ solver_addchoicerules(Solver *solv)
                    continue;
                  if (policy_is_illegal(solv, s2, s, 0))
                    continue;
+#if 0
+                 if (solver_choicerulecheck(solv, p2, r, &m))
+                   continue;
                  queue_push(&qi, p2);
+#else
+                 queue_push2(&qi, p2, p);
+#endif
                  queue_push(&q, p);
                  continue;
                }
@@ -2416,16 +2492,40 @@ solver_addchoicerules(Solver *solv)
          /* package p is independent of the installed ones */
          havechoice = 1;
        }
-      if (!havechoice || !q.count)
+      if (!havechoice || !q.count || !qi.count)
        continue;       /* no choice */
 
-      /* now check the update rules of the installed package.
-       * if all packages of the update rules are contained in
-       * the dependency rules, there's no need to set up the choice rule */
-      map_empty(&m);
       FOR_RULELITERALS(p, pp, r)
         if (p > 0)
          MAPSET(&m, p);
+
+      /* do extra checking */
+      for (i = j = 0; i < qi.count; i += 2)
+       {
+         p2 = qi.elements[i];
+         if (!p2)
+           continue;
+         if (solver_choicerulecheck(solv, p2, r, &m))
+           {
+             /* oops, remove element p from q */
+             queue_removeelement(&q, qi.elements[i + 1]);
+             continue;
+           }
+         qi.elements[j++] = p2;
+       }
+      queue_truncate(&qi, j);
+      if (!q.count || !qi.count)
+       {
+         FOR_RULELITERALS(p, pp, r)
+           if (p > 0)
+             MAPCLR(&m, p);
+         continue;
+       }
+
+
+      /* now check the update rules of the installed package.
+       * if all packages of the update rules are contained in
+       * the dependency rules, there's no need to set up the choice rule */
       for (i = 0; i < qi.count; i++)
        {
          Rule *ur;
@@ -2445,6 +2545,10 @@ solver_addchoicerules(Solver *solv)
            if (qi.elements[i] == qi.elements[j])
              qi.elements[j] = 0;
        }
+      /* empty map again */
+      FOR_RULELITERALS(p, pp, r)
+        if (p > 0)
+         MAPCLR(&m, p);
       if (i == qi.count)
        {
 #if 0
@@ -2484,6 +2588,9 @@ solver_addchoicerules(Solver *solv)
   map_free(&m);
   map_free(&mneg);
   solv->choicerules_end = solv->nrules;
+  /* shrink choicerules_ref */
+  solv->choicerules_ref = solv_realloc2(solv->choicerules_ref, solv->choicerules_end - solv->choicerules, sizeof(Id));
+  POOL_DEBUG(SOLV_DEBUG_STATS, "choice rule creation took %d ms\n", solv_timems(now));
 }
 
 /* called when a choice rule is disabled by analyze_unsolvable. We also
@@ -3447,7 +3554,7 @@ solver_get_unneeded(Solver *solv, Queue *unneededq, int filtered)
        */
       /* leave first element zero to make things easier */
       /* also add trailing zero */
-      queue_insertn(&edges, 0, 1 + count + 1);
+      queue_insertn(&edges, 0, 1 + count + 1, 0);
 
       /* first requires and recommends */
       for (i = 0; i < count; i++)