- split rule generation from solver.c into rules.c
authorMichael Schroeder <mls@suse.de>
Mon, 25 May 2009 16:06:22 +0000 (18:06 +0200)
committerMichael Schroeder <mls@suse.de>
Mon, 25 May 2009 16:07:45 +0000 (18:07 +0200)
src/CMakeLists.txt
src/rules.c [new file with mode: 0644]
src/rules.h [new file with mode: 0644]
src/solver.c
src/solver.h

index a74bf8c..7c0b0e7 100644 (file)
@@ -3,7 +3,7 @@ SET(libsatsolver_SRCS
     bitmap.c poolarch.c poolvendor.c poolid.c strpool.c dirpool.c
     solver.c solverdebug.c repo_solv.c repo_helix.c evr.c pool.c
     queue.c repo.c repodata.c repopage.c util.c policy.c solvable.c
-    transaction.c)
+    transaction.c rules.c)
 
 ADD_LIBRARY(satsolver STATIC ${libsatsolver_SRCS})
 
@@ -11,7 +11,7 @@ SET(libsatsolver_HEADERS
     bitmap.h evr.h hash.h policy.h poolarch.h poolvendor.h pool.h
     poolid.h pooltypes.h queue.h solvable.h solver.h solverdebug.h
     repo.h repodata.h repopage.h repo_solv.h repo_helix.h util.h
-    strpool.h dirpool.h knownid.h transaction.h)
+    strpool.h dirpool.h knownid.h transaction.h rules.h)
 
 SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
 
