- new job commands, now combinded from job type and select type
authorMichael Schroeder <mls@suse.de>
Fri, 29 Aug 2008 18:31:45 +0000 (18:31 +0000)
committerMichael Schroeder <mls@suse.de>
Fri, 29 Aug 2008 18:31:45 +0000 (18:31 +0000)
- support for distupgrade mode

src/policy.c
src/pool.c
src/pool.h
src/solvable.c
src/solver.c
src/solver.h
src/solverdebug.c
src/solverdebug.h

index ffc8233..c6f9a10 100644 (file)
@@ -299,7 +299,7 @@ prune_to_best_version(Solver *solv, Queue *plist)
         }
     }
 
-  if (best == ID_NULL)
+  if (!best)
     best = plist->elements[0];
 
   plist->elements[j++] = best;
@@ -461,7 +461,11 @@ policy_findupdatepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all)
        continue;
       queue_push(qs, p);
     }
-  if (solv->noupdateprovide && solv->obsoletes && solv->obsoletes[n - solv->installed->start])
+  /* if we have found some valid candidates and noupdateprovide is not set, we're
+     done. otherwise we fallback to all obsoletes */
+  if (!solv->noupdateprovide && qs->count)
+    return;
+  if (solv->obsoletes && solv->obsoletes[n - solv->installed->start])
     {
       for (pp = solv->obsoletes_data + solv->obsoletes[n - solv->installed->start]; (p = *pp++) != 0;)
        {
index db9ec8d..1761d42 100644 (file)
@@ -376,8 +376,8 @@ pool_queuetowhatprovides(Pool *pool, Queue *q)
   Offset off;
   int count = q->count;
 
-  if (count == 0)                     /* queue empty -> ID_EMPTY */
-    return ID_EMPTY;
+  if (count == 0)                     /* queue empty -> 1 */
+    return 1;
 
   /* extend whatprovidesdata if needed, +1 for ID_NULL-termination */
   if (pool->whatprovidesdataleft < count + 1)
index 879bfd8..cd3d747 100644 (file)
@@ -178,6 +178,7 @@ int solvable_lookup_void(Solvable *s, Id keyname);
 char * solvable_get_location(Solvable *s, unsigned int *medianrp);
 const unsigned char *solvable_lookup_bin_checksum(Solvable *s, Id keyname, Id *typep);
 const char *solvable_lookup_checksum(Solvable *s, Id keyname, Id *typep);
+int solvable_identical(Pool *pool, Solvable *s1, Solvable *s2);
 
 int solvable_trivial_installable_map(Solvable *s, Map *installedmap, Map *conflictsmap);
 int solvable_trivial_installable_repo(Solvable *s, struct _Repo *installed);
index 5f79c70..c17fe25 100644 (file)
@@ -604,3 +604,39 @@ pool_create_state_maps(Pool *pool, Queue *installed, Map *installedmap, Map *con
     }
 }
 
+int
+solvable_identical(Pool *pool, Solvable *s1, Solvable *s2)
+{
+  unsigned int bt1, bt2;
+  Id rq1, rq2;
+  Id *reqp;
+
+  if (s1->name != s2->name)
+    return 0;
+  if (s1->arch != s2->arch)
+    return 0;
+  if (s1->evr != s2->evr)
+    return 0;
+  if (s1->vendor != s2->vendor)
+    return 0;
+
+  /* first tests passed, try requires */
+  rq1 = rq2 = 0;
+  if (s1->requires)
+    for (reqp = s1->repo->idarraydata + s1->requires; *reqp; reqp++)
+      rq1 ^= *reqp++;
+  if (s2->requires)
+    for (reqp = s2->repo->idarraydata + s2->requires; *reqp; reqp++)
+      rq2 ^= *reqp++;
+  if (rq1 != rq2)
+     return 0;
+
+  /* looking good, try some fancier stuff */
+  bt1 = solvable_lookup_num(s1, SOLVABLE_BUILDTIME, 0);
+  bt2 = solvable_lookup_num(s2, SOLVABLE_BUILDTIME, 0);
+  if (bt1 && bt2 && bt1 != bt2)
+    return 0;
+
+  /* might also look up the package checksum here */
+  return 1;
+}
index 4354511..2d50e63 100644 (file)
@@ -651,7 +651,7 @@ makeruledecisions(Solver *solv)
        disableproblem(solv, v);
        continue;
       }
-       
+
       assert(solv->decisionq_why.elements[i]);
        
         /*
@@ -856,7 +856,7 @@ enableweakrules(Solver *solv)
 
 
 /* FIXME: bad code ahead, replace as soon as possible */
-/* FIXME: should probably look at SOLVER_INSTALL_SOLVABLE_ONE_OF */
+/* FIXME: should probably look at SOLVER_INSTALL|SOLVABLE_ONE_OF */
 
 /*-------------------------------------------------------------------
  * disable update rules
@@ -867,7 +867,7 @@ disableupdaterules(Solver *solv, Queue *job, int jobidx)
 {
   Pool *pool = solv->pool;
   int i, j;
-  Id how, what, p, *pp;
+  Id how, select, what, p, *pp;
   Solvable *s;
   Repo *installed;
   Rule *r;
@@ -879,13 +879,15 @@ disableupdaterules(Solver *solv, Queue *job, int jobidx)
 
   if (jobidx != -1)
     {
-      how = job->elements[jobidx] & ~SOLVER_WEAK;
-      switch(how)
+      how = job->elements[jobidx];
+      select = how & SOLVER_SELECTMASK;
+      switch (how & SOLVER_JOBMASK)
        {
-       case SOLVER_INSTALL_SOLVABLE:
-       case SOLVER_ERASE_SOLVABLE:
-       case SOLVER_ERASE_SOLVABLE_NAME:
-       case SOLVER_ERASE_SOLVABLE_PROVIDES:
+       case SOLVER_ERASE:
+         break;
+       case SOLVER_INSTALL:
+         if (select != SOLVER_SOLVABLE)
+           return;
          break;
        default:
          return;
@@ -902,14 +904,19 @@ disableupdaterules(Solver *solv, Queue *job, int jobidx)
       if (j == lastjob)
        continue;
       lastjob = j;
-      how = job->elements[j] & ~SOLVER_WEAK;
+      how = job->elements[j];
       what = job->elements[j + 1];
-      switch(how)
+      select = how & SOLVER_SELECTMASK;
+      switch (how & SOLVER_JOBMASK)
        {
-       case SOLVER_INSTALL_SOLVABLE:                   /* install specific solvable */
+       case SOLVER_INSTALL:
+         if (select != SOLVER_SOLVABLE)
+           break;
          s = pool->solvables + what;
          if (solv->noobsoletes.size && MAPTST(&solv->noobsoletes, what))
            break;
