Imported Upstream version 0.7.27
[platform/upstream/libsolv.git] / src / policy.c
index 6f06101..02548ea 100644 (file)
@@ -56,11 +56,11 @@ prune_to_best_version_sortcmp(const void *ap, const void *bp, void *dp)
     }
   if (sa->arch != sb->arch)
     {
-      int aa, ab;
-      aa = (sa->arch <= pool->lastarch) ? pool->id2arch[sa->arch] : 0;
-      ab = (sb->arch <= pool->lastarch) ? pool->id2arch[sb->arch] : 0;
+      unsigned int aa, ab;
+      aa = pool_arch2score(pool, sa->arch);
+      ab = pool_arch2score(pool, sb->arch);
       if (aa != ab && aa > 1 && ab > 1)
-       return aa - ab;         /* lowest score first */
+       return aa < ab ? -1 : 1;        /* lowest score first */
     }
 
   /* the same name, bring installed solvables to the front */
@@ -232,13 +232,13 @@ check_complex_dep(Solver *solv, Id dep, Map *m, Queue **cqp)
 {
   Pool *pool = solv->pool;
   Queue q;
-  queue_init(&q);
   Id p;
   int i, qcnt;
 
 #if 0
   printf("check_complex_dep %s\n", pool_dep2str(pool, dep));
 #endif
+  queue_init(&q);
   i = pool_normalize_complex_dep(pool, dep, &q, CPLXDEPS_EXPAND);
   if (i == 0 || i == 1)
     {
@@ -454,86 +454,18 @@ prefer_suggested(Solver *solv, Queue *plist)
 }
 
 static int
-sort_by_favorq_cmp(const void *ap, const void *bp, void *dp)
+sort_by_favor_cmp(const void *ap, const void *bp, void *dp)
 {
   const Id *a = ap, *b = bp, *d = dp;
   return d[b[0]] - d[a[0]];
 }
 
-static void
-sort_by_favorq(Queue *favorq, Id *el, int cnt)
-{
-  int i;
-  /* map to offsets into favorq */
-  for (i = 0; i < cnt; i++)
-    {
-      Id p = el[i];
-      /* lookup p in sorted favorq */
-      int med = 0, low = 0;
-      int high = favorq->count / 2;
-      while (low != high)
-       {
-         med = (low + high) / 2;
-         Id pp = favorq->elements[2 * med];
-         if (pp < p)
-           low = med;
-         else if (pp > p)
-           high = med;
-         else
-           break;
-       }
-      while(med && favorq->elements[2 * med - 2] == p)
-       med--;
-      if (favorq->elements[2 * med] == p)
-        el[i] = 2 * med + 1;
-      else
-        el[i] = 0;     /* hmm */
-    }
-  /* sort by position */
-  solv_sort(el, cnt, sizeof(Id), sort_by_favorq_cmp, favorq->elements);
-  /* map back */
-  for (i = 0; i < cnt; i++)
-    if (el[i])
-      el[i] = favorq->elements[el[i] - 1];
-}
-
 /* bring favored packages to front and disfavored packages to back */
 void
 policy_prefer_favored(Solver *solv, Queue *plist)
 {
-  int i, fav, disfav, count;
-  if (!solv->favormap.size)
-    return;
-  for (i = fav = disfav = 0, count = plist->count; i < count; i++)
-    {
-      Id p = plist->elements[i];
-      if (!MAPTST(&solv->favormap, p))
-       continue;
-      if (solv->isdisfavormap.size && MAPTST(&solv->isdisfavormap, p))
-       {
-         /* disfavored package. bring to back */
-        if (i < plist->count - 1)
-           {
-             memmove(plist->elements + i, plist->elements + i + 1, (plist->count - 1 - i) * sizeof(Id));
-             plist->elements[plist->count - 1] = p;
-           }
-         i--;
-         count--;
-         disfav++;
-       }
-      else
-       {
-         /* favored package. bring to front */
-         if (i > fav)
-           memmove(plist->elements + fav + 1, plist->elements + fav, (i - fav) * sizeof(Id));
-         plist->elements[fav++] = p;
-       }
-    }
-  /* if we have multiple favored/disfavored packages, sort by favorq index */
-  if (fav > 1)
-    sort_by_favorq(solv->favorq, plist->elements, fav);
-  if (disfav > 1)
-    sort_by_favorq(solv->favorq, plist->elements + plist->count - disfav, disfav);
+  if (solv->favormap && plist->count > 1)
+    solv_sort(plist->elements, plist->count, sizeof(Id), sort_by_favor_cmp, solv->favormap);
 }
 
 /*
@@ -646,8 +578,7 @@ prune_to_best_arch(const Pool *pool, Queue *plist)
   for (i = 0; i < plist->count; i++)
     {
       s = pool->solvables + plist->elements[i];
-      a = s->arch;
-      a = (a <= pool->lastarch) ? pool->id2arch[a] : 0;
+      a = pool_arch2score(pool, s->arch);
       if (a && a != 1 && (!bestscore || a < bestscore))
        bestscore = a;
     }
@@ -656,10 +587,9 @@ prune_to_best_arch(const Pool *pool, Queue *plist)
   for (i = j = 0; i < plist->count; i++)
     {
       s = pool->solvables + plist->elements[i];
-      a = s->arch;
-      if (a > pool->lastarch)
+      a = pool_arch2score(pool, s->arch);
+      if (!a)
        continue;
-      a = pool->id2arch[a];
       /* a == 1 -> noarch */
       if (a != 1 && ((a ^ bestscore) & 0xffff0000) != 0)
        continue;
@@ -868,6 +798,8 @@ move_installed_to_front(Pool *pool, Queue *plist)
   Solvable *s;
   Id p, pp;
 
+  if (!pool->installed)
+    return;
   for (i = j = 0; i < plist->count; i++)
     {
       s = pool->solvables + plist->elements[i];
@@ -901,6 +833,38 @@ move_installed_to_front(Pool *pool, Queue *plist)
     }
 }
 
