]> git.ipfire.org Git - thirdparty/libsolv.git/commitdiff
Add alternative introspection functions & testcase support
authorMichael Schroeder <mls@suse.de>
Tue, 3 Mar 2015 13:54:44 +0000 (14:54 +0100)
committerMichael Schroeder <mls@suse.de>
Tue, 3 Mar 2015 13:54:44 +0000 (14:54 +0100)
ext/testcase.c
ext/testcase.h
src/libsolv.ver
src/rules.c
src/rules.h
src/solver.c
src/solver.h

index b4516015e24f4c9e4a8fe2d3d62b076207aba7d2..f0057e6c7a9af86e22dd05fc49f27b653b4c2643 100644 (file)
@@ -77,6 +77,7 @@ static struct resultflags2str {
   { TESTCASE_RESULT_ORPHANED,          "orphaned" },
   { TESTCASE_RESULT_RECOMMENDED,       "recommended" },
   { TESTCASE_RESULT_UNNEEDED,          "unneeded" },
+  { TESTCASE_RESULT_ALTERNATIVES,      "alternatives" },
   { 0, 0 }
 };
 
@@ -1624,6 +1625,33 @@ testcase_solutionid(Solver *solv, Id problem, Id solution)
   return s;
 }
 
+static const char *
+testcase_alternativeid(Solver *solv, int type, Id id, Id from)
+{
+  const char *s;
+  Pool *pool = solv->pool;
+  Chksum *chk;
+  const unsigned char *md5;
+  int md5l;
+  chk = solv_chksum_create(REPOKEY_TYPE_MD5);
+  if (type == SOLVER_ALTERNATIVE_TYPE_RECOMMENDS)
+    {
+      s = testcase_solvid2str(pool, from);
+      solv_chksum_add(chk, s, strlen(s) + 1);
+      s = testcase_dep2str(pool, id);
+      solv_chksum_add(chk, s, strlen(s) + 1);
+    }
+  else if (type == SOLVER_ALTERNATIVE_TYPE_RULE)
+    {
+      s = testcase_ruleid(solv, id);
+      solv_chksum_add(chk, s, strlen(s) + 1);
+    }
+  md5 = solv_chksum_get(chk, &md5l);
+  s = pool_bin2hex(pool, md5, 4);
+  chk = solv_chksum_free(chk, 0);
+  return s;
+}
+
 static struct class2str {
   Id class;
   const char *str;
@@ -1780,6 +1808,72 @@ testcase_solverresult(Solver *solv, int resultflags)
       queue_free(&q);
       queue_free(&qf);
     }