+         if (s->repo == installed)
+           break;
          if (s->obsoletes)
            {
              Id obs, *obsp;
@@ -932,20 +939,10 @@ disableupdaterules(Solver *solv, Queue *job, int jobidx)
                MAPSET(&solv->noupdate, p - installed->start);
            }
          break;
-       case SOLVER_ERASE_SOLVABLE:
-         s = pool->solvables + what;
-         if (s->repo == installed)
-           MAPSET(&solv->noupdate, what - installed->start);
-         break;
-       case SOLVER_ERASE_SOLVABLE_NAME:                  /* remove by capability */
-       case SOLVER_ERASE_SOLVABLE_PROVIDES:
-         FOR_PROVIDES(p, pp, what)
-           {
-             if (how == SOLVER_ERASE_SOLVABLE_NAME && !pool_match_nevr(pool, pool->solvables + p, what))
-               continue;
-             if (pool->solvables[p].repo == installed)
-               MAPSET(&solv->noupdate, p - installed->start);
-           }
+       case SOLVER_ERASE:
+         FOR_JOB_SELECT(p, pp, select, what)
+           if (pool->solvables[p].repo == installed)
+             MAPSET(&solv->noupdate, p - installed->start);
          break;
        default:
          break;
@@ -957,12 +954,17 @@ disableupdaterules(Solver *solv, Queue *job, int jobidx)
     {
       /* we just disabled job #jobidx. enable all update rules
        * that aren't disabled by the remaining job rules */
-      how = job->elements[jobidx] & ~SOLVER_WEAK;
+      how = job->elements[jobidx];
       what = job->elements[jobidx + 1];
-      switch(how)
+      select = how & SOLVER_SELECTMASK;
+      switch (how & SOLVER_JOBMASK)
        {
-       case SOLVER_INSTALL_SOLVABLE:
+       case SOLVER_INSTALL:
+         if (select != SOLVER_SOLVABLE)
+           break;
          s = pool->solvables + what;
+         if (s->repo == installed)
+           break;
          if (s->obsoletes)
            {
              Id obs, *obsp;
@@ -1006,28 +1008,9 @@ disableupdaterules(Solver *solv, Queue *job, int jobidx)
                }
            }
          break;
-       case SOLVER_ERASE_SOLVABLE:
-         s = pool->solvables + what;
-         if (s->repo != installed)
-           break;
-         if (MAPTST(&solv->noupdate, what - installed->start))
-           break;
-         r = solv->rules + solv->updaterules + (what - installed->start);
-         if (r->d >= 0)
-           break;
-         enablerule(solv, r);
-         IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
-           {
-             POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "@@@ re-enabling ");
-             solver_printrule(solv, SAT_DEBUG_SOLUTIONS, r);
-           }
-         break;
-       case SOLVER_ERASE_SOLVABLE_NAME:                  /* remove by capability */
-       case SOLVER_ERASE_SOLVABLE_PROVIDES:
-         FOR_PROVIDES(p, pp, what)
+       case SOLVER_ERASE:
+         FOR_JOB_SELECT(p, pp, select, what)
            {
-             if (how == SOLVER_ERASE_SOLVABLE_NAME && !pool_match_nevr(pool, pool->solvables + p, what))
-               continue;
              if (pool->solvables[p].repo != installed)
                continue;
              if (MAPTST(&solv->noupdate, p - installed->start))
@@ -1415,6 +1398,35 @@ addrpmrulesforupdaters(Solver *solv, Solvable *s, Map *m, int allow_all)
   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforupdaters -----\n");
 }
 
+static Id
+finddistupgradepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all)
+{
+  Pool *pool = solv->pool;
+  int i;
+
+  policy_findupdatepackages(solv, s, qs, allow_all);
+  if (!qs->count)
+    {
+      if (allow_all)
+        return 0;
+      policy_findupdatepackages(solv, s, qs, 1);
+      if (!qs->count)
+       return 0;
+      qs->count = 0;
+      return -SYSTEMSOLVABLE;
+    }
+  if (allow_all)
+    return s - pool->solvables;
+  /* check if it is ok to keep the installed package */
+  for (i = 0; i < qs->count; i++)
+    {
+      Solvable *ns = pool->solvables + qs->elements[i];
+      if (s->evr == ns->evr && solvable_identical(pool, s, ns))
+        return s - pool->solvables;
+    }
+  /* nope, it must be some other package */
+  return queue_shift(qs);
+}
 
 /*-------------------------------------------------------------------
  * 
@@ -1429,21 +1441,21 @@ addupdaterule(Solver *solv, Solvable *s, int allow_all)
 {
   /* installed packages get a special upgrade allowed rule */
   Pool *pool = solv->pool;
-  Id d;
+  Id p, d;
   Queue qs;
   Id qsbuf[64];
 
   POOL_DEBUG(SAT_DEBUG_SCHUBI, "-----  addupdaterule -----\n");
-
   queue_init_buffer(&qs, qsbuf, sizeof(qsbuf)/sizeof(*qsbuf));
-    /* find update candidates for 's' */
-  policy_findupdatepackages(solv, s, &qs, allow_all);
-  if (qs.count == 0)                  /* no updaters found */
-    d = 0;  /* assertion (keep installed) */
+  p = s - pool->solvables;
+  /* find update candidates for 's' */
+  if (solv->distupgrade)
+    p = finddistupgradepackages(solv, s, &qs, allow_all);
   else
-    d = pool_queuetowhatprovides(pool, &qs);   /* intern computed queue */
+    policy_findupdatepackages(solv, s, &qs, allow_all);
+  d = qs.count ? pool_queuetowhatprovides(pool, &qs) : 0;
   queue_free(&qs);
-  addrule(solv, s - pool->solvables, d);       /* allow update of s */
+  addrule(solv, p, d); /* allow update of s */
   POOL_DEBUG(SAT_DEBUG_SCHUBI, "-----  addupdaterule end -----\n");
 }
 
@@ -1812,7 +1824,7 @@ l1retry:
          goto l1retry;
        }
       why = solv->decisionq_why.elements[idx];