+#ifdef ENABLE_CONDA
+static int
+pool_featurecountcmp(Pool *pool, Solvable *s1, Solvable *s2)
+{
+  unsigned int cnt1, cnt2;
+  cnt1 = solvable_lookup_count(s1, SOLVABLE_TRACK_FEATURES);
+  cnt2 = solvable_lookup_count(s2, SOLVABLE_TRACK_FEATURES);
+  return cnt1 == cnt2 ? 0 : cnt1 > cnt2 ? -1 : 1;
+}
+
+static int
+pool_buildversioncmp(Pool *pool, Solvable *s1, Solvable *s2)
+{
+  const char *bv1, *bv2;
+  bv1 = solvable_lookup_str(s1, SOLVABLE_BUILDVERSION);
+  bv2 = solvable_lookup_str(s2, SOLVABLE_BUILDVERSION);
+  if (!bv1 && !bv2)
+    return 0;
+  return pool_evrcmp_str(pool, bv1 ? bv1 : "" , bv2 ? bv2 : "", EVRCMP_COMPARE);
+}
+
+static int
+pool_buildflavorcmp(Pool *pool, Solvable *s1, Solvable *s2)
+{
+  const char *f1 = solvable_lookup_str(s1, SOLVABLE_BUILDFLAVOR);
+  const char *f2 = solvable_lookup_str(s2, SOLVABLE_BUILDFLAVOR);
+  if (!f1 && !f2)
+    return 0;
+  return pool_evrcmp_str(pool, f1 ? f1 : "" , f2 ? f2 : "", EVRCMP_COMPARE);
+}
+#endif
+
 /*
  * prune_to_best_version
  *
@@ -926,9 +890,9 @@ prune_to_best_version(Pool *pool, Queue *plist)
     {
       s = pool->solvables + plist->elements[i];
 
-      POOL_DEBUG(SOLV_DEBUG_POLICY, "- %s[%s]\n",
-                pool_solvable2str(pool, s),
-                (pool->installed && s->repo == pool->installed) ? "installed" : "not installed");
+      POOL_DEBUG(SOLV_DEBUG_POLICY, "- %s [%d]%s\n",
+                pool_solvable2str(pool, s), plist->elements[i], 
+                (pool->installed && s->repo == pool->installed) ? "I" : "");
 
       if (!best)               /* if no best yet, the current is best */
         {
@@ -943,11 +907,29 @@ prune_to_best_version(Pool *pool, Queue *plist)
           best = s;            /* take current as new best */
           continue;
         }
-      r = best->evr != s->evr ? pool_evrcmp(pool, best->evr, s->evr, EVRCMP_COMPARE) : 0;
+     
+      r = 0; 
+#ifdef ENABLE_CONDA
+      if (pool->disttype == DISTTYPE_CONDA)
+        r = pool_featurecountcmp(pool, best, s);
+#endif
+      if (r == 0)
+        r = best->evr != s->evr ? pool_evrcmp(pool, best->evr, s->evr, EVRCMP_COMPARE) : 0;
 #ifdef ENABLE_LINKED_PKGS
       if (r == 0 && has_package_link(pool, s))
         r = pool_link_evrcmp(pool, best, s);
 #endif
+#ifdef ENABLE_CONDA
+      if (pool->disttype == DISTTYPE_CONDA)
+       {
+         if (r == 0)
+           r = (best->repo ? best->repo->subpriority : 0) - (s->repo ? s->repo->subpriority : 0);
+         if (r == 0)
+           r = pool_buildversioncmp(pool, best, s);
+         if (r == 0)
+           r = pool_buildflavorcmp(pool, best, s);
+       }
+#endif
       if (r < 0)
        best = s;
     }
