- start transaction ordering
authorMichael Schroeder <mls@suse.de>
Wed, 13 May 2009 14:31:28 +0000 (16:31 +0200)
committerMichael Schroeder <mls@suse.de>
Wed, 13 May 2009 14:31:28 +0000 (16:31 +0200)
src/CMakeLists.txt
src/solver.c
src/solver.h
src/solverdebug.c
src/transaction.c [new file with mode: 0644]
src/transaction.h [new file with mode: 0644]
tools/CMakeLists.txt
tools/patchcheck.c [new file with mode: 0644]
tools/repo_rpmmd.c

index 0a56baa..a74bf8c 100644 (file)
@@ -2,7 +2,8 @@
 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)
+    queue.c repo.c repodata.c repopage.c util.c policy.c solvable.c
+    transaction.c)
 
 ADD_LIBRARY(satsolver STATIC ${libsatsolver_SRCS})
 
@@ -10,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)
+    strpool.h dirpool.h knownid.h transaction.h)
 
 SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
 
index 2329f19..5c8f997 100644 (file)
@@ -140,8 +140,6 @@ dep_possible(Solver *solv, Id dep, Map *m)
  * - unify rules, remove duplicates
  */
 
-static Pool *unifyrules_sortcmp_data;
-
 /*-------------------------------------------------------------------
  *
  * compare rules for unification sort
@@ -149,9 +147,9 @@ static Pool *unifyrules_sortcmp_data;
  */
 
 static int
-unifyrules_sortcmp(const void *ap, const void *bp)
+unifyrules_sortcmp(const void *ap, const void *bp, void *dp)
 {
-  Pool *pool = unifyrules_sortcmp_data;
+  Pool *pool = dp;
   Rule *a = (Rule *)ap;
   Rule *b = (Rule *)bp;
   Id *ad, *bd;
@@ -206,8 +204,7 @@ unifyrules(Solver *solv)
   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- unifyrules -----\n");
 
   /* sort rules first */
-  unifyrules_sortcmp_data = solv->pool;
-  qsort(solv->rules + 1, solv->nrules - 1, sizeof(Rule), unifyrules_sortcmp);
+  sat_sort(solv->rules + 1, solv->nrules - 1, sizeof(Rule), unifyrules_sortcmp, solv->pool);
 
   /* prune rules
    * i = unpruned
@@ -216,7 +213,7 @@ unifyrules(Solver *solv)
   jr = 0;
   for (i = j = 1, ir = solv->rules + i; i < solv->nrules; i++, ir++)
     {
-      if (jr && !unifyrules_sortcmp(ir, jr))
+      if (jr && !unifyrules_sortcmp(ir, jr, pool))
        continue;                      /* prune! */
       jr = solv->rules + j++;         /* keep! */
       if (ir != jr)
@@ -1409,7 +1406,7 @@ addrpmrulesforsolvable(Solver *solv, Solvable *s, Map *m)
                {
                  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", solvable2str(pool, pool->solvables + dp[i]));
+                   POOL_DEBUG(SAT_DEBUG_RULE_CREATION, "   provided by %s\n", solvid2str(pool, dp[i]));
                }
 
              /* add 'requires' dependency */
@@ -1974,9 +1971,9 @@ propagate(Solver *solv, int level)
                  IF_POOLDEBUG (SAT_DEBUG_PROPAGATE)
                    {
                      if (p > 0)
-                       POOL_DEBUG(SAT_DEBUG_PROPAGATE, "    -> move w%d to %s\n", (pkg == r->w1 ? 1 : 2), solvable2str(pool, pool->solvables + p));
+                       POOL_DEBUG(SAT_DEBUG_PROPAGATE, "    -> move w%d to %s\n", (pkg == r->w1 ? 1 : 2), solvid2str(pool, p));
                      else
-                       POOL_DEBUG(SAT_DEBUG_PROPAGATE,"    -> move w%d to !%s\n", (pkg == r->w1 ? 1 : 2), solvable2str(pool, pool->solvables - p));
+                       POOL_DEBUG(SAT_DEBUG_PROPAGATE,"    -> move w%d to !%s\n", (pkg == r->w1 ? 1 : 2), solvid2str(pool, -p));
                    }
                    
                  *rp = *next_rp;
@@ -2022,11 +2019,10 @@ propagate(Solver *solv, int level)
 
          IF_POOLDEBUG (SAT_DEBUG_PROPAGATE)
            {
-             Solvable *s = pool->solvables + (other_watch > 0 ? other_watch : -other_watch);
              if (other_watch > 0)
-               POOL_DEBUG(SAT_DEBUG_PROPAGATE, "    -> decided to install %s\n", solvable2str(pool, s));
+               POOL_DEBUG(SAT_DEBUG_PROPAGATE, "    -> decided to install %s\n", solvid2str(pool, other_watch));
              else
-               POOL_DEBUG(SAT_DEBUG_PROPAGATE, "    -> decided to conflict %s\n", solvable2str(pool, s));
+               POOL_DEBUG(SAT_DEBUG_PROPAGATE, "    -> decided to conflict %s\n", solvid2str(pool, -other_watch));
            }
            
        } /* foreach rule involving 'pkg' */
@@ -2572,7 +2568,7 @@ selectandinstall(Solver *solv, int level, Queue *dq, int disablerules, Id ruleid
     }
   p = dq->elements[0];
 
-  POOL_DEBUG(SAT_DEBUG_POLICY, "installing %s\n", solvable2str(pool, pool->solvables + p));
+  POOL_DEBUG(SAT_DEBUG_POLICY, "installing %s\n", solvid2str(pool, p));
 
   return setpropagatelearn(solv, level, p, disablerules, ruleid);
 }
@@ -2675,6 +2671,7 @@ solver_free(Solver *solv)
   sat_free(solv->obsoletes);
   sat_free(solv->obsoletes_data);
   sat_free(solv->multiversionupdaters);
+  sat_free(solv->transaction_installed);
   sat_free(solv);
 }
 
@@ -2899,7 +2896,7 @@ run_solver(Solver *solv, int disablerules, int doweak)
                  if (solv->decisionmap[i] == 0)
                    {
                      olevel = level;
-                     POOL_DEBUG(SAT_DEBUG_POLICY, "keeping %s\n", solvable2str(pool, pool->solvables + i));
+                     POOL_DEBUG(SAT_DEBUG_POLICY, "keeping %s\n", solvid2str(pool, i));
                      level = setpropagatelearn(solv, level, i, disablerules, r - solv->rules);
                      if (level == 0)
                        {
@@ -3004,7 +3001,7 @@ run_solver(Solver *solv, int disablerules, int doweak)
              queue_free(&dqs);
              return;
            }
-         if (level < systemlevel)
+         if (level < systemlevel || level == 1)
            break;
          n = 0;
        } /* for(), decide */
@@ -3153,9 +3150,9 @@ run_solver(Solver *solv, int disablerules, int doweak)
                  /* simple case, just one package. no need to choose  */
                  p = dq.elements[0];
                  if (dqs.count)
-                   POOL_DEBUG(SAT_DEBUG_POLICY, "installing supplemented %s\n", solvable2str(pool, pool->solvables + p));
+                   POOL_DEBUG(SAT_DEBUG_POLICY, "installing supplemented %s\n", solvid2str(pool, p));
                  else
-                   POOL_DEBUG(SAT_DEBUG_POLICY, "installing recommended %s\n", solvable2str(pool, pool->solvables + p));
+                   POOL_DEBUG(SAT_DEBUG_POLICY, "installing recommended %s\n", solvid2str(pool, p));
                  queue_push(&solv->recommendations, p);
                  level = setpropagatelearn(solv, level, p, 0, 0);
                  continue;
@@ -3173,7 +3170,7 @@ run_solver(Solver *solv, int disablerules, int doweak)
                  p = dqs.elements[i];
                  if (solv->decisionmap[p] || !MAPTST(&dqmap, p))
                    continue;
-                 POOL_DEBUG(SAT_DEBUG_POLICY, "installing supplemented %s\n", solvable2str(pool, pool->solvables + p));
+                 POOL_DEBUG(SAT_DEBUG_POLICY, "installing supplemented %s\n", solvid2str(pool, p));
                  queue_push(&solv->recommendations, p);
                  olevel = level;
                  level = setpropagatelearn(solv, level, p, 0, 0);
@@ -3224,7 +3221,7 @@ run_solver(Solver *solv, int disablerules, int doweak)
                          queue_push(&solv->branches, -level);
                        }
                      p = dq.elements[0];
-                     POOL_DEBUG(SAT_DEBUG_POLICY, "installing recommended %s\n", solvable2str(pool, pool->solvables + p));
+                     POOL_DEBUG(SAT_DEBUG_POLICY, "installing recommended %s\n", solvid2str(pool, p));
                      queue_push(&solv->recommendations, p);
                      olevel = level;
                      level = setpropagatelearn(solv, level, p, 0, 0);
@@ -3251,7 +3248,7 @@ run_solver(Solver *solv, int disablerules, int doweak)
                    p = dq.elements[i];
                    break;
                  }
-             POOL_DEBUG(SAT_DEBUG_POLICY, "installing recommended %s\n", solvable2str(pool, pool->solvables + p));
+             POOL_DEBUG(SAT_DEBUG_POLICY, "installing recommended %s\n", solvid2str(pool, p));
              queue_push(&solv->recommendations, p);
              level = setpropagatelearn(solv, level, p, 0, 0);
              continue;
@@ -3273,12 +3270,12 @@ run_solver(Solver *solv, int disablerules, int doweak)
              olevel = level;
              if (solv->distupgrade_removeunsupported)
                {
-                 POOL_DEBUG(SAT_DEBUG_STATS, "removing unsupported %s\n", solvable2str(pool, pool->solvables + p));
+                 POOL_DEBUG(SAT_DEBUG_STATS, "removing unsupported %s\n", solvid2str(pool, p));
                  level = setpropagatelearn(solv, level, -p, 0, 0);
                }
              else
                {
-                 POOL_DEBUG(SAT_DEBUG_STATS, "keeping unsupported %s\n", solvable2str(pool, pool->solvables + p));
+                 POOL_DEBUG(SAT_DEBUG_STATS, "keeping unsupported %s\n", solvid2str(pool, p));
                  level = setpropagatelearn(solv, level, p, 0, 0);
                  installedone = 1;
                }
@@ -3302,7 +3299,7 @@ run_solver(Solver *solv, int disablerules, int doweak)
                if (solv->branches.elements[i - 1] < 0)
                  break;
              p = solv->branches.elements[i];
-             POOL_DEBUG(SAT_DEBUG_STATS, "branching with %s\n", solvable2str(pool, pool->solvables + p));
+             POOL_DEBUG(SAT_DEBUG_STATS, "branching with %s\n", solvid2str(pool, p));
              queue_empty(&dq);
              for (j = i + 1; j < solv->branches.count; j++)
                queue_push(&dq, solv->branches.elements[j]);
@@ -3351,7 +3348,7 @@ run_solver(Solver *solv, int disablerules, int doweak)
              /* kill old solvable so that we do not loop */
              p = solv->branches.elements[lasti];
              solv->branches.elements[lasti] = 0;