-      if (!why)                        /* just in case, maye for SYSTEMSOLVABLE */
+      if (!why)                        /* just in case, maybe for SYSTEMSOLVABLE */
        goto l1retry;
       c = solv->rules + why;
     }
@@ -2261,6 +2273,7 @@ solver_create(Pool *pool, Repo *installed)
   queue_init(&solv->problems);
   queue_init(&solv->suggestions);
   queue_init(&solv->recommendations);
+  queue_init(&solv->orphaned);
   queue_init(&solv->learnt_why);
   queue_init(&solv->learnt_pool);
   queue_init(&solv->branches);
@@ -2298,6 +2311,7 @@ solver_free(Solver *solv)
   queue_free(&solv->problems);
   queue_free(&solv->suggestions);
   queue_free(&solv->recommendations);
+  queue_free(&solv->orphaned);
   queue_free(&solv->branches);
   queue_free(&solv->covenantq);
   queue_free(&solv->weakruleq);
@@ -2414,6 +2428,7 @@ run_solver(Solver *solv, int disablerules, int doweak)
                }
              if (l || !dq.count)
                continue;
+             /* prune to installed if not updating */
              if (!solv->updatesystem && solv->installed && dq.count > 1)
                {
                  int j, k;
@@ -2490,7 +2505,7 @@ run_solver(Solver *solv, int disablerules, int doweak)
          for (i = solv->installed->start, r = solv->rules + solv->updaterules; i < solv->installed->end; i++, r++)
            {
              Rule *rr;
-             Id d;
+             Id inst;
              s = pool->solvables + i;
                
                /* skip if not installed (can't update) */
@@ -2505,42 +2520,34 @@ run_solver(Solver *solv, int disablerules, int doweak)
                continue;
                
              queue_empty(&dq);
+
              rr = r;
              if (rr->d < 0)    /* disabled -> look at feature rule ? */
                rr -= solv->installed->end - solv->installed->start;
              if (!rr->p)       /* identical to update rule? */
                rr = r;
-             d = (rr->d < 0) ? -rr->d - 1 : rr->d;
-             if (d == 0)
-               {
-                 if (!rr->w2 || solv->decisionmap[rr->w2] > 0)
-                   continue;
-                   /* decide w2 if yet undecided */
-                 if (solv->decisionmap[rr->w2] == 0)
-                   queue_push(&dq, rr->w2);
-               }
-             else
+             if (rr->p <= 0)
+               continue;
+       
+             FOR_RULELITERALS(p, dp, rr)
                {
-                 dp = pool->whatprovidesdata + d;
-                 while ((p = *dp++) != 0)
-                   {
-                     if (solv->decisionmap[p] > 0)
-                       break;
-                       /* decide p if yet undecided */
-                     if (solv->decisionmap[p] == 0)
-                       queue_push(&dq, p);
-                   }
-                 if (p)
-                   continue;
+                 if (solv->decisionmap[p] > 0)
+                   break;
+                 if (solv->decisionmap[p] == 0)
+                   queue_push(&dq, p);
                }
-             if (!dq.count && solv->decisionmap[i] != 0)
+             if (p || !dq.count)       /* already fulfilled or empty */
                continue;
+             if (dq.elements[0] == i)
+               inst = queue_shift(&dq);
+             else
+               inst = 0;
              olevel = level;
              /* FIXME: it is handled a bit different because we do not want
               * to have it pruned just because it is not recommened.
-              * we should not prune installed packages instead
+              * we should not prune installed packages instead.
               */
-             level = selectandinstall(solv, level, &dq, (solv->decisionmap[i] ? 0 : i), disablerules);
+             level = selectandinstall(solv, level, &dq, inst, disablerules);
              if (level == 0)
                {
                  queue_free(&dq);
@@ -2746,6 +2753,37 @@ run_solver(Solver *solv, int disablerules, int doweak)
            }
        }
 
+     if (solv->distupgrade && solv->installed)
+       {
+         /* let's see if we can install some unsupported package */
+         int ri;
+         POOL_DEBUG(SAT_DEBUG_STATS, "deciding unsupported packages\n");
+         for (i = solv->installed->start, ri = 0; i < solv->installed->end; i++, ri++)
+           {
+             s = pool->solvables + i;
+             if (s->repo != solv->installed)
+               continue;
+             if (solv->decisionmap[i])
+               continue;
+             if (!solv->rules[solv->updaterules + ri].p && !solv->rules[solv->featurerules + ri].p)
+               break;
+           }
+         if (i < solv->installed->end)
+           {
+             if (solv->distupgrade_removeunsupported)
+               {
+                 POOL_DEBUG(SAT_DEBUG_STATS, "removing unsupported %s\n", solvable2str(pool, pool->solvables + i));
+                 level = setpropagatelearn(solv, level, -i, 0);
+               }
+             else
+               {
+                 POOL_DEBUG(SAT_DEBUG_STATS, "keeping unsupported %s\n", solvable2str(pool, pool->solvables + i));
+                 level = setpropagatelearn(solv, level, i, 0);
+               }
+             continue;
+           }
+       }
+
      if (solv->solution_callback)
        {
          solv->solution_callback(solv, solv->solution_callback_data);
@@ -3102,11 +3140,19 @@ problems_to_solutions(Solver *solv, Queue *job)
              Id p, d, *dp, rp = 0;
              Rule *rr;
              p = solv->installed->start + (why - solv->updaterules);
-             if (solv->decisionmap[p] > 0)
-               continue;       /* false alarm, turned out we can keep the package */
              rr = solv->rules + solv->featurerules + (why - solv->updaterules);
              if (!rr->p)
                rr = solv->rules + why;
+             if (solv->distupgrade && solv->rules[why].p != p && solv->decisionmap[p] > 0)
+               {
+                 /* distupgrade case, allow to keep old package */
+                 queue_push(&solutions, p);
+                 queue_push(&solutions, p);
+                 nsol++;
+                 continue;
+               }
+             if (solv->decisionmap[p] > 0)
+               continue;       /* false alarm, turned out we can keep the package */
              if (rr->w2)
                {
                  d = rr->d < 0 ? -rr->d - 1 : rr->d;
@@ -3258,7 +3304,7 @@ solver_problemruleinfo(Solver *solv, Queue *job, Id rid, Id *depp, Id *sourcep,
       *sourcep = p;
       *targetp = job->elements[p];
       d = r->d < 0 ? -r->d - 1 : r->d;
-      if (d == 0 && r->w2 == 0 && r->p == -SYSTEMSOLVABLE && job->elements[p] != SOLVER_INSTALL_SOLVABLE_ONE_OF)
+      if (d == 0 && r->w2 == 0 && r->p == -SYSTEMSOLVABLE && (job->elements[p] & SOLVER_SELECTMASK) != SOLVER_SOLVABLE_ONE_OF)
        return SOLVER_PROBLEM_JOB_NOTHING_PROVIDES_DEP;
       return SOLVER_PROBLEM_JOB_RULE;
     }
@@ -3776,7 +3822,7 @@ weaken_solvable_deps(Solver *solv, Id p)
   int i;
   Rule *r;
 
-  for (i = 1, r = solv->rules + i; i < solv->featurerules; i++, r++)
+  for (i = 1, r = solv->rules + i; i < solv->rpmrules_end; i++, r++)
     {
       if (r->p != -p)
        continue;
@@ -3804,19 +3850,25 @@ solver_solve(Solver *solv, Queue *job)
   int oldnrules;
   Map addedmap;                       /* '1' == have rpm-rules for solvable */
   Map installcandidatemap;
-  Id how, what, name, weak, p, *pp, d;
+  Id how, what, select, name, weak, p, *pp, d;
   Queue q, redoq;
   Solvable *s;
   int goterase;
   Rule *r;
 
+  POOL_DEBUG(SAT_DEBUG_STATS, "solver started\n");
+  POOL_DEBUG(SAT_DEBUG_STATS, "fixsystem=%d updatesystem=%d dosplitprovides=%d, noupdateprovide=%d\n", solv->fixsystem, solv->updatesystem, solv->dosplitprovides, solv->noupdateprovide);
+  POOL_DEBUG(SAT_DEBUG_STATS, "distupgrade=%d distupgrade_removeunsupported=%d\n", solv->distupgrade, solv->distupgrade_removeunsupported);
+  POOL_DEBUG(SAT_DEBUG_STATS, "allowuninstall=%d, allowdowngrade=%d, allowarchchange=%d, allowvendorchange=%d\n", solv->allowuninstall, solv->allowdowngrade, solv->allowarchchange, solv->allowvendorchange);
+  POOL_DEBUG(SAT_DEBUG_STATS, "promoteepoch=%d, allowvirtualconflicts=%d, allowselfconflicts=%d\n", pool->promoteepoch, solv->allowvirtualconflicts, solv->allowselfconflicts);
+  POOL_DEBUG(SAT_DEBUG_STATS, "obsoleteusesprovides=%d, implicitobsoleteusesprovides=%d\n", solv->obsoleteusesprovides, solv->implicitobsoleteusesprovides);
+  POOL_DEBUG(SAT_DEBUG_STATS, "dontinstallrecommended=%d, ignorealreadyrecommended=%d, dontshowinstalledrecommended=%d\n", solv->dontinstallrecommended, solv->ignorealreadyrecommended, solv->dontshowinstalledrecommended);
   /* create whatprovides if not already there */
   if (!pool->whatprovides)
     pool_createwhatprovides(pool);
 
   /* create obsolete index if needed */
-  if (solv->noupdateprovide)
-    create_obsolete_index(solv);
+  create_obsolete_index(solv);
 
   /*
    * create basic rule set of all involved packages
@@ -3828,29 +3880,14 @@ solver_solve(Solver *solv, Queue *job)
   for (i = 0; i < job->count; i += 2)
     {
       how = job->elements[i] & ~SOLVER_WEAK;
+      if ((how & SOLVER_JOBMASK) != SOLVER_NOOBSOLETES)
+       continue;
       what = job->elements[i + 1];
-      switch(how)
-       {
-       case SOLVER_NOOBSOLETES_SOLVABLE:
-       case SOLVER_NOOBSOLETES_SOLVABLE_NAME:
-       case SOLVER_NOOBSOLETES_SOLVABLE_PROVIDES:
-         if (!solv->noobsoletes.size)
-           map_init(&solv->noobsoletes, pool->nsolvables);
-         if (how == SOLVER_NOOBSOLETES_SOLVABLE)
-           {
-             MAPSET(&solv->noobsoletes, what);
-             break;
-           }
-         FOR_PROVIDES(p, pp, what)
-           {
-             if (how == SOLVER_NOOBSOLETES_SOLVABLE_NAME && !pool_match_nevr(pool, pool->solvables + p, what))
-               continue;
-             MAPSET(&solv->noobsoletes, p);
-           }
-         break;
-       default:
-         break;
-       }
+      select = how & SOLVER_SELECTMASK;
+      if (!solv->noobsoletes.size)
+       map_init(&solv->noobsoletes, pool->nsolvables);
+      FOR_JOB_SELECT(p, pp, select, what)
+        MAPSET(&solv->noobsoletes, p);
     }
 
   map_init(&addedmap, pool->nsolvables);
@@ -3893,34 +3930,23 @@ solver_solve(Solver *solv, Queue *job)
   oldnrules = solv->nrules;
   for (i = 0; i < job->count; i += 2)
     {
-      how = job->elements[i] & ~SOLVER_WEAK;
+      how = job->elements[i];
       what = job->elements[i + 1];
+      select = how & SOLVER_SELECTMASK;
 
-      switch(how)
+      switch (how & SOLVER_JOBMASK)
        {
-       case SOLVER_INSTALL_SOLVABLE:
-         MAPSET(&installcandidatemap, what);
-         addrpmrulesforsolvable(solv, pool->solvables + what, &addedmap);
-         break;
-       case SOLVER_INSTALL_SOLVABLE_NAME:
-       case SOLVER_INSTALL_SOLVABLE_PROVIDES:
-         FOR_PROVIDES(p, pp, what)
+       case SOLVER_INSTALL:
+         FOR_JOB_SELECT(p, pp, select, what)
            {
-             /* if by name, ensure that the name matches */
-             if (how == SOLVER_INSTALL_SOLVABLE_NAME && !pool_match_nevr(pool, pool->solvables + p, what))
-               continue;
              MAPSET(&installcandidatemap, p);
              addrpmrulesforsolvable(solv, pool->solvables + p, &addedmap);
            }
          break;
-       case SOLVER_INSTALL_SOLVABLE_UPDATE:
-         /* dont allow downgrade */
-         addrpmrulesforupdaters(solv, pool->solvables + what, &addedmap, 0);
-         break;
-       case SOLVER_INSTALL_SOLVABLE_ONE_OF:
-         pp = pool->whatprovidesdata + what;
-         while ((p = *pp++) != 0)
-           addrpmrulesforsolvable(solv, pool->solvables + p, &addedmap);
+       case SOLVER_UPDATE:
+         /* FIXME: semantics? */
+         FOR_JOB_SELECT(p, pp, select, what)
+           addrpmrulesforupdaters(solv, pool->solvables + what, &addedmap, 0);
          break;
        }
     }
@@ -4003,7 +4029,7 @@ solver_solve(Solver *solv, Queue *job)
      * Add update rules for installed solvables
      * 
      * almost identical to feature rules
-     * except that downgrades are allowed
+     * except that downgrades/archchanges/vendorchanges are not allowed
      */
     
   POOL_DEBUG(SAT_DEBUG_SCHUBI, "*** Add update rules ***\n");
@@ -4021,22 +4047,28 @@ solver_solve(Solver *solv, Queue *job)
              addrule(solv, 0, 0);      /* create dummy rule */
              continue;
            }
