Imported Upstream version 0.7.20
[platform/upstream/libsolv.git] / src / rules.c
index cb8d17d..212df32 100644 (file)
@@ -613,7 +613,7 @@ add_complex_deprules(Solver *solv, Id p, Id dep, int type, int dontfix, Queue *w
        }
       else
        {
-         Id *qele;
+         Id *qele, d;
          int qcnt;
 
          qele = bq.elements + i;
@@ -653,7 +653,17 @@ add_complex_deprules(Solver *solv, Id p, Id dep, int type, int dontfix, Queue *w
              break;
          if (j < qcnt)
            continue;
-         addpkgrule(solv, qele[0], 0, pool_ids2whatprovides(pool, qele + 1, qcnt - 1), type, dep);
+         d = pool_ids2whatprovides(pool, qele + 1, qcnt - 1);
+         if (solv->ruleinfoq && qele[0] != p)
+           {
+             int oldcount = solv->ruleinfoq->count;
+             addpkgrule(solv, qele[0], 0, d, type, dep);
+             /* fixup from element of ruleinfo */
+             if (solv->ruleinfoq->count > oldcount)
+               solv->ruleinfoq->elements[oldcount + 1] = p;
+           }
+         else
+           addpkgrule(solv, qele[0], 0, d, type, dep);
          if (m)
            for (j = 0; j < qcnt; j++)
              if (qele[j] > 0 && !MAPTST(m, qele[j]))
@@ -665,6 +675,34 @@ add_complex_deprules(Solver *solv, Id p, Id dep, int type, int dontfix, Queue *w
 
 #endif
 
+#ifdef ENABLE_CONDA
+void
+add_conda_constrains_rule(Solver *solv, Id n, Id dep, int dontfix)
+{
+  Pool *pool = solv->pool;
+  Reldep *rd;
+  Id p, pp, pdep;
+  if (!ISRELDEP(dep))
+    return;
+  rd = GETRELDEP(pool, dep);
+  pdep = pool_whatprovides(pool, dep);
+  FOR_PROVIDES(p, pp, rd->name)
+    {
+      Id p2;
+      if (p == n)
+       continue;
+      if (dontfix && pool->solvables[p].repo == solv->installed)
+       continue;
+      while ((p2 = pool->whatprovidesdata[pdep]) != 0 && p2 < p)
+       pdep++;
+      if (p == p2)
+       pdep++;
+      else
+        addpkgrule(solv, -n, -p, 0, SOLVER_RULE_PKG_CONSTRAINS, dep);
+    }
+}
+#endif
+
 /*-------------------------------------------------------------------
  *
  * add dependency rules for solvable
@@ -693,8 +731,8 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m)
 
   Queue workq; /* list of solvables we still have to work on */
   Id workqbuf[64];
-  Queue prereqq;       /* list of pre-req ids to ignore */
-  Id prereqbuf[16];
+  Queue depq;  /* list of pre-req ids to ignore */
+  Id depqbuf[16];
 
   int i;
   int dontfix;         /* ignore dependency errors for installed solvables */
@@ -710,7 +748,7 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m)
   queue_init_buffer(&workq, workqbuf, sizeof(workqbuf)/sizeof(*workqbuf));
   queue_push(&workq, s - pool->solvables);     /* push solvable Id to work queue */
 
-  queue_init_buffer(&prereqq, prereqbuf, sizeof(prereqbuf)/sizeof(*prereqbuf));
+  queue_init_buffer(&depq, depqbuf, sizeof(depqbuf)/sizeof(*depqbuf));
 
   /* loop until there's no more work left */
   while (workq.count)
@@ -770,20 +808,18 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m)
                {
                  if (installed && s->repo == installed)
                    {
-                     if (prereqq.count)
-                       queue_empty(&prereqq);
-                     solvable_lookup_idarray(s, SOLVABLE_PREREQ_IGNOREINST, &prereqq);
-                     filterpre = prereqq.count;
+                     solvable_lookup_idarray(s, SOLVABLE_PREREQ_IGNOREINST, &depq);
+                     filterpre = depq.count;
                    }
                  continue;
                }
              if (filterpre)
                {
-                 /* check if this id is filtered. assumes that prereqq.count is small */
-                 for (i = 0; i < prereqq.count; i++)
-                   if (req == prereqq.elements[i])
+                 /* check if this id is filtered. assumes that depq.count is small */
+                 for (i = 0; i < depq.count; i++)
+                   if (req == depq.elements[i])
                      break;
-                 if (i < prereqq.count)
+                 if (i < depq.count)
                    {
                      POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "package %s: ignoring filtered pre-req dependency %s\n", pool_solvable2str(pool, s), pool_dep2str(pool, req));
                      continue;
@@ -896,6 +932,15 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m)
            }
        }
 