-             POOL_DEBUG(SAT_DEBUG_STATS, "minimizing %d -> %d with %s\n", solv->decisionmap[p], lastl, solvable2str(pool, pool->solvables + p));
+             POOL_DEBUG(SAT_DEBUG_STATS, "minimizing %d -> %d with %s\n", solv->decisionmap[p], lastl, solvid2str(pool, p));
              minimizationsteps++;
 
              level = lastl;
@@ -3562,11 +3559,10 @@ refine_suggestion(Solver *solv, Queue *job, Id *problem, Id sug, Queue *refined,
  * make essential job rules last
  */
 
-Queue *problems_sort_data;
-
 static int
-problems_sortcmp(const void *ap, const void *bp)
+problems_sortcmp(const void *ap, const void *bp, void *dp)
 {
+  Queue *job = dp;
   Id a = *(Id *)ap, b = *(Id *)bp;
   if (a < 0 && b > 0)
     return 1;
@@ -3574,7 +3570,6 @@ problems_sortcmp(const void *ap, const void *bp)
     return -1;
   if (a < 0 && b < 0)
     {
-      Queue *job = problems_sort_data;
       int af = job->elements[-a - 1] & SOLVER_ESSENTIAL;
       int bf = job->elements[-b - 1] & SOLVER_ESSENTIAL;
       int x = af - bf;
@@ -3694,6 +3689,36 @@ convertsolution(Solver *solv, Id why, Queue *solutionq)
 }
 
 /*
+ * convert problem data into a form usable for refining.
+ * Returns the number of problems.
+ */
+int
+prepare_solutions(Solver *solv)
+{
+  int i, j = 1, idx = 1;  
+
+  if (!solv->problems.count)
+    return 0;
+  queue_push(&solv->solutions, 0); 
+  queue_push(&solv->solutions, -1); /* unrefined */
+  for (i = 1; i < solv->problems.count; i++) 
+    {   
+      Id p = solv->problems.elements[i];
+      queue_push(&solv->solutions, p); 
+      if (p) 
+        continue;
+      solv->problems.elements[j++] = idx; 
+      if (i + 1 >= solv->problems.count)
+        break;
+      solv->problems.elements[j++] = solv->problems.elements[++i];  /* copy proofidx */
+      idx = solv->solutions.count;
+      queue_push(&solv->solutions, -1); 
+    }   
+  solv->problems.count = j;  
+  return j / 2;
+}
+
+/*
  * refine the simple solution rule list provided by
  * the solver into multiple lists of job modifiers.
  */
@@ -3733,9 +3758,8 @@ create_solutions(Solver *solv, int probnr, int solidx)
        break;
       queue_push(&problem, v);
     }
-  problems_sort_data = &solv->job;
   if (problem.count > 1)
-    qsort(problem.elements, problem.count, sizeof(Id), problems_sortcmp);
+    sat_sort(problem.elements, problem.count, sizeof(Id), problems_sortcmp, &solv->job);
   queue_push(&problem, 0);     /* mark end for refine_suggestion */
   problem.count--;
 #if 0
@@ -3926,14 +3950,13 @@ findproblemrule_internal(Solver *solv, Id idx, Id *reqrp, Id *conrp, Id *sysrp,
     *sysrp = lsysr;
 }
 
-
-/*-------------------------------------------------------------------
- * 
+/* 
  * find problem rule
  *
  * search for a rule that describes the problem to the
- * user. A pretty hopeless task, actually. We currently
- * prefer simple requires.
+ * user. Actually a pretty hopeless task that may leave the user
+ * puzzled. To get all of the needed information use
+ * solver_findallproblemrules() instead.
  */
 
 Id
@@ -3944,16 +3967,18 @@ solver_findproblemrule(Solver *solv, Id problem)
   reqr = conr = sysr = jobr = 0;
   findproblemrule_internal(solv, idx, &reqr, &conr, &sysr, &jobr);
   if (reqr)
-    return reqr;
+    return reqr;       /* some requires */
   if (conr)
-    return conr;
+    return conr;       /* some conflict */
   if (sysr)
-    return sysr;
+    return sysr;       /* an update rule */
   if (jobr)
-    return jobr;
+    return jobr;       /* a user request */
   assert(0);
 }
 
+/*-------------------------------------------------------------------*/
+
 static void
 findallproblemrules_internal(Solver *solv, Id idx, Queue *rules)
 {
@@ -3969,6 +3994,14 @@ findallproblemrules_internal(Solver *solv, Id idx, Queue *rules)
     }
 }
 
+/*
+ * find all problem rule
+ *
+ * return all rules that lead to the problem. This gives the user
+ * all of the information to understand the problem, but the result
+ * can be a large number of rules.
+ */
+
 void
 solver_findallproblemrules(Solver *solv, Id problem, Queue *rules)
 {
@@ -3981,9 +4014,10 @@ solver_findallproblemrules(Solver *solv, Id problem, Queue *rules)
  * 
  * create reverse obsoletes map for installed solvables
  *
- * for each installed solvable find which packages with *different* names
+ * For each installed solvable find which packages with *different* names
  * obsolete the solvable.
- * this index is used in policy_findupdatepackages if noupdateprovide is set.
+ * This index is used in policy_findupdatepackages if noupdateprovide is
+ * set.
  */
 
 static void
@@ -3993,11 +4027,12 @@ create_obsolete_index(Solver *solv)
   Solvable *s;
   Repo *installed = solv->installed;
   Id p, pp, obs, *obsp, *obsoletes, *obsoletes_data;
-  int i, n;
+  int i, n, cnt;
 
-  if (!installed || !installed->nsolvables)
+  if (!installed || installed->start == installed->end)
     return;
-  solv->obsoletes = obsoletes = sat_calloc(installed->end - installed->start, sizeof(Id));
+  cnt = installed->end - installed->start;
+  solv->obsoletes = obsoletes = sat_calloc(cnt, sizeof(Id));
   for (i = 1; i < pool->nsolvables; i++)
     {
       s = pool->solvables + i;
@@ -4021,7 +4056,7 @@ create_obsolete_index(Solver *solv)
        }
     }
   n = 0;
-  for (i = 0; i < installed->nsolvables; i++)
+  for (i = 0; i < cnt; i++)
     if (obsoletes[i])
       {
         n += obsoletes[i] + 1;
@@ -4090,7 +4125,7 @@ removedisabledconflicts(Solver *solv, Queue *removed)
       if (r->d < 0 && decisionmap[-p])
        {
          /* rule is now disabled, remove from decisionmap */
-         POOL_DEBUG(SAT_DEBUG_SCHUBI, "removing conflict for package %s[%d]\n", solvable2str(pool, pool->solvables - p), -p);
+         POOL_DEBUG(SAT_DEBUG_SCHUBI, "removing conflict for package %s[%d]\n", solvid2str(pool, -p), -p);
          queue_push(removed, -p);
          queue_push(removed, decisionmap[-p]);
          decisionmap[-p] = 0;
@@ -4153,7 +4188,7 @@ removedisabledconflicts(Solver *solv, Queue *removed)
        }
       if (new)
        {
-         POOL_DEBUG(SAT_DEBUG_SCHUBI, "re-conflicting package %s[%d]\n", solvable2str(pool, pool->solvables - new), -new);
+         POOL_DEBUG(SAT_DEBUG_SCHUBI, "re-conflicting package %s[%d]\n", solvid2str(pool, -new), -new);
          decisionmap[-new] = -1;
          new = 0;
          n = 0;        /* redo all rules */
@@ -4594,240 +4629,6 @@ findrecommendedsuggested(Solver *solv)
 }
 
 
-Solver *obsq_sortcmp_data;
-
-static int
-obsq_sortcmp(const void *ap, const void *bp)
-{
-  Id a, b, oa, ob;
-  Solver *solv = obsq_sortcmp_data;
-  Pool *pool = solv->pool;
-  Solvable *s, *oas, *obs;
-  int r;
-
-  a = ((Id *)ap)[0];
-  oa = ((Id *)ap)[1];
-  b = ((Id *)bp)[0];
-  ob = ((Id *)bp)[1];
-  if (a != b)
-    return a - b;
-  if (oa == ob)
-    return 0;
-  s = pool->solvables + a;
-  oas = pool->solvables + oa;
-  obs = pool->solvables + ob;
-  if (oas->name != obs->name)
-    {
-      if (oas->name == s->name)
-        return -1;
-      if (obs->name == s->name)
-        return 1;
-      return strcmp(id2str(pool, oas->name), id2str(pool, obs->name));
-    }
-  r = evrcmp(pool, oas->evr, obs->evr, EVRCMP_COMPARE);
-  if (r)
-    return -r; /* highest version first */
-  return oa - ob;
-}
-
-void
-solver_transaction_info(Solver *solv, Id p, Queue *out)
-{
-  Pool *pool = solv->pool;
-  Solvable *s = pool->solvables + p;
-  Queue *ti = &solv->transaction_info;
-  int i;
-
-  queue_empty(out);
-  if (p <= 0 || !s->repo)
-    return;
-  if (s->repo == solv->installed)
-    {
-      /* find which packages obsolete us */
-      for (i = 0; i < ti->count; i += 2)
-       if (ti->elements[i + 1] == p)
-         {
-           queue_push(out, p);
-           queue_push(out, ti->elements[i]);
-         }
-      if (out->count > 2)
-       {
-         /* sort obsoleters */
-         obsq_sortcmp_data = solv;
-         qsort(out->elements, out->count / 2, 2 * sizeof(Id), obsq_sortcmp);
-       }
-      for (i = 0; i < out->count; i += 2)
-       out->elements[i] = out->elements[i / 2 + 1];
-      out->count /= 2;
-    }
-  else
-    {
-      /* find the packages we obsolete */
-      for (i = 0; i < ti->count; i += 2)
-       {
-         if (ti->elements[i] == p)
-           queue_push(out, ti->elements[i + 1]);
-         else if (out->count)
-           break;
-       }
-    }
-}
-
-Id
-solver_transaction_pkg(Solver *solv, Id p)
-{
-  Queue ti;
-  Id tibuf[5];
-
-  queue_init_buffer(&ti, tibuf, sizeof(tibuf)/sizeof(*tibuf));
-  solver_transaction_info(solv, p, &ti);
-  p = ti.count ? ti.elements[0] : 0;
-  queue_free(&ti);
-  return p;
-}
-
-static void
-create_transaction(Solver *solv)
-{
-  Pool *pool = solv->pool;
-  Repo *installed = solv->installed;
-  Queue *ti = &solv->transaction_info;
-  int i, j, r, noobs;
-  Id p, p2, pp2;
-  Solvable *s, *s2;
-
-  queue_empty(&solv->transaction);
-  queue_empty(ti);
-
-  /* first create obsoletes index */
-  if (installed)
-    {
-      for (i = 0; i < solv->decisionq.count; i++)
-       {
-         p = solv->decisionq.elements[i];
-         if (p <= 0 || p == SYSTEMSOLVABLE)
-           continue;
-         s = pool->solvables + p;
-         if (s->repo == installed)
-           continue;
-         noobs = solv->noobsoletes.size && MAPTST(&solv->noobsoletes, p);
-         FOR_PROVIDES(p2, pp2, s->name)
-           {
-             if (solv->decisionmap[p2] > 0)
-               continue;
-             s2 = pool->solvables + p2;
-             if (s2->repo != installed)
-               continue;
-             if (noobs && (s->name != s2->name || s->evr != s2->evr || s->arch != s2->arch))
-               continue;
-             if (!solv->implicitobsoleteusesprovides && s->name != s2->name)
-               continue;
-             queue_push(ti, p);
-             queue_push(ti, p2);
-           }
-         if (s->obsoletes && !noobs)
-           {
-             Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
-             while ((obs = *obsp++) != 0)
-               {
-                 FOR_PROVIDES(p2, pp2, obs)
-                   {
-                     s2 = pool->solvables + p2;
-                     if (s2->repo != installed)
-                       continue;
-                     if (!solv->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p2, obs))
-                       continue;
-                     queue_push(ti, p);
-                     queue_push(ti, p2);
-                   }
-               }
-           }
-       }
-      obsq_sortcmp_data = solv;
-      qsort(ti->elements, ti->count / 2, 2 * sizeof(Id), obsq_sortcmp);
-      /* now unify */
-      for (i = j = 0; i < ti->count; i += 2)
-       {
-         if (j && ti->elements[i] == ti->elements[j - 2] && ti->elements[i + 1] == ti->elements[j - 1])
-           continue;
-         ti->elements[j++] = ti->elements[i];
-         ti->elements[j++] = ti->elements[i + 1];
-       }
-      ti->count = j;
-    }
-
-  if (installed)
-    {
-      FOR_REPO_SOLVABLES(installed, p, s)
-       {
-         if (solv->decisionmap[p] > 0)
-           continue;
-         p2 = solver_transaction_pkg(solv, p);
-         if (!p2)
-           queue_push(&solv->transaction, SOLVER_TRANSACTION_ERASE);
-         else
-           {
-             s2 = pool->solvables + p2;
-             if (s->name == s2->name)
-               {
-                 if (s->evr == s2->evr && solvable_identical(s, s2))
-                   queue_push(&solv->transaction, SOLVER_TRANSACTION_REINSTALLED);
-                 else
-                   {
-                     r = evrcmp(pool, s->evr, s2->evr, EVRCMP_COMPARE);
-                     if (r < 0)
-                       queue_push(&solv->transaction, SOLVER_TRANSACTION_UPGRADED);
-                     else if (r > 0)
-                       queue_push(&solv->transaction, SOLVER_TRANSACTION_DOWNGRADED);
-                     else
-                       queue_push(&solv->transaction, SOLVER_TRANSACTION_CHANGED);
-                   }
-               }
-             else
-               queue_push(&solv->transaction, SOLVER_TRANSACTION_OBSOLETED);
-           }
-         queue_push(&solv->transaction, p);
-       }
-    }
-  for (i = 0; i < solv->decisionq.count; i++)
-    {
-      p = solv->decisionq.elements[i];
-      if (p < 0 || p == SYSTEMSOLVABLE)
-       continue;
-      s = pool->solvables + p;
-      if (solv->installed && s->repo == solv->installed)
-       continue;
-      noobs = solv->noobsoletes.size && MAPTST(&solv->noobsoletes, p);
-      p2 = solver_transaction_pkg(solv, p);
-      if (noobs)
-       queue_push(&solv->transaction, p2 ? SOLVER_TRANSACTION_MULTIREINSTALL : SOLVER_TRANSACTION_MULTIINSTALL);
-      else if (!p2)
-       queue_push(&solv->transaction, SOLVER_TRANSACTION_INSTALL);
-      else
-       {
-         s2 = pool->solvables + p2;
-         if (s->name == s2->name)
-           {
-             if (s->evr == s2->evr && solvable_identical(s, s2))
-               queue_push(&solv->transaction, SOLVER_TRANSACTION_REINSTALL);
-             else
-               {
-                 r = evrcmp(pool, s->evr, s2->evr, EVRCMP_COMPARE);
-                 if (r > 0)
-                   queue_push(&solv->transaction, SOLVER_TRANSACTION_UPGRADE);
-                 else if (r < 0)
-                   queue_push(&solv->transaction, SOLVER_TRANSACTION_DOWNGRADE);
-                 else
-                   queue_push(&solv->transaction, SOLVER_TRANSACTION_CHANGE);
-               }
-           }
-         else
-           queue_push(&solv->transaction, SOLVER_TRANSACTION_RENAME);
-       }
-      queue_push(&solv->transaction, p);
-    }
-}
-
 /*
  *
  * solve job queue
@@ -5072,8 +4873,7 @@ solver_solve(Solver *solv, Queue *job)
              assert(solv->distupgrade && !sr->p);
              continue;
            }
-         unifyrules_sortcmp_data = pool;
-         if (!unifyrules_sortcmp(r, sr))
+         if (!unifyrules_sortcmp(r, sr, pool))
            {
              /* identical rule, kill unneeded one */
              if (solv->allowuninstall)