-
-         addupdaterule(solv, s, 0);    /* allowall = 0: downgrades allowed */
-
+         addupdaterule(solv, s, 0);    /* allowall = 0: downgrades not allowed */
            /*
             * check for and remove duplicate
             */
-           
          r = solv->rules + solv->nrules - 1;           /* r: update rule */
          sr = r - (installed->end - installed->start); /* sr: feature rule */
+         /* it's orphaned if there is no feature rule or the feature rule
+           * consists just of the installed package */
+         if (!sr->p || (sr->p == i && !sr->d && !sr->w2))
+           queue_push(&solv->orphaned, i);
+          if (!r->p)
+           {
+             assert(!sr->p);   /* can't have feature rule and no update rule */
+             continue;
+           }
          unifyrules_sortcmp_data = pool;
          if (!unifyrules_sortcmp(r, sr))
            {
              /* identical rule, kill unneeded rule */
              if (solv->allowuninstall)
                {
-                 /* keep feature rule */
+                 /* keep feature rule, make it weak */
                  memset(r, 0, sizeof(*r));
                  queue_push(&solv->weakruleq, sr - solv->rules);
                }
@@ -4072,101 +4104,77 @@ solver_solve(Solver *solv, Queue *job)
     {
       oldnrules = solv->nrules;
 
-      how = job->elements[i] & ~SOLVER_WEAK;
-      weak = job->elements[i] & SOLVER_WEAK;
+      how = job->elements[i];
       what = job->elements[i + 1];
-      switch(how)
+      weak = how & SOLVER_WEAK;
+      select = how & SOLVER_SELECTMASK;
+      switch (how & SOLVER_JOBMASK)
        {
-       case SOLVER_INSTALL_SOLVABLE:                   /* install specific solvable */
-         s = pool->solvables + what;
-         POOL_DEBUG(SAT_DEBUG_JOB, "job: %sinstall solvable %s\n", weak ? "weak " : "", solvable2str(pool, s));
-          addrule(solv, what, 0);                      /* install by Id */
+       case SOLVER_INSTALL:
+         POOL_DEBUG(SAT_DEBUG_JOB, "job: %sinstall %s\n", weak ? "weak " : "", solver_select2str(solv, select, what));
+         if (select == SOLVER_SOLVABLE)
+           {
+             p = what;
+             d = 0;
+           }
+         else
+           {
+             queue_empty(&q);
+             FOR_JOB_SELECT(p, pp, select, what)
+               queue_push(&q, p);
+             if (!q.count)
+               {
+                 /* no candidate found, make this an impossible rule */
+                 queue_push(&q, -SYSTEMSOLVABLE);
+               }
+             p = queue_shift(&q);      /* get first candidate */
+             d = !q.count ? 0 : pool_queuetowhatprovides(pool, &q);    /* internalize */
+           }
+         addrule(solv, p, d);          /* add install rule */
          queue_push(&solv->ruletojob, i);
          if (weak)
            queue_push(&solv->weakruleq, solv->nrules - 1);
          break;
-       case SOLVER_ERASE_SOLVABLE:
-         s = pool->solvables + what;
-         POOL_DEBUG(SAT_DEBUG_JOB, "job: %serase solvable %s\n", weak ? "weak " : "", solvable2str(pool, s));
-         name = s->name;
-         if (solv->installed && s->repo == solv->installed)
+       case SOLVER_ERASE:
+         POOL_DEBUG(SAT_DEBUG_JOB, "job: %serase %s\n", weak ? "weak " : "", solver_select2str(solv, select, what));
+          if (select == SOLVER_SOLVABLE && solv->installed && pool->solvables[what].repo == solv->installed)
            {
-             FOR_PROVIDES(p, pp, s->name)
+             /* special case for "erase a specific solvable": we also
+               * erase all other solvables with that name, so that they
+               * don't get picked up as replacement */
+             name = pool->solvables[what].name;
+             FOR_PROVIDES(p, pp, name)
                {
+                 if (p == what)
+                   continue;
                  s = pool->solvables + p;
                  if (s->name != name)
                    continue;
-                 if (p != what)
-                   {
-                     /* keep other versions installed */
-                     if (s->repo == solv->installed)
-                       continue;
-                     /* keep installcandidates of other jobs */
-                     if (MAPTST(&installcandidatemap, p))
-                       continue;
-                   }
+                 /* keep other versions installed */
+                 if (s->repo == solv->installed)
+                   continue;
+                 /* keep installcandidates of other jobs */
+                 if (MAPTST(&installcandidatemap, p))
+                   continue;
                  addrule(solv, -p, 0);                 /* remove by Id */
                  queue_push(&solv->ruletojob, i);
                  if (weak)
                    queue_push(&solv->weakruleq, solv->nrules - 1);
                }
            }
-         else
+         FOR_JOB_SELECT(p, pp, select, what)
            {
-             addrule(solv, -what, 0);                  /* remove by Id */
+             addrule(solv, -p, 0);
              queue_push(&solv->ruletojob, i);
              if (weak)
                queue_push(&solv->weakruleq, solv->nrules - 1);
            }
          break;
-       case SOLVER_INSTALL_SOLVABLE_NAME:              /* install by capability */
-       case SOLVER_INSTALL_SOLVABLE_PROVIDES:
-         if (how == SOLVER_INSTALL_SOLVABLE_NAME)
-           POOL_DEBUG(SAT_DEBUG_JOB, "job: %sinstall name %s\n", weak ? "weak " : "", dep2str(pool, what));
-         if (how == SOLVER_INSTALL_SOLVABLE_PROVIDES)
-           POOL_DEBUG(SAT_DEBUG_JOB, "job: %sinstall provides %s\n", weak ? "weak " : "", dep2str(pool, what));
-         queue_empty(&q);
-         FOR_PROVIDES(p, pp, what)
-           {
-              /* if by name, ensure that the name matches */
-             if (how == SOLVER_INSTALL_SOLVABLE_NAME && !pool_match_nevr(pool, pool->solvables + p, what))
-               continue;
-             queue_push(&q, p);
-           }
-         if (!q.count)
-           {
-             /* no provider, make this an impossible rule */
-             queue_push(&q, -SYSTEMSOLVABLE);
-           }
 
-         p = queue_shift(&q);         /* get first provider */
-         if (!q.count)
-           d = 0;                     /* single provider ? -> make assertion */
-         else
-           d = pool_queuetowhatprovides(pool, &q);   /* get all providers */
-         addrule(solv, p, d);         /* add 'requires' rule */
-         queue_push(&solv->ruletojob, i);
-         if (weak)
-           queue_push(&solv->weakruleq, solv->nrules - 1);
-         break;
-       case SOLVER_ERASE_SOLVABLE_NAME:                  /* remove by capability */
-       case SOLVER_ERASE_SOLVABLE_PROVIDES:
-         if (how == SOLVER_ERASE_SOLVABLE_NAME)
-           POOL_DEBUG(SAT_DEBUG_JOB, "job: %serase name %s\n", weak ? "weak " : "", dep2str(pool, what));
-         if (how == SOLVER_ERASE_SOLVABLE_PROVIDES)
-           POOL_DEBUG(SAT_DEBUG_JOB, "job: %serase provides %s\n", weak ? "weak " : "", dep2str(pool, what));
-         FOR_PROVIDES(p, pp, what)
-           {
-             /* if by name, ensure that the name matches */
-             if (how == SOLVER_ERASE_SOLVABLE_NAME && !pool_match_nevr(pool, pool->solvables + p, what))
-               continue;
-             addrule(solv, -p, 0);  /* add 'remove' rule */
-             queue_push(&solv->ruletojob, i);
-             if (weak)
-               queue_push(&solv->weakruleq, solv->nrules - 1);
-           }
-         break;
-       case SOLVER_INSTALL_SOLVABLE_UPDATE:              /* find update for solvable */
+       case SOLVER_UPDATE:
+         POOL_DEBUG(SAT_DEBUG_JOB, "job: %supdate %s\n", weak ? "weak " : "", solver_select2str(solv, select, what));
+         if (select != SOLVER_SOLVABLE)
+           break;
          s = pool->solvables + what;
          POOL_DEBUG(SAT_DEBUG_JOB, "job: %supdate %s\n", weak ? "weak " : "", solvable2str(pool, s));
          addupdaterule(solv, s, 0);
@@ -4174,28 +4182,32 @@ solver_solve(Solver *solv, Queue *job)
          if (weak)
            queue_push(&solv->weakruleq, solv->nrules - 1);
          break;
-       case SOLVER_INSTALL_SOLVABLE_ONE_OF:
-         POOL_DEBUG(SAT_DEBUG_JOB, "job: %sone of\n", weak ? "weak " : "");
-         for (pp = pool->whatprovidesdata + what; *pp; pp++)
-           POOL_DEBUG(SAT_DEBUG_JOB, "  %s\n", solvable2str(pool, pool->solvables + *pp));
-         addrule(solv, -SYSTEMSOLVABLE, what);
-         queue_push(&solv->ruletojob, i);
-         if (weak)
-           queue_push(&solv->weakruleq, solv->nrules - 1);
-         break;
-       case SOLVER_WEAKEN_SOLVABLE_DEPS:
+       case SOLVER_WEAKENDEPS:
+         POOL_DEBUG(SAT_DEBUG_JOB, "job: %sweaken deps %s\n", weak ? "weak " : "", solver_select2str(solv, select, what));
+         if (select != SOLVER_SOLVABLE)
+           break;
          s = pool->solvables + what;
-         POOL_DEBUG(SAT_DEBUG_JOB, "job: weaken deps %s\n", solvable2str(pool, s));
          weaken_solvable_deps(solv, what);
          break;
-       case SOLVER_NOOBSOLETES_SOLVABLE:
-         POOL_DEBUG(SAT_DEBUG_JOB, "job: no obsolete %s\n", solvable2str(pool, pool->solvables + what));
+       case SOLVER_NOOBSOLETES:
+         POOL_DEBUG(SAT_DEBUG_JOB, "job: %sno obsolete %s\n", weak ? "weak " : "", solver_select2str(solv, select, what));
          break;
-       case SOLVER_NOOBSOLETES_SOLVABLE_NAME:
-         POOL_DEBUG(SAT_DEBUG_JOB, "job: no obsolete name %s\n", dep2str(pool, what));
+       case SOLVER_LOCK:
+         POOL_DEBUG(SAT_DEBUG_JOB, "job: %slock %s\n", weak ? "weak " : "", solver_select2str(solv, select, what));
+         FOR_JOB_SELECT(p, pp, select, what)
+           {
+             s = pool->solvables + p;
+             if (installed && s->repo == installed)
+               addrule(solv, p, 0);
+             else
+               addrule(solv, -p, 0);
+             queue_push(&solv->ruletojob, i);
+             if (weak)
+               queue_push(&solv->weakruleq, solv->nrules - 1);
+           }
          break;
-       case SOLVER_NOOBSOLETES_SOLVABLE_PROVIDES:
-         POOL_DEBUG(SAT_DEBUG_JOB, "job: no obsolete provides %s\n", dep2str(pool, what));
+       default:
+         POOL_DEBUG(SAT_DEBUG_JOB, "job: unknown job\n");
          break;
        }
        
index 4751394..13366a3 100644 (file)
@@ -126,6 +126,7 @@ typedef struct solver {
   Queue problems;                       /* index of conflicting rules, < 0 for job rules */
   Queue recommendations;               /* recommended packages */
   Queue suggestions;                   /* suggested packages */
+  Queue orphaned;                      /* orphaned packages */
 
   int stats_learned;                   /* statistic */
   int stats_unsolvable;                        /* statistic */
@@ -157,6 +158,10 @@ typedef struct solver {
   int ignorealreadyrecommended;                /* true: ignore recommended packages that were already recommended by the installed packages */
   int dontshowinstalledrecommended;    /* true: do not show recommended packages that are already installed */
   
+  /* distupgrade also needs updatesystem and dosplitprovides */
+  int distupgrade;
+  int distupgrade_removeunsupported;
+
   /* Callbacks for defining the bahaviour of the SAT solver */
 
   /* Finding best candidate
@@ -208,24 +213,39 @@ typedef struct solver {
  * queue commands
  */
 
-typedef enum {
-  SOLVCMD_NULL=0,
-  SOLVER_INSTALL_SOLVABLE,
-  SOLVER_ERASE_SOLVABLE,
-  SOLVER_INSTALL_SOLVABLE_NAME,
-  SOLVER_ERASE_SOLVABLE_NAME,
-  SOLVER_INSTALL_SOLVABLE_PROVIDES,
-  SOLVER_ERASE_SOLVABLE_PROVIDES,
-  SOLVER_INSTALL_SOLVABLE_UPDATE,
-  SOLVER_INSTALL_SOLVABLE_ONE_OF,
-  SOLVER_WEAKEN_SOLVABLE_DEPS,
-  SOLVER_NOOBSOLETES_SOLVABLE,
-  SOLVER_NOOBSOLETES_SOLVABLE_NAME,
-  SOLVER_NOOBSOLETES_SOLVABLE_PROVIDES,
-
-  /* flags */
-  SOLVER_WEAK = 0x100,
-} SolverCmd;
+#define SOLVER_SOLVABLE                        0x01
+#define SOLVER_SOLVABLE_NAME           0x02
+#define SOLVER_SOLVABLE_PROVIDES       0x03
+#define SOLVER_SOLVABLE_ONE_OF         0x04
+
+#define SOLVER_SELECTMASK              0xff
+
+#define SOLVER_INSTALL                 0x0100
+#define SOLVER_ERASE                   0x0200
+#define SOLVER_UPDATE                  0x0300
+#define SOLVER_WEAKENDEPS                      0x0400
+#define SOLVER_NOOBSOLETES             0x0500
+#define SOLVER_LOCK                    0x0600
+
+#define SOLVER_JOBMASK                 0xff00
+
+#define SOLVER_WEAK                    0x010000
+
+/* old API compatibility, do not use in new code */
+#if 1
+#define SOLVER_INSTALL_SOLVABLE (SOLVER_INSTALL|SOLVER_SOLVABLE)
+#define SOLVER_ERASE_SOLVABLE (SOLVER_ERASE|SOLVER_SOLVABLE)
+#define SOLVER_INSTALL_SOLVABLE_NAME (SOLVER_INSTALL|SOLVER_SOLVABLE_NAME)
+#define SOLVER_ERASE_SOLVABLE_NAME (SOLVER_ERASE|SOLVER_SOLVABLE_NAME)
+#define SOLVER_INSTALL_SOLVABLE_PROVIDES (SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES)
+#define SOLVER_ERASE_SOLVABLE_PROVIDES (SOLVER_ERASE|SOLVER_SOLVABLE_PROVIDES)
+#define SOLVER_INSTALL_SOLVABLE_UPDATE (SOLVER_UPDATE|SOLVER_SOLVABLE)
+#define SOLVER_INSTALL_SOLVABLE_ONE_OF (SOLVER_INSTALL|SOLVER_SOLVABLE_ONE_OF)
+#define SOLVER_WEAKEN_SOLVABLE_DEPS (SOLVER_WEAKENDEPS|SOLVER_SOLVABLE)
+#define SOLVER_NOOBSOLETES_SOLVABLE (SOLVER_NOOBSOLETES|SOLVER_SOLVABLE)
+#define SOLVER_NOOBSOLETES_SOLVABLE_NAME (SOLVER_NOOBSOLETES|SOLVER_SOLVABLE_NAME)
+#define SOLVER_NOOBSOLETES_SOLVABLE_PROVIDES (SOLVER_NOOBSOLETES|SOLVER_SOLVABLE_PROVIDES)
+#endif
 
 typedef enum {
   SOLVER_PROBLEM_UPDATE_RULE,
@@ -325,6 +345,13 @@ solver_create_state_maps(Solver *solv, Map *installedmap, Map *conflictsmap)
          dp = !l ? &r->w2 : pool->whatprovidesdata + l,                \
          l = r->p; l; l = (dp != &r->w2 + 1 ? *dp++ : 0))
 
+#define FOR_JOB_SELECT(p, pp, select, what) \
+    for (pp = (select == SOLVER_SOLVABLE ? pool->whatprovidesdata :    \
+               select == SOLVER_SOLVABLE_ONE_OF ? pool->whatprovidesdata + what : \
+               pool_whatprovides(pool, what)),                         \
+         p = (select == SOLVER_SOLVABLE ? what : *pp++) ; p ; p = *pp++) \
+      if (select != SOLVER_SOLVABLE_NAME || pool_match_nevr(pool, pool->solvables + p, what))
+
 #ifdef __cplusplus
 }
 #endif
index 84166de..2e314cf 100644 (file)
@@ -18,6 +18,7 @@
 #include <assert.h>
 
 #include "solver.h"
+#include "solverdebug.h"
 #include "bitmap.h"
 #include "pool.h"
 #include "util.h"
@@ -362,6 +363,19 @@ solver_printdecisions(Solver *solv)
        }
       POOL_DEBUG(SAT_DEBUG_RESULT, "\n");
     }
+  if (solv->orphaned.count)
+    {
+      POOL_DEBUG(SAT_DEBUG_RESULT, "orphaned packages:\n");
+      for (i = 0; i < solv->orphaned.count; i++)
+       {
+         s = pool->solvables + solv->orphaned.elements[i];
+          if (solv->decisionmap[solv->orphaned.elements[i]] > 0)
+           POOL_DEBUG(SAT_DEBUG_RESULT, "  %s (kept)\n", solvable2str(pool, s));
+         else
+           POOL_DEBUG(SAT_DEBUG_RESULT, "  %s (erased)\n", solvable2str(pool, s));
+       }
+      POOL_DEBUG(SAT_DEBUG_RESULT, "\n");
+    }
 }
 
 void