@@ -963,8 +945,6 @@ prune_to_best_version(Pool *pool, Queue *plist)
       else
         prune_obsoleted(pool, plist);
     }
-  if (plist->count > 1 && pool->installed)
-    move_installed_to_front(pool, plist);
 }
 
 
@@ -1238,7 +1218,7 @@ urpm_reorder(Solver *solv, Queue *plist)
                    {
                      char kn[256];
                      Id p, pp, knid;
-                     memcpy(kn, "kernel", 8);
+                     memcpy(kn, "kernel", 7);
                      memcpy(kn + 6, flavor, release - flavor + 1);
                      memcpy(kn + 6 + (release - flavor) + 1, sn, flavor - sn);
                      strcpy(kn + 6 + (release + 1 - sn), release);
@@ -1302,6 +1282,37 @@ urpm_reorder(Solver *solv, Queue *plist)
   queue_truncate(plist, count);
 }
 
+/* support multiple favor groups by calling policy_filter_unwanted on
+ * each of them and combining the result */
+static void
+policy_filter_unwanted_favored(Solver *solv, Queue *plist, int mode)
+{
+  int i, j, f;
+  Queue qin, qprune;
+  queue_init_clone(&qin, plist);
+  queue_empty(plist);
+  /* sort by favor group */
+  solv_sort(qin.elements, qin.count, sizeof(Id), sort_by_favor_cmp, solv->favormap);
+  /* go over groups */
+  queue_init(&qprune);
+  for (i = 0; i < qin.count; i = j)
+    {
+      /* find end of group */
+      f = solv->favormap[qin.elements[i]];
+      for (j = i + 1; j < qin.count; j++)
+       if (solv->favormap[qin.elements[j]] != f)
+         break;
+      /* prune this group */
+      queue_empty(&qprune);
+      queue_insertn(&qprune, 0, j, qin.elements);
+      policy_filter_unwanted(solv, &qprune, mode | POLICY_MODE_FAVOR_REC);
+      for (i = 0; i < qprune.count; i++)
+       if (solv->favormap[qprune.elements[i]] == f)
+         queue_push(plist, qprune.elements[i]);
+    }
+  queue_free(&qprune);
+  queue_free(&qin);
+}
 
 /*
  *  POLICY_MODE_CHOOSE:     default, do all pruning steps
@@ -1323,6 +1334,21 @@ policy_filter_unwanted(Solver *solv, Queue *plist, int mode)
       policy_prefer_favored(solv, plist);
       return;
     }
+  if (mode & POLICY_MODE_FAVOR_REC)
+    mode ^= POLICY_MODE_FAVOR_REC;
+  else if (solv->favormap && plist->count > 1)
+    {
+      /* check if we have multiple favor groups */
+      int i, f = solv->favormap[plist->elements[0]];
+      for (i = 1; i < plist->count; i++)
+       if (solv->favormap[plist->elements[i]] != f)
+         break;
+      if (i < plist->count)
+       {
+         policy_filter_unwanted_favored(solv, plist, mode);
+         return;
+       }
+    }
   if (plist->count > 1)
     {
       if (mode != POLICY_MODE_SUGGEST)
@@ -1345,6 +1371,7 @@ policy_filter_unwanted(Solver *solv, Queue *plist, int mode)
 #endif
          dislike_old_versions(pool, plist);
          sort_by_common_dep(pool, plist);
+         move_installed_to_front(pool, plist);
          if (solv->urpmreorder)
            urpm_reorder(solv, plist);
          prefer_suggested(solv, plist);
@@ -1366,6 +1393,7 @@ pool_best_solvables(Pool *pool, Queue *plist, int flags)
     {
       dislike_old_versions(pool, plist);
       sort_by_common_dep(pool, plist);
+      move_installed_to_front(pool, plist);
     }
 }
 
@@ -1383,8 +1411,8 @@ policy_illegal_archchange(Solver *solv, Solvable *s1, Solvable *s2)
     return 0;
   if (!pool->id2arch)
     return 0;
-  a1 = a1 <= pool->lastarch ? pool->id2arch[a1] : 0;
-  a2 = a2 <= pool->lastarch ? pool->id2arch[a2] : 0;
+  a1 = pool_arch2score(pool, a1);
+  a2 = pool_arch2score(pool, a2);
   if (((a1 ^ a2) & 0xffff0000) != 0)
     return 1;
   return 0;