diff --git a/src/rules.c b/src/rules.c
new file mode 100644 (file)
index 0000000..07b365b
--- /dev/null
@@ -0,0 +1,1086 @@
+/*
+ * Copyright (c) 2007-2009, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * rules.c
+ *
+ * SAT based dependency solver
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+
+#include "solver.h"
+#include "bitmap.h"
+#include "pool.h"
+#include "util.h"
+#include "policy.h"
+#include "solverdebug.h"
+
+#define RULES_BLOCK 63
+
+static void addrpmruleinfo(Solver *solv, Id p, Id d, int type, Id dep);
+
+/*-------------------------------------------------------------------
+ * Check if dependency is possible
+ * 
+ * this mirrors solver_dep_fulfilled
+ * but uses map m instead of the decisionmap
+ */
+
+static inline int
+dep_possible(Solver *solv, Id dep, Map *m)
+{
+  Pool *pool = solv->pool;
+  Id p, pp;
+
+  if (ISRELDEP(dep))
+    {
+      Reldep *rd = GETRELDEP(pool, dep);
+      if (rd->flags == REL_AND)
+       {
+         if (!dep_possible(solv, rd->name, m))
+           return 0;
+         return dep_possible(solv, rd->evr, m);
+       }
+      if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES)
+       return solver_splitprovides(solv, rd->evr);
+      if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_INSTALLED)
+       return solver_dep_installed(solv, rd->evr);
+    }
+  FOR_PROVIDES(p, pp, dep)
+    {
+      if (MAPTST(m, p))
+       return 1;
+    }
+  return 0;
+}
+
+/********************************************************************
+ *
+ * Rule handling
+ *
+ * - unify rules, remove duplicates
+ */
+
+/*-------------------------------------------------------------------
+ *
+ * compare rules for unification sort
+ *
+ */
+
+static int
+unifyrules_sortcmp(const void *ap, const void *bp, void *dp)
+{
+  Pool *pool = dp;
+  Rule *a = (Rule *)ap;
+  Rule *b = (Rule *)bp;
+  Id *ad, *bd;
+  int x;
+
+  x = a->p - b->p;
+  if (x)
+    return x;                         /* p differs */
+
+  /* identical p */
+  if (a->d == 0 && b->d == 0)
+    return a->w2 - b->w2;             /* assertion: return w2 diff */
+
+  if (a->d == 0)                      /* a is assertion, b not */
+    {
+      x = a->w2 - pool->whatprovidesdata[b->d];
+      return x ? x : -1;
+    }
+
+  if (b->d == 0)                      /* b is assertion, a not */
+    {
+      x = pool->whatprovidesdata[a->d] - b->w2;
+      return x ? x : 1;
+    }
+
+  /* compare whatprovidesdata */
+  ad = pool->whatprovidesdata + a->d;
+  bd = pool->whatprovidesdata + b->d;
+  while (*bd)
+    if ((x = *ad++ - *bd++) != 0)
+      return x;
+  return *ad;
+}
+
+int
+solver_samerule(Solver *solv, Rule *r1, Rule *r2)
+{
+  return unifyrules_sortcmp(r1, r2, solv->pool);
+}
+
+
+/*-------------------------------------------------------------------
+ *
+ * unify rules
+ * go over all rules and remove duplicates
+ */
+
+void
+solver_unifyrules(Solver *solv)
+{
+  Pool *pool = solv->pool;
+  int i, j;
+  Rule *ir, *jr;
+
+  if (solv->nrules <= 1)              /* nothing to unify */
+    return;
+
+  POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- unifyrules -----\n");
+
+  /* sort rules first */
+  sat_sort(solv->rules + 1, solv->nrules - 1, sizeof(Rule), unifyrules_sortcmp, solv->pool);
+
+  /* prune rules
+   * i = unpruned
+   * j = pruned
+   */
+  jr = 0;
+  for (i = j = 1, ir = solv->rules + i; i < solv->nrules; i++, ir++)
+    {
+      if (jr && !unifyrules_sortcmp(ir, jr, pool))
+       continue;                      /* prune! */
+      jr = solv->rules + j++;         /* keep! */
+      if (ir != jr)
+        *jr = *ir;
+    }
+
+  /* reduced count from nrules to j rules */
+  POOL_DEBUG(SAT_DEBUG_STATS, "pruned rules from %d to %d\n", solv->nrules, j);
+
+  /* adapt rule buffer */
+  solv->nrules = j;
+  solv->rules = sat_extend_resize(solv->rules, solv->nrules, sizeof(Rule), RULES_BLOCK);
+    /*
+     * debug: statistics
+     */
+  IF_POOLDEBUG (SAT_DEBUG_STATS)
+    {
+      int binr = 0;
+      int lits = 0;
+      Id *dp;
+      Rule *r;
+
+      for (i = 1; i < solv->nrules; i++)
+       {
+         r = solv->rules + i;
+         if (r->d == 0)
+           binr++;
+         else
+           {
+             dp = solv->pool->whatprovidesdata + r->d;
+             while (*dp++)
+               lits++;
+           }
+       }
+      POOL_DEBUG(SAT_DEBUG_STATS, "  binary: %d\n", binr);
+      POOL_DEBUG(SAT_DEBUG_STATS, "  normal: %d, %d literals\n", solv->nrules - 1 - binr, lits);
+    }
+  POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- unifyrules end -----\n");
+}
+
+#if 0
+
+/*
+ * hash rule
+ */
+
+static Hashval
+hashrule(Solver *solv, Id p, Id d, int n)
+{
+  unsigned int x = (unsigned int)p;
+  int *dp;
+
+  if (n <= 1)
+    return (x * 37) ^ (unsigned int)d;
+  dp = solv->pool->whatprovidesdata + d;
+  while (*dp)
+    x = (x * 37) ^ (unsigned int)*dp++;
+  return x;
+}
+#endif
+
+
+/*-------------------------------------------------------------------
+ * 
+ */
+
+/*
+ * add rule
+ *  p = direct literal; always < 0 for installed rpm rules
+ *  d, if < 0 direct literal, if > 0 offset into whatprovides, if == 0 rule is assertion (look at p only)
+ *
+ *
+ * A requires b, b provided by B1,B2,B3 => (-A|B1|B2|B3)
+ *
+ * p < 0 : pkg id of A
+ * d > 0 : Offset in whatprovidesdata (list of providers of b)
+ *
+ * A conflicts b, b provided by B1,B2,B3 => (-A|-B1), (-A|-B2), (-A|-B3)
+ * p < 0 : pkg id of A
+ * d < 0 : Id of solvable (e.g. B1)
+ *
+ * d == 0: unary rule, assertion => (A) or (-A)
+ *
+ *   Install:    p > 0, d = 0   (A)             user requested install
+ *   Remove:     p < 0, d = 0   (-A)            user requested remove (also: uninstallable)
+ *   Requires:   p < 0, d > 0   (-A|B1|B2|...)  d: <list of providers for requirement of p>
+ *   Updates:    p > 0, d > 0   (A|B1|B2|...)   d: <list of updates for solvable p>
+ *   Conflicts:  p < 0, d < 0   (-A|-B)         either p (conflict issuer) or d (conflict provider) (binary rule)
+ *                                              also used for obsoletes
+ *   ?:          p > 0, d < 0   (A|-B)          
+ *   No-op ?:    p = 0, d = 0   (null)          (used as policy rule placeholder)
+ *
+ *   resulting watches:
+ *   ------------------
+ *   Direct assertion (no watch needed)( if d <0 ) --> d = 0, w1 = p, w2 = 0
+ *   Binary rule: p = first literal, d = 0, w2 = second literal, w1 = p
+ *   every other : w1 = p, w2 = whatprovidesdata[d];
+ *   Disabled rule: w1 = 0
+ *
+ *   always returns a rule for non-rpm rules
+ */
+
+Rule *
+solver_addrule(Solver *solv, Id p, Id d)
+{
+  Pool *pool = solv->pool;
+  Rule *r = 0;
+  Id *dp = 0;
+
+  int n = 0;                          /* number of literals in rule - 1
+                                         0 = direct assertion (single literal)
+                                         1 = binary rule
+                                         >1 = 
+                                       */
+
+  /* it often happenes that requires lead to adding the same rpm rule
+   * multiple times, so we prune those duplicates right away to make
+   * the work for unifyrules a bit easier */
+
+  if (solv->nrules                      /* we already have rules */
+      && !solv->rpmrules_end)           /* but are not done with rpm rules */
+    {
+      r = solv->rules + solv->nrules - 1;   /* get the last added rule */
+      if (r->p == p && r->d == d && d != 0)   /* identical and not user requested */
+       return r;
+    }
+
+    /*
+     * compute number of literals (n) in rule
+     */
+    
+  if (d < 0)
+    {
+      /* always a binary rule */
+      if (p == d)
+       return 0;                      /* ignore self conflict */
+      n = 1;
+    }
+  else if (d > 0)
+    {
+      for (dp = pool->whatprovidesdata + d; *dp; dp++, n++)
+       if (*dp == -p)
+         return 0;                     /* rule is self-fulfilling */
+       
+      if (n == 1)   /* have single provider */
+       d = dp[-1];                     /* take single literal */
+    }
+
+  if (n == 1 && p > d && !solv->rpmrules_end)
+    {
+      /* smallest literal first so we can find dups */
+      n = p; p = d; d = n;             /* p <-> d */
+      n = 1;                          /* re-set n, was used as temp var */
+    }
+
+  /*
+   * check for duplicate
+   */
+    
+  /* check if the last added rule (r) is exactly the same as what we're looking for. */
+  if (r && n == 1 && !r->d && r->p == p && r->w2 == d)
+    return r;  /* binary rule */
+
+    /* have n-ary rule with same first literal, check other literals */
+  if (r && n > 1 && r->d && r->p == p)
+    {
+      /* Rule where d is an offset in whatprovidesdata */
+      Id *dp2;
+      if (d == r->d)
+       return r;
+      dp2 = pool->whatprovidesdata + r->d;
+      for (dp = pool->whatprovidesdata + d; *dp; dp++, dp2++)
+       if (*dp != *dp2)
+         break;
+      if (*dp == *dp2)
+       return r;
+   }
+
+  /*
+   * allocate new rule
+   */
+
+  /* extend rule buffer */
+  solv->rules = sat_extend(solv->rules, solv->nrules, 1, sizeof(Rule), RULES_BLOCK);
+  r = solv->rules + solv->nrules++;    /* point to rule space */
+
+    /*
+     * r = new rule
+     */
+    
+  r->p = p;
+  if (n == 0)
+    {
+      /* direct assertion, no watch needed */
+      r->d = 0;
+      r->w1 = p;
+      r->w2 = 0;
+    }
+  else if (n == 1)
+    {
+      /* binary rule */
+      r->d = 0;
+      r->w1 = p;
+      r->w2 = d;
+    }
+  else
+    {
+      r->d = d;
+      r->w1 = p;
+      r->w2 = pool->whatprovidesdata[d];
+    }
+  r->n1 = 0;
+  r->n2 = 0;
+
+  IF_POOLDEBUG (SAT_DEBUG_RULE_CREATION)
+    {
+      POOL_DEBUG(SAT_DEBUG_RULE_CREATION, "  Add rule: ");
+      solver_printrule(solv, SAT_DEBUG_RULE_CREATION, r);
+    }
+
+  return r;
+}
+
+/*-------------------------------------------------------------------
+ * disable rule
+ */
+
+static inline void
+disablerule(Solver *solv, Rule *r)
+{
+  if (r->d >= 0)
+    r->d = -r->d - 1;
+}
+
+/*-------------------------------------------------------------------
+ * enable rule
+ */
+
+static inline void
+enablerule(Solver *solv, Rule *r)
+{
+  if (r->d < 0)
+    r->d = -r->d - 1;
+}
+
+/*
+ *  special multiversion patch conflict handling:
+ *  a patch conflict is also satisfied, if some other
+ *  version with the same name/arch that doesn't conflict
+ *  get's installed. The generated rule is thus:
+ *  -patch|-cpack|opack1|opack2|...
+ */
+static Id
+makemultiversionconflict(Solver *solv, Id n, Id con)
+{
+  Pool *pool = solv->pool;
+  Solvable *s, *sn;
+  Queue q;
+  Id p, pp, qbuf[64];
+
+  sn = pool->solvables + n;
+  queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf));
+  queue_push(&q, -n);
+  FOR_PROVIDES(p, pp, sn->name)
+    {
+      s = pool->solvables + p;
+      if (s->name != sn->name || s->arch != sn->arch)
+       continue;
+      if (!MAPTST(&solv->noobsoletes, p))
+       continue;
+      if (pool_match_nevr(pool, pool->solvables + p, con))
+       continue;
+      /* here we have a multiversion solvable that doesn't conflict */
+      /* thus we're not in conflict if it is installed */
+      queue_push(&q, p);
+    }
+  if (q.count == 1)
+    return -n; /* no other package found, generate normal conflict */
+  return pool_queuetowhatprovides(pool, &q);
+}
+
+static inline void
+addrpmrule(Solver *solv, Id p, Id d, int type, Id dep)
+{
+  if (!solv->ruleinfoq)
+    solver_addrule(solv, p, d);
+  else
+    addrpmruleinfo(solv, p, d, type, dep);
+}
+
+/*-------------------------------------------------------------------
+ * 
+ * add (install) rules for solvable
+ * 
+ * s: Solvable for which to add rules
+ * m: m[s] = 1 for solvables which have rules, prevent rule duplication
+ * 
+ * Algorithm: 'visit all nodes of a graph'. The graph nodes are
+ *  solvables, the edges their dependencies.
+ *  Starting from an installed solvable, this will create all rules
+ *  representing the graph created by the solvables dependencies.
+ * 
+ * for unfulfilled requirements, conflicts, obsoletes,....
+ * add a negative assertion for solvables that are not installable
+ * 
+ * It will also create rules for all solvables referenced by 's'
+ *  i.e. descend to all providers of requirements of 's'
+ *
+ */
+
+void
+solver_addrpmrulesforsolvable(Solver *solv, Solvable *s, Map *m)
+{
+  Pool *pool = solv->pool;
+  Repo *installed = solv->installed;
+
+  /* 'work' queue. keeps Ids of solvables we still have to work on.
+     And buffer for it. */
+  Queue workq;
+  Id workqbuf[64];
+    
+  int i;
+    /* if to add rules for broken deps ('rpm -V' functionality)
+     * 0 = yes, 1 = no
+     */
+  int dontfix;
+    /* Id var and pointer for each dependency
+     * (not used in parallel)
+     */
+  Id req, *reqp;
+  Id con, *conp;
+  Id obs, *obsp;
+  Id rec, *recp;
+  Id sug, *sugp;
+  Id p, pp;            /* whatprovides loops */
+  Id *dp;              /* ptr to 'whatprovides' */
+  Id n;                        /* Id for current solvable 's' */
+
+  POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforsolvable -----\n");
+
+  queue_init_buffer(&workq, workqbuf, sizeof(workqbuf)/sizeof(*workqbuf));
+  queue_push(&workq, s - pool->solvables);     /* push solvable Id to work queue */
+
+  /* loop until there's no more work left */
+  while (workq.count)
+    {
+      /*
+       * n: Id of solvable
+       * s: Pointer to solvable
+       */
+
+      n = queue_shift(&workq);         /* 'pop' next solvable to work on from queue */
+      if (m)
+       {
+         if (MAPTST(m, n))             /* continue if already visited */
+           continue;
+         MAPSET(m, n);                 /* mark as visited */
+       }
+
+      s = pool->solvables + n;         /* s = Solvable in question */
+
+      dontfix = 0;
+      if (installed                    /* Installed system available */
+         && !solv->fixsystem           /* NOT repair errors in rpm dependency graph */
+         && s->repo == installed)      /* solvable is installed? */
+        {
+         dontfix = 1;                  /* dont care about broken rpm deps */
+        }
+
+      if (!dontfix
+         && s->arch != ARCH_SRC
+         && s->arch != ARCH_NOSRC
+         && !pool_installable(pool, s))
+       {
+         POOL_DEBUG(SAT_DEBUG_RULE_CREATION, "package %s [%d] is not installable\n", solvable2str(pool, s), (Id)(s - pool->solvables));
+         addrpmrule(solv, -n, 0, SOLVER_RULE_RPM_NOT_INSTALLABLE, 0);
+       }
+
+      /* yet another SUSE hack, sigh */
+      if (pool->nscallback && !strncmp("product:", id2str(pool, s->name), 8))
+        {
+          Id buddy = pool->nscallback(pool, pool->nscallbackdata, NAMESPACE_PRODUCTBUDDY, n);
+          if (buddy > 0 && buddy != SYSTEMSOLVABLE && buddy != n && buddy < pool->nsolvables)
+            {
+              addrpmrule(solv, n, -buddy, SOLVER_RULE_RPM_PACKAGE_REQUIRES, solvable_selfprovidedep(pool->solvables + n));
+              addrpmrule(solv, buddy, -n, SOLVER_RULE_RPM_PACKAGE_REQUIRES, solvable_selfprovidedep(pool->solvables + buddy)); 
+             if (m && !MAPTST(m, buddy))
+               queue_push(&workq, buddy);
+            }
+        }
+
+      /*-----------------------------------------
+       * check requires of s
+       */
+
+      if (s->requires)
+       {
+         reqp = s->repo->idarraydata + s->requires;
+         while ((req = *reqp++) != 0)            /* go through all requires */
+           {
+             if (req == SOLVABLE_PREREQMARKER)   /* skip the marker */
+               continue;
+
+             /* find list of solvables providing 'req' */
+             dp = pool_whatprovides_ptr(pool, req);
+
+             if (*dp == SYSTEMSOLVABLE)          /* always installed */
+               continue;
+
+             if (dontfix)
+               {
+                 /* the strategy here is to not insist on dependencies
+                   * that are already broken. so if we find one provider
+                   * that was already installed, we know that the
+                   * dependency was not broken before so we enforce it */
+                
+                 /* check if any of the providers for 'req' is installed */
+                 for (i = 0; (p = dp[i]) != 0; i++)
+                   {
+                     if (pool->solvables[p].repo == installed)
+                       break;          /* provider was installed */
+                   }
+                 /* didn't find an installed provider: previously broken dependency */
+                 if (!p)
+                   {
+                     POOL_DEBUG(SAT_DEBUG_RULE_CREATION, "ignoring broken requires %s of installed package %s\n", dep2str(pool, req), solvable2str(pool, s));
+                     continue;
+                   }
+               }
+
+             if (!*dp)
+               {
+                 /* nothing provides req! */
+                 POOL_DEBUG(SAT_DEBUG_RULE_CREATION, "package %s [%d] is not installable (%s)\n", solvable2str(pool, s), (Id)(s - pool->solvables), dep2str(pool, req));
+                 addrpmrule(solv, -n, 0, SOLVER_RULE_RPM_NOTHING_PROVIDES_DEP, req);
+                 continue;
+               }
+
+             IF_POOLDEBUG (SAT_DEBUG_RULE_CREATION)
+               {
+                 POOL_DEBUG(SAT_DEBUG_RULE_CREATION,"  %s requires %s\n", solvable2str(pool, s), dep2str(pool, req));
+                 for (i = 0; dp[i]; i++)
+                   POOL_DEBUG(SAT_DEBUG_RULE_CREATION, "   provided by %s\n", solvid2str(pool, dp[i]));
+               }
+
+             /* add 'requires' dependency */
+              /* rule: (-requestor|provider1|provider2|...|providerN) */
+             addrpmrule(solv, -n, dp - pool->whatprovidesdata, SOLVER_RULE_RPM_PACKAGE_REQUIRES, req);
+
+             /* descend the dependency tree
+                push all non-visited providers on the work queue */
+             if (m)
+               {
+                 for (; *dp; dp++)
+                   {
+                     if (!MAPTST(m, *dp))
+                       queue_push(&workq, *dp);
+                   }
+               }
+
+           } /* while, requirements of n */
+
+       } /* if, requirements */
+
+      /* that's all we check for src packages */
+      if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
+       continue;
+
+      /*-----------------------------------------
+       * check conflicts of s
+       */
+
+      if (s->conflicts)
+       {
+         int ispatch = 0;
+
+         /* we treat conflicts in patches a bit differen:
+          * - nevr matching
+          * - multiversion handling
+          * XXX: we should really handle this different, looking
+          * at the name is a bad hack
+          */
+         if (!strncmp("patch:", id2str(pool, s->name), 6))
+           ispatch = 1;
+         conp = s->repo->idarraydata + s->conflicts;
+         /* foreach conflicts of 's' */
+         while ((con = *conp++) != 0)
+           {
+             /* foreach providers of a conflict of 's' */
+             FOR_PROVIDES(p, pp, con)
+               {
+                 if (ispatch && !pool_match_nevr(pool, pool->solvables + p, con))
+                   continue;
+                 /* dontfix: dont care about conflicts with already installed packs */
+                 if (dontfix && pool->solvables[p].repo == installed)
+                   continue;
+                 /* p == n: self conflict */
+                 if (p == n && !solv->allowselfconflicts)
+                   {
+                     if (ISRELDEP(con))
+                       {
+                         Reldep *rd = GETRELDEP(pool, con);
+                         if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_OTHERPROVIDERS)
+                           continue;
+                       }
+                     p = 0;    /* make it a negative assertion, aka 'uninstallable' */
+                   }
+                 if (p && ispatch && solv->noobsoletes.size && MAPTST(&solv->noobsoletes, p) && ISRELDEP(con))
+                   {
+                     /* our patch conflicts with a noobsoletes (aka multiversion) package */
+                     p = -makemultiversionconflict(solv, p, con);
+                   }
+                 /* rule: -n|-p: either solvable _or_ provider of conflict */
+                 addrpmrule(solv, -n, -p, p ? SOLVER_RULE_RPM_PACKAGE_CONFLICT : SOLVER_RULE_RPM_SELF_CONFLICT, con);
+               }
+           }
+       }
+
+      /*-----------------------------------------
+       * check obsoletes if not installed
+       * (only installation will trigger the obsoletes in rpm)
+       */
+      if (!installed || pool->solvables[n].repo != installed)
+       {                              /* not installed */
+         int noobs = solv->noobsoletes.size && MAPTST(&solv->noobsoletes, n);
+         if (s->obsoletes && !noobs)
+           {
+             obsp = s->repo->idarraydata + s->obsoletes;
+             /* foreach obsoletes */
+             while ((obs = *obsp++) != 0)
+               {
+                 /* foreach provider of an obsoletes of 's' */ 
+                 FOR_PROVIDES(p, pp, obs)
+                   {
+                     if (!solv->obsoleteusesprovides /* obsoletes are matched names, not provides */
+                         && !pool_match_nevr(pool, pool->solvables + p, obs))
+                       continue;
+                     addrpmrule(solv, -n, -p, SOLVER_RULE_RPM_PACKAGE_OBSOLETES, obs);
+                   }
+               }
+           }
+         FOR_PROVIDES(p, pp, s->name)
+           {
+             Solvable *ps = pool->solvables + p;
+             /* we still obsolete packages with same nevra, like rpm does */
+             /* (actually, rpm mixes those packages. yuck...) */
+             if (noobs && (s->name != ps->name || s->evr != ps->evr || s->arch != ps->arch))
+               continue;
+             if (!solv->implicitobsoleteusesprovides && s->name != ps->name)
+               continue;
+             if (s->name == ps->name)
+               addrpmrule(solv, -n, -p, SOLVER_RULE_RPM_SAME_NAME, 0);
+             else
+               addrpmrule(solv, -n, -p, SOLVER_RULE_RPM_IMPLICIT_OBSOLETES, s->name);
+           }
+       }
+
+      /*-----------------------------------------
+       * add recommends to the work queue
+       */
+      if (s->recommends && m)
+       {
+         recp = s->repo->idarraydata + s->recommends;
+         while ((rec = *recp++) != 0)
+           {
+             FOR_PROVIDES(p, pp, rec)
+               if (!MAPTST(m, p))
+                 queue_push(&workq, p);
+           }
+       }
+      if (s->suggests && m)
+       {
+         sugp = s->repo->idarraydata + s->suggests;
+         while ((sug = *sugp++) != 0)
+           {
+             FOR_PROVIDES(p, pp, sug)
+               if (!MAPTST(m, p))
+                 queue_push(&workq, p);
+           }
+       }
+    }
+  queue_free(&workq);
+  POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforsolvable end -----\n");
+}
+
+
+/*-------------------------------------------------------------------
+ * 
+ * Add package rules for weak rules
+ *
+ * m: visited solvables
+ */
+
+void
+solver_addrpmrulesforweak(Solver *solv, Map *m)
+{
+  Pool *pool = solv->pool;
+  Solvable *s;
+  Id sup, *supp;
+  int i, n;
+
+  POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforweak -----\n");
+    /* foreach solvable in pool */
+  for (i = n = 1; n < pool->nsolvables; i++, n++)
+    {
+      if (i == pool->nsolvables)               /* wrap i */
+       i = 1;
+      if (MAPTST(m, i))                                /* been there */
+       continue;
+
+      s = pool->solvables + i;
+      if (!pool_installable(pool, s))          /* only look at installable ones */
+       continue;
+
+      sup = 0;
+      if (s->supplements)
+       {
+         /* find possible supplements */
+         supp = s->repo->idarraydata + s->supplements;
+         while ((sup = *supp++) != ID_NULL)
+           if (dep_possible(solv, sup, m))
+             break;
+       }
+
+      /* if nothing found, check for enhances */
+      if (!sup && s->enhances)
+       {
+         supp = s->repo->idarraydata + s->enhances;
+         while ((sup = *supp++) != ID_NULL)
+           if (dep_possible(solv, sup, m))
+             break;
+       }
+      /* if nothing found, goto next solvables */
+      if (!sup)
+       continue;
+      solver_addrpmrulesforsolvable(solv, s, m);
+      n = 0;                   /* check all solvables again */
+    }
+  POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforweak end -----\n");
+}
+
+
+/*-------------------------------------------------------------------
+ * 
+ * add package rules for possible updates
+ * 
+ * s: solvable
+ * m: map of already visited solvables
+ * allow_all: 0 = dont allow downgrades, 1 = allow all candidates
+ */
+
+void
+solver_addrpmrulesforupdaters(Solver *solv, Solvable *s, Map *m, int allow_all)
+{
+  Pool *pool = solv->pool;
+  int i;
+    /* queue and buffer for it */
+  Queue qs;
+  Id qsbuf[64];
+
+  POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforupdaters -----\n");
+
+  queue_init_buffer(&qs, qsbuf, sizeof(qsbuf)/sizeof(*qsbuf));
+    /* find update candidates for 's' */
+  policy_findupdatepackages(solv, s, &qs, allow_all);
+    /* add rule for 's' if not already done */
+  if (!MAPTST(m, s - pool->solvables))
+    solver_addrpmrulesforsolvable(solv, s, m);
+    /* foreach update candidate, add rule if not already done */
+  for (i = 0; i < qs.count; i++)
+    if (!MAPTST(m, qs.elements[i]))
+      solver_addrpmrulesforsolvable(solv, pool->solvables + qs.elements[i], m);
+  queue_free(&qs);
+
+  POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforupdaters -----\n");
+}
+
+
+
+static void
+addrpmruleinfo(Solver *solv, Id p, Id d, int type, Id dep)
+{
+  Pool *pool = solv->pool;
+  Rule *r;
+  Id w2, op, od, ow2;
+
+  /* check if this creates the rule we're searching for */
+  r = solv->rules + solv->ruleinfoq->elements[0];
+  op = r->p;
+  od = r->d < 0 ? -r->d - 1 : r->d;
+  ow2 = 0;
+
+  /* normalize */
+  w2 = d > 0 ? 0 : d;
+  if (p < 0 && d > 0 && (!pool->whatprovidesdata[d] || !pool->whatprovidesdata[d + 1]))
+    {
+      w2 = pool->whatprovidesdata[d];
+      d = 0;
+
+    }
+  if (p > 0 && d < 0)          /* this hack is used for buddy deps */
+    {
+      w2 = p;
+      p = d;
+    }
+
+  if (d > 0)
+    {
+      if (p != op && !od)
+       return;
+      if (d != od)
+       {
+         Id *dp = pool->whatprovidesdata + d;
+         Id *odp = pool->whatprovidesdata + od;
+         while (*dp)
+           if (*dp++ != *odp++)
+             return;
+         if (*odp)
+           return;
+       }
+      w2 = 0;
+      /* handle multiversion conflict rules */
+      if (p < 0 && pool->whatprovidesdata[d] < 0)
+       {
+         w2 = pool->whatprovidesdata[d];
+         /* XXX: free memory */
+       }
+    }
+  else
+    {
+      if (od)
+       return;
+      ow2 = r->w2;
+      if (p > w2)
+       {
+         if (w2 != op || p != ow2)
+           return;
+       }
+      else
+       {
+         if (p != op || w2 != ow2)
+           return;
+       }
+    }
+  /* yep, rule matches. record info */
+  queue_push(solv->ruleinfoq, type);
+  if (type == SOLVER_RULE_RPM_SAME_NAME)
+    {
+      /* we normalize same name order */
+      queue_push(solv->ruleinfoq, op < 0 ? -op : 0);
+      queue_push(solv->ruleinfoq, ow2 < 0 ? -ow2 : 0);
+    }
+  else
+    {
+      queue_push(solv->ruleinfoq, p < 0 ? -p : 0);
+      queue_push(solv->ruleinfoq, w2 < 0 ? -w2 : 0);
+    }
+  queue_push(solv->ruleinfoq, dep);
+}
+
+static int
+solver_allruleinfos_cmp(const void *ap, const void *bp, void *dp)
+{
+  const Id *a = ap, *b = bp;
+  int r;
+
+  r = a[0] - b[0];
+  if (r)
+    return r;
+  r = a[1] - b[1];
+  if (r)
+    return r;
+  r = a[2] - b[2];
+  if (r)
+    return r;
+  r = a[3] - b[3];
+  if (r)
+    return r;
+  return 0;
+}
+
+int
+solver_allruleinfos(Solver *solv, Id rid, Queue *rq)
+{
+  Pool *pool = solv->pool;
+  Rule *r = solv->rules + rid;
+  int i, j;
+
+  queue_empty(rq);
+  if (rid <= 0 || rid >= solv->rpmrules_end)
+    {
+      Id type, from, to, dep;
+      type = solver_ruleinfo(solv, rid, &from, &to, &dep);
+      queue_push(rq, type);
+      queue_push(rq, from);
+      queue_push(rq, to);
+      queue_push(rq, dep);
+      return 1;
+    }
+  if (r->p >= 0)
+    return 0;
+  queue_push(rq, rid);
+  solv->ruleinfoq = rq;
+  solver_addrpmrulesforsolvable(solv, pool->solvables - r->p, 0);
+  /* also try reverse direction for conflicts */
+  if ((r->d == 0 || r->d == -1) && r->w2 < 0)
+    solver_addrpmrulesforsolvable(solv, pool->solvables - r->w2, 0);
+  solv->ruleinfoq = 0;
+  queue_shift(rq);
+  /* now sort & unify em */
+  if (!rq->count)
+    return 0;
+  sat_sort(rq->elements, rq->count / 4, 4 * sizeof(Id), solver_allruleinfos_cmp, 0);
+  /* throw out identical entries */
+  for (i = j = 0; i < rq->count; i += 4)
+    {
+      if (j)
+       {
+         if (rq->elements[i] == rq->elements[j - 4] && 
+             rq->elements[i + 1] == rq->elements[j - 3] &&
+             rq->elements[i + 2] == rq->elements[j - 2] &&
+             rq->elements[i + 3] == rq->elements[j - 1])
+           continue;
+       }
+      rq->elements[j++] = rq->elements[i];
+      rq->elements[j++] = rq->elements[i + 1];
+      rq->elements[j++] = rq->elements[i + 2];
+      rq->elements[j++] = rq->elements[i + 3];
+    }
+  rq->count = j;
+  return j / 4;
+}
+
+SolverRuleinfo
+solver_ruleinfo(Solver *solv, Id rid, Id *fromp, Id *top, Id *depp)
+{
+  Pool *pool = solv->pool;
+  Rule *r = solv->rules + rid;
+  SolverRuleinfo type = SOLVER_RULE_UNKNOWN;
+
+  if (fromp)
+    *fromp = 0;
+  if (top)
+    *top = 0;
+  if (depp)
+    *depp = 0;
+  if (rid > 0 && rid < solv->rpmrules_end)
+    {
+      Queue rq;
+      int i;
+
+      if (r->p >= 0)
+       return SOLVER_RULE_RPM;
+      if (fromp)
+       *fromp = -r->p;
+      queue_init(&rq);
+      queue_push(&rq, rid);
+      solv->ruleinfoq = &rq;
+      solver_addrpmrulesforsolvable(solv, pool->solvables - r->p, 0);
+      /* also try reverse direction for conflicts */
+      if ((r->d == 0 || r->d == -1) && r->w2 < 0)
+       solver_addrpmrulesforsolvable(solv, pool->solvables - r->w2, 0);
+      solv->ruleinfoq = 0;
+      type = SOLVER_RULE_RPM;
+      for (i = 1; i < rq.count; i += 4)
+       {
+         Id qt, qo, qp, qd;
+         qt = rq.elements[i];
+         qp = rq.elements[i + 1];
+         qo = rq.elements[i + 2];
+         qd = rq.elements[i + 3];
+         if (type == SOLVER_RULE_RPM || type > qt)
+           {
+             type = qt;
+             if (fromp)
+               *fromp = qp;
+             if (top)
+               *top = qo;
+             if (depp)
+               *depp = qd;
+           }
+       }
+      queue_free(&rq);
+      return type;
+    }
+  if (rid >= solv->jobrules && rid < solv->jobrules_end)
+    {
+      Id jidx = solv->ruletojob.elements[rid - solv->jobrules];
+      if (fromp)
+       *fromp = jidx;
+      if (top)
+       *top = solv->job.elements[jidx];
+      if (depp)
+       *depp = solv->job.elements[jidx + 1];
+      if ((r->d == 0 || r->d == -1) && r->w2 == 0 && r->p == -SYSTEMSOLVABLE && (solv->job.elements[jidx] & SOLVER_SELECTMASK) != SOLVER_SOLVABLE_ONE_OF)
+       return SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP;
+      return SOLVER_RULE_JOB;
+    }
+  if (rid >= solv->updaterules && rid < solv->updaterules_end)
+    {
+      if (fromp)
+       *fromp = solv->installed->start + (rid - solv->updaterules);
+      return SOLVER_RULE_UPDATE;
+    }
+  if (rid >= solv->featurerules && rid < solv->featurerules_end)
+    {
+      if (fromp)
+       *fromp = solv->installed->start + (rid - solv->featurerules);
+      return SOLVER_RULE_FEATURE;
+    }
+  if (rid >= solv->duprules && rid < solv->duprules_end)
+    {
+      if (fromp)
+       *fromp = -r->p;
+      if (depp)
+       *depp = pool->solvables[-r->p].name;
+      return SOLVER_RULE_DISTUPGRADE;
+    }
+  if (rid >= solv->infarchrules && rid < solv->infarchrules_end)
+    {
+      if (fromp)
+       *fromp = -r->p;
+      if (depp)
+       *depp = pool->solvables[-r->p].name;
+      return SOLVER_RULE_INFARCH;
+    }
+  if (rid >= solv->learntrules)
+    {
+      return SOLVER_RULE_LEARNT;
+    }
+  return SOLVER_RULE_UNKNOWN;
+}
+
+/* EOF */
diff --git a/src/rules.h b/src/rules.h
new file mode 100644 (file)
index 0000000..084fecd
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2007-2009, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * rules.h
+ *
+ */
+
+#ifndef SATSOLVER_RULES_H
+#define SATSOLVER_RULES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ----------------------------------------------
+ * Rule
+ *
+ *   providerN(B) == Package Id of package providing tag B
+ *   N = 1, 2, 3, in case of multiple providers
+ *
+ * A requires B : !A | provider1(B) | provider2(B)
+ *
+ * A conflicts B : (!A | !provider1(B)) & (!A | !provider2(B)) ...
+ *
+ * 'not' is encoded as a negative Id
+ *
+ * Binary rule: p = first literal, d = 0, w2 = second literal, w1 = p
+ *
+ * There are a lot of rules, so the struct is kept as small as
+ * possible. Do not add new members unless there is no other way.
+ */
+
+typedef struct _Rule {
+  Id p;                /* first literal in rule */
+  Id d;                /* Id offset into 'list of providers terminated by 0' as used by whatprovides; pool->whatprovides + d */
+               /* in case of binary rules, d == 0, w1 == p, w2 == other literal */
+               /* in case of disabled rules: ~d, aka -d - 1 */
+  Id w1, w2;   /* watches, literals not-yet-decided */
+               /* if !w2, assertion, not rule */
+  Id n1, n2;   /* next rules in linked list, corresponding to w1, w2 */
+} Rule;
+
+
+typedef enum {
+  SOLVER_RULE_UNKNOWN = 0,
+  SOLVER_RULE_RPM = 0x100,
+  SOLVER_RULE_RPM_NOT_INSTALLABLE,
+  SOLVER_RULE_RPM_NOTHING_PROVIDES_DEP,
+  SOLVER_RULE_RPM_PACKAGE_REQUIRES,
+  SOLVER_RULE_RPM_SELF_CONFLICT,
+  SOLVER_RULE_RPM_PACKAGE_CONFLICT,
+  SOLVER_RULE_RPM_SAME_NAME,
+  SOLVER_RULE_RPM_PACKAGE_OBSOLETES,
+  SOLVER_RULE_RPM_IMPLICIT_OBSOLETES,
+  SOLVER_RULE_UPDATE = 0x200,
+  SOLVER_RULE_FEATURE = 0x300,
+  SOLVER_RULE_JOB = 0x400,
+  SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP,
+  SOLVER_RULE_DISTUPGRADE = 0x500,
+  SOLVER_RULE_INFARCH = 0x600,
+  SOLVER_RULE_LEARNT = 0x700
+} SolverRuleinfo;
+
+#define SOLVER_RULE_TYPEMASK    0xff00
+
+struct _Solver;
+
+/*-------------------------------------------------------------------
+ * disable rule
+ */
+
+static inline void
+solver_disablerule(struct _Solver *solv, Rule *r)
+{
+  if (r->d >= 0)
+    r->d = -r->d - 1;
+}
+
+/*-------------------------------------------------------------------
+ * enable rule
+ */
+
+static inline void
+solver_enablerule(struct _Solver *solv, Rule *r)
+{
+  if (r->d < 0)
+    r->d = -r->d - 1;
+}
+
+Rule *solver_addrule(struct _Solver *solv, Id p, Id d);
+void solver_unifyrules(struct _Solver *solv);
+int solver_samerule(struct _Solver *solv, Rule *r1, Rule *r2);
+void solver_addrpmrulesforsolvable(struct _Solver *solv, Solvable *s, Map *m);
+void solver_addrpmrulesforweak(struct _Solver *solv, Map *m);
+void solver_addrpmrulesforupdaters(struct _Solver *solv, Solvable *s, Map *m, int allow_all);
+int solver_allruleinfos(struct _Solver *solv, Id rid, Queue *rq);
+SolverRuleinfo solver_ruleinfo(struct _Solver *solv, Id rid, Id *fromp, Id *top, Id *depp);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
index b994d52..8762540 100644 (file)
@@ -28,7 +28,6 @@
 #define RULES_BLOCK 63
 
 static void reenablepolicyrules(Solver *solv, int jobidx);