+#ifdef ENABLE_CONDA
+      if (pool->disttype == DISTTYPE_CONDA)
+       {
+         solvable_lookup_idarray(s, SOLVABLE_CONSTRAINS, &depq);
+         for (i = 0; i < depq.count; i++)
+           add_conda_constrains_rule(solv, n, depq.elements[i], dontfix);
+       }
+#endif
+
       /* that's all we check for src packages */
       if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
        continue;
@@ -1099,7 +1144,7 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m)
            }
        }
     }
-  queue_free(&prereqq);
+  queue_free(&depq);
   queue_free(&workq);
 }
 
@@ -1621,13 +1666,16 @@ solver_addinfarchrules(Solver *solv, Map *addedmap)
            }
        }
       if (first)
-       continue;
+       continue;               /* not the first in the group */
+
+      if (!bestscore)
+       continue;               /* did not find a score for this group */
 
       /* speed up common case where installed package already has best arch */
       if (allowedarchs.count == 1 && bests && allowedarchs.elements[0] == bests->arch)
        allowedarchs.count--;   /* installed arch is best */
 
-      if (allowedarchs.count && pool->implicitobsoleteusescolors && installed && bestscore)
+      if (allowedarchs.count && pool->implicitobsoleteusescolors && installed)
        {
          /* need an extra pass for lockstep checking: we only allow to keep an inferior arch
           * if the corresponding installed package is not lock-stepped */
@@ -1672,7 +1720,7 @@ solver_addinfarchrules(Solver *solv, Map *addedmap)
          if (ps->name != s->name || !MAPTST(addedmap, p))
            continue;
          a = pool_arch2score(pool, ps->arch);
-         if (a != 1 && bestscore && ((a ^ bestscore) & 0xffff0000) != 0)
+         if (a != 1 && ((a ^ bestscore) & 0xffff0000) != 0)
            {
              if (installed && ps->repo == installed)
                {
@@ -2691,7 +2739,8 @@ addpkgruleinfo(Solver *solv, Id p, Id p2, Id d, int type, Id dep)
          if (*odp)
            return;
        }
-      if (p < 0 && pool->whatprovidesdata[d] < 0 && type == SOLVER_RULE_PKG_CONFLICTS)
+      /* set p2 for multiversion conflicts */
+      if (p < 0 && pool->whatprovidesdata[d] < 0 && pool->whatprovidesdata[d + 1] >= 0 && type == SOLVER_RULE_PKG_CONFLICTS)
        p2 = pool->whatprovidesdata[d];
     }
   else
@@ -3138,6 +3187,78 @@ solver_choicerulecheck(Solver *solv, Id pi, Rule *r, Map *m, Queue *q)
   return 1;    /* none of the new packages provided it */
 }
 
