]> git.ipfire.org Git - thirdparty/libsolv.git/commitdiff
Move decisionlist generation into the library
authorMichael Schroeder <mls@suse.de>
Fri, 25 Nov 2022 10:36:19 +0000 (11:36 +0100)
committerMichael Schroeder <mls@suse.de>
Fri, 25 Nov 2022 10:36:19 +0000 (11:36 +0100)
This functionality is useful for multiple programs that use
libsolv, so it does not make sense to duplicate the code
into each of them.

So we now offer solver_get_decisionlist() to get a list of
decisions that let to the installation/deinstallation of a
package. There is also solver_get_decisionlist_multiple() that
can be used if multiple packages should be considered.

The output is a list of (package, reason, info) triplets.
Package is positive for installs, negative for conflicts.

This commits also deprecates solver_describe_weakdep_decision().
it makes more sense to unify weakdep decisions with rule
decisions as both come from package dependencies.
So we now have solver_allweakdepinfos() and solver_weakdepinfo()
that returns the ruleinfo for a weakdep decision. You can then
use solver_ruleinfo2str() to convert the ruleinfo to a string.

src/libsolv.ver
src/rules.c
src/rules.h
src/solver.c

index cf2576102988d38729bd7a1ce184821d2e75592b..3d1752111b20b81e42936216e1c2dbde0d58d76c 100644 (file)
@@ -342,6 +342,7 @@ SOLV_1.0 {
                solvable_trivial_installable_repo;
                solvable_unset;
                solver_allruleinfos;
+               solver_allweakdepinfos;
                solver_alternative2str;
                solver_alternatives_count;
                solver_calc_duchanges;
@@ -360,6 +361,8 @@ SOLV_1.0 {
                solver_get_alternative;
                solver_get_decisionblock;
                solver_get_decisionlevel;
+               solver_get_decisionlist;
+               solver_get_decisionlist_multiple;
                solver_get_decisionqueue;
                solver_get_flag;
                solver_get_lastdecisionblocklevel;
@@ -411,6 +414,7 @@ SOLV_1.0 {
                solver_take_solutionelement;
                solver_trivial_installable;
                solver_unifyrules;
+               solver_weakdepinfo;
                stringpool_clone;
                stringpool_free;
                stringpool_freehash;
index 61833c10e5955b95c494b8c25ae5ca453106ec37..1b0bf48d4606c54ecae2039e1eba94b33516cd77 100644 (file)
@@ -4375,6 +4375,11 @@ solver_ruleinfo2str(Solver *solv, SolverRuleinfo type, Id source, Id target, Id
     case SOLVER_RULE_PKG_CONSTRAINS:
       s = pool_tmpappend(pool, pool_solvid2str(pool, source), " has constraint ", pool_dep2str(pool, dep));
       return pool_tmpappend(pool, s, " conflicting with ", pool_solvid2str(pool, target));
+    case SOLVER_RULE_PKG_SUPPLEMENTS:
+      s = pool_tmpjoin(pool, pool_solvid2str(pool, source), " supplements ", pool_dep2str(pool, dep));
+      if (target)
+       s = pool_tmpappend(pool, s, " provided by ", pool_solvid2str(pool, target));
+      return s;
     case SOLVER_RULE_YUMOBS:
       s = pool_tmpjoin(pool, "both ", pool_solvid2str(pool, source), " and ");
       s = pool_tmpjoin(pool, s, pool_solvid2str(pool, target), " obsolete ");
index 98709b23cfa45e97c58da13f5658492bcd6d1483..92efe8a7c59ed7e77f2c29cdfc03ea731bcc804a 100644 (file)
@@ -60,6 +60,7 @@ typedef enum {
   SOLVER_RULE_PKG_INSTALLED_OBSOLETES,
   SOLVER_RULE_PKG_RECOMMENDS,
   SOLVER_RULE_PKG_CONSTRAINS,
+  SOLVER_RULE_PKG_SUPPLEMENTS,
   SOLVER_RULE_UPDATE = 0x200,
   SOLVER_RULE_FEATURE = 0x300,
   SOLVER_RULE_JOB = 0x400,
@@ -163,6 +164,10 @@ extern void solver_rule2rules(struct s_Solver *solv, Id rid, Queue *q, int recur
 extern Id   solver_rule2pkgrule(struct s_Solver *solv, Id rid);
 extern const char *solver_ruleinfo2str(struct s_Solver *solv, SolverRuleinfo type, Id source, Id target, Id dep);
 
+/* rule infos for weakdep decisions */
+extern int  solver_allweakdepinfos(struct s_Solver *solv, Id p, Queue *rq);
+extern SolverRuleinfo solver_weakdepinfo(struct s_Solver *solv, Id p, Id *fromp, Id *top, Id *depp);
+
 /* orphan handling */
 extern void solver_breakorphans(struct s_Solver *solv);
 extern void solver_check_brokenorphanrules(struct s_Solver *solv, Queue *dq);
index 42498fa226085d66b7df9323d3fa1756aa81d974..468cbcb8fbbe33a7c9fc0c5fc542b8560b0e71d0 100644 (file)
@@ -4662,7 +4662,7 @@ solver_describe_decision(Solver *solv, Id p, Id *infop)
     return SOLVER_REASON_UNRELATED;
   why = solv->decisionq_why.elements[i];
   if (infop)
-    *infop = why > 0 ? why : -why;
+    *infop = why >= 0 ? why : -why;
   if (why > 0)
     return SOLVER_REASON_UNIT_RULE;
   i = solv->decisionmap[p] >= 0 ? solv->decisionmap[p] : -solv->decisionmap[p];
@@ -4670,8 +4670,8 @@ solver_describe_decision(Solver *solv, Id p, Id *infop)
 }
 
 
-void
-solver_describe_weakdep_decision(Solver *solv, Id p, Queue *whyq)
+int
+solver_allweakdepinfos(Solver *solv, Id p, Queue *whyq)
 {
   Pool *pool = solv->pool;
   int i;
@@ -4681,15 +4681,15 @@ solver_describe_weakdep_decision(Solver *solv, Id p, Queue *whyq)
 
   queue_empty(whyq);
   if (level < 0)
-    return;    /* huh? */
+    return 0;  /* huh? */
   for (decisionno = 0; decisionno < solv->decisionq.count; decisionno++)
     if (solv->decisionq.elements[decisionno] == p)
       break;
   if (decisionno == solv->decisionq.count)
-    return;    /* huh? */
+    return 0;  /* huh? */
   i = solv->decisionmap[p] >= 0 ? solv->decisionmap[p] : -solv->decisionmap[p];
   if (solv->decisionq_reason.elements[i] != SOLVER_REASON_WEAKDEP)
-    return;    /* huh? */
+    return 0;  /* huh? */
 
   /* 1) list all packages that recommend us */
   for (i = 1; i < pool->nsolvables; i++)
@@ -4719,8 +4719,8 @@ solver_describe_weakdep_decision(Solver *solv, Id p, Queue *whyq)
            }
          if (!p2 && found)
            {
-             queue_push(whyq, SOLVER_REASON_RECOMMENDED);
-             queue_push2(whyq, i, rec);
+             queue_push2(whyq, SOLVER_RULE_PKG_RECOMMENDS, i);
+             queue_push2(whyq, 0, rec);
            }
        }
     }
@@ -4752,7 +4752,7 @@ solver_describe_weakdep_decision(Solver *solv, Id p, Queue *whyq)
                  }
                if (solv->decisionmap[p2] > 0 && solv->decisionmap[p2] < level)
                  {
-                   queue_push(whyq, SOLVER_REASON_SUPPLEMENTED);
+                   queue_push2(whyq, SOLVER_RULE_PKG_SUPPLEMENTS, p);
                    queue_push2(whyq, p2, sup);
                    found = 1;
                  }
@@ -4760,7 +4760,7 @@ solver_describe_weakdep_decision(Solver *solv, Id p, Queue *whyq)
            if (!found)
              {
                /* hard case, just note dependency with no package */
-               queue_push(whyq, SOLVER_REASON_SUPPLEMENTED);
+               queue_push2(whyq, SOLVER_RULE_PKG_SUPPLEMENTS, p);
                queue_push2(whyq, 0, sup);
              }
          }
@@ -4771,6 +4771,155 @@ solver_describe_weakdep_decision(Solver *solv, Id p, Queue *whyq)
            solv->decisionmap[p2] = -solv->decisionmap[p2];
        }
     }