-static void addrpmruleinfo(Solver *solv, Id p, Id d, int type, Id dep);
 
 /********************************************************************
  *
@@ -98,367 +97,6 @@ solver_dep_installed(Solver *solv, Id dep)
 }
 
 
-/*-------------------------------------------------------------------
- * Check if dependenc is possible
- * 
- * this mirrors solver_dep_fulfilled
- * but uses map m instead of the decisionmap
- */
-
-static inline int
-dep_possible(Solver *solv, Id dep, Map *m)
-{
-  Pool *pool = solv->pool;
-  Id p, pp;
-
-  if (ISRELDEP(dep))
-    {
-      Reldep *rd = GETRELDEP(pool, dep);
-      if (rd->flags == REL_AND)
-       {
-         if (!dep_possible(solv, rd->name, m))
-           return 0;
-         return dep_possible(solv, rd->evr, m);
-       }
-      if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES)
-       return solver_splitprovides(solv, rd->evr);
-      if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_INSTALLED)
-       return solver_dep_installed(solv, rd->evr);
-    }
-  FOR_PROVIDES(p, pp, dep)
-    {
-      if (MAPTST(m, p))
-       return 1;
-    }
-  return 0;
-}
-
-/********************************************************************
- *
- * Rule handling
- *
- * - unify rules, remove duplicates
- */
-
-/*-------------------------------------------------------------------
- *
- * compare rules for unification sort
- *
- */
-
-static int
-unifyrules_sortcmp(const void *ap, const void *bp, void *dp)
-{
-  Pool *pool = dp;
-  Rule *a = (Rule *)ap;
-  Rule *b = (Rule *)bp;
-  Id *ad, *bd;
-  int x;
-
-  x = a->p - b->p;
-  if (x)
-    return x;                         /* p differs */
-
-  /* identical p */
-  if (a->d == 0 && b->d == 0)
-    return a->w2 - b->w2;             /* assertion: return w2 diff */
-
-  if (a->d == 0)                      /* a is assertion, b not */
-    {
-      x = a->w2 - pool->whatprovidesdata[b->d];
-      return x ? x : -1;
-    }
-
-  if (b->d == 0)                      /* b is assertion, a not */
-    {
-      x = pool->whatprovidesdata[a->d] - b->w2;
-      return x ? x : 1;
-    }
-
-  /* compare whatprovidesdata */
-  ad = pool->whatprovidesdata + a->d;
-  bd = pool->whatprovidesdata + b->d;
-  while (*bd)
-    if ((x = *ad++ - *bd++) != 0)
-      return x;
-  return *ad;
-}
-
-
-/*-------------------------------------------------------------------
- *
- * unify rules
- * go over all rules and remove duplicates
- */
-
-static void
-unifyrules(Solver *solv)
-{
-  Pool *pool = solv->pool;
-  int i, j;
-  Rule *ir, *jr;
-
-  if (solv->nrules <= 1)              /* nothing to unify */
-    return;
-
-  POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- unifyrules -----\n");
-
-  /* sort rules first */
-  sat_sort(solv->rules + 1, solv->nrules - 1, sizeof(Rule), unifyrules_sortcmp, solv->pool);
-
-  /* prune rules
-   * i = unpruned
-   * j = pruned
-   */
-  jr = 0;
-  for (i = j = 1, ir = solv->rules + i; i < solv->nrules; i++, ir++)
-    {
-      if (jr && !unifyrules_sortcmp(ir, jr, pool))
-       continue;                      /* prune! */
-      jr = solv->rules + j++;         /* keep! */
-      if (ir != jr)
-        *jr = *ir;
-    }
-
-  /* reduced count from nrules to j rules */
-  POOL_DEBUG(SAT_DEBUG_STATS, "pruned rules from %d to %d\n", solv->nrules, j);
-
-  /* adapt rule buffer */
-  solv->nrules = j;
-  solv->rules = sat_extend_resize(solv->rules, solv->nrules, sizeof(Rule), RULES_BLOCK);
-    /*
-     * debug: statistics
-     */
-  IF_POOLDEBUG (SAT_DEBUG_STATS)
-    {
-      int binr = 0;
-      int lits = 0;
-      Id *dp;
-      Rule *r;
-
-      for (i = 1; i < solv->nrules; i++)
-       {
-         r = solv->rules + i;
-         if (r->d == 0)
-           binr++;
-         else
-           {
-             dp = solv->pool->whatprovidesdata + r->d;
-             while (*dp++)
-               lits++;
-           }
-       }
-      POOL_DEBUG(SAT_DEBUG_STATS, "  binary: %d\n", binr);
-      POOL_DEBUG(SAT_DEBUG_STATS, "  normal: %d, %d literals\n", solv->nrules - 1 - binr, lits);
-    }
-  POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- unifyrules end -----\n");
-}
-
-#if 0
-
-/*
- * hash rule
- */
-
-static Hashval
-hashrule(Solver *solv, Id p, Id d, int n)
-{
-  unsigned int x = (unsigned int)p;
-  int *dp;
-
-  if (n <= 1)
-    return (x * 37) ^ (unsigned int)d;
-  dp = solv->pool->whatprovidesdata + d;
-  while (*dp)
-    x = (x * 37) ^ (unsigned int)*dp++;
-  return x;
-}
-#endif
-
-
-/*-------------------------------------------------------------------
- * 
- */
-
-/*
- * add rule
- *  p = direct literal; always < 0 for installed rpm rules
- *  d, if < 0 direct literal, if > 0 offset into whatprovides, if == 0 rule is assertion (look at p only)
- *
- *
- * A requires b, b provided by B1,B2,B3 => (-A|B1|B2|B3)
- *
- * p < 0 : pkg id of A
- * d > 0 : Offset in whatprovidesdata (list of providers of b)
- *
- * A conflicts b, b provided by B1,B2,B3 => (-A|-B1), (-A|-B2), (-A|-B3)
- * p < 0 : pkg id of A
- * d < 0 : Id of solvable (e.g. B1)
- *
- * d == 0: unary rule, assertion => (A) or (-A)
- *
- *   Install:    p > 0, d = 0   (A)             user requested install
- *   Remove:     p < 0, d = 0   (-A)            user requested remove (also: uninstallable)
- *   Requires:   p < 0, d > 0   (-A|B1|B2|...)  d: <list of providers for requirement of p>
- *   Updates:    p > 0, d > 0   (A|B1|B2|...)   d: <list of updates for solvable p>
- *   Conflicts:  p < 0, d < 0   (-A|-B)         either p (conflict issuer) or d (conflict provider) (binary rule)
- *                                              also used for obsoletes
- *   ?:          p > 0, d < 0   (A|-B)          
- *   No-op ?:    p = 0, d = 0   (null)          (used as policy rule placeholder)
- *
- *   resulting watches:
- *   ------------------
- *   Direct assertion (no watch needed)( if d <0 ) --> d = 0, w1 = p, w2 = 0
- *   Binary rule: p = first literal, d = 0, w2 = second literal, w1 = p
- *   every other : w1 = p, w2 = whatprovidesdata[d];
- *   Disabled rule: w1 = 0
- *
- *   always returns a rule for non-rpm rules
- */
-
-static Rule *
-addrule(Solver *solv, Id p, Id d)
-{
-  Pool *pool = solv->pool;
-  Rule *r = 0;
-  Id *dp = 0;
-
-  int n = 0;                          /* number of literals in rule - 1
-                                         0 = direct assertion (single literal)
-                                         1 = binary rule
-                                         >1 = 
-                                       */
-
-  /* it often happenes that requires lead to adding the same rpm rule
-   * multiple times, so we prune those duplicates right away to make
-   * the work for unifyrules a bit easier */
-
-  if (solv->nrules                      /* we already have rules */
-      && !solv->rpmrules_end)           /* but are not done with rpm rules */
-    {
-      r = solv->rules + solv->nrules - 1;   /* get the last added rule */
-      if (r->p == p && r->d == d && d != 0)   /* identical and not user requested */
-       return r;
-    }
-
-    /*
-     * compute number of literals (n) in rule
-     */
-    
-  if (d < 0)
-    {
-      /* always a binary rule */
-      if (p == d)
-       return 0;                      /* ignore self conflict */
-      n = 1;
-    }
-  else if (d > 0)
-    {
-      for (dp = pool->whatprovidesdata + d; *dp; dp++, n++)
-       if (*dp == -p)
-         return 0;                     /* rule is self-fulfilling */
-       
-      if (n == 1)   /* have single provider */
-       d = dp[-1];                     /* take single literal */
-    }
-
-  if (n == 1 && p > d && !solv->rpmrules_end)
-    {
-      /* smallest literal first so we can find dups */
-      n = p; p = d; d = n;             /* p <-> d */
-      n = 1;                          /* re-set n, was used as temp var */
-    }
-
-  /*
-   * check for duplicate
-   */
-    
-  /* check if the last added rule (r) is exactly the same as what we're looking for. */
-  if (r && n == 1 && !r->d && r->p == p && r->w2 == d)
-    return r;  /* binary rule */
-
-    /* have n-ary rule with same first literal, check other literals */
-  if (r && n > 1 && r->d && r->p == p)
-    {
-      /* Rule where d is an offset in whatprovidesdata */
-      Id *dp2;
-      if (d == r->d)
-       return r;
-      dp2 = pool->whatprovidesdata + r->d;
-      for (dp = pool->whatprovidesdata + d; *dp; dp++, dp2++)
-       if (*dp != *dp2)
-         break;
-      if (*dp == *dp2)
-       return r;
-   }
-
-  /*
-   * allocate new rule
-   */
-
-  /* extend rule buffer */
-  solv->rules = sat_extend(solv->rules, solv->nrules, 1, sizeof(Rule), RULES_BLOCK);
-  r = solv->rules + solv->nrules++;    /* point to rule space */
-
-    /*
-     * r = new rule
-     */
-    
-  r->p = p;
-  if (n == 0)
-    {
-      /* direct assertion, no watch needed */
-      r->d = 0;
-      r->w1 = p;
-      r->w2 = 0;
-    }
-  else if (n == 1)
-    {
-      /* binary rule */
-      r->d = 0;
-      r->w1 = p;
-      r->w2 = d;
-    }
-  else
-    {
-      r->d = d;
-      r->w1 = p;
-      r->w2 = pool->whatprovidesdata[d];
-    }
-  r->n1 = 0;
-  r->n2 = 0;
-
-  IF_POOLDEBUG (SAT_DEBUG_RULE_CREATION)
-    {
-      POOL_DEBUG(SAT_DEBUG_RULE_CREATION, "  Add rule: ");
-      solver_printrule(solv, SAT_DEBUG_RULE_CREATION, r);
-    }
-
-  return r;
-}
-
-/*-------------------------------------------------------------------
- * disable rule
- */
-
-static inline void
-disablerule(Solver *solv, Rule *r)
-{
-  if (r->d >= 0)
-    r->d = -r->d - 1;
-}
-
-/*-------------------------------------------------------------------
- * enable rule
- */
-
-static inline void
-enablerule(Solver *solv, Rule *r)
-{
-  if (r->d < 0)
-    r->d = -r->d - 1;
-}
-
 
 /**********************************************************************************/
 