@@ -5259,10 +5059,10 @@ solver_solve(Solver *solv, Queue *job)
     solv->duprules = solv->duprules_end = solv->nrules;
 
 
-    /* all rules created
-     * --------------------------------------------------------------
-     * prepare for solving
-     */
+  /* all rules created
+   * --------------------------------------------------------------
+   * prepare for solving
+   */
     
   /* free unneeded memory */
   map_free(&addedmap);
@@ -5315,33 +5115,14 @@ solver_solve(Solver *solv, Queue *job)
   findrecommendedsuggested(solv);
 
   /*
-   * if unsolvable, prepare solution queue
+   * prepare solution queue if there were problems
    */
-  if (solv->problems.count)
-    {
-      int j = 1, idx = 1;
-      queue_push(&solv->solutions, 0);
-      queue_push(&solv->solutions, -1);        /* unrefined */
-      for (i = 1; i < solv->problems.count; i++)
-       {
-         Id p = solv->problems.elements[i];
-         queue_push(&solv->solutions, p);
-         if (p)
-           continue;
-         solv->problems.elements[j++] = idx;
-         if (i + 1 >= solv->problems.count)
-           break;
-         solv->problems.elements[j++] = solv->problems.elements[++i];  /* copy proofidx */
-         idx = solv->solutions.count;
-         queue_push(&solv->solutions, -1);
-       }
-      solv->problems.count = j;
-    }
+  prepare_solutions(solv);
 
   /*
    * finally prepare transaction info
    */
-  create_transaction(solv);
+  solver_create_transaction(solv);
 
   POOL_DEBUG(SAT_DEBUG_STATS, "final solver statistics: %d problems, %d learned rules, %d unsolvable\n", solv->problems.count / 2, solv->stats_learned, solv->stats_unsolvable);
   POOL_DEBUG(SAT_DEBUG_STATS, "solver_solve took %d ms\n", sat_timems(solve_start));
@@ -5465,7 +5246,7 @@ solver_find_involved(Solver *solv, Queue *installedq, Solvable *ts, Queue *q)
                  if (MAPTST(&im, p))
                    {
 #if FIND_INVOLVED_DEBUG
-                     printf("%s requires %s\n", solvable2str(pool, pool->solvables + ip), solvable2str(pool, pool->solvables + p));
+                     printf("%s requires %s\n", solvid2str(pool, ip), solvid2str(pool, p));
 #endif
                      queue_push(&iq, p);
                    }
@@ -5488,7 +5269,7 @@ solver_find_involved(Solver *solv, Queue *installedq, Solvable *ts, Queue *q)
                  if (MAPTST(&im, p))
                    {
 #if FIND_INVOLVED_DEBUG
-                     printf("%s recommends %s\n", solvable2str(pool, pool->solvables + ip), solvable2str(pool, pool->solvables + p));
+                     printf("%s recommends %s\n", solvid2str(pool, ip), solvid2str(pool, p));
 #endif
                      queue_push(&iq, p);
                    }
@@ -5514,7 +5295,7 @@ solver_find_involved(Solver *solv, Queue *installedq, Solvable *ts, Queue *q)
              if (sup)
                {
 #if FIND_INVOLVED_DEBUG
-                 printf("%s supplemented\n", solvable2str(pool, pool->solvables + ip));
+                 printf("%s supplemented\n", solvid2str(pool, ip));
 #endif
                  queue_push(&iq, ip);
                }
@@ -5550,7 +5331,7 @@ solver_find_involved(Solver *solv, Queue *installedq, Solvable *ts, Queue *q)
                      if (p == tp)
                        continue;
 #if FIND_INVOLVED_DEBUG
-                     printf("%s requires %s\n", solvable2str(pool, pool->solvables + ip), solvable2str(pool, pool->solvables + p));
+                     printf("%s requires %s\n", solvid2str(pool, ip), solvid2str(pool, p));
 #endif
                      MAPSET(&im, p);
                      queue_push(&iq, p);
@@ -5570,7 +5351,7 @@ solver_find_involved(Solver *solv, Queue *installedq, Solvable *ts, Queue *q)
                      if (p == tp)
                        continue;
 #if FIND_INVOLVED_DEBUG
-                     printf("%s recommends %s\n", solvable2str(pool, pool->solvables + ip), solvable2str(pool, pool->solvables + p));
+                     printf("%s recommends %s\n", solvid2str(pool, ip), solvid2str(pool, p));
 #endif
                      MAPSET(&im, p);
                      queue_push(&iq, p);
@@ -5598,7 +5379,7 @@ solver_find_involved(Solver *solv, Queue *installedq, Solvable *ts, Queue *q)
              if (sup)
                {
 #if FIND_INVOLVED_DEBUG
-                 printf("%s supplemented\n", solvable2str(pool, pool->solvables + ip));
+                 printf("%s supplemented\n", solvid2str(pool, ip));
 #endif
                  MAPSET(&im, ip);
                  queue_push(&iq, ip);
@@ -5707,7 +5488,7 @@ addrpmruleinfo(Solver *solv, Id p, Id d, int type, Id dep)
 }
 
 static int