+static int
+solver_choicerulecheck2(Solver *solv, Id pi, Id pt, Queue *q)
+{
+  Pool *pool = solv->pool;
+  Rule *ur;
+  Id p, pp;
+  int 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 1;               /* orphaned, thus newest */
+      queue_push2(q, pi, 0);
+      FOR_RULELITERALS(p, pp, ur)
+       if (p > 0 && p != pi)
+         queue_push(q, p);
+      queue_push(q, pi);
+    }
+  if (q->count <= 3)
+    return q->count == 3 && q->elements[2] == pt ? 1 : 0;
+  if (!q->elements[1])
+    {
+      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 (q->elements[i] == pt)
+      return 1;
+  return 0;    /* not newest */
+}
+
+static int
+solver_choicerulecheck3(Solver *solv, Id pt, Queue *q)
+{
+  Pool *pool = solv->pool;
+  Id p, pp;
+  int i;
+
+  if (!q->count || q->elements[0] != pt)
+    {
+      Solvable *s = pool->solvables + pt;
+      if (q->count)
+        queue_empty(q);
+      /* no installed package, so check all with same name */
+      queue_push2(q, pt, 0);
+      FOR_PROVIDES(p, pp, s->name)
+        if (pool->solvables[p].name == s->name && p != pt)
+          queue_push(q, p);
+      queue_push(q, pt);
+    }
+  if (q->count <= 3)
+    return q->count == 3 && q->elements[2] == pt ? 1 : 0;
+  if (!q->elements[1])
+    {
+      queue_deleten(q, 0, 2);
+      policy_filter_unwanted(solv, q, POLICY_MODE_CHOOSE);
+      queue_unshift(q, 1);     /* filter mark */
+      queue_unshift(q, pt);
+    }
+  for (i = 2; i < q->count; i++)
+    if (q->elements[i] == pt)
+      return 1;
+  return 0;    /* not newest */
+}
+
 static inline void
 queue_removeelement(Queue *q, Id el)
 {
@@ -3154,20 +3275,62 @@ queue_removeelement(Queue *q, Id el)
     }
 }
 
+static Id
+choicerule_find_installed(Pool *pool, Id p)
+{
+  Solvable *s = pool->solvables + p;
+  Id p2, pp2;
+
+  if (!s->repo)
+    return 0;
+  if (s->repo == pool->installed)
+    return p;
+  FOR_PROVIDES(p2, pp2, s->name)
+    {
+      Solvable *s2 = pool->solvables + p2;
+      if (s2->repo != pool->installed)
+       continue;
+      if (!pool->implicitobsoleteusesprovides && s->name != s2->name)
+       continue;
+      if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, s2))
+       continue;
+      return p2;
+    }
+  if (s->obsoletes)
+    {
+      Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
+      while ((obs = *obsp++) != 0)
+       {
+         FOR_PROVIDES(p2, pp2, obs)
+           {
+             Solvable *s2 = pool->solvables + p2;
+             if (s2->repo != pool->installed)
+               continue;
+             if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p2, obs))
+               continue;
+             if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2))
+               continue;
+             return p2;
+           }
+       }
+    }
+  return 0;
+}
+
 void
 solver_addchoicerules(Solver *solv)
 {
   Pool *pool = solv->pool;
   Map m, mneg;
   Rule *r;
-  Queue q, qi, qcheck, infoq;
-  int i, j, rid, havechoice;
-  Id p, d, pp;
-  Id p2, pp2;
-  Solvable *s, *s2;
+  Queue q, qi, qcheck, qcheck2, infoq;
+  int i, j, rid, havechoice, negcnt;
+  Id p, d, pp, p2;
+  Solvable *s;
   Id lastaddedp, lastaddedd;
   int lastaddedcnt;
   unsigned int now;
+  int isnewest = 0;
 
   solv->choicerules = solv->nrules;
   if (!pool->installed)
@@ -3176,10 +3339,10 @@ solver_addchoicerules(Solver *solv)
       return;
     }
   now = solv_timems(0);
-  solv->choicerules_info = solv_calloc(solv->pkgrules_end, sizeof(Id));
   queue_init(&q);
   queue_init(&qi);
   queue_init(&qcheck);
+  queue_init(&qcheck2);
   queue_init(&infoq);
   map_init(&m, pool->nsolvables);
   map_init(&mneg, pool->nsolvables);
@@ -3211,80 +3374,28 @@ solver_addchoicerules(Solver *solv)
            continue;
          if (s->repo == pool->installed)
            {
+             queue_push2(&qi, p, p);
              queue_push(&q, p);
              continue;
            }
