bah revert... you dreamer
[platform/upstream/libsolv.git] / src / policy.c
index 121c8a6..ffc8233 100644 (file)
@@ -7,7 +7,7 @@
 
 /*
  * Generic policy interface for SAT solver
- * 
+ *
  */
 
 #include <stdio.h>
@@ -22,7 +22,7 @@
 #include "poolarch.h"
 
 
-static Pool *prune_best_version_arch_sortcmp_data;
+static Solver *prune_best_version_arch_sortcmp_data;
 
 /*-----------------------------------------------------------------*/
 
@@ -34,7 +34,8 @@ static Pool *prune_best_version_arch_sortcmp_data;
 static int
 prune_best_version_arch_sortcmp(const void *ap, const void *bp)
 {
-  Pool *pool = prune_best_version_arch_sortcmp_data;
+  Solver *solv = prune_best_version_arch_sortcmp_data;
+  Pool *pool = solv->pool;
   int r;
   Id a = *(Id *)ap;
   Id b = *(Id *)bp;
@@ -46,7 +47,8 @@ prune_best_version_arch_sortcmp(const void *ap, const void *bp)
        * is not depending on some random solvable order */
       na = id2str(pool, pool->solvables[a].name);
       nb = id2str(pool, pool->solvables[b].name);
-      /* bring selections and patterns to the front */
+      /* bring patterns to the front */
+      /* XXX: no longer needed? */
       if (!strncmp(na, "pattern:", 8))
        {
           if (strncmp(nb, "pattern:", 8))
@@ -57,21 +59,26 @@ prune_best_version_arch_sortcmp(const void *ap, const void *bp)
           if (strncmp(na, "pattern:", 8))
            return 1;
        }
-      if (!strncmp(na, "selection:", 10))
-       {
-          if (strncmp(nb, "selection:", 10))
-           return -1;
-       }
-      else if (!strncmp(nb, "selection:", 10))
-       {
-          if (strncmp(na, "selection:", 10))
-           return 1;
-       }
       return strcmp(na, nb);
     }
+  /* the same name */
+  if (pool->solvables[a].evr == pool->solvables[b].evr && solv->installed)
+    {
+       /* prefer installed solvables */
+      if (pool->solvables[a].repo == solv->installed)
+       return -1;
+      if (pool->solvables[b].repo == solv->installed)
+       return 1;       
+    }
   return a - b;
 }
 
