From: Michael Schroeder Date: Tue, 3 Mar 2015 13:54:44 +0000 (+0100) Subject: Add alternative introspection functions & testcase support X-Git-Tag: 0.6.9~5 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f00efbde7262eee136120f0f78a260862a734847;p=thirdparty%2Flibsolv.git Add alternative introspection functions & testcase support --- diff --git a/ext/testcase.c b/ext/testcase.c index b4516015..f0057e6c 100644 --- a/ext/testcase.c +++ b/ext/testcase.c @@ -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); diff --git a/ext/testcase.h b/ext/testcase.h index 80bf966d..14a2ccab 100644 --- a/ext/testcase.h +++ b/ext/testcase.h @@ -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); diff --git a/src/libsolv.ver b/src/libsolv.ver index 91337ea4..c8601714 100644 --- a/src/libsolv.ver +++ b/src/libsolv.ver @@ -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; diff --git a/src/rules.c b/src/rules.c index e6b578cd..fc4fbb1e 100644 --- a/src/rules.c +++ b/src/rules.c @@ -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) { diff --git a/src/rules.h b/src/rules.h index 83a26794..8f55af36 100644 --- a/src/rules.h +++ b/src/rules.h @@ -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); diff --git a/src/solver.c b/src/solver.c index 3dce8d0b..9c84d58e 100644 --- a/src/solver.c +++ b/src/solver.c @@ -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) { diff --git a/src/solver.h b/src/solver.h index 2a7f060f..9904bd9c 100644 --- a/src/solver.h +++ b/src/solver.h @@ -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 */