+  if ((resultflags & TESTCASE_RESULT_ALTERNATIVES) != 0)
+    {
+      char *altprefix;
+      Queue q, rq;
+      int cnt;
+      Id alternative;
+      queue_init(&q);
+      queue_init(&rq);
+      cnt = solver_alternatives_count(solv);
+      for (alternative = 1; alternative <= cnt; alternative++)
+       {
+         Id id, from, chosen;
+         char num[20];
+         int type = solver_get_alternative(solv, alternative, &id, &from, &chosen, &q, 0);
+         altprefix = solv_dupjoin("alternative ", testcase_alternativeid(solv, type, id, from), " ");
+         strcpy(num, " 0 ");
+         if (type == SOLVER_ALTERNATIVE_TYPE_RECOMMENDS)
+           {
+             char *s = pool_tmpjoin(pool, altprefix, num, testcase_solvid2str(pool, from));
+             s = pool_tmpappend(pool, s, " recommends ", testcase_dep2str(pool, id));
+             strqueue_push(&sq, s);
+           }
+         else if (type == SOLVER_ALTERNATIVE_TYPE_RULE)
+           {
+             /* map choice rules back to pkg rules */
+             if (solver_ruleclass(solv, id) == SOLVER_RULE_CHOICE)
+               id = solver_rule2pkgrule(solv, id);
+             solver_allruleinfos(solv, id, &rq);
+             for (i = 0; i < rq.count; i += 4)
+               {
+                 int rtype = rq.elements[i];
+                 if ((rtype & SOLVER_RULE_TYPEMASK) == SOLVER_RULE_JOB)
+                   {
+                     const char *js = testcase_job2str(pool, rq.elements[i + 2], rq.elements[i + 3]);
+                     char *s = pool_tmpjoin(pool, altprefix, num, " job ");
+                     s = pool_tmpappend(pool, s, js, 0);
+                     strqueue_push(&sq, s);
+                   }
+                 else if (rtype == SOLVER_RULE_PKG_REQUIRES)
+                   {
+                     char *s = pool_tmpjoin(pool, altprefix, num, testcase_solvid2str(pool, rq.elements[i + 1]));
+                     s = pool_tmpappend(pool, s, " requires ", testcase_dep2str(pool, rq.elements[i + 3]));
+                     strqueue_push(&sq, s);
+                   }
+               }
+           }
+         for (i = 0; i < q.count; i++)
+           {
+             Id p = q.elements[i];
+             if (i >= 9)
+               num[0] = '0' + (i + 1) / 10;
+             num[1] = '0' + (i + 1) % 10;
+             if (-p == chosen)
+               s = pool_tmpjoin(pool, altprefix, num, "+ ");
+             else if (p < 0)
+               s = pool_tmpjoin(pool, altprefix, num, "- ");
+             else if (p >= 0)
+               s = pool_tmpjoin(pool, altprefix, num, "  ");
+             s = pool_tmpappend(pool, s,  testcase_solvid2str(pool, p < 0 ? -p : p), 0);
+             strqueue_push(&sq, s);
+           }
+         solv_free(altprefix);
+       }
+      queue_free(&q);
+      queue_free(&rq);
+    }
 
   strqueue_sort(&sq);
   result = strqueue_join(&sq);
index 80bf966d67590f5c1b4aa5c9c91c81fbac610049..14a2ccab56605d54acfbb1c87f9dde0d3715b640 100644 (file)
@@ -14,6 +14,7 @@
 #define TESTCASE_RESULT_ORPHANED       (1 << 2)
 #define TESTCASE_RESULT_RECOMMENDED    (1 << 3)
 #define TESTCASE_RESULT_UNNEEDED       (1 << 4)
+#define TESTCASE_RESULT_ALTERNATIVES   (1 << 5)
 
 extern Id testcase_str2dep(Pool *pool, const char *s);
 extern const char *testcase_dep2str(Pool *pool, Id id);