@@ -427,7 +441,7 @@ solver_printsolutions(Solver *solv, Queue *job)
 {
   Pool *pool = solv->pool;
   int pcnt;
-  Id p, rp, how, what;
+  Id p, rp, how, what, select;
   Id problem, solution, element;
   Solvable *s, *sd;
 
@@ -451,37 +465,30 @@ solver_printsolutions(Solver *solv, Queue *job)
                  /* job, rp is index into job queue */
                  how = job->elements[rp - 1] & ~SOLVER_WEAK;
                  what = job->elements[rp];
-                 switch (how)
+                 select = how & SOLVER_SELECTMASK;
+                 switch (how & SOLVER_JOBMASK)
                    {
-                   case SOLVER_INSTALL_SOLVABLE:
-                     s = pool->solvables + what;
-                     if (solv->installed && s->repo == solv->installed)
-                       POOL_DEBUG(SAT_DEBUG_RESULT, "- do not keep %s installed\n", solvable2str(pool, s));
+                   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));
+                     else if (select == SOLVER_SOLVABLE_PROVIDES)
+                       POOL_DEBUG(SAT_DEBUG_RESULT, "- do not install a solvable %s\n", solver_select2str(solv, select, what));
                      else
-                       POOL_DEBUG(SAT_DEBUG_RESULT, "- do not install %s\n", solvable2str(pool, s));
+                       POOL_DEBUG(SAT_DEBUG_RESULT, "- do not install %s\n", solver_select2str(solv, select, what));
                      break;