@@ -483,7 +121,7 @@ disableproblem(Solver *solv, Id v)
          while (v > solv->infarchrules && pool->solvables[-solv->rules[v - 1].p].name == name)
            v--;
          for (; v < solv->infarchrules_end && pool->solvables[-solv->rules[v].p].name == name; v++)
-           disablerule(solv, solv->rules + v);
+           solver_disablerule(solv, solv->rules + v);
          return;
        }
       if (v >= solv->duprules && v < solv->duprules_end)
@@ -493,17 +131,17 @@ disableproblem(Solver *solv, Id v)
          while (v > solv->duprules && pool->solvables[-solv->rules[v - 1].p].name == name)
            v--;
          for (; v < solv->duprules_end && pool->solvables[-solv->rules[v].p].name == name; v++)
-           disablerule(solv, solv->rules + v);
+           solver_disablerule(solv, solv->rules + v);
          return;
        }
-      disablerule(solv, solv->rules + v);
+      solver_disablerule(solv, solv->rules + v);
       return;
     }
   v = -(v + 1);
   jp = solv->ruletojob.elements;
   for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++, jp++)
     if (*jp == v)
-      disablerule(solv, r);
+      solver_disablerule(solv, r);
 }
 
 /*-------------------------------------------------------------------
@@ -526,7 +164,7 @@ enableproblem(Solver *solv, Id v)
          while (v > solv->infarchrules && pool->solvables[-solv->rules[v - 1].p].name == name)
            v--;
          for (; v < solv->infarchrules_end && pool->solvables[-solv->rules[v].p].name == name; v++)
-           enablerule(solv, solv->rules + v);
+           solver_enablerule(solv, solv->rules + v);
          return;
        }
       if (v >= solv->duprules && v < solv->duprules_end)
@@ -536,7 +174,7 @@ enableproblem(Solver *solv, Id v)
          while (v > solv->duprules && pool->solvables[-solv->rules[v - 1].p].name == name)
            v--;
          for (; v < solv->duprules_end && pool->solvables[-solv->rules[v].p].name == name; v++)
-           enablerule(solv, solv->rules + v);
+           solver_enablerule(solv, solv->rules + v);
          return;
        }
       if (v >= solv->featurerules && v < solv->featurerules_end)
@@ -546,13 +184,13 @@ enableproblem(Solver *solv, Id v)
          if (r->d >= 0)
            return;
        }
-      enablerule(solv, solv->rules + v);
+      solver_enablerule(solv, solv->rules + v);
       if (v >= solv->updaterules && v < solv->updaterules_end)
        {
          /* disable feature rule when enabling update rule */
          r = solv->rules + (v - solv->updaterules + solv->featurerules);
          if (r->p)
