- add experimental support for choice rules to fix #485409
authorMichael Schroeder <mls@suse.de>
Fri, 24 Jul 2009 12:55:55 +0000 (14:55 +0200)
committerMichael Schroeder <mls@suse.de>
Fri, 24 Jul 2009 12:55:55 +0000 (14:55 +0200)
examples/solv.c
src/rules.c
src/rules.h
src/solver.c
src/solver.h
src/solverdebug.c

index 051d547..52a965e 100644 (file)
@@ -62,6 +62,7 @@
 #else
 # define REPOINFO_PATH "/etc/zypp/repos.d"
 # define PRODUCTS_PATH "/etc/products.d"
+# define SOFTLOCKS_PATH "/var/lib/zypp/SoftLocks"
 #endif
 
 #define SOLVCACHE_PATH "/var/cache/solv"
@@ -1932,6 +1933,49 @@ nscallback(Pool *pool, void *data, Id name, Id evr)
   return 0;
 }
 
+#ifdef SOFTLOCKS_PATH
+
+void
+addsoftlocks(Pool *pool, Queue *job)
+{
+  FILE *fp;
+  Id type, id, p, pp;
+  char *bp, *ep, buf[4096];
+
+  if ((fp = fopen(SOFTLOCKS_PATH, "r")) == 0)
+    return;
+  while((bp = fgets(buf, sizeof(buf), fp)) != 0)
+    {
+      while (*bp == ' ' || *bp == '\t')
+       bp++;
+      if (!*bp || *bp == '#')
+       continue;
+      for (ep = bp; *ep; ep++)
+       if (*ep == ' ' || *ep == '\t' || *ep == '\n')
+         break;
+      *ep = 0;
+      type = SOLVER_SOLVABLE_NAME;
+      if (!strncmp(bp, "provides:", 9) && bp[9])
+       {
+         type = SOLVER_SOLVABLE_PROVIDES;
+         bp += 9;
+       }
+      id = str2id(pool, bp, 1);
+      if (pool->installed)
+       {
+         FOR_JOB_SELECT(p, pp, type, id)
+           if (pool->solvables[p].repo == pool->installed)
+             break;
+         if (p)
+           continue;   /* ignore, as it is already installed */
+       }
+      queue_push2(job, SOLVER_LOCK|SOLVER_WEAK|type, id);
+    }
+  fclose(fp);
+}
+
+#endif
+
 #define MODE_LIST        0
 #define MODE_INSTALL     1
 #define MODE_ERASE       2
@@ -2259,6 +2303,10 @@ main(int argc, char **argv)
   // queue_push2(&job, SOLVER_NOOBSOLETES|SOLVER_SOLVABLE_NAME, str2id(pool, "kernel-pae-base", 1));
   // queue_push2(&job, SOLVER_NOOBSOLETES|SOLVER_SOLVABLE_NAME, str2id(pool, "kernel-pae-extra", 1));
 
+#ifdef SOFTLOCKS_PATH
+  addsoftlocks(pool, &job);
+#endif
+
 rerunsolver:
   for (;;)
     {
index 02a918d..4429f50 100644 (file)
@@ -1760,6 +1760,10 @@ solver_ruleinfo(Solver *solv, Id rid, Id *fromp, Id *top, Id *depp)
        *depp = pool->solvables[-r->p].name;
       return SOLVER_RULE_INFARCH;
     }
+  if (rid >= solv->choicerules && rid < solv->choicerules_end)
+    {
+      return SOLVER_RULE_CHOICE;
+    }
   if (rid >= solv->learntrules)
     {
       return SOLVER_RULE_LEARNT;
@@ -1767,4 +1771,130 @@ solver_ruleinfo(Solver *solv, Id rid, Id *fromp, Id *top, Id *depp)
   return SOLVER_RULE_UNKNOWN;
 }
 