index 91337ea404710ec9d9dc0f1ad5b2ac04e9dfec0f..c8601714c0181c094b96b18998e52ad5d086f5ce 100644 (file)
@@ -314,6 +314,7 @@ SOLV_1.0 {
                solvable_trivial_installable_repo;
                solvable_unset;
                solver_allruleinfos;
+               solver_alternatives_count;
                solver_calc_duchanges;
                solver_calc_installsizechange;
                solver_calculate_multiversionmap;
@@ -329,6 +330,7 @@ SOLV_1.0 {
                solver_findproblemrule;
                solver_free;
                solver_freedupmaps;
+               solver_get_alternative;
                solver_get_decisionblock;
                solver_get_decisionlevel;
                solver_get_decisionqueue;
@@ -360,6 +362,7 @@ SOLV_1.0 {
                solver_problemruleinfo2str;
                solver_rule2job;
                solver_rule2jobidx;
+               solver_rule2pkgrule;
                solver_rule2rules;
                solver_rule2solvable;
                solver_ruleclass;
index e6b578cda4722b99747b971df8dbe48ef6fa5ece..fc4fbb1e0415c6367f3175d33bfe9b105c82cc1e 100644 (file)
@@ -2763,6 +2763,14 @@ solver_rule2solvable(Solver *solv, Id rid)
   return 0;
 }
 
+Id
+solver_rule2pkgrule(Solver *solv, Id rid)
+{
+  if (rid >= solv->choicerules && rid < solv->choicerules_end)
+    return solv->choicerules_ref[rid - solv->choicerules];
+  return 0;
+}
+
 static void
 solver_rule2rules_rec(Solver *solv, Id rid, Queue *q, Map *seen)
 {
index 83a26794104ffd77ae50b2a20425484c2376d6e1..8f55af365a622a08dae13fdae7815411f66e52c6 100644 (file)
@@ -145,6 +145,7 @@ extern int  solver_rule2jobidx(struct _Solver *solv, Id rid);
 extern Id   solver_rule2job(struct _Solver *solv, Id rid, Id *whatp);
 extern Id   solver_rule2solvable(struct _Solver *solv, Id rid);
 extern void solver_rule2rules(struct _Solver *solv, Id rid, Queue *q, int recursive);
+extern Id   solver_rule2pkgrule(struct _Solver *solv, Id rid);
 
 /* orphan handling */
 extern void solver_breakorphans(struct _Solver *solv);
index 3dce8d0bcbd5d3484d18a05542be481ba3896297..9c84d58eb9afc970aba1d450fe4959a9c2c35b38 100644 (file)
@@ -4870,6 +4870,54 @@ pool_add_userinstalled_jobs(Pool *pool, Queue *q, Queue *job, int flags)
     }
 }
 
+int
+solver_alternatives_count(Solver *solv)
+{
+  Id *elements = solv->branches.elements;
+  int res, count;
+  for (res = 0, count = solv->branches.count; count; res++)
+    count -= elements[count - 2];
+  return res;
+}
+
+int
+solver_get_alternative(Solver *solv, Id alternative, Id *idp, Id *fromp, Id *chosenp, Queue *choices, int *levelp)
+{
+  int cnt = solver_alternatives_count(solv);
+  int count = solv->branches.count;
+  Id *elements = solv->branches.elements;
+  if (choices)
+    queue_empty(choices);
+  if (alternative <= 0 || alternative > cnt)
+    return 0;
+  elements += count;
+  for (; cnt > alternative; cnt--)
+    elements -= elements[-2];
+  if (levelp)
+    *levelp = elements[-1];
+  if (fromp)
+    *fromp = elements[-4];
+  if (idp)
+    *idp = elements[-3];
+  if (chosenp)
+    {
+      int i;
+      *chosenp = 0;
+      for (i = elements[-2]; i > 4; i--)
+       {
+         Id p = -elements[-i];
+         if (p > 0 && solv->decisionmap[p] == elements[-1] + 1)
+           {
+             *chosenp = p;
+             break;
+           }
+       }
+    }
+  if (choices)
+    queue_insertn(choices, 0, elements[-2] - 4, elements - elements[-2]);
+  return elements[-4] ? SOLVER_ALTERNATIVE_TYPE_RECOMMENDS : SOLVER_ALTERNATIVE_TYPE_RULE;
+}
+
 const char *
 solver_select2str(Pool *pool, Id select, Id what)
 {
index 2a7f060f86f2ffa68e89c858ee4b3c8d6853a7ae..9904bd9ce51ee8b23e100679a8d3de5804ef0a44 100644 (file)
@@ -299,6 +299,10 @@ typedef struct _Solver Solver;
 #define GET_USERINSTALLED_NAMES                        (1 << 0)        /* package names instead if ids */
 #define GET_USERINSTALLED_INVERTED             (1 << 1)        /* autoinstalled */
 
+#define SOLVER_ALTERNATIVE_TYPE_RULE           1
+#define SOLVER_ALTERNATIVE_TYPE_RECOMMENDS     2
+#define SOLVER_ALTERNATIVE_TYPE_SUGGESTS       3
+
 extern Solver *solver_create(Pool *pool);
 extern void solver_free(Solver *solv);
 extern int  solver_solve(Solver *solv, Queue *job);
@@ -320,6 +324,8 @@ extern void pool_add_userinstalled_jobs(Pool *pool, Queue *q, Queue *job, int fl
 extern int  solver_describe_decision(Solver *solv, Id p, Id *infop);
 extern void solver_describe_weakdep_decision(Solver *solv, Id p, Queue *whyq);
 
+extern int solver_alternatives_count(Solver *solv);
+extern int solver_get_alternative(Solver *solv, Id alternative, Id *idp, Id *fromp, Id *chosenp, Queue *choices, int *levelp);
 
 extern void solver_calculate_multiversionmap(Pool *pool, Queue *job, Map *multiversionmap);
 extern void solver_calculate_noobsmap(Pool *pool, Queue *job, Map *multiversionmap);   /* obsolete */