-           disablerule(solv, r);
+           solver_disablerule(solv, r);
        }
       return;
     }
@@ -560,7 +198,7 @@ enableproblem(Solver *solv, Id v)
   jp = solv->ruletojob.elements;
   for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++, jp++)
     if (*jp == v)
-      enablerule(solv, r);
+      solver_enablerule(solv, r);
 }
 
 
@@ -646,7 +284,7 @@ makeruledecisions(Solver *solv)
          /* can happen when packages cannot be installed for
            * multiple reasons. */
           /* we disable the learnt rule in this case */
-         disablerule(solv, r);
+         solver_disablerule(solv, r);
          continue;
        }
        
@@ -849,7 +487,7 @@ enabledisablelearntrules(Solver *solv)
              POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "disabling ");
              solver_printruleclass(solv, SAT_DEBUG_SOLUTIONS, r);
            }
-          disablerule(solv, r);
+          solver_disablerule(solv, r);
        }
       else if (!why && r->d < 0)
        {
@@ -858,7 +496,7 @@ enabledisablelearntrules(Solver *solv)
              POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "re-enabling ");
              solver_printruleclass(solv, SAT_DEBUG_SOLUTIONS, r);
            }
-          enablerule(solv, r);
+          solver_enablerule(solv, r);
        }
     }
 }
@@ -883,7 +521,7 @@ enableweakrules(Solver *solv)
        continue;
       if (!MAPTST(&solv->weakrulemap, i))
        continue;
-      enablerule(solv, r);
+      solver_enablerule(solv, r);
     }
 }
 
@@ -905,7 +543,7 @@ disableinfarchrule(Solver *solv, Id name)
   for (i = solv->infarchrules, r = solv->rules + i; i < solv->infarchrules_end; i++, r++)
     {
       if (r->p < 0 && r->d >= 0 && pool->solvables[-r->p].name == name)
-       disablerule(solv, r);
+       solver_disablerule(solv, r);
     }
 }
 