+  return whyq->count / 4;
+}
+
+SolverRuleinfo
+solver_weakdepinfo(Solver *solv, Id p, Id *fromp, Id *top, Id *depp)
+{
+  Queue iq;
+  queue_init(&iq);
+  solver_allweakdepinfos(solv, p, &iq);
+  if (fromp)
+    *fromp = iq.count ? iq.elements[1] : 0;
+  if (top)
+    *top = iq.count ? iq.elements[2] : 0;
+  if (depp)
+    *depp = iq.count ? iq.elements[3] : 0;
+  return iq.count ? iq.elements[0] : SOLVER_RULE_UNKNOWN;
+}
+
+/* deprecated, use solver_allweakdepinfos instead */
+void
+solver_describe_weakdep_decision(Solver *solv, Id p, Queue *whyq)
+{
+  int i, j;
+  solver_allweakdepinfos(solv, p, whyq);
+  for (i = j = 0; i < whyq->count; i += 4)
+    {
+      if (whyq->elements[i] == SOLVER_RULE_PKG_RECOMMENDS)
+        {
+         whyq->elements[j++] = SOLVER_REASON_RECOMMENDED;
+         whyq->elements[j++] = whyq->elements[i + 1];
+         whyq->elements[j++] = whyq->elements[i + 3];
+        }
+      else if (whyq->elements[i] == SOLVER_RULE_PKG_SUPPLEMENTS)
+       {
+         whyq->elements[j++] = SOLVER_REASON_SUPPLEMENTED;
+         whyq->elements[j++] = whyq->elements[i + 2];
+         whyq->elements[j++] = whyq->elements[i + 3];
+       }
+    }
+  queue_truncate(whyq, j);
+}
+
+static void
+getdecisionlist(Solver *solv, Map *dm, Queue *decisionlistq)
+{
+  Pool *pool = solv->pool;
+  int i, ii, reason, info;
+  Queue iq;
+
+  queue_empty(decisionlistq);
+  queue_init(&iq);
+  for (ii = solv->decisionq.count - 1; ii >= 0; ii--)
+    {
+      Id v = solv->decisionq.elements[ii];
+      Id vv = (v > 0 ? v : -v);
+      if (!MAPTST(dm, vv))
+       continue;
+      info = solv->decisionq_why.elements[ii];
+      if (info > 0)
+       reason = SOLVER_REASON_UNIT_RULE;
+      else if (info <= 0)
+       {
+         info = -info;
+         reason = solv->decisionmap[vv];
+         reason = solv->decisionq_reason.elements[reason >= 0 ? reason : -reason];
+       }
+      queue_unshift(decisionlistq, info);
+      queue_unshift(decisionlistq, reason);
+      queue_unshift(decisionlistq, v);
+      switch (reason)
+       {
+       case SOLVER_REASON_WEAKDEP:
+         if (v <= 0)
+           break;
+         solver_allweakdepinfos(solv, v, &iq);
+         for (i = 0; i < iq.count; i += 4)
+           {
+             if (iq.elements[i + 1])
+               MAPSET(dm, iq.elements[i + 1]);
+             if (iq.elements[i + 2])
+               MAPSET(dm, iq.elements[i + 2]);
+             else if (iq.elements[i] == SOLVER_RULE_PKG_SUPPLEMENTS)
+               {
+                 Id p2, pp2, id = iq.elements[i + 3];
+                 FOR_PROVIDES(p2, pp2, id)
+                   if (solv->decisionmap[p2] > 0)
+                     MAPSET(dm, p2);
+               }
+           }
+         break;
+       case SOLVER_REASON_RESOLVE_JOB:
+       case SOLVER_REASON_UNIT_RULE:
+       case SOLVER_REASON_RESOLVE:
+         solver_ruleliterals(solv, info, &iq);
+         for (i = 0; i < iq.count; i++)
+           {
+             Id p2 = iq.elements[i];
+             if (p2 < 0)
+               MAPSET(dm, -p2);
+             else if (solv->decisionmap[p2] > 0)
+               MAPSET(dm, p2);
+           }
+         break;
+       default:
+         break;
+       }
+    }
+  queue_free(&iq);
+}
+
+void
+solver_get_decisionlist(Solver *solv, Id p, Queue *decisionlistq)
+{
+  Pool *pool = solv->pool;
+  Map dm;
+  map_init(&dm, pool->nsolvables);
+  MAPSET(&dm, p);
+  getdecisionlist(solv, &dm, decisionlistq);
+  if (!decisionlistq->count)
+    {
+      queue_push(decisionlistq, -p);
+      queue_push2(decisionlistq, SOLVER_REASON_UNRELATED, 0);
+    }
+  map_free(&dm);
+}
+
+void
+solver_get_decisionlist_multiple(Solver *solv, Queue *pq, Queue *decisionlistq)
+{
+  Pool *pool = solv->pool;
+  int i;
+  Map dm;
+  map_init(&dm, pool->nsolvables);
+  for (i = 0; i < pq->count; i++)
+    {
+      Id p = pq->elements[i];
+      if (solv->decisionmap[p] != 0)
+       MAPSET(&dm, p);
+    }
+  getdecisionlist(solv, &dm, decisionlistq);
+  for (i = 0; i < pq->count; i++)
+    {
+      Id p = pq->elements[i];
+      if (solv->decisionmap[p] != 0)
+       continue;
+      queue_push(decisionlistq, -p);
+      queue_push2(decisionlistq, SOLVER_REASON_UNRELATED, 0);
+    }
+  map_free(&dm);
 }
 
 void