-                   case SOLVER_ERASE_SOLVABLE:
-                     s = pool->solvables + what;
-                     if (solv->installed && s->repo == solv->installed)
-                       POOL_DEBUG(SAT_DEBUG_RESULT, "- do not deinstall %s\n", solvable2str(pool, s));
+                   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));
+                     else if (select == SOLVER_SOLVABLE_PROVIDES)
+                       POOL_DEBUG(SAT_DEBUG_RESULT, "- do not deinstall all solvables %s\n", solver_select2str(solv, select, what));
                      else
-                       POOL_DEBUG(SAT_DEBUG_RESULT, "- do not forbid installation of %s\n", solvable2str(pool, s));
+                       POOL_DEBUG(SAT_DEBUG_RESULT, "- do not deinstall %s\n", solver_select2str(solv, select, what));
                      break;
-                   case SOLVER_INSTALL_SOLVABLE_NAME:
-                     POOL_DEBUG(SAT_DEBUG_RESULT, "- do not install %s\n", dep2str(pool, what));
+                   case SOLVER_UPDATE:
+                     POOL_DEBUG(SAT_DEBUG_RESULT, "- do not install most recent version of %s\n", solver_select2str(solv, select, what));
                      break;
-                   case SOLVER_ERASE_SOLVABLE_NAME:
-                     POOL_DEBUG(SAT_DEBUG_RESULT, "- do not deinstall %s\n", dep2str(pool, what));
-                     break;
-                   case SOLVER_INSTALL_SOLVABLE_PROVIDES:
-                     POOL_DEBUG(SAT_DEBUG_RESULT, "- do not install a solvable providing %s\n", dep2str(pool, what));
-                     break;
-                   case SOLVER_ERASE_SOLVABLE_PROVIDES:
-                     POOL_DEBUG(SAT_DEBUG_RESULT, "- do not deinstall all solvables providing %s\n", dep2str(pool, what));
-                     break;
-                   case SOLVER_INSTALL_SOLVABLE_UPDATE:
-                     s = pool->solvables + what;
-                     POOL_DEBUG(SAT_DEBUG_RESULT, "- do not install most recent version of %s\n", solvable2str(pool, s));
+                   case SOLVER_LOCK:
+                     POOL_DEBUG(SAT_DEBUG_RESULT, "- do not lock %s\n", solver_select2str(solv, select, what));
                      break;
                    default:
                      POOL_DEBUG(SAT_DEBUG_RESULT, "- do something different\n");