@@ -919,7 +557,7 @@ reenableinfarchrule(Solver *solv, Id name)
     {
       if (r->p < 0 && r->d < 0 && pool->solvables[-r->p].name == name)
        {
-         enablerule(solv, r);
+         solver_enablerule(solv, r);
          IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
            {
              POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "@@@ re-enabling ");
@@ -938,7 +576,7 @@ disableduprule(Solver *solv, Id name)
   for (i = solv->duprules, r = solv->rules + i; i < solv->duprules_end; i++, r++)
     {
       if (r->p < 0 && r->d >= 0 && pool->solvables[-r->p].name == name)
-       disablerule(solv, r);
+       solver_disablerule(solv, r);
     }
 }
 
@@ -952,7 +590,7 @@ reenableduprule(Solver *solv, Id name)
     {
       if (r->p < 0 && r->d < 0 && pool->solvables[-r->p].name == name)
        {
-         enablerule(solv, r);
+         solver_enablerule(solv, r);
          IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
            {
              POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "@@@ re-enabling ");
@@ -970,10 +608,10 @@ disableupdaterule(Solver *solv, Id p)
   MAPSET(&solv->noupdate, p - solv->installed->start);
   r = solv->rules + solv->updaterules + (p - solv->installed->start);
   if (r->p && r->d >= 0)
-    disablerule(solv, r);
+    solver_disablerule(solv, r);
   r = solv->rules + solv->featurerules + (p - solv->installed->start);
   if (r->p && r->d >= 0)
-    disablerule(solv, r);
+    solver_disablerule(solv, r);
 }
 
 static inline void
@@ -988,7 +626,7 @@ reenableupdaterule(Solver *solv, Id p)
     {
       if (r->d >= 0)
        return;
-      enablerule(solv, r);
+      solver_enablerule(solv, r);
       IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
        {
          POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "@@@ re-enabling ");
@@ -999,7 +637,7 @@ reenableupdaterule(Solver *solv, Id p)
   r = solv->rules + solv->featurerules + (p - solv->installed->start);
   if (r->p && r->d < 0)
     {
-      enablerule(solv, r);
+      solver_enablerule(solv, r);
       IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
        {
          POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "@@@ re-enabling ");
@@ -1215,438 +853,6 @@ reenablepolicyrules(Solver *solv, int jobidx)
  *
  */
 
-/*
- *  special multiversion patch conflict handling:
- *  a patch conflict is also satisfied, if some other
- *  version with the same name/arch that doesn't conflict
- *  get's installed. The generated rule is thus:
- *  -patch|-cpack|opack1|opack2|...
- */
-static Id
-makemultiversionconflict(Solver *solv, Id n, Id con)
-{
-  Pool *pool = solv->pool;
-  Solvable *s, *sn;
-  Queue q;
-  Id p, pp, qbuf[64];
-
-  sn = pool->solvables + n;
-  queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf));
-  queue_push(&q, -n);
-  FOR_PROVIDES(p, pp, sn->name)
-    {
-      s = pool->solvables + p;
-      if (s->name != sn->name || s->arch != sn->arch)
-       continue;
-      if (!MAPTST(&solv->noobsoletes, p))
-       continue;
-      if (pool_match_nevr(pool, pool->solvables + p, con))
-       continue;
-      /* here we have a multiversion solvable that doesn't conflict */
-      /* thus we're not in conflict if it is installed */
-      queue_push(&q, p);
-    }
-  if (q.count == 1)
-    return -n; /* no other package found, generate normal conflict */
-  return pool_queuetowhatprovides(pool, &q);
-}
-
-static inline void
-addrpmrule(Solver *solv, Id p, Id d, int type, Id dep)
-{
-  if (!solv->ruleinfoq)
-    addrule(solv, p, d);
-  else
-    addrpmruleinfo(solv, p, d, type, dep);
-}
-
-/*-------------------------------------------------------------------
- * 
- * add (install) rules for solvable
- * 
- * s: Solvable for which to add rules
- * m: m[s] = 1 for solvables which have rules, prevent rule duplication
- * 
- * Algorithm: 'visit all nodes of a graph'. The graph nodes are
- *  solvables, the edges their dependencies.
- *  Starting from an installed solvable, this will create all rules
- *  representing the graph created by the solvables dependencies.
- * 
- * for unfulfilled requirements, conflicts, obsoletes,....
- * add a negative assertion for solvables that are not installable
- * 
- * It will also create rules for all solvables referenced by 's'
- *  i.e. descend to all providers of requirements of 's'
- *
- */
-
-static void
-addrpmrulesforsolvable(Solver *solv, Solvable *s, Map *m)
-{
-  Pool *pool = solv->pool;
-  Repo *installed = solv->installed;
-
-  /* 'work' queue. keeps Ids of solvables we still have to work on.
-     And buffer for it. */
-  Queue workq;
-  Id workqbuf[64];
-    
-  int i;
-    /* if to add rules for broken deps ('rpm -V' functionality)
-     * 0 = yes, 1 = no
-     */
-  int dontfix;
-    /* Id var and pointer for each dependency
-     * (not used in parallel)
-     */
-  Id req, *reqp;
-  Id con, *conp;
-  Id obs, *obsp;
-  Id rec, *recp;
-  Id sug, *sugp;
-  Id p, pp;            /* whatprovides loops */
-  Id *dp;              /* ptr to 'whatprovides' */
-  Id n;                        /* Id for current solvable 's' */
-
-  POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforsolvable -----\n");
-
-  queue_init_buffer(&workq, workqbuf, sizeof(workqbuf)/sizeof(*workqbuf));
-  queue_push(&workq, s - pool->solvables);     /* push solvable Id to work queue */
-
-  /* loop until there's no more work left */
-  while (workq.count)
-    {
-      /*
-       * n: Id of solvable
-       * s: Pointer to solvable
-       */
-
-      n = queue_shift(&workq);         /* 'pop' next solvable to work on from queue */
-      if (m)
-       {
-         if (MAPTST(m, n))             /* continue if already visited */
-           continue;
-         MAPSET(m, n);                 /* mark as visited */
-       }
-
-      s = pool->solvables + n;         /* s = Solvable in question */
-
-      dontfix = 0;
-      if (installed                    /* Installed system available */
-         && !solv->fixsystem           /* NOT repair errors in rpm dependency graph */
-         && s->repo == installed)      /* solvable is installed? */
-        {
-         dontfix = 1;                  /* dont care about broken rpm deps */
-        }
-
-      if (!dontfix
-         && s->arch != ARCH_SRC
-         && s->arch != ARCH_NOSRC
-         && !pool_installable(pool, s))
-       {
-         POOL_DEBUG(SAT_DEBUG_RULE_CREATION, "package %s [%d] is not installable\n", solvable2str(pool, s), (Id)(s - pool->solvables));
-         addrpmrule(solv, -n, 0, SOLVER_RULE_RPM_NOT_INSTALLABLE, 0);
-       }
-
-      /* yet another SUSE hack, sigh */
-      if (pool->nscallback && !strncmp("product:", id2str(pool, s->name), 8))
-        {
-          Id buddy = pool->nscallback(pool, pool->nscallbackdata, NAMESPACE_PRODUCTBUDDY, n);
-          if (buddy > 0 && buddy != SYSTEMSOLVABLE && buddy != n && buddy < pool->nsolvables)
-            {
-              addrpmrule(solv, n, -buddy, SOLVER_RULE_RPM_PACKAGE_REQUIRES, solvable_selfprovidedep(pool->solvables + n));
-              addrpmrule(solv, buddy, -n, SOLVER_RULE_RPM_PACKAGE_REQUIRES, solvable_selfprovidedep(pool->solvables + buddy)); 
-             if (m && !MAPTST(m, buddy))
-               queue_push(&workq, buddy);
-            }
-        }
-
-      /*-----------------------------------------
-       * check requires of s
-       */
-
-      if (s->requires)
-       {
-         reqp = s->repo->idarraydata + s->requires;
-         while ((req = *reqp++) != 0)            /* go through all requires */
-           {
-             if (req == SOLVABLE_PREREQMARKER)   /* skip the marker */
-               continue;
-
-             /* find list of solvables providing 'req' */
-             dp = pool_whatprovides_ptr(pool, req);
-
-             if (*dp == SYSTEMSOLVABLE)          /* always installed */
-               continue;
-
-             if (dontfix)
-               {
-                 /* the strategy here is to not insist on dependencies
-                   * that are already broken. so if we find one provider
-                   * that was already installed, we know that the
-                   * dependency was not broken before so we enforce it */
-                
-                 /* check if any of the providers for 'req' is installed */
-                 for (i = 0; (p = dp[i]) != 0; i++)
-                   {
-                     if (pool->solvables[p].repo == installed)
-                       break;          /* provider was installed */
-                   }
-                 /* didn't find an installed provider: previously broken dependency */
-                 if (!p)
-                   {
-                     POOL_DEBUG(SAT_DEBUG_RULE_CREATION, "ignoring broken requires %s of installed package %s\n", dep2str(pool, req), solvable2str(pool, s));
-                     continue;
-                   }
-               }
-
-             if (!*dp)
-               {
-                 /* nothing provides req! */
-                 POOL_DEBUG(SAT_DEBUG_RULE_CREATION, "package %s [%d] is not installable (%s)\n", solvable2str(pool, s), (Id)(s - pool->solvables), dep2str(pool, req));
-                 addrpmrule(solv, -n, 0, SOLVER_RULE_RPM_NOTHING_PROVIDES_DEP, req);
-                 continue;
-               }
-
-             IF_POOLDEBUG (SAT_DEBUG_RULE_CREATION)
-               {
-                 POOL_DEBUG(SAT_DEBUG_RULE_CREATION,"  %s requires %s\n", solvable2str(pool, s), dep2str(pool, req));
-                 for (i = 0; dp[i]; i++)
-                   POOL_DEBUG(SAT_DEBUG_RULE_CREATION, "   provided by %s\n", solvid2str(pool, dp[i]));
-               }
-
-             /* add 'requires' dependency */
-              /* rule: (-requestor|provider1|provider2|...|providerN) */
-             addrpmrule(solv, -n, dp - pool->whatprovidesdata, SOLVER_RULE_RPM_PACKAGE_REQUIRES, req);
-
-             /* descend the dependency tree
-                push all non-visited providers on the work queue */
-             if (m)
-               {
-                 for (; *dp; dp++)
-                   {
-                     if (!MAPTST(m, *dp))
-                       queue_push(&workq, *dp);
-                   }
-               }
-
-           } /* while, requirements of n */
-
-       } /* if, requirements */
-
-      /* that's all we check for src packages */
-      if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
-       continue;
-
-      /*-----------------------------------------
-       * check conflicts of s
-       */
-
-      if (s->conflicts)
-       {
-         int ispatch = 0;
-
-         /* we treat conflicts in patches a bit differen:
-          * - nevr matching
-          * - multiversion handling
-          * XXX: we should really handle this different, looking
-          * at the name is a bad hack
-          */
-         if (!strncmp("patch:", id2str(pool, s->name), 6))
-           ispatch = 1;
-         conp = s->repo->idarraydata + s->conflicts;
-         /* foreach conflicts of 's' */
-         while ((con = *conp++) != 0)
-           {
-             /* foreach providers of a conflict of 's' */
-             FOR_PROVIDES(p, pp, con)
-               {
-                 if (ispatch && !pool_match_nevr(pool, pool->solvables + p, con))
-                   continue;
-                 /* dontfix: dont care about conflicts with already installed packs */
-                 if (dontfix && pool->solvables[p].repo == installed)
-                   continue;
-                 /* p == n: self conflict */
-                 if (p == n && !solv->allowselfconflicts)
-                   {
-                     if (ISRELDEP(con))
-                       {
-                         Reldep *rd = GETRELDEP(pool, con);
-                         if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_OTHERPROVIDERS)
-                           continue;
-                       }
-                     p = 0;    /* make it a negative assertion, aka 'uninstallable' */
-                   }
-                 if (p && ispatch && solv->noobsoletes.size && MAPTST(&solv->noobsoletes, p) && ISRELDEP(con))
-                   {
-                     /* our patch conflicts with a noobsoletes (aka multiversion) package */
-                     p = -makemultiversionconflict(solv, p, con);
-                   }
-                 /* rule: -n|-p: either solvable _or_ provider of conflict */
-                 addrpmrule(solv, -n, -p, p ? SOLVER_RULE_RPM_PACKAGE_CONFLICT : SOLVER_RULE_RPM_SELF_CONFLICT, con);
-               }
-           }
-       }
-
-      /*-----------------------------------------
-       * check obsoletes if not installed
-       * (only installation will trigger the obsoletes in rpm)
-       */
-      if (!installed || pool->solvables[n].repo != installed)
-       {                              /* not installed */
-         int noobs = solv->noobsoletes.size && MAPTST(&solv->noobsoletes, n);
-         if (s->obsoletes && !noobs)
-           {
-             obsp = s->repo->idarraydata + s->obsoletes;
-             /* foreach obsoletes */
-             while ((obs = *obsp++) != 0)
-               {
-                 /* foreach provider of an obsoletes of 's' */ 
-                 FOR_PROVIDES(p, pp, obs)
-                   {
-                     if (!solv->obsoleteusesprovides /* obsoletes are matched names, not provides */
-                         && !pool_match_nevr(pool, pool->solvables + p, obs))
-                       continue;
-                     addrpmrule(solv, -n, -p, SOLVER_RULE_RPM_PACKAGE_OBSOLETES, obs);
-                   }
-               }
-           }
-         FOR_PROVIDES(p, pp, s->name)
-           {
-             Solvable *ps = pool->solvables + p;
-             /* we still obsolete packages with same nevra, like rpm does */
-             /* (actually, rpm mixes those packages. yuck...) */
-             if (noobs && (s->name != ps->name || s->evr != ps->evr || s->arch != ps->arch))
-               continue;
-             if (!solv->implicitobsoleteusesprovides && s->name != ps->name)
-               continue;
-             if (s->name == ps->name)
-               addrpmrule(solv, -n, -p, SOLVER_RULE_RPM_SAME_NAME, 0);
-             else
-               addrpmrule(solv, -n, -p, SOLVER_RULE_RPM_IMPLICIT_OBSOLETES, s->name);
-           }
-       }
-
-      /*-----------------------------------------
-       * add recommends to the work queue
-       */
-      if (s->recommends && m)
-       {
-         recp = s->repo->idarraydata + s->recommends;
-         while ((rec = *recp++) != 0)
-           {
-             FOR_PROVIDES(p, pp, rec)
-               if (!MAPTST(m, p))
-                 queue_push(&workq, p);
-           }
-       }
-      if (s->suggests && m)
-       {
-         sugp = s->repo->idarraydata + s->suggests;
-         while ((sug = *sugp++) != 0)
-           {
-             FOR_PROVIDES(p, pp, sug)
-               if (!MAPTST(m, p))
-                 queue_push(&workq, p);
-           }
-       }
-    }
-  queue_free(&workq);
-  POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforsolvable end -----\n");
-}
-
-
-/*-------------------------------------------------------------------
- * 
- * Add package rules for weak rules
- *
- * m: visited solvables
- */
-
-static void
-addrpmrulesforweak(Solver *solv, Map *m)
-{
-  Pool *pool = solv->pool;
-  Solvable *s;
-  Id sup, *supp;
-  int i, n;
-
-  POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforweak -----\n");
-    /* foreach solvable in pool */
-  for (i = n = 1; n < pool->nsolvables; i++, n++)
-    {
-      if (i == pool->nsolvables)               /* wrap i */
-       i = 1;
-      if (MAPTST(m, i))                                /* been there */
-       continue;
-
-      s = pool->solvables + i;
-      if (!pool_installable(pool, s))          /* only look at installable ones */
-       continue;
-
-      sup = 0;
-      if (s->supplements)
-       {
-         /* find possible supplements */
-         supp = s->repo->idarraydata + s->supplements;
-         while ((sup = *supp++) != ID_NULL)
-           if (dep_possible(solv, sup, m))
-             break;
-       }
-
-      /* if nothing found, check for enhances */
-      if (!sup && s->enhances)
-       {
-         supp = s->repo->idarraydata + s->enhances;
-         while ((sup = *supp++) != ID_NULL)
-           if (dep_possible(solv, sup, m))
-             break;
-       }
-      /* if nothing found, goto next solvables */
-      if (!sup)
-       continue;
-      addrpmrulesforsolvable(solv, s, m);
-      n = 0;                   /* check all solvables again */
-    }
-  POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforweak end -----\n");
-}
-
-
-/*-------------------------------------------------------------------
- * 
- * add package rules for possible updates
- * 
- * s: solvable
- * m: map of already visited solvables
- * allow_all: 0 = dont allow downgrades, 1 = allow all candidates
- */
-
-static void
-addrpmrulesforupdaters(Solver *solv, Solvable *s, Map *m, int allow_all)
-{
-  Pool *pool = solv->pool;
-  int i;
-    /* queue and buffer for it */
-  Queue qs;
-  Id qsbuf[64];
-
-  POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforupdaters -----\n");
-
-  queue_init_buffer(&qs, qsbuf, sizeof(qsbuf)/sizeof(*qsbuf));
-    /* find update candidates for 's' */
-  policy_findupdatepackages(solv, s, &qs, allow_all);
-    /* add rule for 's' if not already done */
-  if (!MAPTST(m, s - pool->solvables))
-    addrpmrulesforsolvable(solv, s, m);
-    /* foreach update candidate, add rule if not already done */
-  for (i = 0; i < qs.count; i++)
-    if (!MAPTST(m, qs.elements[i]))
-      addrpmrulesforsolvable(solv, pool->solvables + qs.elements[i], m);
-  queue_free(&qs);
-
-  POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforupdaters -----\n");
-}
-
 static Id
 finddistupgradepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all)
 {
@@ -1767,7 +973,7 @@ addupdaterule(Solver *solv, Solvable *s, int allow_all)
     p = queue_shift(&qs);
   d = qs.count ? pool_queuetowhatprovides(pool, &qs) : 0;
   queue_free(&qs);
-  addrule(solv, p, d); /* allow update of s */
+  solver_addrule(solv, p, d);  /* allow update of s */
   POOL_DEBUG(SAT_DEBUG_SCHUBI, "-----  addupdaterule end -----\n");
 }
 
