From: Michael Schroeder Date: Tue, 6 Dec 2022 14:24:32 +0000 (+0100) Subject: Add support for decisioninfo merging X-Git-Tag: 0.7.23~26 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7f015b5c8ab47f9889fe0c4db580c482f6ca7af5;p=thirdparty%2Flibsolv.git Add support for decisioninfo merging This is not 100% fixed, the names might still change if I come up with something better. Also add code to stringify the decision reason. --- diff --git a/src/decision.c b/src/decision.c index 47a68215..8e8d9c0f 100644 --- a/src/decision.c +++ b/src/decision.c @@ -704,3 +704,242 @@ solver_get_decisionlist_multiple(Solver *solv, Queue *idq, int flags, Queue *dec map_free(&dm); } + +const char * +solver_reason2str(Solver *solv, int reason) +{ + switch(reason) + { + case SOLVER_REASON_WEAKDEP: + return "a weak dependency"; + case SOLVER_REASON_RESOLVE_JOB: + return "a job rule"; + case SOLVER_REASON_RESOLVE: + return "a rule"; + case SOLVER_REASON_UNIT_RULE: + return "an unit rule"; + case SOLVER_REASON_KEEP_INSTALLED: + return "update/keep installed"; + case SOLVER_REASON_UPDATE_INSTALLED: + return "update installed"; + case SOLVER_REASON_CLEANDEPS_ERASE: + return "cleandeps erase"; + case SOLVER_REASON_RESOLVE_ORPHAN: + return "orphaned package"; + case SOLVER_REASON_UNSOLVABLE: + return "unsolvable"; + case SOLVER_REASON_PREMISE: + return "learnt rule premise"; + default: + break; + } + return "an unknown reason"; +} + +const char * +solver_decisionreason2str(Solver *solv, Id decision, int reason, Id info) +{ + if (reason == SOLVER_REASON_WEAKDEP && decision > 0) + { + Id from, to, dep; + int type = solver_weakdepinfo(solv, decision, &from, &to, &dep); + if (type) + { + int state = solver_init_decisioninfo(solv, decision, type, from, to, dep); + return solver_decisioninfo2str(solv, state, type, from, to, dep); + } + } + if ((reason == SOLVER_REASON_RESOLVE_JOB || reason == SOLVER_REASON_UNIT_RULE || reason == SOLVER_REASON_RESOLVE || reason == SOLVER_REASON_UNSOLVABLE) && info > 0) + { + Id from, to, dep; + int type = solver_ruleinfo(solv, info, &from, &to, &dep); + if (type == SOLVER_RULE_CHOICE || type == SOLVER_RULE_RECOMMENDS) + { + Id rid2 = solver_rule2pkgrule(solv, info); + if (rid2) + { + type = solver_ruleinfo(solv, rid2, &from, &to, &dep); + if (type) + { + int state = solver_init_decisioninfo(solv, decision, type, from, to, dep); + return pool_tmpappend(solv->pool, solver_decisioninfo2str(solv, state, type, from, to, dep), " (limited)", 0); + } + } + } + if (type) + { + int state = solver_init_decisioninfo(solv, decision, type, from, to, dep); + return solver_decisioninfo2str(solv, state, type, from, to, dep); + } + } + return solver_reason2str(solv, reason); +} + +/* decision merge state bits */ +#define DMS_INITED (1 << 0) +#define DMS_IDENTICAL_FROM (1 << 1) +#define DMS_IDENTICAL_TO (1 << 2) +#define DMS_MULTIPLE (1 << 3) +#define DMS_NEGATIVE (1 << 4) +#define DMS_NOMERGE (1 << 5) + +/* add some bits about the decision to the ruleinfo type so we can joint decisions */ +int +solver_init_decisioninfo(Solver *solv, Id decision, int type, Id from, Id to, Id dep) +{ + Id decisionpkg = decision >= 0 ? decision : -decision; + int state = DMS_INITED | (decision < 0 ? DMS_NEGATIVE : 0); + switch (type) + { + case SOLVER_RULE_DISTUPGRADE: + case SOLVER_RULE_INFARCH: + case SOLVER_RULE_UPDATE: + case SOLVER_RULE_FEATURE: + case SOLVER_RULE_BLACK: + case SOLVER_RULE_STRICT_REPO_PRIORITY: + case SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP: + case SOLVER_RULE_PKG_REQUIRES: + case SOLVER_RULE_PKG_RECOMMENDS: + case SOLVER_RULE_PKG_SUPPLEMENTS: + if (decisionpkg == from) + state |= DMS_IDENTICAL_FROM; + break; + case SOLVER_RULE_PKG_SAME_NAME: + case SOLVER_RULE_PKG_CONFLICTS: + case SOLVER_RULE_PKG_OBSOLETES: + case SOLVER_RULE_PKG_INSTALLED_OBSOLETES: + case SOLVER_RULE_PKG_IMPLICIT_OBSOLETES: + case SOLVER_RULE_PKG_CONSTRAINS: + if (decisionpkg == from) + state |= DMS_IDENTICAL_FROM; + else if (decisionpkg == to) + state |= DMS_IDENTICAL_TO; + break; + default: + break; + } + if (!decision) + state |= DMS_NOMERGE; + return state; +} + +/* try to merge the ruleinfos of two decisions */ +int +solver_merge_decisioninfo(Solver *solv, int *statep, int oldtype, Id oldfrom, Id oldto, Id olddep, Id decision, int type, Id from, Id to, Id dep) +{ + int state = *statep, newstate; + Id decisionpkg = decision >= 0 ? decision : -decision; + if (!state || (state & DMS_NOMERGE) != 0 || !type || type != oldtype) + return 0; + if (!decision || (decision > 0 && (state & DMS_NEGATIVE) != 0) || (decision < 0 && (state & DMS_NEGATIVE) == 0)) + return 0; + newstate = (state & ~(DMS_IDENTICAL_FROM | DMS_IDENTICAL_TO)) | DMS_MULTIPLE; + if (decisionpkg == from && (state & DMS_IDENTICAL_FROM) != 0) + newstate |= DMS_IDENTICAL_FROM; + else if (oldfrom != from) + return 0; + if (decisionpkg == to && (state & DMS_IDENTICAL_TO) != 0) + newstate |= DMS_IDENTICAL_TO; + else if (oldto != to) + return 0; + /* if MULTIPLE is set we need to keep the identical from/to bits */ + if ((state & DMS_MULTIPLE) != 0 && ((state ^ newstate) & (DMS_IDENTICAL_FROM|DMS_IDENTICAL_TO)) != 0) + return 0; + *statep = newstate; + return 1; +} + +/* special version of solver_ruleinfo2str which supports merged decisions */ +const char * +solver_decisioninfo2str(Solver *solv, int state, int type, Id from, Id to, Id dep) +{ + Pool *pool = solv->pool; + const char *s; + int multiple = state & DMS_MULTIPLE; + + /* use it/they variants if DMS_IDENTICAL_FROM is set */ + if ((state & DMS_IDENTICAL_FROM) != 0) + { + switch (type) + { + case SOLVER_RULE_DISTUPGRADE: + return multiple ? "they do not belong to a distupgrade repository" : "it does not belong to a distupgrade repository"; + case SOLVER_RULE_INFARCH: + return multiple ? "they have inferior architecture": "it has inferior architecture"; + case SOLVER_RULE_UPDATE: + return multiple ? "they need to stay installed or be updated" : "it needs to stay installed or be updated"; + case SOLVER_RULE_FEATURE: + return multiple ? "they need to stay installed or be updated/downgraded" : "it needs to stay installed or be updated/downgraded"; + case SOLVER_RULE_BLACK: + return multiple ? "they can only be installed by a direct request" : "it can only be installed by a direct request"; + case SOLVER_RULE_STRICT_REPO_PRIORITY: + return multiple ? "they are excluded by strict repo priority" : "it is excluded by strict repo priority"; + + case SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP: + return pool_tmpjoin(pool, "nothing provides ", pool_dep2str(pool, dep), 0); + case SOLVER_RULE_PKG_REQUIRES: + return pool_tmpjoin(pool, multiple ? "they require " : "it requires ", pool_dep2str(pool, dep), 0); + case SOLVER_RULE_PKG_RECOMMENDS: + return pool_tmpjoin(pool, multiple ? "they recommend " : "it recommends ", pool_dep2str(pool, dep), 0); + case SOLVER_RULE_PKG_SUPPLEMENTS: + s = pool_tmpjoin(pool, multiple ? "they supplement " : "it supplements ", pool_dep2str(pool, dep), 0); + if (to) + s = pool_tmpappend(pool, s, " provided by ", pool_solvid2str(pool, to)); + return s; + case SOLVER_RULE_PKG_SAME_NAME: + return pool_tmpappend(pool, multiple ? "they have the same name as " : "it has the same name as ", pool_solvid2str(pool, to), 0); + case SOLVER_RULE_PKG_CONFLICTS: + s = pool_tmpappend(pool, multiple ? "they conflict with " : "it conflicts with ", pool_dep2str(pool, dep), 0); + if (to) + s = pool_tmpappend(pool, s, " provided by ", pool_solvid2str(pool, to)); + return s; + case SOLVER_RULE_PKG_OBSOLETES: + s = pool_tmpappend(pool, multiple ? "they obsolete " : "it obsoletes ", pool_dep2str(pool, dep), 0); + if (to) + s = pool_tmpappend(pool, s, " provided by ", pool_solvid2str(pool, to)); + return s; + case SOLVER_RULE_PKG_INSTALLED_OBSOLETES: + s = pool_tmpjoin(pool, multiple ? "they are installed and obsolete " : "it is installed and obsoletes ", pool_dep2str(pool, dep), 0); + if (to) + s = pool_tmpappend(pool, s, " provided by ", pool_solvid2str(pool, to)); + return s; + case SOLVER_RULE_PKG_IMPLICIT_OBSOLETES: + s = pool_tmpjoin(pool, multiple ? "they implicitly obsolete " : "it implicitly obsoletes ", pool_dep2str(pool, dep), 0); + if (to) + s = pool_tmpappend(pool, s, " provided by ", pool_solvid2str(pool, to)); + return s; + case SOLVER_RULE_PKG_CONSTRAINS: + s = pool_tmpappend(pool, multiple ? "they have constraint " : "it has constraint ", pool_dep2str(pool, dep), 0); + if (to) + s = pool_tmpappend(pool, s, " conflicting with ", pool_solvid2str(pool, to)); + return s; + default: + break; + } + } + + /* in some cases we can drop the "to" part if DMS_IDENTICAL_TO is set */ + if ((state & DMS_IDENTICAL_TO) != 0) + { + switch (type) + { + case SOLVER_RULE_PKG_SAME_NAME: + return pool_tmpappend(pool, multiple ? "they have the same name as " : "it has the same name as ", pool_solvid2str(pool, from), 0); + case SOLVER_RULE_PKG_CONFLICTS: + case SOLVER_RULE_PKG_OBSOLETES: + case SOLVER_RULE_PKG_IMPLICIT_OBSOLETES: + case SOLVER_RULE_PKG_INSTALLED_OBSOLETES: + case SOLVER_RULE_PKG_CONSTRAINS: + state &= ~DMS_IDENTICAL_TO; + to = 0; + break; + default: + break; + } + } + + /* fallback to solver_ruleinfo2str if we can */ + if (multiple && (state & (DMS_IDENTICAL_FROM|DMS_IDENTICAL_TO)) != 0) + return "unsupported decision merge?"; + return solver_ruleinfo2str(solv, type, from, to, dep); +} diff --git a/src/libsolv.ver b/src/libsolv.ver index f411c290..d8a8496d 100644 --- a/src/libsolv.ver +++ b/src/libsolv.ver @@ -353,6 +353,8 @@ SOLV_1.0 { solver_create; solver_create_state_maps; solver_create_transaction; + solver_decisioninfo2str; + solver_decisionreason2str; solver_describe_decision; solver_describe_weakdep_decision; solver_findallproblemrules; @@ -372,6 +374,8 @@ SOLV_1.0 { solver_get_recommendations; solver_get_unneeded; solver_get_userinstalled; + solver_init_decisioninfo; + solver_merge_decisioninfo; solver_next_problem; solver_next_solution; solver_next_solutionelement; @@ -392,6 +396,7 @@ SOLV_1.0 { solver_problem2str; solver_problem_count; solver_problemruleinfo2str; + solver_reason2str; solver_rule2job; solver_rule2jobidx; solver_rule2pkgrule; diff --git a/src/solver.h b/src/solver.h index 5f837bde..24221ce4 100644 --- a/src/solver.h +++ b/src/solver.h @@ -393,9 +393,17 @@ extern int solver_calc_installsizechange(Solver *solv); extern void pool_job2solvables(Pool *pool, Queue *pkgs, Id how, Id what); extern int pool_isemptyupdatejob(Pool *pool, Id how, Id what); +/* decisioninfo merging */ +extern int solver_init_decisioninfo(Solver *solv, Id decision, int type, Id from, Id to, Id dep); +extern int solver_merge_decisioninfo(Solver *solv, int *statep, int oldtype, Id oldfrom, Id oldto, Id olddep, Id decision, int type, Id from, Id to, Id dep); + extern const char *solver_select2str(Pool *pool, Id select, Id what); extern const char *pool_job2str(Pool *pool, Id how, Id what, Id flagmask); extern const char *solver_alternative2str(Solver *solv, int type, Id id, Id from); +extern const char *solver_reason2str(Solver *solv, int reason); +extern const char *solver_decisionreason2str(Solver *solv, Id decision, int reason, Id info); +extern const char *solver_decisioninfo2str(Solver *solv, int state, int type, Id from, Id to, Id dep); + /* deprecated, use solver_allweakdepinfos/solver_weakdepinfo instead */ extern void solver_describe_weakdep_decision(Solver *solv, Id p, Queue *whyq);