-solver_allruleinfos_cmp(const void *ap, const void *bp)
+solver_allruleinfos_cmp(const void *ap, const void *bp, void *dp)
 {
   const Id *a = ap, *b = bp;
   int r;
@@ -5758,7 +5539,7 @@ solver_allruleinfos(Solver *solv, Id rid, Queue *rq)
   /* now sort & unify em */
   if (!rq->count)
     return 0;
-  qsort(rq->elements, rq->count / 4, 4 * sizeof(Id), solver_allruleinfos_cmp);
+  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)
     {
index c271591..5330d3a 100644 (file)
@@ -22,6 +22,7 @@ extern "C" {
 #include "repo.h"
 #include "queue.h"
 #include "bitmap.h"
+#include "transaction.h"
 /*
  * Callback definitions in order to "overwrite" the policies by an external application.
  */
@@ -57,14 +58,15 @@ typedef struct rule {
   Id n1, n2;           /* next rules in linked list, corresponding to w1,w2 */
 } Rule;
 
-struct solver;
+struct _Solver;
 
-typedef struct solver {
+typedef struct _Solver {
   Pool *pool;
   Queue job;                           /* copy of the job we're solving */
 
   Queue transaction;                   /* solver result */
   Queue transaction_info;              /* transaction obsoletes info */
+  Id *transaction_installed;            /* data for installed packages */
 
   Repo *installed;                     /* copy of pool->installed */
   
@@ -130,7 +132,7 @@ typedef struct solver {
   Queue learnt_pool;
 
   Queue branches;
-  int (*solution_callback)(struct solver *solv, void *data);
+  int (*solution_callback)(struct _Solver *solv, void *data);
   void *solution_callback_data;
 
   int propagate_index;                  /* index into decisionq for non-propagated decisions */
@@ -328,29 +330,9 @@ typedef enum {
 #define SOLVER_SOLUTION_DISTUPGRADE    (-1)
 #define SOLVER_SOLUTION_INFARCH                (-2)
 
-#define SOLVER_TRANSACTION_ERASE               0x10
-#define SOLVER_TRANSACTION_REINSTALLED         0x11
-#define SOLVER_TRANSACTION_DOWNGRADED          0x12
-#define SOLVER_TRANSACTION_CHANGED             0x13
-#define SOLVER_TRANSACTION_UPGRADED            0x14
-#define SOLVER_TRANSACTION_OBSOLETED           0x15
-
-#define SOLVER_TRANSACTION_INSTALL             0x20
-#define SOLVER_TRANSACTION_REINSTALL           0x21
-#define SOLVER_TRANSACTION_DOWNGRADE           0x22
-#define SOLVER_TRANSACTION_CHANGE              0x23
-#define SOLVER_TRANSACTION_UPGRADE             0x24
-#define SOLVER_TRANSACTION_RENAME              0x25
-
-#define SOLVER_TRANSACTION_MULTIINSTALL                0x30
-#define SOLVER_TRANSACTION_MULTIREINSTALL      0x31
-
-
 extern Solver *solver_create(Pool *pool);
 extern void solver_free(Solver *solv);
 extern void solver_solve(Solver *solv, Queue *job);
-extern void solver_transaction_info(Solver *solv, Id p, Queue *info);
-extern Id solver_transaction_pkg(Solver *solv, Id p);
 
 extern int solver_dep_installed(Solver *solv, Id dep);
 extern int solver_splitprovides(Solver *solv, Id dep);
index 1b74e1e..6bfc2a3 100644 (file)
@@ -297,7 +297,7 @@ solver_printdecisions(Solver *solv)
           POOL_DEBUG(SAT_DEBUG_RESULT, "  change    %s", solvable2str(pool, s));
          break;
        case SOLVER_TRANSACTION_UPGRADE:
-       case SOLVER_TRANSACTION_RENAME:
+       case SOLVER_TRANSACTION_REPLACE:
           POOL_DEBUG(SAT_DEBUG_RESULT, "  upgrade   %s", solvable2str(pool, s));
          break;
        case SOLVER_TRANSACTION_ERASE:
@@ -316,13 +316,13 @@ solver_printdecisions(Solver *solv)
        case SOLVER_TRANSACTION_DOWNGRADE:
        case SOLVER_TRANSACTION_CHANGE:
        case SOLVER_TRANSACTION_UPGRADE:
-       case SOLVER_TRANSACTION_RENAME:
-         solver_transaction_info(solv, solv->transaction.elements[i + 1], &iq);
+       case SOLVER_TRANSACTION_REPLACE:
+         solver_transaction_all_pkgs(solv, solv->transaction.elements[i + 1], &iq);
          if (iq.count)
            {
              POOL_DEBUG(SAT_DEBUG_RESULT, "  (obsoletes");
              for (j = 0; j < iq.count; j++)
-               POOL_DEBUG(SAT_DEBUG_RESULT, " %s", solvable2str(pool, pool->solvables + iq.elements[j]));
+               POOL_DEBUG(SAT_DEBUG_RESULT, " %s", solvid2str(pool, iq.elements[j]));
              POOL_DEBUG(SAT_DEBUG_RESULT, ")");
            }
          POOL_DEBUG(SAT_DEBUG_RESULT, "\n");
@@ -393,22 +393,18 @@ solver_printprobleminfo(Solver *solv, Queue *job, Id problem)
   Pool *pool = solv->pool;
   Id probr;
   Id dep, source, target;
-  Solvable *s, *s2;
 
   probr = solver_findproblemrule(solv, problem);
   switch (solver_problemruleinfo(solv, job, probr, &dep, &source, &target))
     {
     case SOLVER_RULE_DISTUPGRADE:
-      s = pool_id2solvable(pool, source);
-      POOL_DEBUG(SAT_DEBUG_RESULT, "%s does not belong to a distupgrade repository\n", solvable2str(pool, s));
+      POOL_DEBUG(SAT_DEBUG_RESULT, "%s does not belong to a distupgrade repository\n", solvid2str(pool, source));
       return;
     case SOLVER_RULE_INFARCH:
-      s = pool_id2solvable(pool, source);
-      POOL_DEBUG(SAT_DEBUG_RESULT, "%s has inferior architecture\n", solvable2str(pool, s));
+      POOL_DEBUG(SAT_DEBUG_RESULT, "%s has inferior architecture\n", solvid2str(pool, source));
       return;
     case SOLVER_RULE_UPDATE:
-      s = pool_id2solvable(pool, source);
-      POOL_DEBUG(SAT_DEBUG_RESULT, "problem with installed package %s\n", solvable2str(pool, s));
+      POOL_DEBUG(SAT_DEBUG_RESULT, "problem with installed package %s\n", solvid2str(pool, source));
       return;
     case SOLVER_RULE_JOB:
       POOL_DEBUG(SAT_DEBUG_RESULT, "conflicting requests\n");
@@ -420,40 +416,28 @@ solver_printprobleminfo(Solver *solv, Queue *job, Id problem)
       POOL_DEBUG(SAT_DEBUG_RESULT, "some dependency problem\n");
       return;
     case SOLVER_RULE_RPM_NOT_INSTALLABLE:
-      s = pool_id2solvable(pool, source);
-      POOL_DEBUG(SAT_DEBUG_RESULT, "package %s is not installable\n", solvable2str(pool, s));
+      POOL_DEBUG(SAT_DEBUG_RESULT, "package %s is not installable\n", solvid2str(pool, source));
       return;
     case SOLVER_RULE_RPM_NOTHING_PROVIDES_DEP:
-      s = pool_id2solvable(pool, source);
-      POOL_DEBUG(SAT_DEBUG_RESULT, "nothing provides %s needed by %s\n", dep2str(pool, dep), solvable2str(pool, s));
+      POOL_DEBUG(SAT_DEBUG_RESULT, "nothing provides %s needed by %s\n", dep2str(pool, dep), solvid2str(pool, source));
       return;
     case SOLVER_RULE_RPM_SAME_NAME:
-      s = pool_id2solvable(pool, source);
-      s2 = pool_id2solvable(pool, target);
-      POOL_DEBUG(SAT_DEBUG_RESULT, "cannot install both %s and %s\n", solvable2str(pool, s), solvable2str(pool, s2));
+      POOL_DEBUG(SAT_DEBUG_RESULT, "cannot install both %s and %s\n", solvid2str(pool, source), solvid2str(pool, target));
       return;
     case SOLVER_RULE_RPM_PACKAGE_CONFLICT:
-      s = pool_id2solvable(pool, source);
-      s2 = pool_id2solvable(pool, target);
-      POOL_DEBUG(SAT_DEBUG_RESULT, "package %s conflicts with %s provided by %s\n", solvable2str(pool, s), dep2str(pool, dep), solvable2str(pool, s2));
+      POOL_DEBUG(SAT_DEBUG_RESULT, "package %s conflicts with %s provided by %s\n", solvid2str(pool, source), dep2str(pool, dep), solvid2str(pool, target));
       return;
     case SOLVER_RULE_RPM_PACKAGE_OBSOLETES:
-      s = pool_id2solvable(pool, source);
-      s2 = pool_id2solvable(pool, target);
-      POOL_DEBUG(SAT_DEBUG_RESULT, "package %s obsoletes %s provided by %s\n", solvable2str(pool, s), dep2str(pool, dep), solvable2str(pool, s2));
+      POOL_DEBUG(SAT_DEBUG_RESULT, "package %s obsoletes %s provided by %s\n", solvid2str(pool, source), dep2str(pool, dep), solvid2str(pool, target));
       return;
     case SOLVER_RULE_RPM_IMPLICIT_OBSOLETES:
-      s = pool_id2solvable(pool, source);
-      s2 = pool_id2solvable(pool, target);
-      POOL_DEBUG(SAT_DEBUG_RESULT, "package %s implicitely obsoletes %s provided by %s\n", solvable2str(pool, s), dep2str(pool, dep), solvable2str(pool, s2));
+      POOL_DEBUG(SAT_DEBUG_RESULT, "package %s implicitely obsoletes %s provided by %s\n", solvid2str(pool, source), dep2str(pool, dep), solvid2str(pool, target));
       return;
     case SOLVER_RULE_RPM_PACKAGE_REQUIRES:
-      s = pool_id2solvable(pool, source);
-      POOL_DEBUG(SAT_DEBUG_RESULT, "package %s requires %s, but none of the providers can be installed\n", solvable2str(pool, s), dep2str(pool, dep));
+      POOL_DEBUG(SAT_DEBUG_RESULT, "package %s requires %s, but none of the providers can be installed\n", solvid2str(pool, source), dep2str(pool, dep));
       return;
     case SOLVER_RULE_RPM_SELF_CONFLICT:
-      s = pool_id2solvable(pool, source);
-      POOL_DEBUG(SAT_DEBUG_RESULT, "package %s conflicts with %s provided by itself\n", solvable2str(pool, s), dep2str(pool, dep));
+      POOL_DEBUG(SAT_DEBUG_RESULT, "package %s conflicts with %s provided by itself\n", solvid2str(pool, source), dep2str(pool, dep));
       return;
     case SOLVER_RULE_UNKNOWN:
     case SOLVER_RULE_FEATURE:
@@ -497,7 +481,7 @@ solver_printsolutions(Solver *solv, Queue *job)
                    {
                    case SOLVER_INSTALL:
                      if (select == SOLVER_SOLVABLE && solv->installed && pool->solvables[what].repo == solv->installed)
-                       POOL_DEBUG(SAT_DEBUG_RESULT, "- do not keep %s installed\n", solvable2str(pool, pool->solvables + what));
+                       POOL_DEBUG(SAT_DEBUG_RESULT, "- do not keep %s installed\n", solvid2str(pool, what));
                      else if (select == SOLVER_SOLVABLE_PROVIDES)
                        POOL_DEBUG(SAT_DEBUG_RESULT, "- do not install a solvable %s\n", solver_select2str(solv, select, what));
                      else
@@ -505,7 +489,7 @@ solver_printsolutions(Solver *solv, Queue *job)
                      break;
                    case SOLVER_ERASE:
                      if (select == SOLVER_SOLVABLE && !(solv->installed && pool->solvables[what].repo == solv->installed))
-                       POOL_DEBUG(SAT_DEBUG_RESULT, "- do not forbid installation of %s\n", solvable2str(pool, pool->solvables + what));
+                       POOL_DEBUG(SAT_DEBUG_RESULT, "- do not forbid installation of %s\n", solvid2str(pool, what));
                      else if (select == SOLVER_SOLVABLE_PROVIDES)
                        POOL_DEBUG(SAT_DEBUG_RESULT, "- do not deinstall all solvables %s\n", solver_select2str(solv, select, what));
                      else
@@ -610,7 +594,7 @@ solver_printtrivial(Solver *solv)
   solver_trivial_installable(solv, &in, &out);
   POOL_DEBUG(SAT_DEBUG_RESULT, "trivial installable status:\n");
   for (i = 0; i < in.count; i++)
-    POOL_DEBUG(SAT_DEBUG_RESULT, "  %s: %d\n", solvable2str(pool, pool->solvables + in.elements[i]), out.elements[i]);
+    POOL_DEBUG(SAT_DEBUG_RESULT, "  %s: %d\n", solvid2str(pool, in.elements[i]), out.elements[i]);
   POOL_DEBUG(SAT_DEBUG_RESULT, "\n");
   queue_free(&in);
   queue_free(&out);
@@ -623,7 +607,7 @@ solver_select2str(Solver *solv, Id select, Id what)
   const char *s;
   char *b;
   if (select == SOLVER_SOLVABLE)
-    return solvable2str(pool, pool->solvables + what);
+    return solvid2str(pool, what);
   if (select == SOLVER_SOLVABLE_NAME)
     return dep2str(pool, what);
   if (select == SOLVER_SOLVABLE_PROVIDES)
@@ -640,7 +624,7 @@ solver_select2str(Solver *solv, Id select, Id what)
       b = "";
       while ((p = pool->whatprovidesdata[what++]) != 0)
        {
-         s = solvable2str(pool, pool->solvables + p);
+         s = solvid2str(pool, p);
          b2 = pool_alloctmpspace(pool, strlen(b) + strlen(s) + 3);
          sprintf(b2, "%s, %s", b, s);
          b = b2;
diff --git a/src/transaction.c b/src/transaction.c
new file mode 100644 (file)
index 0000000..cf682f3
--- /dev/null
@@ -0,0 +1,690 @@
+/*
+ * Copyright (c) 2007-2009, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * transaction.c
+ *
+ * Transaction handling
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+
+#include "transaction.h"
+#include "solver.h"
+#include "bitmap.h"
+#include "pool.h"
+#include "evr.h"
+#include "util.h"
+
+static int
+obsq_sortcmp(const void *ap, const void *bp, void *dp)
+{
+  Id a, b, oa, ob;
+  Pool *pool = dp;
+  Solvable *s, *oas, *obs;
+  int r;
+
+  a = ((Id *)ap)[0];
+  oa = ((Id *)ap)[1];
+  b = ((Id *)bp)[0];
+  ob = ((Id *)bp)[1];
+  if (a != b)
+    return a - b;
+  if (oa == ob)
+    return 0;
+  s = pool->solvables + a;
+  oas = pool->solvables + oa;
+  obs = pool->solvables + ob;
+  if (oas->name != obs->name)
+    {
+      if (oas->name == s->name)
+        return -1;
+      if (obs->name == s->name)
+        return 1;
+      return strcmp(id2str(pool, oas->name), id2str(pool, obs->name));
+    }
+  r = evrcmp(pool, oas->evr, obs->evr, EVRCMP_COMPARE);
+  if (r)
+    return -r; /* highest version first */
+  return oa - ob;
+}
+
+void
+solver_transaction_all_pkgs(Solver *solv, Id p, Queue *pkgs)
+{
+  Pool *pool = solv->pool;
+  Solvable *s = pool->solvables + p;
+  Queue *ti = &solv->transaction_info;
+  Id q;
+  int i;
+
+  queue_empty(pkgs);
+  if (p <= 0 || !s->repo)
+    return;
+  if (s->repo == solv->installed)
+    {
+      q = solv->transaction_installed[p - solv->installed->start];
+      if (!q)
+       return;
+      if (q > 0)
+       {
+         queue_push(pkgs, q);
+         return;
+       }
+      /* find which packages obsolete us */
+      for (i = 0; i < ti->count; i += 2)
+       if (ti->elements[i + 1] == p)
+         {
+           queue_push(pkgs, p);
+           queue_push(pkgs, ti->elements[i]);
+         }
+      /* sort obsoleters */
+      if (pkgs->count > 2)
+       sat_sort(pkgs->elements, pkgs->count / 2, 2 * sizeof(Id), obsq_sortcmp, pool);
+      for (i = 0; i < pkgs->count; i += 2)
+       pkgs->elements[i / 2] = pkgs->elements[i + 1];
+      pkgs->count /= 2;
+    }
+  else
+    {
+      /* find the packages we obsolete */
+      for (i = 0; i < ti->count; i += 2)
+       {
+         if (ti->elements[i] == p)
+           queue_push(pkgs, ti->elements[i + 1]);
+         else if (pkgs->count)
+           break;
+       }
+    }
+}
+
+Id
+solver_transaction_pkg(Solver *solv, Id p)
+{
+  Pool *pool = solv->pool;
+  Solvable *s = pool->solvables + p;
+  Queue ti;
+  Id tibuf[5];
+
+  if (p <= 0 || !s->repo)
+    return 0;
+  if (s->repo == solv->installed)
+    {
+      p = solv->transaction_installed[p - solv->installed->start];
+      return p < 0 ? -p : p;
+    }
+  queue_init_buffer(&ti, tibuf, sizeof(tibuf)/sizeof(*tibuf));
+  solver_transaction_all_pkgs(solv, p, &ti);
+  p = ti.count ? ti.elements[0] : 0;
+  queue_free(&ti);
+  return p;
+}
+
+/* type filtering, needed if either not all packages are shown
+ * or replaces are not shown, as otherwise parts of the
+ * transaction might not be shown to the user */
+
+Id
+solver_transaction_filter(Solver *solv, Id type, Id p, int flags)
+{
+  Pool *pool = solv->pool;
+  Solvable *s = pool->solvables + p;
+  Queue oq, rq;
+  Id q;
+  int i, j, ref = 0;
+
+  if (type == SOLVER_TRANSACTION_ERASE || type == SOLVER_TRANSACTION_INSTALL || type == SOLVER_TRANSACTION_MULTIINSTALL)
+    return type;
+
+  if (s->repo == pool->installed && (flags & SOLVER_TRANSACTION_SHOW_ACTIVE) == 0)
+    {
+      /* erase element */
+      if ((flags & SOLVER_TRANSACTION_SHOW_REPLACES) == 0 && type == SOLVER_TRANSACTION_REPLACED)
+       type = SOLVER_TRANSACTION_ERASE;
+      return type;
+    }
+  if (s->repo != pool->installed && (flags & SOLVER_TRANSACTION_SHOW_ACTIVE) != 0)
+    {
+      if ((flags & SOLVER_TRANSACTION_SHOW_REPLACES) == 0 && type == SOLVER_TRANSACTION_REPLACE)
+       type = SOLVER_TRANSACTION_INSTALL;
+      return type;
+    }
+
+  /* most of the time there's only one reference, so check it first */
+  q = solver_transaction_pkg(solv, p);
+  if ((flags & SOLVER_TRANSACTION_SHOW_REPLACES) == 0)
+    {
+      Solvable *sq = pool->solvables + q;
+      if (sq->name != s->name)
+       {
+         if (s->repo == pool->installed)
+           return SOLVER_TRANSACTION_ERASE;
+         else if (type == SOLVER_TRANSACTION_MULTIREINSTALL)
+           return SOLVER_TRANSACTION_MULTIINSTALL;
+         else
+           return SOLVER_TRANSACTION_INSTALL;
+       }
+    }
+  if (solver_transaction_pkg(solv, q) == p)
+    return type;
+
+  /* too bad, a miss. check em all */
+  queue_init(&oq);
+  queue_init(&rq);
+  solver_transaction_all_pkgs(solv, p, &oq);
+  for (i = 0; i < oq.count; i++)
+    {
+      q = oq.elements[i];
+      if ((flags & SOLVER_TRANSACTION_SHOW_REPLACES) == 0)
+       {
+         Solvable *sq = pool->solvables + q;
+         if (sq->name != s->name)
+           continue;
+       }
+      /* check if we are referenced? */
+      if ((flags & SOLVER_TRANSACTION_SHOW_ALL) != 0)
+       {
+         solver_transaction_all_pkgs(solv, q, &rq);
+         for (j = 0; j < rq.count; j++)
+           if (rq.elements[j] == p)
+             {
+               ref = 1;
+               break;
+             }
+         if (ref)
+           break;
+       }
+      else if (solver_transaction_pkg(solv, q) == p)
+        {
+         ref = 1;
+         break;
+        }
+    }
+  queue_free(&oq);
+  queue_free(&rq);
+
+  if (!ref)
+    {
+      if (s->repo == pool->installed)
+       type = SOLVER_TRANSACTION_ERASE;
+      else if (type == SOLVER_TRANSACTION_MULTIREINSTALL)
+       type = SOLVER_TRANSACTION_MULTIINSTALL;
+      else
+       type = SOLVER_TRANSACTION_INSTALL;
+    }
+  return type;
+}
+
+static void
+create_transaction_info(Solver *solv)
+{
+  Pool *pool = solv->pool;
+  Queue *ti = &solv->transaction_info;
+  Repo *installed = solv->installed;
+  int i, j, noobs;
+  Id p, p2, pp2;
+  Solvable *s, *s2;
+
+  queue_empty(ti);
+  if (!installed)
+    return;    /* no info needed */
+  for (i = 0; i < solv->decisionq.count; i++)
+    {
+      p = solv->decisionq.elements[i];
+      if (p <= 0 || p == SYSTEMSOLVABLE)
+       continue;
+      s = pool->solvables + p;
+      if (s->repo == installed)
+       continue;
+      noobs = solv->noobsoletes.size && MAPTST(&solv->noobsoletes, p);
+      FOR_PROVIDES(p2, pp2, s->name)
+       {
+         if (solv->decisionmap[p2] > 0)
+           continue;
+         s2 = pool->solvables + p2;
+         if (s2->repo != installed)
+           continue;
+         if (noobs && (s->name != s2->name || s->evr != s2->evr || s->arch != s2->arch))
+           continue;
+         if (!solv->implicitobsoleteusesprovides && s->name != s2->name)
+           continue;
+         queue_push(ti, p);
+         queue_push(ti, p2);
+       }
+      if (s->obsoletes && !noobs)
+       {
+         Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
+         while ((obs = *obsp++) != 0)
+           {
+             FOR_PROVIDES(p2, pp2, obs)
+               {
+                 s2 = pool->solvables + p2;
+                 if (s2->repo != installed)
+                   continue;
+                 if (!solv->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p2, obs))
+                   continue;
+                 queue_push(ti, p);
+                 queue_push(ti, p2);
+               }
+           }
+       }
+    }
+  sat_sort(ti->elements, ti->count / 2, 2 * sizeof(Id), obsq_sortcmp, pool);
+  /* now unify */
+  for (i = j = 0; i < ti->count; i += 2)
+    {
+      if (j && ti->elements[i] == ti->elements[j - 2] && ti->elements[i + 1] == ti->elements[j - 1])
+       continue;
+      ti->elements[j++] = ti->elements[i];
+      ti->elements[j++] = ti->elements[i + 1];
+    }
+  ti->count = j;
+
+  /* create transaction_installed helper */
+  solv->transaction_installed = sat_calloc(installed->end - installed->start, sizeof(Id));
+  for (i = 0; i < ti->count; i += 2)
+    {
+      j = ti->elements[i + 1] - installed->start;
+      if (!solv->transaction_installed[j])
+       solv->transaction_installed[j] = ti->elements[i];
+      else
+       {
+         /* more than one package obsoletes us. compare */
+         Id q[4];
+         if (solv->transaction_installed[j] > 0)
+           solv->transaction_installed[j] = -solv->transaction_installed[j];
+         q[0] = q[2] = ti->elements[i + 1];
+         q[1] = ti->elements[i];
+         q[3] = -solv->transaction_installed[j];
+         if (obsq_sortcmp(q, q + 2, pool) < 0)
+           solv->transaction_installed[j] = -ti->elements[i];
+       }
+    }
+}
+
+
+void
+solver_create_transaction(Solver *solv)
+{
+  Pool *pool = solv->pool;
+  Repo *installed = solv->installed;
+  int i, r, noobs;
+  Id p, p2;
+  Solvable *s, *s2;
+
+  queue_empty(&solv->transaction);
+  create_transaction_info(solv);
+
+  if (installed)
+    {
+      FOR_REPO_SOLVABLES(installed, p, s)
+       {
+         if (solv->decisionmap[p] > 0)
+           continue;
+         p2 = solver_transaction_pkg(solv, p);
+         if (!p2)
+           queue_push(&solv->transaction, SOLVER_TRANSACTION_ERASE);
+         else
+           {
+             s2 = pool->solvables + p2;
+             if (s->name == s2->name)
+               {
+                 if (s->evr == s2->evr && solvable_identical(s, s2))
+                   queue_push(&solv->transaction, SOLVER_TRANSACTION_REINSTALLED);
+                 else
+                   {
+                     r = evrcmp(pool, s->evr, s2->evr, EVRCMP_COMPARE);
+                     if (r < 0)
+                       queue_push(&solv->transaction, SOLVER_TRANSACTION_UPGRADED);
+                     else if (r > 0)
+                       queue_push(&solv->transaction, SOLVER_TRANSACTION_DOWNGRADED);
+                     else
+                       queue_push(&solv->transaction, SOLVER_TRANSACTION_CHANGED);
+                   }
+               }
+             else
+               queue_push(&solv->transaction, SOLVER_TRANSACTION_REPLACED);
+           }
+         queue_push(&solv->transaction, p);
+       }
+    }
+  for (i = 0; i < solv->decisionq.count; i++)
+    {
+      p = solv->decisionq.elements[i];
+      if (p < 0 || p == SYSTEMSOLVABLE)
+       continue;
+      s = pool->solvables + p;
+      if (solv->installed && s->repo == solv->installed)
+       continue;
+      noobs = solv->noobsoletes.size && MAPTST(&solv->noobsoletes, p);
+      p2 = solver_transaction_pkg(solv, p);
+      if (noobs)
+       queue_push(&solv->transaction, p2 ? SOLVER_TRANSACTION_MULTIREINSTALL : SOLVER_TRANSACTION_MULTIINSTALL);
+      else if (!p2)
+       queue_push(&solv->transaction, SOLVER_TRANSACTION_INSTALL);
+      else
+       {
+         s2 = pool->solvables + p2;
+         if (s->name == s2->name)
+           {
+             if (s->evr == s2->evr && solvable_identical(s, s2))
+               queue_push(&solv->transaction, SOLVER_TRANSACTION_REINSTALL);
+             else
+               {
+                 r = evrcmp(pool, s->evr, s2->evr, EVRCMP_COMPARE);
+                 if (r > 0)
+                   queue_push(&solv->transaction, SOLVER_TRANSACTION_UPGRADE);
+                 else if (r < 0)
+                   queue_push(&solv->transaction, SOLVER_TRANSACTION_DOWNGRADE);
+                 else
+                   queue_push(&solv->transaction, SOLVER_TRANSACTION_CHANGE);
+               }
+           }
+         else
+           queue_push(&solv->transaction, SOLVER_TRANSACTION_REPLACE);
+       }
+      queue_push(&solv->transaction, p);
+    }
+}
+
+#define TYPE_REQ    (1<<0)
+#define TYPE_PREREQ (1<<1)
+#define TYPE_CON    (1<<2)
+#define TYPE_ERASE  (1<<3)
+
+#define EDGEDATA_BLOCK 127
+
+struct transel {
+  Id p;
+  Id edges;
+};
+
+struct orderdata {
+  Solver *solv;
+  struct transel *tes;
+  int ntes;
+  Id *edgedata;
+  int nedgedata;
+};
+
+static void
+addedge(struct orderdata *od, Id from, Id to, int type)
+{
+  Solver *solv = od->solv;
+  Pool *pool = solv->pool;
+  Solvable *s;
+  struct transel *te;
+  int i;
+
+  // printf("addedge %d %d type %d\n", from, to, type);
+  s = pool->solvables + from;
+  if (s->repo == solv->installed && solv->transaction_installed[from - solv->installed->start])
+    {
+      /* passive, map to active */
+      if (solv->transaction_installed[from - solv->installed->start] > 0)
+       from = solv->transaction_installed[from - solv->installed->start];
+      else
+       {
+         Queue ti;
+         Id tibuf[5];
+         queue_init_buffer(&ti, tibuf, sizeof(tibuf)/sizeof(*tibuf));
+         solver_transaction_all_pkgs(solv, from, &ti);
+         for (i = 0; i < ti.count; i++)
+           addedge(od, ti.elements[i], to, type);
+         queue_free(&ti);
+       }
+      return;
+    }
+  s = pool->solvables + to;
+  if (s->repo == solv->installed && solv->transaction_installed[to - solv->installed->start])
+    {
+      /* passive, map to active */
+      if (solv->transaction_installed[to - solv->installed->start] > 0)
+       to = solv->transaction_installed[to - solv->installed->start];
+      else
+       {
+         Queue ti;
+         Id tibuf[5];
+         queue_init_buffer(&ti, tibuf, sizeof(tibuf)/sizeof(*tibuf));
+         solver_transaction_all_pkgs(solv, to, &ti);
+         for (i = 0; i < ti.count; i++)
+           addedge(od, from, ti.elements[i], type);
+         queue_free(&ti);
+         return;
+       }
+    }
+
+  /* map target to te num */
+  for (i = 1, te = od->tes + i; i < od->ntes; i++, te++)
+    if (te->p == to)
+      break;
+  if (i == od->ntes)
+    return;
+  to = i;
+
+  for (i = 1, te = od->tes + i; i < od->ntes; i++, te++)
+    if (te->p == from)
+      break;
+  if (i == od->ntes)
+    return;
+
+  if (i == to)
+    return;    /* no edges to ourselfes */
+
+  // printf("edge %d -> %d type %x\n", i, to, type);
+
+  for (i = te->edges; od->edgedata[i]; i += 2)
+    if (od->edgedata[i] == to)
+      break;
+  if (od->edgedata[i])
+    {
+      od->edgedata[i + 1] |= type;
+      return;
+    }
+  if (i + 1 == od->nedgedata)
+    {
+      // printf("tail add %d\n", i - te->edges);
+      if (!i)
+       te->edges = ++i;
+      od->edgedata = sat_extend(od->edgedata, od->nedgedata, 3, sizeof(Id), EDGEDATA_BLOCK);
+    }
+  else
+    {
+      // printf("extend %d\n", i - te->edges);
+      od->edgedata = sat_extend(od->edgedata, od->nedgedata, 3 + (i - te->edges), sizeof(Id), EDGEDATA_BLOCK);
+      if (i > te->edges)
+       memcpy(od->edgedata + od->nedgedata, od->edgedata + te->edges, sizeof(Id) * (i - te->edges));
+      i = od->nedgedata + (i - te->edges);
+      te->edges = od->nedgedata;
+    }
+  od->edgedata[i] = to;
+  od->edgedata[i + 1] = type;
+  od->edgedata[i + 2] = 0;
+  od->nedgedata = i + 3;
+}
+
+void
+solver_order_transaction(Solver *solv)
+{
+  Pool *pool = solv->pool;
+  Queue *tr = &solv->transaction;
+  Repo *installed = solv->installed;
+  Id type, p;
+  Solvable *s, *s2;
+  Id req, *reqp, con, *conp;
+  Id p2, pp2;
+  int i, j, pre, numte, numedge;
+  struct orderdata od;
+  struct transel *te;
+
+  /* create a transaction element for every active component */
+  numte = 0;
+  for (i = 0; i < tr->count; i += 2)
+    {
+      p = tr->elements[i + 1];
+      s = pool->solvables + p;
+      if (s->repo != installed || !solv->transaction_installed[p - solv->installed->start])
+       numte++;
+    }
+  if (!numte)
+    return;    /* nothing to do... */
+
+
+  printf("numte = %d\n", numte);
+  numte++;     /* leave first one zero */
+  od.solv = solv;
+  od.ntes = numte;
+  od.tes = sat_calloc(numte, sizeof(*od.tes));
+  od.edgedata = sat_extend(0, 0, 1, sizeof(Id), EDGEDATA_BLOCK);
+  od.edgedata[0] = 0;
+  od.nedgedata = 1;
+
+  for (i = 0, te = od.tes + 1; i < tr->count; i += 2)
+    {
+      p = tr->elements[i + 1];
+      s = pool->solvables + p;
+      if (s->repo == installed && solv->transaction_installed[p - solv->installed->start])
+       continue;
+      te->p = p;
+      te++;
+    }
+
+  /* create dependency graph */
+  for (i = 0; i < tr->count; i += 2)
+    {
+      type = tr->elements[i];
+      p = tr->elements[i + 1];
+      s = pool->solvables + p;
+      if (s->requires)
+       {
+         reqp = s->repo->idarraydata + s->requires;
+         pre = TYPE_REQ;
+         while ((req = *reqp++) != 0)
+           {
+             int eraseonly = 0;
+             if (req == SOLVABLE_PREREQMARKER)
+               {
+                 pre = TYPE_PREREQ;
+                 continue;
+               }
+#if 1
+             if (s->repo == installed && pre != TYPE_PREREQ)
+               continue;
+#endif
+             FOR_PROVIDES(p2, pp2, req)
+               {
+                 if (p2 == p)
+                   continue;
+                 s2 = pool->solvables + p2;
+                 if (!s2->repo)
+                   continue;
+                 if (s2->repo == installed && solv->decisionmap[p2] > 0)
+                   continue;
+                 if (s2->repo != installed && solv->decisionmap[p2] < 0)
+                   continue;   /* not interesting */
+                 if (s->repo == installed)
+                   {
+                     /* we're uninstalling s */
+                     if (s2->repo == installed)
+                       {
+                         if (eraseonly == 0)
+                           eraseonly = 1;
+                       }
+                     if (s2->repo != installed)
+                       {
+                         /* update p2 before erasing p */
+#if 1
+                         addedge(&od, p, p2, pre);
+#endif
+                         eraseonly = -1;
+                       }
+                   }
+                 else
+                   {
+                     /* install p2 before installing p */
+                     if (s2->repo != installed)
+                       addedge(&od, p, p2, pre);
+                   }
+               }
+             if (eraseonly == 1)
+               {
+                 printf("eraseonlyedge for %s req %s\n", solvable2str(pool, s), dep2str(pool, req));
+                 /* need edges to uninstalled pkgs */
+#if 1
+                 FOR_PROVIDES(p2, pp2, req)
+                   {
+                     if (p2 == p)
+                       continue;
+                     s2 = pool->solvables + p2;
+                     if (!s2->repo || s2->repo != installed)
+                       continue;
+                     if (solv->decisionmap[p2] > 0)
+                       continue;
+#if 0
+                     addedge(&od, p2, p, pre);
+#else
+                     addedge(&od, p2, p, TYPE_ERASE);
+#endif
+                   }
+#endif
+               }
+           }
+       }
+      if (s->conflicts)
+       {
+         conp = s->repo->idarraydata + s->conflicts;
+         while ((con = *conp++) != 0)
+           {
+#if 1
+             FOR_PROVIDES(p2, pp2, con)
+               {
+                 if (p2 == p)
+                   continue;
+                 s2 = pool->solvables + p2;
+                 if (!s2->repo)
+                   continue;
+                 if (s->repo == installed)
+                   {
+                     if (s2->repo != installed && solv->decisionmap[p2] >= 0)
+                       {
+                         /* deinstall p before installing p2 */
+                         addedge(&od, p2, p, TYPE_CON);
+                       }
+                   }
+                 else
+                   {
+                     if (s2->repo == installed && solv->decisionmap[p2] < 0)
+                       {
+                         /* deinstall p2 before installing p */
+#if 1
+                         addedge(&od, p, p2, TYPE_CON);
+#endif
+                       }
+                   }
+
+               }
+#endif
+           }
+       }
+    }
+  numedge = 0;
+  for (i = 1, te = od.tes + i; i < numte; i++, te++)
+    {
+      printf("TE #%d, %d(%s)\n", i, te->p, solvid2str(pool, te->p));
+      for (j = te->edges; od.edgedata[j]; j += 2)
+        {
+         struct transel *te2 = od.tes + od.edgedata[j];
+         printf("  depends %x on TE %d, %d(%s)\n", od.edgedata[j + 1], od.edgedata[j], te2->p, solvid2str(pool, te2->p));
+          numedge++;
+       }
+    }
+  printf("TEs: %d, Edges: %d, Space: %d\n", numte - 1, numedge, od.nedgedata / 2);
+}
diff --git a/src/transaction.h b/src/transaction.h
new file mode 100644 (file)
index 0000000..25a7967
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2007-2009, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * transaction.h
+ *
+ */
+
+#ifndef SATSOLVER_TRANSACTION_H
+#define SATSOLVER_TRANSACTION_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "pooltypes.h"
+#include "queue.h"
+
+struct _Solver;
+
+#define SOLVER_TRANSACTION_ERASE               0x10
+#define SOLVER_TRANSACTION_REINSTALLED         0x11
+#define SOLVER_TRANSACTION_DOWNGRADED          0x12
+#define SOLVER_TRANSACTION_CHANGED             0x13
+#define SOLVER_TRANSACTION_UPGRADED            0x14
+#define SOLVER_TRANSACTION_REPLACED            0x15
+
+#define SOLVER_TRANSACTION_INSTALL             0x20
+#define SOLVER_TRANSACTION_REINSTALL           0x21
+#define SOLVER_TRANSACTION_DOWNGRADE           0x22
+#define SOLVER_TRANSACTION_CHANGE              0x23
+#define SOLVER_TRANSACTION_UPGRADE             0x24
+#define SOLVER_TRANSACTION_REPLACE             0x25
+
+#define SOLVER_TRANSACTION_MULTIINSTALL                0x30
+#define SOLVER_TRANSACTION_MULTIREINSTALL      0x31
+
+#define SOLVER_TRANSACTION_SHOW_ACTIVE          (1 << 0)
+#define SOLVER_TRANSACTION_SHOW_ALL             (1 << 1)
+#define SOLVER_TRANSACTION_SHOW_REPLACES        (1 << 2)
+
+extern void solver_create_transaction(struct _Solver *solv);
+extern void solver_transaction_all_pkgs(struct _Solver *solv, Id p, Queue *pkgs);
+extern Id   solver_transaction_pkg(struct _Solver *solv, Id p);
+extern Id   solver_transaction_filter(struct _Solver *solv, Id type, Id p, int mode);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
index 7fca8f3..5f20cf0 100644 (file)
@@ -47,6 +47,10 @@ SET(installcheck_SOURCES installcheck.c repo_rpmmd.c repo_susetags.c)
 ADD_EXECUTABLE(installcheck ${installcheck_SOURCES})
 TARGET_LINK_LIBRARIES(installcheck satsolver ${EXPAT_LIBRARY} ${ZLIB_LIBRARY})
 
+SET(patchcheck_SOURCES patchcheck.c repo_rpmmd.c repo_susetags.c repo_updateinfoxml.c)
+ADD_EXECUTABLE(patchcheck ${patchcheck_SOURCES})
+TARGET_LINK_LIBRARIES(patchcheck satsolver ${EXPAT_LIBRARY} ${ZLIB_LIBRARY})
+
 ADD_EXECUTABLE( dumpsolv dumpsolv.c )
 TARGET_LINK_LIBRARIES( dumpsolv satsolver)
 
diff --git a/tools/patchcheck.c b/tools/patchcheck.c
new file mode 100644 (file)
index 0000000..e24d88d
--- /dev/null
@@ -0,0 +1,487 @@
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <zlib.h>
+
+#include "pool.h"
+#include "evr.h"
+#include "poolarch.h"
+#include "repo_solv.h"
+#include "repo_susetags.h"
+#include "repo_updateinfoxml.h"
+#include "repo_rpmmd.h"
+#include "solver.h"
+#include "solverdebug.h"
+
+static ssize_t
+cookie_gzread(void *cookie, char *buf, size_t nbytes)
+{
+  return gzread((gzFile *)cookie, buf, nbytes);
+}
+
+static int
+cookie_gzclose(void *cookie)
+{
+  return gzclose((gzFile *)cookie);
+}
+
+FILE *
+myfopen(const char *fn)
+{
+  cookie_io_functions_t cio;
+  char *suf;
+  gzFile *gzf;
+
+  if (!fn)
+    return 0;
+  suf = strrchr(fn, '.');
+  if (!suf || strcmp(suf, ".gz") != 0)
+    return fopen(fn, "r");
+  gzf = gzopen(fn, "r");
+  if (!gzf)
+    return 0;
+  memset(&cio, 0, sizeof(cio));
+  cio.read = cookie_gzread;
+  cio.close = cookie_gzclose;
+  return  fopencookie(gzf, "r", cio);
+}
+
+void
+showproblems(Solver *solv, Solvable *s, Queue *cand, Queue *badguys)
+{
+  Pool *pool = solv->pool;
+  Queue rids, rinfo;
+  Id problem = 0;
+  int jj;
+  int rerun = 0;
+
+  queue_init(&rids);
+  queue_init(&rinfo);
+  printf("can't install %s:\n", solvable2str(pool, s));
+  while ((problem = solver_next_problem(solv, problem)) != 0)
+    {
+      solver_findallproblemrules(solv, problem, &rids);
+      for (jj = 0; jj < rids.count; jj++)
+       {
+         Id probr = rids.elements[jj];
+         int k, l;
+
+         queue_empty(&rinfo);
+         solver_allruleinfos(solv, probr, &rinfo);
+         for (k = 0; k < rinfo.count; k += 4)
+           {
+             Id dep, source, target;
+             source = rinfo.elements[k + 1];
+             target = rinfo.elements[k + 2];
+             dep = rinfo.elements[k + 3];
+             switch (rinfo.elements[k])
+               {
+               case SOLVER_PROBLEM_DISTUPGRADE_RULE:
+                 break;
+               case SOLVER_PROBLEM_INFARCH_RULE:
+                 printf("  %s has inferior architecture\n", solvid2str(pool, source));
+                 break;
+               case SOLVER_PROBLEM_UPDATE_RULE:
+                 printf("  update rule for %s\n", solvid2str(pool, source));
+                 if (badguys)
+                   queue_pushunique(badguys, source);
+                 if (!cand)
+                   break;
+                 /* only drop update problem packages from cand so that we see all problems of this patch */
+                 for (l = 0; l < cand->count; l++)
+                   if (cand->elements[l] == source || cand->elements[l] == -source)
+                     break;
+                 if (l == cand->count)
+                   break;
+                 if (!rerun)
+                   {
+                     for (l = 0; l < cand->count; l++)
+                       if (cand->elements[l] < 0)
+                         cand->elements[l] = -cand->elements[l];
+                     rerun = 1;
+                   }
+                 for (l = 0; l < cand->count; l++)
+                   if (cand->elements[l] == source)
+                     {
+                       cand->elements[l] = -source;
+                     }
+                 break;
+               case SOLVER_PROBLEM_JOB_RULE:
+                 break;
+               case SOLVER_PROBLEM_RPM_RULE:
+                 printf("  some dependency problem\n");
+                 break;
+               case SOLVER_PROBLEM_JOB_NOTHING_PROVIDES_DEP:
+                 printf("  nothing provides requested %s\n", dep2str(pool, dep));
+                 break;
+               case SOLVER_PROBLEM_NOT_INSTALLABLE:
+                 printf("  package %s is not installable\n", solvid2str(pool, source));
+                 break;
+               case SOLVER_PROBLEM_NOTHING_PROVIDES_DEP:
+                 printf("  nothing provides %s needed by %s\n", dep2str(pool, dep), solvid2str(pool, source));
+                 if (ISRELDEP(dep))
+                   {
+                     Reldep *rd = GETRELDEP(pool, dep);
+                     if (!ISRELDEP(rd->name))
+                       {
+                         Id rp, rpp;
+                         FOR_PROVIDES(rp, rpp, rd->name)
+                           printf("    (we have %s)\n", solvid2str(pool, rp));
+                       }
+                   }
+                 break;
+               case SOLVER_PROBLEM_SAME_NAME:
+                 printf("  cannot install both %s and %s\n", solvid2str(pool, source), solvid2str(pool, target));
+                 break;
+               case SOLVER_PROBLEM_PACKAGE_CONFLICT:
+                 printf("  package %s conflicts with %s provided by %s\n", solvid2str(pool, source), dep2str(pool, dep), solvid2str(pool, target));
+                 break;
+               case SOLVER_PROBLEM_PACKAGE_OBSOLETES:
+                 printf("  package %s obsoletes %s provided by %s\n", solvid2str(pool, source), dep2str(pool, dep), solvid2str(pool, target));
+                 break;
+               case SOLVER_PROBLEM_DEP_PROVIDERS_NOT_INSTALLABLE:
+                 printf("  package %s requires %s, but none of the providers can be installed\n", solvid2str(pool, source), dep2str(pool, dep));
+                 break;
+               case SOLVER_PROBLEM_SELF_CONFLICT:
+                 printf("  package %s conflicts with %s provided by itself\n", solvid2str(pool, source), dep2str(pool, dep));
+                 break;
+               }
+           }
+       }
+    }
+  queue_free(&rids);
+  queue_free(&rinfo);
+}
+
+void
+toinst(Solver *solv, Repo *repo, Repo *instrepo)
+{
+  Pool *pool = solv->pool;
+  int k;
+  Id p;
+
+  for (k = 0; k < solv->decisionq.count; k++)
+    {
+      p = solv->decisionq.elements[k];
+      if (p < 0 || p == SYSTEMSOLVABLE)
+       continue;
+      /* oh my! */
+      pool->solvables[p].repo = instrepo;
+    }
+}
+
+void
+frominst(Solver *solv, Repo *repo, Repo *instrepo)
+{
+  Pool *pool = solv->pool;
+  int k;
+
+  for (k = 1; k < pool->nsolvables; k++)
+    if (pool->solvables[k].repo == instrepo)
+      pool->solvables[k].repo = repo;
+}
+
+int
+main(int argc, char **argv)
+{
+  Pool *pool;
+  char *arch, *mypatch;
+  const char *pname;
+  int l;
+  FILE *fp;
+  int i, j;
+  Queue job;
+  Queue cand;
+  Queue badguys;
+  Id pid, p, pp;
+  Id con, *conp;
+  Solver *solv;
+  Repo *repo, *instrepo;
+  int status = 0;
+  int tests = 0;
+  int updatestart = 0;
+
+  arch = argv[1];
+  pool = pool_create();
+  pool_setarch(pool, arch);
+  mypatch = argv[2];
+
+  repo = repo_create(pool, 0);
+  instrepo = repo_create(pool, 0);
+  for (i = 3; i < argc; i++)
+    {
+      if (!strcmp(argv[i], "--updaterepos"))
+       {
+         updatestart = pool->nsolvables;
+         continue;
+       }
+      l = strlen(argv[i]);
+      if (!strcmp(argv[i], "-"))
+        fp = stdin;
+      else if ((fp = myfopen(argv[i])) == 0)
+        {
+          perror(argv[i]);
+          exit(1);
+        }
+      if (l >= 8 && !strcmp(argv[i] + l - 8, "packages"))
+        {
+          repo_add_susetags(repo, fp, 0, 0, 0);
+        }
+      else if (l >= 11 && !strcmp(argv[i] + l - 11, "packages.gz"))
+        {
+          repo_add_susetags(repo, fp, 0, 0, 0);
+        }
+      else if (l >= 14 && !strcmp(argv[i] + l - 14, "primary.xml.gz"))
+        {
+          repo_add_rpmmd(repo, fp, 0, 0);
+        }
+      else if (l >= 17 && !strcmp(argv[i] + l - 17, "updateinfo.xml.gz"))
+       {
+          repo_add_updateinfoxml(repo, fp, 0);
+       }
+      else if (repo_add_solv(repo, fp))
+        {
+          fprintf(stderr, "could not add repo %s\n", argv[i]);
+          exit(1);
+        }
+      if (fp != stdin)
+        fclose(fp);
+    }
+
+  /* bad hack ahead: clone repo */
+  instrepo->idarraydata = repo->idarraydata;
+  instrepo->start = repo->start;
+  instrepo->end = repo->end;
+  instrepo->nsolvables = repo->nsolvables;     /* sic! */
+  pool_set_installed(pool, instrepo);
+
+  pool_addfileprovides(pool);
+  pool_createwhatprovides(pool);
+
+  queue_init(&job);
+  queue_init(&cand);
+  queue_init(&badguys);
+
+#if 0
+  pool_setdebuglevel(pool, 2);
+#endif
+
+  for (pid = 1; pid < pool->nsolvables; pid++)
+    {
+      Solvable *s = pool->solvables + pid;
+      if (!s->repo)
+        continue;
+      if (!pool_installable(pool, s))
+        continue;
+      pname = id2str(pool, s->name);
+      if (strncmp(pname, "patch:", 6) != 0)
+       continue;
+      if (*mypatch)
+       {
+         if (strncmp(mypatch, pname + 6, strlen(pname + 6)) != 0)
+           continue;
+         if (strcmp(mypatch, pname + 6) != 0)
+           {
+             l = strlen(pname + 6);
+             if (mypatch[l] != '-')
+               continue;
+             if (strcmp(mypatch + l + 1, id2str(pool, s->evr)) != 0)
+               continue;
+           }
+       }
+      else
+       {
+         FOR_PROVIDES(p, pp, s->name)
+           {
+             Solvable *s2 = pool->solvables + p;
+             if (evrcmp(pool, s->evr, s2->evr, EVRCMP_COMPARE) < 0)
+               break;
+           }
+         if (p)
+           continue;   /* found a newer one */
+       }
+      tests++;
+      if (!s->conflicts)
+       continue;
+
+#if 0
+      printf("testing patch %s-%s\n", pname + 6, id2str(pool, s->evr));
+#endif
+
+      /* Test 1: are all old patches included */
+      FOR_PROVIDES(p, pp, s->name)
+        {
+         Solvable *s2 = pool->solvables + p;
+         Id con2, *conp2;
+         int shown = 0;
+
+         if (evrcmp(pool, s->evr, s2->evr, EVRCMP_COMPARE) <= 0)
+           continue;
+         if (!s2->conflicts)
+           continue;
+         conp2 = s2->repo->idarraydata + s2->conflicts;
+          while ((con2 = *conp2++) != 0)
+           {
+             Reldep *rd2;
+             if (!ISRELDEP(con2))
+               continue;
+             rd2 = GETRELDEP(pool, con2);
+             conp = s->repo->idarraydata + s->conflicts;
+             while ((con = *conp++) != 0)
+               {
+                 Reldep *rd;
+                 if (!ISRELDEP(con))
+                   continue;
+                 rd = GETRELDEP(pool, con);
+                 if (rd->name == rd2->name)
+                   break;
+               }
+             if (!con)
+               {
+                 if (!shown++)
+                   printf("%s:\n", solvable2str(pool, s));
+                 printf("  %s contained %s\n", solvable2str(pool, s2), dep2str(pool, rd2->name));
+               }
+           }
+       }
+
+      /* Test 2: are the packages installable */
+      conp = s->repo->idarraydata + s->conflicts;
+      while ((con = *conp++) != 0)
+       {
+         FOR_PROVIDES(p, pp, con)
+           {
+             queue_empty(&job);
+             queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_WEAK);
+             queue_push(&job, p);
+
+             /* also set up some minimal system */
+             queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES|SOLVER_WEAK);
+             queue_push(&job, str2id(pool, "rpm", 1));
+             queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES|SOLVER_WEAK);
+             queue_push(&job, str2id(pool, "aaa_base", 1));
+
+             solv = solver_create(pool);
+             solv->dontinstallrecommended = 1;
+             solv = solver_create(pool);
+             solver_solve(solv, &job);
+             toinst(solv, repo, instrepo);
+             solver_free(solv);
+             queue_empty(&job);
+             for (i = 1; i < updatestart; i++)
+               {
+                 if (pool->solvables[i].repo != repo || i == pid)
+                   continue;
+                 queue_push(&job, SOLVER_ERASE|SOLVER_SOLVABLE);
+                 queue_push(&job, i);
+               }
+             queue_push(&job, SOLVER_INSTALL_SOLVABLE);
+             queue_push(&job, pid);
+             solv = solver_create(pool);
+             solv->dontinstallrecommended = 1;
+             solver_solve(solv, &job);
+             if (solv->problems.count)
+               {
+                 status = 1;
+                 showproblems(solv, s, 0, 0);
+               }
+             frominst(solv, repo, instrepo);
+             solver_free(solv);
+           }
+       }
+
+      if (0)
+       continue;
+
+      /* Test 3: can we upgrade all packages? */
+      queue_empty(&cand);
+      queue_empty(&badguys);
+      for (p = 1; p < pool->nsolvables; p++)
+       {
+         Solvable *s = pool->solvables + p;
+          if (!s->repo)
+           continue;
+          if (strchr(id2str(pool, s->name), ':'))
+           continue;   /* only packages, please */
+         if (!pool_installable(pool, s))
+           continue;
+         queue_push(&cand, p);
+       }
+      while (cand.count)
+       {
+         solv = solver_create(pool);
+         solv->dontinstallrecommended = 1;
+         solv = solver_create(pool);
+         queue_empty(&job);
+         for (i = 0; i < badguys.count; i++)
+           {
+             queue_push(&job, SOLVER_ERASE|SOLVER_SOLVABLE|SOLVER_WEAK);
+             queue_push(&job, badguys.elements[i]);
+           }
+         conp = s->repo->idarraydata + s->conflicts;
+          while ((con = *conp++) != 0)
+           {
+             queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES|SOLVER_WEAK);
+             queue_push(&job, con);
+           }
+         for (i = 0; i < cand.count; i++)
+           {
+             p = cand.elements[i];
+             queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_WEAK);
+             queue_push(&job, p);
+           }
+         solver_solve(solv, &job);
+#if 0
+         solver_printdecisions(solv);
+#endif
+         /* put packages into installed repo and prune them from cand */
+          toinst(solv, repo, instrepo);
+         for (i = 0; i < cand.count; i++)
+           {
+             p = cand.elements[i];
+             if (p > 0 && solv->decisionmap[p] > 0)
+               cand.elements[i] = -p;  /* drop candidate */
+           }
+         solver_free(solv);
+
+         /* now the interesting part: test patch */
+         queue_empty(&job);
+#if 0
+         for (i = 1; i < updatestart; i++)
+           {
+             if (pool->solvables[i].repo != repo || i == pid)
+               continue;
+             queue_push(&job, SOLVER_ERASE|SOLVER_SOLVABLE);
+             queue_push(&job, i);
+           }
+#endif
+         queue_push(&job, SOLVER_INSTALL_SOLVABLE);
+         queue_push(&job, pid);
+         solv = solver_create(pool);
+         solv->dontinstallrecommended = 1;
+         solver_solve(solv, &job);
+
+         if (solv->problems.count)
+           {
+             status = 1;
+             showproblems(solv, s, &cand, &badguys);
+           }
+          frominst(solv, repo, instrepo);
+         solver_free(solv);
+         /* now drop all negative elements from cand */
+         for (i = j = 0; i < cand.count; i++)
+           {
+             if (cand.elements[i] < 0)
+               continue;
+             cand.elements[j++] = cand.elements[i];
+           }
+         if (i == j)
+           break;      /* no progress */
+         cand.count = j;
+       }
+    }
+  exit(status);
+}
index 867c026..eed0ab1 100644 (file)
@@ -269,7 +269,7 @@ langtag(struct parsedata *pd, Id tag, const char *language)
 }
 
 static int
-id3_cmp (const void *v1, const void *v2)
+id3_cmp (const void *v1, const void *v2, void *dp)
 {
   Id *i1 = (Id*)v1;
   Id *i2 = (Id*)v2;
@@ -284,7 +284,7 @@ commit_diskusage (struct parsedata *pd, unsigned handle)
   /* Now sort in dirid order.  This ensures that parents come before
      their children.  */
   if (pd->ndirs > 1)
-    qsort(pd->dirs, pd->ndirs, sizeof (pd->dirs[0]), id3_cmp);
+    sat_sort(pd->dirs, pd->ndirs, sizeof (pd->dirs[0]), id3_cmp, 0);
   /* Substract leaf numbers from all parents to make the numbers
      non-cumulative.  This must be done post-order (i.e. all leafs
      adjusted before parents).  We ensure this by starting at the end of