@@ -493,7 +500,11 @@ solver_printsolutions(Solver *solv, Queue *job)
                  /* policy, replace p with rp */
                  s = pool->solvables + p;
                  sd = rp ? pool->solvables + rp : 0;
-                 if (sd)
+                 if (s == sd && solv->distupgrade)
+                   {
+                     POOL_DEBUG(SAT_DEBUG_RESULT, "- keep obsolete %s\n", solvable2str(pool, s));
+                   }
+                 else if (sd)
                    {
                      int gotone = 0;
                      if (!solv->allowdowngrade && evrcmp(pool, s->evr, sd->evr, EVRCMP_MATCH_RELEASE) > 0)
@@ -564,3 +575,37 @@ solver_printtrivial(Solver *solv)
   queue_free(&in);
   queue_free(&out);
 }
+
+const char *
+solver_select2str(Solver *solv, Id select, Id what)
+{
+  Pool *pool = solv->pool;
+  const char *s;
+  char *b;
+  if (select == SOLVER_SOLVABLE)
+    return solvable2str(pool, pool->solvables + what);
+  if (select == SOLVER_SOLVABLE_NAME)
+    return dep2str(pool, what);
+  if (select == SOLVER_SOLVABLE_PROVIDES)
+    {
+      s = dep2str(pool, what);
+      b = pool_alloctmpspace(pool, 11 + strlen(s));
+      sprintf(b, "providing %s", s);
+      return b;
+    }
+  if (select == SOLVER_SOLVABLE_ONE_OF)
+    {
+      Id p;
+      char *b2;
+      b = "";
+      while ((p = pool->whatprovidesdata[what++]) != 0)
+       {
+         s = solvable2str(pool, pool->solvables + p);
+         b2 = pool_alloctmpspace(pool, strlen(b) + strlen(s) + 3);
+         sprintf(b2, "%s, %s", b, s);
+         b = b2;
+       }
+      return *b ? b + 2 : "nothing";
+    }
+  return "unknown job select";
+}
index cb90fdb..2b8493b 100644 (file)
@@ -27,6 +27,8 @@ extern void solver_printdecisions(Solver *solv);
 extern void solver_printprobleminfo(Solver *solv, Queue *job, Id problem);
 extern void solver_printsolutions(Solver *solv, Queue *job);
 extern void solver_printtrivial(Solver *solv);
+extern const char *solver_select2str(Solver *solv, Id select, Id what);
+
 
 #endif /* SATSOLVER_SOLVERDEBUG_H */