-         /* check if this package is "blocked" by a installed package */
-         s2 = 0;
-         FOR_PROVIDES(p2, pp2, s->name)
-           {
-             s2 = pool->solvables + p2;
-             if (s2->repo != pool->installed)
-               continue;
-             if (!pool->implicitobsoleteusesprovides && s->name != s2->name)
-               continue;
-             if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, s2))
-               continue;
-             break;
-           }
+         /* find an installed package p2 that we can update/downgrade to p */
+         p2 = choicerule_find_installed(pool, p);
          if (p2)
            {
-             /* found installed package p2 that we can update to p */
              if (MAPTST(&mneg, p))
                continue;
-             if (policy_is_illegal(solv, s2, s, 0))
-               continue;
-#if 0
-             if (solver_choicerulecheck(solv, p2, r, &m))
+             if (policy_is_illegal(solv, pool->solvables + p2, s, 0))
                continue;
-             queue_push(&qi, p2);
-#else
              queue_push2(&qi, p2, p);
-#endif
              queue_push(&q, p);
              continue;
            }
-         if (s->obsoletes)
-           {
-             Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
-             s2 = 0;
-             while ((obs = *obsp++) != 0)
-               {
-                 FOR_PROVIDES(p2, pp2, obs)
-                   {
-                     s2 = pool->solvables + p2;
-                     if (s2->repo != pool->installed)
-                       continue;
-                     if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p2, obs))
-                       continue;
-                     if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2))
-                       continue;
-                     break;
-                   }
-                 if (p2)
-                   break;
-               }
-             if (obs)
-               {
-                 /* found installed package p2 that we can update to p */
-                 if (MAPTST(&mneg, p))
-                   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;
-               }
-           }
          /* package p is independent of the installed ones */
          havechoice = 1;
        }
+#if 0
+      printf("havechoice: %d qcount %d qicount %d\n", havechoice, q.count, qi.count);
+#endif
       if (!havechoice || !q.count || !qi.count)
        continue;       /* no choice */
 
@@ -3292,13 +3403,30 @@ solver_addchoicerules(Solver *solv)
         if (p > 0)
          MAPSET(&m, p);
 
+      isnewest = 1;
+      FOR_RULELITERALS(p, pp, r)
+       {
+         if (p > 0)
+           break;
+         p2 = choicerule_find_installed(pool, -p);
+         if (p2 && !solver_choicerulecheck2(solv, p2, -p, &qcheck2))
+           {
+             isnewest = 0;
+             break;
+           }
+         if (!p2 && !solver_choicerulecheck3(solv, -p, &qcheck2))
+           {
+             isnewest = 0;
+             break;
+           }
+       }
       /* 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, &qcheck))
+         if (isnewest && solver_choicerulecheck(solv, p2, r, &m, &qcheck))
            {
              /* oops, remove element p from q */
              queue_removeelement(&q, qi.elements[i + 1]);
@@ -3340,9 +3468,12 @@ solver_addchoicerules(Solver *solv)
              qi.elements[j] = 0;
        }
       /* empty map again */
+      negcnt = 0;
       FOR_RULELITERALS(p, pp, r)
         if (p > 0)
          MAPCLR(&m, p);
+       else
+         negcnt++;
       if (i == qi.count)
        {
 #if 0
@@ -3351,7 +3482,14 @@ solver_addchoicerules(Solver *solv)
 #endif
          continue;
        }
-
+      /* add neg elements to the front */
+      if (negcnt > 1)
+       {
+         i = 0;
+         FOR_RULELITERALS(p, pp, r)
+          if (p < 0 && p != r->p)
+            queue_insert(&q, i++, p);
+       }
       /* don't add identical rules */
       if (lastaddedp == r->p && lastaddedcnt == q.count)
        {
@@ -3382,6 +3520,7 @@ solver_addchoicerules(Solver *solv)
   queue_free(&q);
   queue_free(&qi);
   queue_free(&qcheck);
+  queue_free(&qcheck2);
   queue_free(&infoq);
   map_free(&m);
   map_free(&mneg);