@@ -2498,7 +1704,7 @@ setpropagatelearn(Solver *solv, int level, Id decision, int disablerules, Id rul
       POOL_DEBUG(SAT_DEBUG_ANALYZE, "reverting decisions (level %d -> %d)\n", level, l);
       level = l;
       revert(solv, level);
-      r = addrule(solv, p, d);
+      r = solver_addrule(solv, p, d);
       assert(r);
       assert(solv->learnt_why.count == (r - solv->rules) - solv->learntrules);
       queue_push(&solv->learnt_why, why);
@@ -3436,7 +2642,7 @@ refine_suggestion(Solver *solv, Id *problem, Id sug, Queue *refined, int essenti
       /* enable feature rule */
       Rule *r = solv->rules + solv->featurerules + (sug - solv->updaterules);
       if (r->p)
-       enablerule(solv, r);
+       solver_enablerule(solv, r);
     }
 
   enableweakrules(solv);
@@ -3515,7 +2721,7 @@ refine_suggestion(Solver *solv, Id *problem, Id sug, Queue *refined, int essenti
            {
              Rule *r = solv->rules + (v - solv->updaterules + solv->featurerules);
              if (r->p)
-               enablerule(solv, r);    /* enable corresponding feature rule */
+               solver_enablerule(solv, r);     /* enable corresponding feature rule */
            }
          if (v < 0)
            reenablepolicyrules(solv, -(v + 1));
@@ -3540,7 +2746,7 @@ refine_suggestion(Solver *solv, Id *problem, Id sug, Queue *refined, int essenti
                {
                  Rule *r = solv->rules + (v - solv->updaterules + solv->featurerules);
                  if (r->p)
-                   enablerule(solv, r);
+                   solver_enablerule(solv, r);
                }
            }
        }
@@ -4262,7 +3468,7 @@ addinfarchrules(Solver *solv, Map *addedmap)
       for (j = 0; j < badq.count; j++)
        {
          p = badq.elements[j];
-         addrule(solv, -p, 0);
+         solver_addrule(solv, -p, 0);
        }
     }
   queue_free(&badq);
@@ -4375,11 +3581,11 @@ addduprules(Solver *solv, Map *addedmap)
                        break;
                    }
                  if (!ip)
-                   addrule(solv, -p, 0);       /* no match, sorry */
+                   solver_addrule(solv, -p, 0);        /* no match, sorry */
                }
            }
          else if (!MAPTST(&solv->dupmap, p))
-           addrule(solv, -p, 0);
+           solver_addrule(solv, -p, 0);
        }
     }
   solv->duprules_end = solv->nrules;
@@ -4428,7 +3634,7 @@ findrecommendedsuggested(Solver *solv)
       if (r->p >= 0)   /* install job? */
        continue;
       queue_push(&disabledq, i);
-      disablerule(solv, r);
+      solver_disablerule(solv, r);
       goterase++;
     }
   
@@ -4577,7 +3783,7 @@ findrecommendedsuggested(Solver *solv)
   
   /* undo job rule disabling */
   for (i = 0; i < disabledq.count; i++)
-    enablerule(solv, solv->rules + disabledq.elements[i]);
+    solver_enablerule(solv, solv->rules + disabledq.elements[i]);
   queue_free(&disabledq);
   map_free(&obsmap);
 }
@@ -4663,12 +3869,12 @@ solver_solve(Solver *solv, Queue *job)
       oldnrules = solv->nrules;
       POOL_DEBUG(SAT_DEBUG_SCHUBI, "*** create rpm rules for installed solvables ***\n");
       FOR_REPO_SOLVABLES(installed, p, s)
-       addrpmrulesforsolvable(solv, s, &addedmap);
+       solver_addrpmrulesforsolvable(solv, s, &addedmap);
       POOL_DEBUG(SAT_DEBUG_STATS, "added %d rpm rules for installed solvables\n", solv->nrules - oldnrules);
       POOL_DEBUG(SAT_DEBUG_SCHUBI, "*** create rpm rules for updaters of installed solvables ***\n");
       oldnrules = solv->nrules;
       FOR_REPO_SOLVABLES(installed, p, s)
-       addrpmrulesforupdaters(solv, s, &addedmap, 1);
+       solver_addrpmrulesforupdaters(solv, s, &addedmap, 1);
       POOL_DEBUG(SAT_DEBUG_STATS, "added %d rpm rules for updaters of installed solvables\n", solv->nrules - oldnrules);
     }
 
@@ -4691,7 +3897,7 @@ solver_solve(Solver *solv, Queue *job)
          FOR_JOB_SELECT(p, pp, select, what)
            {
              MAPSET(&installcandidatemap, p);
-             addrpmrulesforsolvable(solv, pool->solvables + p, &addedmap);
+             solver_addrpmrulesforsolvable(solv, pool->solvables + p, &addedmap);
            }
          break;
        case SOLVER_DISTUPGRADE:
@@ -4711,7 +3917,7 @@ solver_solve(Solver *solv, Queue *job)
     /*
      * add rules for suggests, enhances
      */
-  addrpmrulesforweak(solv, &addedmap);
+  solver_addrpmrulesforweak(solv, &addedmap);
   POOL_DEBUG(SAT_DEBUG_STATS, "added %d rpm rules because of weak dependencies\n", solv->nrules - oldnrules);
 
   IF_POOLDEBUG (SAT_DEBUG_STATS)
@@ -4735,7 +3941,7 @@ solver_solve(Solver *solv, Queue *job)
    * as an empty system (remove all packages) is a valid solution
    */
 
-  unifyrules(solv);                              /* remove duplicate rpm rules */
+  solver_unifyrules(solv);                          /* remove duplicate rpm rules */
 
   solv->rpmrules_end = solv->nrules;              /* mark end of rpm rules */
 
@@ -4768,7 +3974,7 @@ solver_solve(Solver *solv, Queue *job)
        {
          if (s->repo != installed)
            {
-             addrule(solv, 0, 0);      /* create dummy rule */
+             solver_addrule(solv, 0, 0);       /* create dummy rule */
              continue;
            }
          addupdaterule(solv, s, 1);    /* allow s to be updated */
@@ -4801,7 +4007,7 @@ solver_solve(Solver *solv, Queue *job)
 
          if (s->repo != installed)
            {
-             addrule(solv, 0, 0);      /* create dummy rule */
+             solver_addrule(solv, 0, 0);       /* create dummy rule */
              continue;
            }
          addupdaterule(solv, s, 0);    /* allowall = 0: downgrades not allowed */
@@ -4819,7 +4025,7 @@ solver_solve(Solver *solv, Queue *job)
              assert(solv->distupgrade && !sr->p);
              continue;
            }
-         if (!unifyrules_sortcmp(r, sr, pool))
+         if (!solver_samerule(solv, r, sr))
            {
              /* identical rule, kill unneeded one */
              if (solv->allowuninstall)
@@ -4841,7 +4047,7 @@ solver_solve(Solver *solv, Queue *job)
              queue_push(&solv->weakruleq, sr - solv->rules);
            }
          else
-           disablerule(solv, sr);
+           solver_disablerule(solv, sr);
        }
       /* consistency check: we added a rule for _every_ installed solvable */
       assert(solv->nrules - solv->updaterules == installed->end - installed->start);
@@ -4886,7 +4092,7 @@ solver_solve(Solver *solv, Queue *job)
              p = queue_shift(&q);      /* get first candidate */
              d = !q.count ? 0 : pool_queuetowhatprovides(pool, &q);    /* internalize */
            }
-         addrule(solv, p, d);          /* add install rule */
+         solver_addrule(solv, p, d);           /* add install rule */
          queue_push(&solv->ruletojob, i);
          if (weak)
            queue_push(&solv->weakruleq, solv->nrules - 1);
@@ -4912,7 +4118,7 @@ solver_solve(Solver *solv, Queue *job)
                  /* keep installcandidates of other jobs */
                  if (MAPTST(&installcandidatemap, p))
                    continue;
-                 addrule(solv, -p, 0);                 /* remove by Id */
+                 solver_addrule(solv, -p, 0);                  /* remove by Id */
                  queue_push(&solv->ruletojob, i);
                  if (weak)
                    queue_push(&solv->weakruleq, solv->nrules - 1);
@@ -4920,7 +4126,7 @@ solver_solve(Solver *solv, Queue *job)
            }
          FOR_JOB_SELECT(p, pp, select, what)
            {
-             addrule(solv, -p, 0);
+             solver_addrule(solv, -p, 0);
              queue_push(&solv->ruletojob, i);
              if (weak)
                queue_push(&solv->weakruleq, solv->nrules - 1);
@@ -4955,9 +4161,9 @@ solver_solve(Solver *solv, Queue *job)
            {
              s = pool->solvables + p;
              if (installed && s->repo == installed)
-               addrule(solv, p, 0);
+               solver_addrule(solv, p, 0);
              else
-               addrule(solv, -p, 0);
+               solver_addrule(solv, -p, 0);
              queue_push(&solv->ruletojob, i);
              if (weak)
                queue_push(&solv->weakruleq, solv->nrules - 1);
@@ -5119,6 +4325,7 @@ solver_trivial_installable(Solver *solv, Queue *pkgs, Queue *res)
 }
 
 
+#if 0
 #define FIND_INVOLVED_DEBUG 0
 void
 solver_find_involved(Solver *solv, Queue *installedq, Solvable *ts, Queue *q)
@@ -5349,262 +4556,9 @@ solver_find_involved(Solver *solv, Queue *installedq, Solvable *ts, Queue *q)
   map_free(&installedm);
   queue_free(&installedq_internal);
 }