@@ -1483,7 +1511,7 @@ policy_create_obsolete_index(Solver *solv)
        {
          FOR_PROVIDES(p, pp, obs)
            {
-             Solvable *ps = pool->solvables + p;;
+             Solvable *ps = pool->solvables + p;
              if (ps->repo != installed)
                continue;
              if (ps->name == s->name)
@@ -1517,7 +1545,7 @@ policy_create_obsolete_index(Solver *solv)
        {
          FOR_PROVIDES(p, pp, obs)
            {
-             Solvable *ps = pool->solvables + p;;
+             Solvable *ps = pool->solvables + p;
              if (ps->repo != installed)
                continue;
              if (ps->name == s->name)
@@ -1534,6 +1562,29 @@ policy_create_obsolete_index(Solver *solv)
 }
 
 
+/* return true if solvable s obsoletes solvable with id pi */
+static inline int
+is_obsoleting(Pool *pool, Solvable *s, Id pi)
+{
+  Id p, pp, obs, *obsp;
+  Solvable *si = pool->solvables + pi;
+  if (pool->obsoleteusescolors && !pool_colormatch(pool, si, s))
+    return 0;
+  obsp = s->repo->idarraydata + s->obsoletes;
+  while ((obs = *obsp++) != 0) /* for all obsoletes */
+    {
+      FOR_PROVIDES(p, pp, obs)   /* and all matching providers of the obsoletes */
+       {
+         if (p != pi)
+           continue;
+         if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, si, obs))
+           continue;
+         return 1;
+       }
+    }
+  return 0;
+}
+
 /*
  * find update candidates
  *
@@ -1548,8 +1599,7 @@ policy_findupdatepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all)
 {
   /* installed packages get a special upgrade allowed rule */
   Pool *pool = solv->pool;
-  Id p, pp, n, p2, pp2;
-  Id obs, *obsp;
+  Id p, pp, n;
   Solvable *ps;
   int haveprovobs = 0;
   int allowdowngrade = allow_all ? 1 : solv->allowdowngrade;
@@ -1577,6 +1627,8 @@ policy_findupdatepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all)
        continue;
 
       ps = pool->solvables + p;
+      if (pool->considered && pool->whatprovideswithdisabled && ps->repo != pool->installed && pool_disabled_solvable(pool, ps)) 
+       continue;
       if (s->name == ps->name) /* name match */
        {
          if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps))
@@ -1588,31 +1640,14 @@ policy_findupdatepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all)
        continue;
       else if ((!solv->noupdateprovide || solv->needupdateprovide) && ps->obsoletes)   /* provides/obsoletes combination ? */
        {
-         /* check if package ps obsoletes installed package s */
+         /* check if package ps that provides s->name obsoletes installed package s */
          /* implicitobsoleteusescolors is somewhat wrong here, but we nevertheless
           * use it to limit our update candidates */
-         if ((pool->obsoleteusescolors || pool->implicitobsoleteusescolors) && !pool_colormatch(pool, s, ps))
+         if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps))
            continue;
-         obsp = ps->repo->idarraydata + ps->obsoletes;
-         while ((obs = *obsp++) != 0)  /* for all obsoletes */
-           {
-             FOR_PROVIDES(p2, pp2, obs)   /* and all matching providers of the obsoletes */
-               {
-                 Solvable *ps2 = pool->solvables + p2;
-                 if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps2, obs))
-                   continue;
-                 if (p2 == n)          /* match ! */
-                   break;
-               }
-             if (p2)                   /* match! */
-               break;
-           }
-         if (!obs)                     /* continue if no match */
+         if (!is_obsoleting(pool, ps, n))
            continue;
-         /* here we have 'p' with a matching provides/obsoletes combination
-          * thus flagging p as a valid update candidate for s
-          */
-         haveprovobs = 1;
+         haveprovobs = 1;              /* have matching provides/obsoletes combination */
        }
       else
         continue;
@@ -1634,14 +1669,14 @@ policy_findupdatepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all)
       for (opp = solv->obsoletes_data + solv->obsoletes[n - solv->installed->start]; (p = *opp++) != 0;)
        {
          ps = pool->solvables + p;
-         if (!allowarchchange && s->arch != ps->arch && policy_illegal_archchange(solv, s, ps))
-           continue;
-         if (!allowvendorchange && s->vendor != ps->vendor && policy_illegal_vendorchange(solv, s, ps))
-           continue;
          /* implicitobsoleteusescolors is somewhat wrong here, but we nevertheless
           * use it to limit our update candidates */
          if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps))
            continue;
+         if (!allowarchchange && s->arch != ps->arch && policy_illegal_archchange(solv, s, ps))
+           continue;
+         if (!allowvendorchange && s->vendor != ps->vendor && policy_illegal_vendorchange(solv, s, ps))
+           continue;
          queue_push(qs, p);
        }
     }