+void
+addchoicerules(Solver *solv)
+{
+  Pool *pool = solv->pool;
+  Rule *r;
+  Queue q;
+  int i, rid, havechoice;
+  Id p, d, *pp;
+  Id p2, pp2;
+  Solvable *s, *s2;
+
+  solv->choicerules = solv->nrules;
+  if (!pool->installed)
+    {
+      solv->choicerules_end = solv->nrules;
+      return;
+    }
+  queue_init(&q);
+  for (rid = 1; rid < solv->rpmrules_end ; rid++)
+    {
+      r = solv->rules + rid;
+      if (r->p >= 0 || ((r->d == 0 || r->d == -1) && r->w2 < 0))
+       continue;       /* only look at requires rules */
+      // solver_printrule(solv, SAT_DEBUG_RESULT, r);
+      queue_empty(&q);
+      havechoice = 0;
+      FOR_RULELITERALS(p, pp, r)
+       {
+         if (p < 0)
+           continue;
+         s = pool->solvables + p;
+         if (!s->repo)
+           continue;
+         if (s->repo == pool->installed)
+           {
+             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->obsoleteusescolors && !pool_colormatch(pool, s, s2))
+               continue;
+             break;
+           }
+         if (p2)
+           {
+             /* found one */
+             if (!solv->allowarchchange && s->arch != s2->arch && policy_illegal_archchange(solv, s, s2))
+               continue;
+             if (!solv->allowvendorchange && s->vendor != s2->vendor && policy_illegal_vendorchange(solv, s, s2))
+               continue;
+             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 one */
+                 if (!solv->allowarchchange && s->arch != s2->arch && policy_illegal_archchange(solv, s, s2))
+                   continue;
+                 if (!solv->allowvendorchange && s->vendor != s2->vendor && policy_illegal_vendorchange(solv, s, s2))
+                   continue;
+                 queue_push(&q, p);
+                 continue;
+               }
+           }
+         /* this package is independent if the installed ones */
+         havechoice = 1;
+       }
+      if (!havechoice || !q.count)
+       continue;       /* no choice */
+      for (i = 0; i < q.count; i++)
+       {
+         int j;
+         s = pool->solvables + q.elements[i];
+         if (s->repo == pool->installed)
+           continue;
+         for (j = 0; j < q.count; j++)
+           {
+             if (i == j)
+               continue;
+             s2 = pool->solvables + q.elements[j];
+             if (s2->repo != pool->installed)
+               continue;
+             if (solvable_identical(s, s2))
+               break;
+           }
+         if (j == q.count)
+           break;
+       }
+      if (i == q.count)
+       continue;       /* only (identical to) installed packages */
+      d = q.count ? pool_queuetowhatprovides(pool, &q) : 0;
+      solver_addrule(solv, r->p, d);
+      queue_push(&solv->weakruleq, solv->nrules - 1);
+    }
+  queue_free(&q);
+  solv->choicerules_end = solv->nrules;
+}
+
 /* EOF */
index d9f4e36..2cd4035 100644 (file)
@@ -63,7 +63,8 @@ typedef enum {
   SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP,
   SOLVER_RULE_DISTUPGRADE = 0x500,
   SOLVER_RULE_INFARCH = 0x600,
-  SOLVER_RULE_LEARNT = 0x700
+  SOLVER_RULE_CHOICE = 0x700,
+  SOLVER_RULE_LEARNT = 0x800
 } SolverRuleinfo;
 
 #define SOLVER_RULE_TYPEMASK    0xff00
index c45d676..206be13 100644 (file)
@@ -2804,6 +2804,11 @@ solver_solve(Solver *solv, Queue *job)
   else
     solv->duprules = solv->duprules_end = solv->nrules;
 
+  if (1)
+    {
+      extern void addchoicerules(Solver *solv);
+      addchoicerules(solv);
+    }
 
   /* all rules created
    * --------------------------------------------------------------
@@ -2815,7 +2820,7 @@ solver_solve(Solver *solv, Queue *job)
   map_free(&installcandidatemap);
   queue_free(&q);
 
-  POOL_DEBUG(SAT_DEBUG_STATS, "%d rpm rules, %d job rules, %d infarch rules, %d dup rules\n", solv->rpmrules_end - 1, solv->jobrules_end - solv->jobrules, solv->infarchrules_end - solv->infarchrules, solv->duprules_end - solv->duprules);
+  POOL_DEBUG(SAT_DEBUG_STATS, "%d rpm rules, %d job rules, %d infarch rules, %d dup rules, %d choice rules\n", solv->rpmrules_end - 1, solv->jobrules_end - solv->jobrules, solv->infarchrules_end - solv->infarchrules, solv->duprules_end - solv->duprules, solv->choicerules_end - solv->choicerules);
 
   /* create weak map */
   map_init(&solv->weakrulemap, solv->nrules);
index 096d378..91a7664 100644 (file)
@@ -74,6 +74,9 @@ typedef struct _Solver {
   Id duprules;                         /* dist upgrade rules */
   Id duprules_end;
     
+  Id choicerules;                      /* choice rules (always weak) */
+  Id choicerules_end;
+
   Id learntrules;                      /* learnt rules, (end == nrules) */
 
   Map noupdate;                                /* don't try to update these
index d95416a..ee43212 100644 (file)
@@ -136,6 +136,8 @@ solver_printruleelement(Solver *solv, int type, Rule *r, Id v)
       s = pool->solvables + v;
       POOL_DEBUG(type, "    %s [%d]", solvable2str(pool, s), v);
     }
+  if (pool->installed && s->repo == pool->installed)
+    POOL_DEBUG(type, "I");
   if (r)
     {
       if (r->w1 == v)
@@ -203,6 +205,8 @@ solver_printruleclass(Solver *solv, int type, Rule *r)
       POOL_DEBUG(type, "WEAK ");
   if (p >= solv->learntrules)
     POOL_DEBUG(type, "LEARNT ");
+  else if (p >= solv->choicerules && p < solv->choicerules_end)
+    POOL_DEBUG(type, "CHOICE ");
   else if (p >= solv->infarchrules && p < solv->infarchrules_end)
     POOL_DEBUG(type, "INFARCH ");
   else if (p >= solv->duprules && p < solv->duprules_end)
@@ -561,6 +565,7 @@ solver_printprobleminfo(Solver *solv, Id problem)
     case SOLVER_RULE_UNKNOWN:
     case SOLVER_RULE_FEATURE:
     case SOLVER_RULE_LEARNT:
+    case SOLVER_RULE_CHOICE:
       POOL_DEBUG(SAT_DEBUG_RESULT, "bad rule type\n");
       return;
     }