+#endif
 
 
-static void
-addrpmruleinfo(Solver *solv, Id p, Id d, int type, Id dep)
-{
-  Pool *pool = solv->pool;
-  Rule *r;
-  Id w2, op, od, ow2;
-
-  /* check if this creates the rule we're searching for */
-  r = solv->rules + solv->ruleinfoq->elements[0];
-  op = r->p;
-  od = r->d < 0 ? -r->d - 1 : r->d;
-  ow2 = 0;
-
-  /* normalize */
-  w2 = d > 0 ? 0 : d;
-  if (p < 0 && d > 0 && (!pool->whatprovidesdata[d] || !pool->whatprovidesdata[d + 1]))
-    {
-      w2 = pool->whatprovidesdata[d];
-      d = 0;
-
-    }
-  if (p > 0 && d < 0)          /* this hack is used for buddy deps */
-    {
-      w2 = p;
-      p = d;
-    }
-
-  if (d > 0)
-    {
-      if (p != op && !od)
-       return;
-      if (d != od)
-       {
-         Id *dp = pool->whatprovidesdata + d;
-         Id *odp = pool->whatprovidesdata + od;
-         while (*dp)
-           if (*dp++ != *odp++)
-             return;
-         if (*odp)
-           return;
-       }
-      w2 = 0;
-      /* handle multiversion conflict rules */
-      if (p < 0 && pool->whatprovidesdata[d] < 0)
-       {
-         w2 = pool->whatprovidesdata[d];
-         /* XXX: free memory */
-       }
-    }
-  else
-    {
-      if (od)
-       return;
-      ow2 = r->w2;
-      if (p > w2)
-       {
-         if (w2 != op || p != ow2)
-           return;
-       }
-      else
-       {
-         if (p != op || w2 != ow2)
-           return;
-       }
-    }
-  /* yep, rule matches. record info */
-  queue_push(solv->ruleinfoq, type);
-  if (type == SOLVER_RULE_RPM_SAME_NAME)
-    {
-      /* we normalize same name order */
-      queue_push(solv->ruleinfoq, op < 0 ? -op : 0);
-      queue_push(solv->ruleinfoq, ow2 < 0 ? -ow2 : 0);
-    }
-  else
-    {
-      queue_push(solv->ruleinfoq, p < 0 ? -p : 0);
-      queue_push(solv->ruleinfoq, w2 < 0 ? -w2 : 0);
-    }
-  queue_push(solv->ruleinfoq, dep);
-}
-
-static int
-solver_allruleinfos_cmp(const void *ap, const void *bp, void *dp)
-{
-  const Id *a = ap, *b = bp;
-  int r;
-
-  r = a[0] - b[0];
-  if (r)
-    return r;
-  r = a[1] - b[1];
-  if (r)
-    return r;
-  r = a[2] - b[2];
-  if (r)
-    return r;
-  r = a[3] - b[3];
-  if (r)
-    return r;
-  return 0;
-}
-
-int
-solver_allruleinfos(Solver *solv, Id rid, Queue *rq)
-{
-  Pool *pool = solv->pool;
-  Rule *r = solv->rules + rid;
-  int i, j;
-
-  queue_empty(rq);
-  if (rid <= 0 || rid >= solv->rpmrules_end)
-    {
-      Id type, from, to, dep;
-      type = solver_ruleinfo(solv, rid, &from, &to, &dep);
-      queue_push(rq, type);
-      queue_push(rq, from);
-      queue_push(rq, to);
-      queue_push(rq, dep);
-      return 1;
-    }
-  if (r->p >= 0)
-    return 0;
-  queue_push(rq, rid);
-  solv->ruleinfoq = rq;
-  addrpmrulesforsolvable(solv, pool->solvables - r->p, 0);
-  /* also try reverse direction for conflicts */
-  if ((r->d == 0 || r->d == -1) && r->w2 < 0)
-    addrpmrulesforsolvable(solv, pool->solvables - r->w2, 0);
-  solv->ruleinfoq = 0;
-  queue_shift(rq);
-  /* now sort & unify em */
-  if (!rq->count)
-    return 0;
-  sat_sort(rq->elements, rq->count / 4, 4 * sizeof(Id), solver_allruleinfos_cmp, 0);
-  /* throw out identical entries */
-  for (i = j = 0; i < rq->count; i += 4)
-    {
-      if (j)
-       {
-         if (rq->elements[i] == rq->elements[j - 4] && 
-             rq->elements[i + 1] == rq->elements[j - 3] &&
-             rq->elements[i + 2] == rq->elements[j - 2] &&
-             rq->elements[i + 3] == rq->elements[j - 1])
-           continue;
-       }
-      rq->elements[j++] = rq->elements[i];
-      rq->elements[j++] = rq->elements[i + 1];
-      rq->elements[j++] = rq->elements[i + 2];
-      rq->elements[j++] = rq->elements[i + 3];
-    }
-  rq->count = j;
-  return j / 4;
-}
-
-SolverRuleinfo
-solver_ruleinfo(Solver *solv, Id rid, Id *fromp, Id *top, Id *depp)
-{
-  Pool *pool = solv->pool;
-  Rule *r = solv->rules + rid;
-  SolverRuleinfo type = SOLVER_RULE_UNKNOWN;
-
-  if (fromp)
-    *fromp = 0;
-  if (top)
-    *top = 0;
-  if (depp)
-    *depp = 0;
-  if (rid > 0 && rid < solv->rpmrules_end)
-    {
-      Queue rq;
-      int i;
-
-      if (r->p >= 0)
-       return SOLVER_RULE_RPM;
-      if (fromp)
-       *fromp = -r->p;
-      queue_init(&rq);
-      queue_push(&rq, rid);
-      solv->ruleinfoq = &rq;
-      addrpmrulesforsolvable(solv, pool->solvables - r->p, 0);
-      /* also try reverse direction for conflicts */
-      if ((r->d == 0 || r->d == -1) && r->w2 < 0)
-       addrpmrulesforsolvable(solv, pool->solvables - r->w2, 0);
-      solv->ruleinfoq = 0;
-      type = SOLVER_RULE_RPM;
-      for (i = 1; i < rq.count; i += 4)
-       {
-         Id qt, qo, qp, qd;
-         qt = rq.elements[i];
-         qp = rq.elements[i + 1];
-         qo = rq.elements[i + 2];
-         qd = rq.elements[i + 3];
-         if (type == SOLVER_RULE_RPM || type > qt)
-           {
-             type = qt;
-             if (fromp)
-               *fromp = qp;
-             if (top)
-               *top = qo;
-             if (depp)
-               *depp = qd;
-           }
-       }
-      queue_free(&rq);
-      return type;
-    }
-  if (rid >= solv->jobrules && rid < solv->jobrules_end)
-    {
-      Id jidx = solv->ruletojob.elements[rid - solv->jobrules];
-      if (fromp)
-       *fromp = jidx;
-      if (top)
-       *top = solv->job.elements[jidx];
-      if (depp)
-       *depp = solv->job.elements[jidx + 1];
-      if ((r->d == 0 || r->d == -1) && r->w2 == 0 && r->p == -SYSTEMSOLVABLE && (solv->job.elements[jidx] & SOLVER_SELECTMASK) != SOLVER_SOLVABLE_ONE_OF)
-       return SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP;
-      return SOLVER_RULE_JOB;
-    }
-  if (rid >= solv->updaterules && rid < solv->updaterules_end)
-    {
-      if (fromp)
-       *fromp = solv->installed->start + (rid - solv->updaterules);
-      return SOLVER_RULE_UPDATE;
-    }
-  if (rid >= solv->featurerules && rid < solv->featurerules_end)
-    {
-      if (fromp)
-       *fromp = solv->installed->start + (rid - solv->featurerules);
-      return SOLVER_RULE_FEATURE;
-    }
-  if (rid >= solv->duprules && rid < solv->duprules_end)
-    {
-      if (fromp)
-       *fromp = -r->p;
-      if (depp)
-       *depp = pool->solvables[-r->p].name;
-      return SOLVER_RULE_DISTUPGRADE;
-    }
-  if (rid >= solv->infarchrules && rid < solv->infarchrules_end)
-    {
-      if (fromp)
-       *fromp = -r->p;
-      if (depp)
-       *depp = pool->solvables[-r->p].name;
-      return SOLVER_RULE_INFARCH;
-    }
-  if (rid >= solv->learntrules)
-    {
-      return SOLVER_RULE_LEARNT;
-    }
-  return SOLVER_RULE_UNKNOWN;
-}
-
 /* obsolete function */
 SolverRuleinfo
 solver_problemruleinfo(Solver *solv, Queue *job, Id rid, Id *depp, Id *sourcep, Id *targetp)
index 2c2a2b1..446d106 100644 (file)
@@ -23,6 +23,8 @@ extern "C" {
 #include "queue.h"
 #include "bitmap.h"
 #include "transaction.h"
+#include "rules.h"
+
 /*
  * Callback definitions in order to "overwrite" the policies by an external application.
  */
@@ -33,31 +35,6 @@ typedef int  (*VendorCheckCb) (Pool *pool, Solvable *solvable1, Solvable *solvab
 typedef void (*UpdateCandidateCb) (Pool *pool, Solvable *solvable, Queue *canditates);
 
 
-/* ----------------------------------------------
- * Rule
- *
- *   providerN(B) == Package Id of package providing tag B
- *   N = 1, 2, 3, in case of multiple providers
- *
- * A requires B : !A | provider1(B) | provider2(B)
- *
- * A conflicts B : (!A | !provider1(B)) & (!A | !provider2(B)) ...
- *
- * 'not' is encoded as a negative Id
- * 
- * Binary rule: p = first literal, d = 0, w2 = second literal, w1 = p
- */
-
-typedef struct rule {
-  Id p;                        /* first literal in rule */
-  Id d;                        /* Id offset into 'list of providers terminated by 0' as used by whatprovides; pool->whatprovides + d */
-                       /* in case of binary rules, d == 0, w1 == p, w2 == other literal */
-                       /* in case of disabled rules: ~d, aka -d - 1 */
-  Id w1, w2;           /* watches, literals not-yet-decided */
-                                      /* if !w2, assertion, not rule */
-  Id n1, n2;           /* next rules in linked list, corresponding to w1,w2 */
-} Rule;
-
 struct _Solver;
 
 typedef struct _Solver {
@@ -271,44 +248,6 @@ typedef struct _Solver {
 #define SOLVER_NOOBSOLETES_SOLVABLE_PROVIDES (SOLVER_NOOBSOLETES|SOLVER_SOLVABLE_PROVIDES)
 #endif
 
-typedef enum {
-  SOLVER_PROBLEM_UPDATE_RULE,
-  SOLVER_PROBLEM_JOB_RULE,
-  SOLVER_PROBLEM_JOB_NOTHING_PROVIDES_DEP,
-  SOLVER_PROBLEM_NOT_INSTALLABLE,
-  SOLVER_PROBLEM_NOTHING_PROVIDES_DEP,
-  SOLVER_PROBLEM_SAME_NAME,
-  SOLVER_PROBLEM_PACKAGE_CONFLICT,
-  SOLVER_PROBLEM_PACKAGE_OBSOLETES,
-  SOLVER_PROBLEM_DEP_PROVIDERS_NOT_INSTALLABLE,
-  SOLVER_PROBLEM_SELF_CONFLICT,
-  SOLVER_PROBLEM_RPM_RULE,
-  SOLVER_PROBLEM_DISTUPGRADE_RULE,
-  SOLVER_PROBLEM_INFARCH_RULE
-} SolverProbleminfo;
-
-typedef enum {
-  SOLVER_RULE_UNKNOWN = 0,
-  SOLVER_RULE_RPM = 0x100,
-  SOLVER_RULE_RPM_NOT_INSTALLABLE,
-  SOLVER_RULE_RPM_NOTHING_PROVIDES_DEP,
-  SOLVER_RULE_RPM_PACKAGE_REQUIRES,
-  SOLVER_RULE_RPM_SELF_CONFLICT,
-  SOLVER_RULE_RPM_PACKAGE_CONFLICT,
-  SOLVER_RULE_RPM_SAME_NAME,
-  SOLVER_RULE_RPM_PACKAGE_OBSOLETES,
-  SOLVER_RULE_RPM_IMPLICIT_OBSOLETES,
-  SOLVER_RULE_UPDATE = 0x200,
-  SOLVER_RULE_FEATURE = 0x300,
-  SOLVER_RULE_JOB = 0x400,
-  SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP,
-  SOLVER_RULE_DISTUPGRADE = 0x500,
-  SOLVER_RULE_INFARCH = 0x600,
-  SOLVER_RULE_LEARNT = 0x700
-} SolverRuleinfo;
-
-#define SOLVER_RULE_TYPEMASK   0xff00
-
 /* backward compatibility */
 #define SOLVER_PROBLEM_UPDATE_RULE             SOLVER_RULE_UPDATE
 #define SOLVER_PROBLEM_JOB_RULE                        SOLVER_RULE_JOB
@@ -346,8 +285,6 @@ extern Id solver_findproblemrule(Solver *solv, Id problem);
 extern void solver_findallproblemrules(Solver *solv, Id problem, Queue *rules);
 
 extern SolverRuleinfo solver_problemruleinfo(Solver *solv, Queue *job, Id rid, Id *depp, Id *sourcep, Id *targetp);
-extern SolverRuleinfo solver_ruleinfo(Solver *solv, Id rid, Id *fromp, Id *top, Id *depp);
-extern int solver_allruleinfos(Solver *solv, Id rid, Queue *rq);
 
 /* XXX: why is this not static? */
 Id *solver_create_decisions_obsoletesmap(Solver *solv);