+
+/*
+ * prune to repository with highest priority
+ * 
+ */
+
 static void
 prune_to_highest_prio(Pool *pool, Queue *plist)
 {
@@ -80,13 +87,13 @@ prune_to_highest_prio(Pool *pool, Queue *plist)
   int bestprio = 0;
 
   /* prune to highest priority */
-  for (i = 0; i < plist->count; i++)
+  for (i = 0; i < plist->count; i++)  /* find highest prio in queue */
     {
       s = pool->solvables + plist->elements[i];
       if (i == 0 || s->repo->priority > bestprio)
        bestprio = s->repo->priority;
     }
-  for (i = j = 0; i < plist->count; i++)
+  for (i = j = 0; i < plist->count; i++) /* remove all with lower prio */
     {
       s = pool->solvables + plist->elements[i];
       if (s->repo->priority == bestprio)
@@ -95,12 +102,14 @@ prune_to_highest_prio(Pool *pool, Queue *plist)
   plist->count = j;
 }
 
+
 /*
  * prune_to_recommended
  *
  * XXX: should we prune to requires/suggests that are already
  * fulfilled by other packages?
  */
+
 static void
 prune_to_recommended(Solver *solv, Queue *plist)
 {
@@ -169,7 +178,7 @@ prune_to_recommended(Solver *solv, Queue *plist)
     plist->count = j;
 }
 
-static void
+void
 prune_to_best_arch(Pool *pool, Queue *plist)
 {
   Id a, bestscore;
@@ -205,17 +214,16 @@ prune_to_best_arch(Pool *pool, Queue *plist)
 
 /*
  * prune_best_version_arch
- * 
+ *
  * sort list of packages (given through plist) by name and evr
  * return result through plist
- * 
+ *
  */
 
-/* FIXME: should prefer installed if identical version */
-
-static void
-prune_to_best_version(Pool *pool, Queue *plist)
+void
+prune_to_best_version(Solver *solv, Queue *plist)
 {
+  Pool *pool = solv->pool;
   Id best = ID_NULL;
   int i, j;
   Solvable *s;
@@ -224,11 +232,8 @@ prune_to_best_version(Pool *pool, Queue *plist)
     return;
   POOL_DEBUG(SAT_DEBUG_POLICY, "prune_to_best_version %d\n", plist->count);
 
-  /* prune to best architecture */
-  if (pool->id2arch)
-
-  prune_best_version_arch_sortcmp_data = pool;
-  /* sort by name first */
+  prune_best_version_arch_sortcmp_data = solv;
+  /* sort by name first, prefer installed */
   qsort(plist->elements, plist->count, sizeof(Id), prune_best_version_arch_sortcmp);
 
   /* delete obsoleted. hmm, looks expensive! */
@@ -247,6 +252,8 @@ prune_to_best_version(Pool *pool, Queue *plist)
            {
              if (pool->solvables[p].name == s->name)
                continue;
+             if (!solv->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p, obs))
+               continue;
              for (j = 0; j < plist->count; j++)
                {
                  if (i == j)
@@ -267,7 +274,9 @@ prune_to_best_version(Pool *pool, Queue *plist)
     {
       s = pool->solvables + plist->elements[i];
 
-      POOL_DEBUG(SAT_DEBUG_POLICY, "- %s\n", solvable2str(pool, s));
+      POOL_DEBUG(SAT_DEBUG_POLICY, "- %s[%s]\n",
+                solvable2str(pool, s),
+                (solv->installed && s->repo == solv->installed) ? "installed" : "not installed");
 
       if (!best)                      /* if no best yet, the current is best */
         {
@@ -285,7 +294,7 @@ prune_to_best_version(Pool *pool, Queue *plist)
 
       if (pool->solvables[best].evr != s->evr)   /* compare evr */
         {
-          if (evrcmp(pool, pool->solvables[best].evr, s->evr) < 0)
+          if (evrcmp(pool, pool->solvables[best].evr, s->evr, EVRCMP_MATCH_RELEASE) < 0)
             best = plist->elements[i];
         }
     }
@@ -297,14 +306,23 @@ prune_to_best_version(Pool *pool, Queue *plist)
   plist->count = j;
 }
 
-/* legacy, do not use anymore! */
+
+/* legacy, do not use anymore!
+ * (rates arch higher than version, but thats a policy)
+ */
+
 void
-prune_best_version_arch(Pool *pool, Queue *plist)
+prune_best_arch_name_version(Solver *solv, Pool *pool, Queue *plist)
 {
+  if (solv && solv->bestSolvableCb)
+    { /* The application is responsible for */
+      return solv->bestSolvableCb(solv->pool, plist);
+    }
+
   if (plist->count > 1)
     prune_to_best_arch(pool, plist);
   if (plist->count > 1)
-    prune_to_best_version(pool, plist);
+    prune_to_best_version(solv, plist);
 }
 
 
@@ -319,18 +337,22 @@ policy_filter_unwanted(Solver *solv, Queue *plist, Id inst, int mode)
   /* FIXME: do this different! */
   if (inst)
     queue_push(plist, inst);
-  if (plist->count > 1)
-    prune_to_best_arch(pool, plist);
-  if (plist->count > 1)
-    prune_to_best_version(pool, plist);
+
+  prune_best_arch_name_version(solv, pool, plist);
 }
 
 
 int
-policy_illegal_archchange(Pool *pool, Solvable *s1, Solvable *s2)
+policy_illegal_archchange(Solver *solv, Solvable *s1, Solvable *s2)
 {
+  Pool *pool = solv->pool;
   Id a1 = s1->arch, a2 = s2->arch;
 
+  if (solv && solv->archCheckCb)
+    { /* The application is responsible for */
+      return solv->archCheckCb(solv->pool, s1, s2);
+    }
+
   /* we allow changes to/from noarch */
   if (a1 == a2 || a1 == ARCH_NOARCH || a2 == ARCH_NOARCH)
     return 0;
@@ -344,9 +366,16 @@ policy_illegal_archchange(Pool *pool, Solvable *s1, Solvable *s2)
 }
 
 int
-policy_illegal_vendorchange(Pool *pool, Solvable *s1, Solvable *s2)
+policy_illegal_vendorchange(Solver *solv, Solvable *s1, Solvable *s2)
 {
+  Pool *pool = solv->pool;
   Id vendormask1, vendormask2;
+
+  if (solv && solv->vendorCheckCb)
+   {   /* The application is responsible for */
+     return solv->vendorCheckCb(solv->pool, s1, s2);
+   }
+
   if (s1->vendor == s2->vendor)
     return 0;
   vendormask1 = pool_vendor2mask(pool, s1->vendor);
@@ -358,23 +387,36 @@ policy_illegal_vendorchange(Pool *pool, Solvable *s1, Solvable *s2)
   return 1;
 }
 
+
+/*
+ * find update candidates
+ * 
+ * s: solvable to be updated
+ * qs: [out] queue to hold Ids of candidates
+ * allow_all: 0 = dont allow downgrades, 1 = allow all candidates
+ * 
+ */
 void
-policy_findupdatepackages(Solver *solv, Solvable *s, Queue *qs, int allowall)
+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;
   Solvable *ps;
-  Id vendormask;
 
   queue_empty(qs);
+
+  if (solv && solv->updateCandidateCb)
+    { /* The application is responsible for */
+      return solv->updateCandidateCb(solv->pool, s, qs);
+    }
+
   /*
    * s = solvable ptr
    * n = solvable Id
    */
   n = s - pool->solvables;
-  vendormask = pool_vendor2mask(pool, s->vendor);
 
   /*
    * look for updates for s
@@ -387,15 +429,8 @@ policy_findupdatepackages(Solver *solv, Solvable *s, Queue *qs, int allowall)
       ps = pool->solvables + p;
       if (s->name == ps->name) /* name match */
        {
-         if (!allowall)
-           {
-             if (!solv->allowdowngrade && evrcmp(pool, s->evr, ps->evr) > 0)
-               continue;
-             if (!solv->allowarchchange && s->arch != ps->arch && policy_illegal_archchange(pool, s, ps))
-               continue;
-             if (!solv->allowvendorchange && s->vendor != ps->vendor && policy_illegal_vendorchange(pool, s, ps))
-               continue;
-           }
+         if (!allow_all && !solv->allowdowngrade && evrcmp(pool, s->evr, ps->evr, EVRCMP_MATCH_RELEASE) > 0)
+           continue;
        }
       else if (!solv->noupdateprovide && ps->obsoletes)   /* provides/obsoletes combination ? */
        {
@@ -404,6 +439,8 @@ policy_findupdatepackages(Solver *solv, Solvable *s, Queue *qs, int allowall)
            {
              FOR_PROVIDES(p2, pp2, obs)   /* and all matching providers of the obsoletes */
                {
+                 if (!solv->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p2, obs))
+                   continue;
                  if (p2 == n)          /* match ! */
                    break;
                }
@@ -418,12 +455,23 @@ policy_findupdatepackages(Solver *solv, Solvable *s, Queue *qs, int allowall)
        }
       else
         continue;
+      if (!allow_all && !solv->allowarchchange && s->arch != ps->arch && policy_illegal_archchange(solv, s, ps))
+       continue;
+      if (!allow_all && !solv->allowvendorchange && s->vendor != ps->vendor && policy_illegal_vendorchange(solv, s, ps))
+       continue;
       queue_push(qs, p);
     }
   if (solv->noupdateprovide && solv->obsoletes && solv->obsoletes[n - solv->installed->start])
     {
       for (pp = solv->obsoletes_data + solv->obsoletes[n - solv->installed->start]; (p = *pp++) != 0;)
-       queue_push(qs, p);
+       {
+         ps = pool->solvables + p;
+         if (!allow_all && !solv->allowarchchange && s->arch != ps->arch && policy_illegal_archchange(solv, s, ps))
+           continue;
+         if (!allow_all && !solv->allowvendorchange && s->vendor != ps->vendor && policy_illegal_vendorchange(solv, s, ps))
+           continue;
+         queue_push(qs, p);
+       }
     }
 }