From d06c560f7b8bd5c83824fbcc5caff6d545350d85 Mon Sep 17 00:00:00 2001 From: Michael Schroeder Date: Mon, 19 Jan 2009 16:01:18 +0100 Subject: [PATCH] - add inferior arch handling - add installcheck tool - add support for repo local distupgrades - add debian version compare function --- src/evr.c | 49 +++- src/knownid.h | 2 + src/pool.c | 7 +- src/solver.c | 687 +++++++++++++++++++++++++++++++++++++++------------ src/solver.h | 15 +- src/solverdebug.c | 28 ++- tools/CMakeLists.txt | 3 + tools/installcheck.c | 314 +++++++++++++++++++++++ 8 files changed, 940 insertions(+), 165 deletions(-) create mode 100644 tools/installcheck.c diff --git a/src/evr.c b/src/evr.c index 28d16ca..b01adeb 100644 --- a/src/evr.c +++ b/src/evr.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Novell Inc. + * Copyright (c) 2007-2009, Novell Inc. * * This program is licensed under the BSD license, read LICENSE.BSD * for further information @@ -16,6 +16,50 @@ #include "evr.h" #include "pool.h" + +#ifdef DEBIAN_SEMANTICS + +int +vercmp(const char *s1, const char *q1, const char *s2, const char *q2) +{ + int r, c1, c2; + while (1) + { + c1 = s1 < q1 ? *(const unsigned char *)s1++ : 0; + c2 = s2 < q2 ? *(const unsigned char *)s2++ : 0; + if ((c1 >= '0' && c1 <= '9') && (c2 >= '0' && c2 <= '9')) + { + while (c1 == '0') + c1 = s1 < q1 ? *(const unsigned char *)s1++ : 0; + while (c2 == '0') + c2 = s2 < q2 ? *(const unsigned char *)s2++ : 0; + r = 0; + while ((c1 >= '0' && c1 <= '9') && (c2 >= '0' && c2 <= '9')) + { + if (!r) + r = c1 - c2; + c1 = s1 < q1 ? *(const unsigned char *)s1++ : 0; + c2 = s2 < q2 ? *(const unsigned char *)s2++ : 0; + } + if (c1 >= '0' && c1 <= '9') + return 1; + if (c2 >= '0' && c2 <= '9') + return -1; + if (r) + return r < 0 ? -1 : 1; + } + c1 = c1 == '~' ? -1 : !c1 || (c1 >= '0' && c1 <= '9') || (c1 >= 'A' && c1 <= 'Z') || (c1 >= 'a' && c1 <= 'z') ? c1 : c1 + 256; + c2 = c2 == '~' ? -1 : !c2 || (c2 >= '0' && c2 <= '9') || (c2 >= 'A' && c2 <= 'Z') || (c2 >= 'a' && c2 <= 'z') ? c2 : c2 + 256; + r = c1 - c2; + if (r) + return r < 0 ? -1 : 1; + if (!c1) + return 0; + } +} + +#else + int vercmp(const char *s1, const char *q1, const char *s2, const char *q2) { @@ -73,6 +117,9 @@ vercmp(const char *s1, const char *q1, const char *s2, const char *q2) return s1 < q1 ? 1 : s2 < q2 ? -1 : 0; } +#endif + + /* edition (e:v-r) compare */ int evrcmp_str(Pool *pool, const char *evr1, const char *evr2, int mode) diff --git a/src/knownid.h b/src/knownid.h index b2567ea..a2ee407 100644 --- a/src/knownid.h +++ b/src/knownid.h @@ -207,6 +207,8 @@ KNOWNID(DELTA_SEQ_NAME, "delta:seqname"), KNOWNID(DELTA_SEQ_EVR, "delta:seqevr"), KNOWNID(DELTA_SEQ_NUM, "delta:seqnum"), +KNOWNID(NAMESPACE_PRODUCTBUDDY, "namespace:productbuddy"), + KNOWNID(ID_NUM_INTERNAL, 0) #ifdef KNOWNID_INITIALIZE diff --git a/src/pool.c b/src/pool.c index 39b60b5..f35ca8f 100644 --- a/src/pool.c +++ b/src/pool.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Novell Inc. + * Copyright (c) 2007-2009, Novell Inc. * * This program is licensed under the BSD license, read LICENSE.BSD * for further information @@ -636,8 +636,13 @@ pool_addrelproviders(Pool *pool, Id d) else { int f = flags == 5 ? 5 : flags == 2 ? pflags : (flags ^ 5) & (pflags | 5); +#ifdef DEBIAN_SEMANTICS + if ((f & (1 << (1 + evrcmp(pool, pevr, evr, EVRCMP_COMPARE)))) != 0) + break; +#else if ((f & (1 << (1 + evrcmp(pool, pevr, evr, EVRCMP_MATCH_RELEASE)))) != 0) break; +#endif } } if (!pid) diff --git a/src/solver.c b/src/solver.c index fd547d5..71c957c 100644 --- a/src/solver.c +++ b/src/solver.c @@ -478,6 +478,26 @@ disableproblem(Solver *solv, Id v) if (v > 0) { + if (v >= solv->infarchrules && v < solv->infarchrules_end) + { + Pool *pool = solv->pool; + Id name = pool->solvables[-solv->rules[v].p].name; + while (v > solv->infarchrules && pool->solvables[-solv->rules[v - 1].p].name == name) + v--; + for (; v < solv->infarchrules_end && pool->solvables[-solv->rules[v].p].name == name; v++) + disablerule(solv, solv->rules + v); + return; + } + if (v >= solv->duprules && v < solv->duprules_end) + { + Pool *pool = solv->pool; + Id name = pool->solvables[-solv->rules[v].p].name; + while (v > solv->duprules && pool->solvables[-solv->rules[v - 1].p].name == name) + v--; + for (; v < solv->duprules_end && pool->solvables[-solv->rules[v].p].name == name; v++) + disablerule(solv, solv->rules + v); + return; + } disablerule(solv, solv->rules + v); return; } @@ -501,6 +521,26 @@ enableproblem(Solver *solv, Id v) if (v > 0) { + if (v >= solv->infarchrules && v < solv->infarchrules_end) + { + Pool *pool = solv->pool; + Id name = pool->solvables[-solv->rules[v].p].name; + while (v > solv->infarchrules && pool->solvables[-solv->rules[v - 1].p].name == name) + v--; + for (; v < solv->infarchrules_end && pool->solvables[-solv->rules[v].p].name == name; v++) + enablerule(solv, solv->rules + v); + return; + } + if (v >= solv->duprules && v < solv->duprules_end) + { + Pool *pool = solv->pool; + Id name = pool->solvables[-solv->rules[v].p].name; + while (v > solv->duprules && pool->solvables[-solv->rules[v - 1].p].name == name) + v--; + for (; v < solv->duprules_end && pool->solvables[-solv->rules[v].p].name == name; v++) + enablerule(solv, solv->rules + v); + return; + } if (v >= solv->featurerules && v < solv->featurerules_end) { /* do not enable feature rule if update rule is enabled */ @@ -850,7 +890,10 @@ enableweakrules(Solver *solv) /* FIXME: maybe also look at SOLVER_INSTALL|SOLVABLE_ONE_OF */ /*------------------------------------------------------------------- - * disable update rules + * disable update rules depending on enabled job + * if jobidx is set we just disabled this job, so we may want + * to re-enable some rules + * otherwise we disable all update rules that conflict with some job. */ static void @@ -863,10 +906,9 @@ disableupdaterules(Solver *solv, Queue *job, int jobidx) Repo *installed; Rule *r; Id lastjob = -1; + Map nolockrules; installed = solv->installed; - if (!installed) - return; if (jobidx != -1) { @@ -885,6 +927,7 @@ disableupdaterules(Solver *solv, Queue *job, int jobidx) } } /* go through all enabled job rules */ + map_init(&nolockrules, pool->nsolvables); MAPZERO(&solv->noupdate); for (i = solv->jobrules; i < solv->jobrules_end; i++) { @@ -904,6 +947,14 @@ disableupdaterules(Solver *solv, Queue *job, int jobidx) if (select != SOLVER_SOLVABLE) break; s = pool->solvables + what; + FOR_PROVIDES(p, pp, s->name) + { + Solvable *ps = pool->solvables + p; + if (ps->name == s->name) + MAPSET(&nolockrules, p); + } + if (!installed) + break; if (solv->noobsoletes.size && MAPTST(&solv->noobsoletes, what)) break; if (s->repo == installed) @@ -918,22 +969,27 @@ disableupdaterules(Solver *solv, Queue *job, int jobidx) while ((obs = *obsp++) != 0) FOR_PROVIDES(p, pp, obs) { - if (pool->solvables[p].repo != installed) + Solvable *ps = pool->solvables + p; + if (ps->repo != installed) continue; - if (!solv->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p, obs)) + if (!solv->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs)) continue; MAPSET(&solv->noupdate, p - installed->start); } } FOR_PROVIDES(p, pp, s->name) { - if (!solv->implicitobsoleteusesprovides && pool->solvables[p].name != s->name) + Solvable *ps = pool->solvables + p; + if (ps->repo != installed) + continue; + if (!solv->implicitobsoleteusesprovides && ps->name != s->name) continue; - if (pool->solvables[p].repo == installed) - MAPSET(&solv->noupdate, p - installed->start); + MAPSET(&solv->noupdate, p - installed->start); } break; case SOLVER_ERASE: + if (!installed) + break; FOR_JOB_SELECT(p, pp, select, what) if (pool->solvables[p].repo == installed) MAPSET(&solv->noupdate, p - installed->start); @@ -951,6 +1007,35 @@ disableupdaterules(Solver *solv, Queue *job, int jobidx) how = job->elements[jobidx]; what = job->elements[jobidx + 1]; select = how & SOLVER_SELECTMASK; + if ((how & SOLVER_JOBMASK) == SOLVER_INSTALL && select == SOLVER_SOLVABLE) + { + /* check if we need to enable some lock rule */ + for (i = solv->infarchrules, r = solv->rules + i; i < solv->infarchrules_end; i++, r++) + { + if (r->p != -what || r->d >= 0 || !MAPTST(&nolockrules, -r->p)) + continue; + enablerule(solv, r); + IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS) + { + POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "@@@ re-enabling "); + solver_printrule(solv, SAT_DEBUG_SOLUTIONS, r); + } + } + for (i = solv->duprules, r = solv->rules + i; i < solv->duprules_end; i++, r++) + { + if (r->p != -what || r->d >= 0 || !MAPTST(&nolockrules, -r->p)) + continue; + enablerule(solv, r); + IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS) + { + POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "@@@ re-enabling "); + solver_printrule(solv, SAT_DEBUG_SOLUTIONS, r); + } + } + } + map_free(&nolockrules); + if (!installed) + return; switch (how & SOLVER_JOBMASK) { case SOLVER_INSTALL: @@ -1039,14 +1124,28 @@ disableupdaterules(Solver *solv, Queue *job, int jobidx) return; } - for (i = 0; i < installed->nsolvables; i++) + for (i = solv->infarchrules, r = solv->rules + i; i < solv->infarchrules_end; i++, r++) { - r = solv->rules + solv->updaterules + i; - if (r->d >= 0 && MAPTST(&solv->noupdate, i)) - disablerule(solv, r); /* was enabled, need to disable */ - r = solv->rules + solv->featurerules + i; - if (r->d >= 0 && MAPTST(&solv->noupdate, i)) - disablerule(solv, r); /* was enabled, need to disable */ + if (r->p < 0 && r->d >= 0 && MAPTST(&nolockrules, -r->p)) + disablerule(solv, r); /* was enabled, need to disable */ + } + for (i = solv->duprules, r = solv->rules + i; i < solv->duprules_end; i++, r++) + { + if (r->p < 0 && r->d >= 0 && MAPTST(&nolockrules, -r->p)) + disablerule(solv, r); /* was enabled, need to disable */ + } + map_free(&nolockrules); + if (installed) + { + for (i = 0; i < installed->nsolvables; i++) + { + r = solv->rules + solv->updaterules + i; + if (r->d >= 0 && MAPTST(&solv->noupdate, i)) + disablerule(solv, r); /* was enabled, need to disable */ + r = solv->rules + solv->featurerules + i; + if (r->d >= 0 && MAPTST(&solv->noupdate, i)) + disablerule(solv, r); /* was enabled, need to disable */ + } } } @@ -1176,6 +1275,17 @@ addrpmrulesforsolvable(Solver *solv, Solvable *s, Map *m) addrule(solv, -n, 0); /* uninstallable */ } + /* yet another SUSE hack, sigh */ + if (pool->nscallback && !strncmp("product:", id2str(pool, s->name), 8)) + { + Id buddy = pool->nscallback(pool, pool->nscallbackdata, NAMESPACE_PRODUCTBUDDY, n); + if (buddy > 0 && buddy != SYSTEMSOLVABLE && buddy != n && buddy < pool->nsolvables) + { + addrule(solv, n, -buddy); + addrule(solv, buddy, -n); + } + } + /*----------------------------------------- * check requires of s */ @@ -1466,12 +1576,13 @@ finddistupgradepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all) if (!qs->count) { if (allow_all) - return 0; + return 0; /* orphaned, don't create feature rule */ + /* check if this is an orphaned package */ policy_findupdatepackages(solv, s, qs, 1); if (!qs->count) - return 0; /* orphaned */ + return 0; /* orphaned, don't create update rule */ qs->count = 0; - return -SYSTEMSOLVABLE; + return -SYSTEMSOLVABLE; /* supported but not installable */ } if (allow_all) return s - pool->solvables; @@ -1486,6 +1597,30 @@ finddistupgradepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all) return -SYSTEMSOLVABLE; } +/* add packages from the dup repositories to the update candidates + * this isn't needed for the global dup mode as all packages are + * from dup repos in that case */ +static void +addduppackages(Solver *solv, Solvable *s, Queue *qs) +{ + Queue dupqs; + Id p, dupqsbuf[64]; + int i; + int oldnoupdateprovide = solv->noupdateprovide; + + queue_init_buffer(&dupqs, dupqsbuf, sizeof(dupqsbuf)/sizeof(*dupqsbuf)); + solv->noupdateprovide = 1; + policy_findupdatepackages(solv, s, &dupqs, 2); + solv->noupdateprovide = oldnoupdateprovide; + for (i = 0; i < dupqs.count; i++) + { + p = dupqs.elements[i]; + if (MAPTST(&solv->dupmap, p)) + queue_pushunique(qs, p); + } + queue_free(&dupqs); +} + /*------------------------------------------------------------------- * * add rule for update @@ -1511,6 +1646,9 @@ addupdaterule(Solver *solv, Solvable *s, int allow_all) p = finddistupgradepackages(solv, s, &qs, allow_all); else policy_findupdatepackages(solv, s, &qs, allow_all); + if (!allow_all && !solv->distupgrade && solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p)) + addduppackages(solv, s, &qs); + if (!allow_all && qs.count && solv->noobsoletes.size) { int i, j; @@ -2013,6 +2151,20 @@ analyze_unsolvable_rule(Solver *solv, Rule *r, Id *lastweakp) /* turn rule into problem */ if (why >= solv->jobrules && why < solv->jobrules_end) why = -(solv->ruletojob.elements[why - solv->jobrules] + 1); + /* normalize dup/infarch rules */ + if (why > solv->infarchrules && why < solv->infarchrules_end) + { + Id name = pool->solvables[-solv->rules[why].p].name; + while (why > solv->infarchrules && pool->solvables[-solv->rules[why - 1].p].name == name) + why--; + } + if (why > solv->duprules && why < solv->duprules_end) + { + Id name = pool->solvables[-solv->rules[why].p].name; + while (why > solv->duprules && pool->solvables[-solv->rules[why - 1].p].name == name) + why--; + } + /* return if problem already countains our rule */ if (solv->problems.count) { @@ -2429,6 +2581,10 @@ solver_free(Solver *solv) map_free(&solv->weakrulemap); map_free(&solv->noobsoletes); + map_free(&solv->updatemap); + map_free(&solv->dupmap); + map_free(&solv->dupinvolvedmap); + sat_free(solv->decisionmap); sat_free(solv->rules); sat_free(solv->watches); @@ -2574,150 +2730,65 @@ run_solver(Solver *solv, int disablerules, int doweak) if (level < systemlevel && solv->installed && solv->installed->nsolvables) { - if (!solv->updatesystem) + Repo *installed = solv->installed; + FOR_REPO_SOLVABLES(installed, i, s) { - /* - * Normal run (non-updating) - * Keep as many packages installed as possible - */ - POOL_DEBUG(SAT_DEBUG_STATS, "installing old packages\n"); - - for (i = solv->installed->start; i < solv->installed->end; i++) - { - s = pool->solvables + i; - - /* skip if not installed */ - if (s->repo != solv->installed) - continue; - - /* skip if already decided */ - if (solv->decisionmap[i] != 0) - continue; - - r = solv->rules + solv->updaterules + (i - solv->installed->start); - if (!r->p) /* update rule == feature rule? */ - r = r - solv->updaterules + solv->featurerules; - if (r->p != i) /* allowed to keep package? */ - continue; - - POOL_DEBUG(SAT_DEBUG_PROPAGATE, "keeping %s\n", solvable2str(pool, s)); - - olevel = level; - level = setpropagatelearn(solv, level, i, disablerules, r->p ? r - solv->rules : 0); + Rule *rr; + Id d; - if (level == 0) /* unsolvable */ - { - queue_free(&dq); - queue_free(&dqs); - return; - } - if (level <= olevel) - break; - } - systemlevel = level + 1; - if (i < solv->installed->end) + if (MAPTST(&solv->noupdate, i - installed->start)) continue; - } - else if (solv->noobsoletes.size && solv->multiversionupdaters) - { - /* see if we can multi-version install the newest package */ - for (i = solv->installed->start; i < solv->installed->end; i++) + if (solv->decisionmap[i] > 0) + continue; + r = solv->rules + solv->updaterules + (i - installed->start); + rr = r; + if (!rr->p || rr->d < 0) /* disabled -> look at feature rule */ + rr -= solv->installed->end - solv->installed->start; + if (!rr->p) /* identical to update rule? */ + rr = r; + if (!rr->p) + continue; /* orpaned package */ + + queue_empty(&dq); + if (solv->decisionmap[i] < 0 || solv->updatesystem || (solv->updatemap.size && MAPTST(&solv->updatemap, i - installed->start)) || rr->p != i) { - Id d; - s = pool->solvables + i; - if (s->repo != solv->installed) - continue; - if (MAPTST(&solv->noupdate, i - solv->installed->start)) - continue; - d = solv->multiversionupdaters[i - solv->installed->start]; - if (!d) - continue; - queue_empty(&dq); - queue_push(&dq, i); - while ((p = pool->whatprovidesdata[d++]) != 0) - if (solv->decisionmap[p] >= 0) - queue_push(&dq, p); - policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE); - p = dq.elements[0]; - if (p != i && solv->decisionmap[p] == 0) + if (solv->noobsoletes.size && solv->multiversionupdaters + && (d = solv->multiversionupdaters[i - installed->start]) != 0) { - r = solv->rules + solv->featurerules + (i - solv->installed->start); - if (!r->p) /* update rule == feature rule? */ - r = r - solv->featurerules + solv->updaterules; - olevel = level; - POOL_DEBUG(SAT_DEBUG_POLICY, "installing (multi-version) %s\n", solvable2str(pool, pool->solvables + p)); - level = setpropagatelearn(solv, level, p, disablerules, r->p ? r - solv->rules : 0); - if (level == 0) + /* special multiversion handling, make sure best version is chosen */ + queue_push(&dq, i); + while ((p = pool->whatprovidesdata[d++]) != 0) + if (solv->decisionmap[p] >= 0) + queue_push(&dq, p); + policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE); + p = dq.elements[0]; + if (p != i && solv->decisionmap[p] == 0) { - queue_free(&dq); - queue_free(&dqs); - return; + rr = solv->rules + solv->featurerules + (i - solv->installed->start); + if (!rr->p) /* update rule == feature rule? */ + rr = rr - solv->featurerules + solv->updaterules; + dq.count = 1; } - if (level <= olevel) - break; + else + dq.count = 0; } - p = i; - /* now that the best version is installed, try to - * keep the original one */ - if (solv->decisionmap[p]) /* already decided? */ - continue; - r = solv->rules + solv->updaterules + (i - solv->installed->start); - if (!r->p) /* update rule == feature rule? */ - r = r - solv->updaterules + solv->featurerules; - if (r->p == p) /* allowed to keep package? */ + else { - olevel = level; - POOL_DEBUG(SAT_DEBUG_POLICY, "keeping (multi-version) %s\n", solvable2str(pool, pool->solvables + p)); - level = setpropagatelearn(solv, level, p, disablerules, r - solv->rules); - if (level == 0) + /* update to best package */ + FOR_RULELITERALS(p, dp, rr) { - queue_free(&dq); - queue_free(&dqs); - return; + if (solv->decisionmap[p] > 0) + { + dq.count = 0; /* already fulfilled */ + break; + } + if (!solv->decisionmap[p]) + queue_push(&dq, p); } - if (level <= olevel) - break; } } - systemlevel = level + 1; - if (i < solv->installed->end) - continue; - } - - POOL_DEBUG(SAT_DEBUG_STATS, "resolving update/feature rules\n"); - - for (i = solv->installed->start, r = solv->rules + solv->updaterules; i < solv->installed->end; i++, r++) - { - Rule *rr; - s = pool->solvables + i; - if (s->repo != solv->installed) - continue; - - /* skip if already decided */ - if (solv->decisionmap[i] > 0) - continue; - - /* noupdate is set if a job is erasing the installed solvable or installing a specific version */ - if (MAPTST(&solv->noupdate, i - solv->installed->start)) - continue; - - 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; - if (!rr->p || rr->d < 0) - continue; /* no such rule (orpaned package) or disabled */ - - queue_empty(&dq); - FOR_RULELITERALS(p, dp, rr) - { - if (solv->decisionmap[p] > 0) - break; - if (solv->decisionmap[p] == 0) - queue_push(&dq, p); - } - if (!p && dq.count) /* neither fulfilled nor empty */ + /* install best version */ + if (dq.count) { olevel = level; level = selectandinstall(solv, level, &dq, disablerules, rr - solv->rules); @@ -2730,7 +2801,7 @@ run_solver(Solver *solv, int disablerules, int doweak) if (level <= olevel) break; } - /* if still undecided, keep it */ + /* if still undecided keep package */ if (solv->decisionmap[i] == 0) { olevel = level; @@ -2747,7 +2818,7 @@ run_solver(Solver *solv, int disablerules, int doweak) } } systemlevel = level + 1; - if (i < solv->installed->end) + if (i < installed->end) continue; } @@ -3093,17 +3164,16 @@ run_solver(Solver *solv, int disablerules, int doweak) if (solv->distupgrade && solv->installed) { + int installedone = 0; + /* let's see if we can install some unsupported package */ POOL_DEBUG(SAT_DEBUG_STATS, "deciding unsupported packages\n"); for (i = 0; i < solv->orphaned.count; i++) { p = solv->orphaned.elements[i]; - if (!solv->decisionmap[p]) - break; - } - if (i < solv->orphaned.count) - { - p = solv->orphaned.elements[i]; + if (solv->decisionmap[p]) + continue; /* already decided */ + olevel = level; if (solv->distupgrade_removeunsupported) { POOL_DEBUG(SAT_DEBUG_STATS, "removing unsupported %s\n", solvable2str(pool, pool->solvables + p)); @@ -3113,9 +3183,13 @@ run_solver(Solver *solv, int disablerules, int doweak) { POOL_DEBUG(SAT_DEBUG_STATS, "keeping unsupported %s\n", solvable2str(pool, pool->solvables + p)); level = setpropagatelearn(solv, level, p, 0, 0); + installedone = 1; } - continue; + if (level < olevel) + break; } + if (installedone || i < solv->orphaned.count) + continue; } if (solv->solution_callback) @@ -3370,6 +3444,7 @@ refine_suggestion(Solver *solv, Queue *job, Id *problem, Id sug, Queue *refined) /* enable refined rules again */ for (i = 0; i < disabled.count; i++) enableproblem(solv, disabled.elements[i]); + queue_free(&disabled); /* disable problem rules again */ /* FIXME! */ @@ -3505,7 +3580,6 @@ problems_to_solutions(Solver *solv, Queue *job) { why = solution.elements[j]; /* must be either job descriptor or update rule */ - assert(why < 0 || (why >= solv->updaterules && why < solv->updaterules_end)); #if 0 solver_printproblem(solv, why); #endif @@ -3515,11 +3589,61 @@ problems_to_solutions(Solver *solv, Queue *job) queue_push(&solutions, 0); queue_push(&solutions, -why); } + else if (why >= solv->infarchrules && why < solv->infarchrules_end) + { + Id p, name; + /* infarch rule, find replacement */ + assert(solv->rules[why].p < 0); + name = pool->solvables[-solv->rules[why].p].name; + while (why >= solv->infarchrules && pool->solvables[-solv->rules[why - 1].p].name == name) + why--; + p = 0; + for (; why < solv->infarchrules_end && pool->solvables[-solv->rules[why].p].name == name; why++) + if (solv->decisionmap[-solv->rules[why].p] > 0) + { + p = -solv->rules[why].p; + break; + } + if (!p) + p = -solv->rules[why].p; /* XXX: what to do here? */ + queue_push(&solutions, SOLVER_SOLUTION_INFARCH); + queue_push(&solutions, p); + } + else if (why >= solv->duprules && why < solv->duprules_end) + { + Id p, name; + /* dist upgrade rule, find replacement */ + assert(solv->rules[why].p < 0); + name = pool->solvables[-solv->rules[why].p].name; + while (why >= solv->infarchrules && pool->solvables[-solv->rules[why - 1].p].name == name) + why--; + p = 0; + for (; why < solv->infarchrules_end && pool->solvables[-solv->rules[why].p].name == name; why++) + if (solv->decisionmap[-solv->rules[why].p] > 0) + { + p = -solv->rules[why].p; + break; + } + if (!p) + p = -solv->rules[why].p; /* XXX: what to do here? */ + queue_push(&solutions, SOLVER_SOLUTION_DISTUPGRADE); + queue_push(&solutions, p); + } else { /* update rule, find replacement package */ Id p, *dp, rp = 0; Rule *rr; + + assert(why >= solv->updaterules && why < solv->updaterules_end); + /* check if this is a false positive, i.e. the update rule is fulfilled */ + rr = solv->rules + why; + FOR_RULELITERALS(p, dp, rr) + if (p > 0 && solv->decisionmap[p] > 0) + break; + if (p) + continue; /* false alarm */ + p = solv->installed->start + (why - solv->updaterules); rr = solv->rules + solv->featurerules + (why - solv->updaterules); if (!rr->p) @@ -3680,6 +3804,22 @@ solver_problemruleinfo(Solver *solv, Queue *job, Id rid, Id *depp, Id *sourcep, Id p, d, w2, pp, req, *reqp, con, *conp, obs, *obsp, *dp; assert(rid > 0); + if (rid >= solv->infarchrules && rid < solv->infarchrules_end) + { + r = solv->rules + rid; + *depp = r->p < 0 ? pool->solvables[-r->p].name : 0; + *sourcep = 0; + *targetp = 0; + return SOLVER_PROBLEM_INFARCH_RULE; + } + if (rid >= solv->duprules && rid < solv->duprules_end) + { + r = solv->rules + rid; + *depp = r->p < 0 ? pool->solvables[-r->p].name : 0; + *sourcep = 0; + *targetp = 0; + return SOLVER_PROBLEM_DISTUPGRADE_RULE; + } if (rid >= solv->jobrules && rid < solv->jobrules_end) { @@ -3943,7 +4083,7 @@ findproblemrule_internal(Solver *solv, Id idx, Id *reqrp, Id *conrp, Id *sysrp, assert(rid > 0); if (rid >= solv->learntrules) findproblemrule_internal(solv, solv->learnt_why.elements[rid - solv->learntrules], &lreqr, &lconr, &lsysr, &ljobr); - else if (rid >= solv->jobrules && rid < solv->jobrules_end) + else if ((rid >= solv->jobrules && rid < solv->jobrules_end) || (rid >= solv->infarchrules && rid < solv->infarchrules_end) || (rid >= solv->duprules && rid < solv->duprules_end)) { if (!*jobrp) *jobrp = rid; @@ -4253,6 +4393,204 @@ weaken_solvable_deps(Solver *solv, Id p) /********************************************************************/ /* main() */ + +static void +addinfarchrules(Solver *solv, Map *addedmap) +{ + Pool *pool = solv->pool; + int first, i, j; + Id p, pp, a, aa, bestarch; + Solvable *s, *ps, *bests; + Queue badq, allowedarchs; + + queue_init(&badq); + queue_init(&allowedarchs); + solv->infarchrules = solv->nrules; + for (i = 1; i < pool->nsolvables; i++) + { + if (i == SYSTEMSOLVABLE || !MAPTST(addedmap, i)) + continue; + s = pool->solvables + i; + first = i; + bestarch = 0; + bests = 0; + queue_empty(&allowedarchs); + FOR_PROVIDES(p, pp, s->name) + { + ps = pool->solvables + p; + if (ps->name != s->name || !MAPTST(addedmap, p)) + continue; + if (p == i) + first = 0; + if (first) + break; + a = ps->arch; + a = (a <= pool->lastarch) ? pool->id2arch[a] : 0; + if (a != 1 && pool->installed && ps->repo == pool->installed && !solv->distupgrade) + queue_pushunique(&allowedarchs, ps->arch); /* also ok to keep this architecture */ + if (a && a != 1 && (!bestarch || a < bestarch)) + { + bestarch = a; + bests = ps; + } + } + if (first) + continue; + /* speed up common case where installed package already has best arch */ + if (allowedarchs.count == 1 && bests && allowedarchs.elements[0] == bests->arch) + allowedarchs.count--; /* installed arch is best */ + queue_empty(&badq); + FOR_PROVIDES(p, pp, s->name) + { + ps = pool->solvables + p; + if (ps->name != s->name || !MAPTST(addedmap, p)) + continue; + a = ps->arch; + a = (a <= pool->lastarch) ? pool->id2arch[a] : 0; + if (a != 1 && bestarch && ((a ^ bestarch) & 0xffff0000) != 0) + { + for (j = 0; j < allowedarchs.count; j++) + { + aa = allowedarchs.elements[j]; + if (ps->arch == aa) + break; + aa = (aa <= pool->lastarch) ? pool->id2arch[aa] : 0; + if (aa && ((a ^ aa) & 0xffff0000) == 0) + break; /* compatible */ + } + if (j == allowedarchs.count) + queue_push(&badq, p); + } + } + if (!badq.count) + continue; + /* block all solvables in the badq! */ + for (j = 0; j < badq.count; j++) + { + p = badq.elements[j]; + addrule(solv, -p, 0); + } + } + queue_free(&badq); + queue_free(&allowedarchs); + solv->infarchrules_end = solv->nrules; +} + +static void +createdupmaps(Solver *solv, Queue *job) +{ + Pool *pool = solv->pool; + Repo *repo; + Id how, what, p, pi, pp, obs, *obsp; + Solvable *s, *ps; + int i; + + map_init(&solv->dupmap, pool->nsolvables); + map_init(&solv->dupinvolvedmap, pool->nsolvables); + for (i = 0; i < job->count; i += 2) + { + how = job->elements[i]; + what = job->elements[i + 1]; + switch (how & SOLVER_JOBMASK) + { + case SOLVER_DISTUPGRADE: + if (what < 0 || what > pool->nrepos) + break; + repo = pool->repos[what]; + FOR_REPO_SOLVABLES(repo, p, s) + { + MAPSET(&solv->dupmap, p); + FOR_PROVIDES(pi, pp, s->name) + { + ps = pool->solvables + pi; + if (ps->name != s->name) + continue; + MAPSET(&solv->dupinvolvedmap, pi); + } + if (s->obsoletes) + { + /* FIXME: check obsoletes/provides combination */ + obsp = s->repo->idarraydata + s->obsoletes; + while ((obs = *obsp++) != 0) + { + FOR_PROVIDES(pi, pp, obs) + { + if (!solv->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + pi, obs)) + continue; + MAPSET(&solv->dupinvolvedmap, pi); + } + } + } + } + break; + default: + break; + } + } + MAPCLR(&solv->dupinvolvedmap, SYSTEMSOLVABLE); +} + +static void +freedupmaps(Solver *solv) +{ + map_free(&solv->dupmap); + map_free(&solv->dupinvolvedmap); +} + +static void +addduprules(Solver *solv, Map *addedmap) +{ + Pool *pool = solv->pool; + Id p, pp; + Solvable *s, *ps; + int first, i; + + solv->duprules = solv->nrules; + for (i = 1; i < pool->nsolvables; i++) + { + if (i == SYSTEMSOLVABLE || !MAPTST(addedmap, i)) + continue; + s = pool->solvables + i; + first = i; + FOR_PROVIDES(p, pp, s->name) + { + ps = pool->solvables + p; + if (ps->name != s->name || !MAPTST(addedmap, p)) + continue; + if (p == i) + first = 0; + if (first) + break; + if (!MAPTST(&solv->dupinvolvedmap, p)) + continue; + if (solv->installed && ps->repo == solv->installed) + { + if (!solv->updatemap.size) + map_init(&solv->updatemap, pool->nsolvables); + MAPSET(&solv->updatemap, p); + if (!MAPTST(&solv->dupmap, p)) + { + Id ip, ipp; + /* is installed identical to a good one? */ + FOR_PROVIDES(ip, ipp, s->name) + { + Solvable *is = pool->solvables + ip; + if (!MAPTST(&solv->dupmap, ip)) + continue; + if (is->evr == s->evr && solvable_identical(s, is)) + break; + } + if (!ip) + addrule(solv, -p, 0); /* no match, sorry */ + } + } + else if (!MAPTST(&solv->dupmap, p)) + addrule(solv, -p, 0); + } + } + solv->duprules_end = solv->nrules; +} + /* * * solve job queue @@ -4274,6 +4612,7 @@ solver_solve(Solver *solv, Queue *job) int goterase; Rule *r; int now, solve_start; + int hasdupjob = 0; solve_start = sat_timems(0); POOL_DEBUG(SAT_DEBUG_STATS, "solver started\n"); @@ -4372,6 +4711,12 @@ solver_solve(Solver *solv, Queue *job) FOR_JOB_SELECT(p, pp, select, what) addrpmrulesforupdaters(solv, pool->solvables + what, &addedmap, 0); break; + case SOLVER_DISTUPGRADE: + if (!solv->distupgrade) + hasdupjob = 1; + break; + default: + break; } } POOL_DEBUG(SAT_DEBUG_STATS, "added %d rpm rules for packages involved in a job\n", solv->nrules - oldnrules); @@ -4416,6 +4761,11 @@ solver_solve(Solver *solv, Queue *job) POOL_DEBUG(SAT_DEBUG_STATS, "decisions so far: %d\n", solv->decisionq.count); POOL_DEBUG(SAT_DEBUG_STATS, "rpm rule creation took %d ms\n", sat_timems(now)); + /* create dup maps if needed. We need the maps to create our + * update rules */ + if (hasdupjob) + createdupmaps(solv, job); + /* * create feature rules * @@ -4632,6 +4982,9 @@ solver_solve(Solver *solv, Queue *job) queue_push(&solv->weakruleq, solv->nrules - 1); } break; + case SOLVER_DISTUPGRADE: + POOL_DEBUG(SAT_DEBUG_JOB, "job: distupgrade repo #%d\n", what); + break; default: POOL_DEBUG(SAT_DEBUG_JOB, "job: unknown job\n"); break; @@ -4656,6 +5009,16 @@ solver_solve(Solver *solv, Queue *job) assert(solv->ruletojob.count == solv->nrules - solv->jobrules); solv->jobrules_end = solv->nrules; + /* now create infarch and dup rules */ + addinfarchrules(solv, &addedmap); + if (hasdupjob) + { + addduprules(solv, &addedmap); + freedupmaps(solv); /* no longer needed */ + } + else + solv->duprules = solv->duprules_end = solv->nrules; + /* all rules created * -------------------------------------------------------------- * prepare for solving @@ -4666,6 +5029,8 @@ solver_solve(Solver *solv, Queue *job) map_free(&installcandidatemap); queue_free(&q); + POOL_DEBUG(SAT_DEBUG_STATS, "%d rpm rules, %d job rules, %d infarch rules, %d dup rules\n", solv->rpmrules_end - 1, solv->jobrules_end - solv->jobrules, solv->infarchrules_end - solv->infarchrules, solv->duprules_end - solv->duprules); + /* create weak map */ map_init(&solv->weakrulemap, solv->nrules); for (i = 0; i < solv->weakruleq.count; i++) @@ -4707,7 +5072,7 @@ solver_solve(Solver *solv, Queue *job) queue_init(&redoq); goterase = 0; /* disable all erase jobs (including weak "keep uninstalled" rules) */ - for (i = solv->jobrules, r = solv->rules + i; i < solv->learntrules; i++, r++) + for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++) { if (r->d < 0) /* disabled ? */ continue; diff --git a/src/solver.h b/src/solver.h index b8f0c38..1f4d96e 100644 --- a/src/solver.h +++ b/src/solver.h @@ -208,6 +208,13 @@ typedef struct solver { Queue *job; /* tmp store for job we're working on */ + Id infarchrules; /* inferior arch rules */ + Id infarchrules_end; + Id duprules; /* dist upgrade rules */ + Id duprules_end; + Map updatemap; /* bring those packages to the newest version */ + Map dupmap; /* packages from dup repos */ + Map dupinvolvedmap; /* packages involved in dup process */ } Solver; /* @@ -227,6 +234,7 @@ typedef struct solver { #define SOLVER_WEAKENDEPS 0x0400 #define SOLVER_NOOBSOLETES 0x0500 #define SOLVER_LOCK 0x0600 +#define SOLVER_DISTUPGRADE 0x0700 #define SOLVER_JOBMASK 0xff00 @@ -260,9 +268,14 @@ typedef enum { SOLVER_PROBLEM_PACKAGE_OBSOLETES, SOLVER_PROBLEM_DEP_PROVIDERS_NOT_INSTALLABLE, SOLVER_PROBLEM_SELF_CONFLICT, - SOLVER_PROBLEM_RPM_RULE + SOLVER_PROBLEM_RPM_RULE, + SOLVER_PROBLEM_DISTUPGRADE_RULE, + SOLVER_PROBLEM_INFARCH_RULE } SolverProbleminfo; +#define SOLVER_SOLUTION_JOB (0) +#define SOLVER_SOLUTION_DISTUPGRADE (-1) +#define SOLVER_SOLUTION_INFARCH (-2) extern Solver *solver_create(Pool *pool); extern void solver_free(Solver *solv); diff --git a/src/solverdebug.c b/src/solverdebug.c index 65ad974..cdd783e 100644 --- a/src/solverdebug.c +++ b/src/solverdebug.c @@ -195,6 +195,10 @@ solver_printruleclass(Solver *solv, int type, Rule *r) POOL_DEBUG(type, "WEAK "); if (p >= solv->learntrules) POOL_DEBUG(type, "LEARNT "); + else if (p >= solv->infarchrules && p < solv->infarchrules_end) + POOL_DEBUG(type, "INFARCH "); + else if (p >= solv->duprules && p < solv->duprules_end) + POOL_DEBUG(type, "DUP "); else if (p >= solv->jobrules && p < solv->jobrules_end) POOL_DEBUG(type, "JOB "); else if (p >= solv->updaterules && p < solv->updaterules_end) @@ -389,6 +393,12 @@ solver_printprobleminfo(Solver *solv, Queue *job, Id problem) probr = solver_findproblemrule(solv, problem); switch (solver_problemruleinfo(solv, job, probr, &dep, &source, &target)) { + case SOLVER_PROBLEM_DISTUPGRADE_RULE: + POOL_DEBUG(SAT_DEBUG_RESULT, "install %s from distupgrade repositories\n", dep2str(pool, dep)); + return; + case SOLVER_PROBLEM_INFARCH_RULE: + POOL_DEBUG(SAT_DEBUG_RESULT, "do not install %s because of inferior architecture\n", dep2str(pool, dep)); + return; case SOLVER_PROBLEM_UPDATE_RULE: s = pool_id2solvable(pool, source); POOL_DEBUG(SAT_DEBUG_RESULT, "problem with installed package %s\n", solvable2str(pool, s)); @@ -460,7 +470,7 @@ solver_printsolutions(Solver *solv, Queue *job) element = 0; while ((element = solver_next_solutionelement(solv, problem, solution, element, &p, &rp)) != 0) { - if (p == 0) + if (p == SOLVER_SOLUTION_JOB) { /* job, rp is index into job queue */ how = job->elements[rp - 1]; @@ -495,6 +505,22 @@ solver_printsolutions(Solver *solv, Queue *job) break; } } + else if (p == SOLVER_SOLUTION_INFARCH) + { + s = pool->solvables + rp; + if (solv->installed && s->repo == solv->installed) + POOL_DEBUG(SAT_DEBUG_RESULT, "- keep %s despite the inferior architecture\n", solvable2str(pool, s)); + else + POOL_DEBUG(SAT_DEBUG_RESULT, "- install %s despite the inferior architecture\n", solvable2str(pool, s)); + } + else if (p == SOLVER_SOLUTION_DISTUPGRADE) + { + s = pool->solvables + rp; + if (solv->installed && s->repo == solv->installed) + POOL_DEBUG(SAT_DEBUG_RESULT, "- keep obsolete %s\n", solvable2str(pool, s)); + else + POOL_DEBUG(SAT_DEBUG_RESULT, "- install %s from excluded repository\n", solvable2str(pool, s)); + } else { /* policy, replace p with rp */ diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index a5ab951..8945361 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -47,6 +47,9 @@ SET(repomdxml2solv_REPOS repomdxml2solv.c repo_repomdxml.c) ADD_EXECUTABLE( repomdxml2solv ${repomdxml2solv_REPOS} ) TARGET_LINK_LIBRARIES( repomdxml2solv satsolver toolstuff ${EXPAT_LIBRARY}) +SET(installcheck_SOURCES installcheck.c repo_rpmmd.c repo_susetags.c) +ADD_EXECUTABLE(installcheck ${installcheck_SOURCES}) +TARGET_LINK_LIBRARIES(installcheck satsolver ${EXPAT_LIBRARY} ${ZLIB_LIBRARY}) ADD_EXECUTABLE( dumpsolv dumpsolv.c ) TARGET_LINK_LIBRARIES( dumpsolv satsolver) diff --git a/tools/installcheck.c b/tools/installcheck.c new file mode 100644 index 0000000..e70a828 --- /dev/null +++ b/tools/installcheck.c @@ -0,0 +1,314 @@ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include + +#include "pool.h" +#include "poolarch.h" +#include "repo_solv.h" +#include "repo_susetags.h" +#include "repo_rpmmd.h" +#include "solver.h" + +static ssize_t +cookie_gzread(void *cookie, char *buf, size_t nbytes) +{ + return gzread((gzFile *)cookie, buf, nbytes); +} + +static int +cookie_gzclose(void *cookie) +{ + return gzclose((gzFile *)cookie); +} + +FILE * +myfopen(const char *fn) +{ + cookie_io_functions_t cio; + char *suf; + gzFile *gzf; + + if (!fn) + return 0; + suf = strrchr(fn, '.'); + if (!suf || strcmp(suf, ".gz") != 0) + return fopen(fn, "r"); + gzf = gzopen(fn, "r"); + if (!gzf) + return 0; + memset(&cio, 0, sizeof(cio)); + cio.read = cookie_gzread; + cio.close = cookie_gzclose; + return fopencookie(gzf, "r", cio); +} + +int +main(int argc, char **argv) +{ + Pool *pool; + Solver *solv; + Queue job; + Queue rids; + Queue cand; + Queue archlocks; + char *arch; + int i, j; + Id p; + Id rpmid, rpmarch, rpmrel, archlock; + int status = 0; + int nocheck = 0; + + archlock = 0; + arch = argv[1]; + pool = pool_create(); + pool_setarch(pool, arch); + for (i = 2; i < argc; i++) + { + FILE *fp; + int l; + + if (!strcmp(argv[i], "--nocheck")) + { + if (!nocheck) + nocheck = pool->nsolvables; + continue; + } + l = strlen(argv[i]); + if (!strcmp(argv[i], "-")) + fp = stdin; + else if ((fp = myfopen(argv[i])) == 0) + { + perror(argv[i]); + exit(1); + } + Repo *repo = repo_create(pool, argv[i]); + if (l >= 8 && !strcmp(argv[i] + l - 8, "packages")) + { + repo_add_susetags(repo, fp, 0, 0, 0); + } + else if (l >= 11 && !strcmp(argv[i] + l - 11, "packages.gz")) + { + repo_add_susetags(repo, fp, 0, 0, 0); + } + else if (l >= 14 && !strcmp(argv[i] + l - 14, "primary.xml.gz")) + { + repo_add_rpmmd(repo, fp, 0, 0); + } + else if (repo_add_solv(repo, fp)) + { + fprintf(stderr, "could not add repo %s\n", argv[i]); + exit(1); + } + if (fp != stdin) + fclose(fp); + } + pool_addfileprovides(pool); + pool_createwhatprovides(pool); + rpmid = str2id(pool, "rpm", 0); + rpmarch = str2id(pool, arch, 0); + rpmrel = 0; + if (rpmid && rpmarch) + { + for (p = 1; p < pool->nsolvables; p++) + { + Solvable *s = pool->solvables + p; + if (s->name == rpmid && s->arch == rpmarch) + break; + } + if (p < pool->nsolvables) + rpmrel = rel2id(pool, rpmid, rpmarch, REL_ARCH, 1); + } + + queue_init(&job); + queue_init(&rids); + queue_init(&cand); + queue_init(&archlocks); + for (p = 1; p < pool->nsolvables; p++) + { + Solvable *s = pool->solvables + p; + if (!s->repo) + continue; + if (!pool_installable(pool, s)) + continue; + if (rpmrel && s->arch != rpmarch) + { + Id rp, rpp; + FOR_PROVIDES(rp, rpp, s->name) + { + if (pool->solvables[rp].name != s->name) + continue; + if (pool->solvables[rp].arch == rpmarch) + break; + } + if (rp) + { + queue_push(&archlocks, p); + continue; + } + } + queue_push(&cand, p); + } + + if (archlocks.count) + { + archlock = pool_queuetowhatprovides(pool, &archlocks); + } + /* prune cand by doing weak installs */ + while (cand.count) + { + solv = solver_create(pool); + queue_empty(&job); + for (i = 0; i < cand.count; i++) + { + p = cand.elements[i]; + queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_WEAK); + queue_push(&job, p); + } + if (rpmrel) + { + queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_NAME); + queue_push(&job, rpmrel); + } + if (archlock) + { + queue_push(&job, SOLVER_LOCK|SOLVER_SOLVABLE_ONE_OF); + queue_push(&job, archlock); + } + solv->dontinstallrecommended = 1; + solver_solve(solv, &job); + /* prune... */ + for (i = j = 0; i < cand.count; i++) + { + p = cand.elements[i]; + if (solv->decisionmap[p] <= 0) + { + cand.elements[j++] = p; + continue; + } +#if 0 + Solvable *s = pool->solvables + p; + if (!strcmp(id2str(pool, s->name), "libusb-compat-devel")) + { + cand.elements[j++] = p; + continue; + } +#endif + } + cand.count = j; + if (i == j) + break; + } + + /* now check every candidate */ + for (i = 0; i < cand.count; i++) + { + Solvable *s; + + p = cand.elements[i]; + if (nocheck && p >= nocheck) + continue; + s = pool->solvables + p; + solv = solver_create(pool); + queue_empty(&job); + queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE); + queue_push(&job, p); + if (rpmrel) + { + queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_NAME); + queue_push(&job, rpmrel); + } + if (archlock) + { + queue_push(&job, SOLVER_LOCK|SOLVER_SOLVABLE_ONE_OF); + queue_push(&job, archlock); + } + solv->dontinstallrecommended = 1; + solver_solve(solv, &job); + if (solv->problems.count) + { + Id problem = 0; + Solvable *s2; + + status = 1; + printf("can't install %s:\n", solvable2str(pool, s)); + while ((problem = solver_next_problem(solv, problem)) != 0) + { + solver_findallproblemrules(solv, problem, &rids); + for (j = 0; j < rids.count; j++) + { + Id probr = rids.elements[j]; + Id dep, source, target; + switch (solver_problemruleinfo(solv, &job, probr, &dep, &source, &target)) + { + case SOLVER_PROBLEM_UPDATE_RULE: + break; + case SOLVER_PROBLEM_JOB_RULE: + break; + case SOLVER_PROBLEM_RPM_RULE: + printf(" some dependency problem\n"); + break; + case SOLVER_PROBLEM_JOB_NOTHING_PROVIDES_DEP: + printf(" nothing provides requested %s\n", dep2str(pool, dep)); + break; + case SOLVER_PROBLEM_NOT_INSTALLABLE: + s = pool_id2solvable(pool, source); + printf(" package %s is not installable\n", solvable2str(pool, s)); + break; + case SOLVER_PROBLEM_NOTHING_PROVIDES_DEP: + s = pool_id2solvable(pool, source); + printf(" nothing provides %s needed by %s\n", dep2str(pool, dep), solvable2str(pool, s)); + if (ISRELDEP(dep)) + { + Reldep *rd = GETRELDEP(pool, dep); + if (!ISRELDEP(rd->name)) + { + Id rp, rpp; + FOR_PROVIDES(rp, rpp, rd->name) + printf(" (we have %s)\n", solvable2str(pool, pool->solvables + rp)); + } + } + break; + case SOLVER_PROBLEM_SAME_NAME: + s = pool_id2solvable(pool, source); + s2 = pool_id2solvable(pool, target); + printf(" cannot install both %s and %s\n", solvable2str(pool, s), solvable2str(pool, s2)); + break; + case SOLVER_PROBLEM_PACKAGE_CONFLICT: + s = pool_id2solvable(pool, source); + s2 = pool_id2solvable(pool, target); + printf(" package %s conflicts with %s provided by %s\n", solvable2str(pool, s), dep2str(pool, dep), solvable2str(pool, s2)); + break; + case SOLVER_PROBLEM_PACKAGE_OBSOLETES: + s = pool_id2solvable(pool, source); + s2 = pool_id2solvable(pool, target); + printf(" package %s obsoletes %s provided by %s\n", solvable2str(pool, s), dep2str(pool, dep), solvable2str(pool, s2)); + break; + case SOLVER_PROBLEM_DEP_PROVIDERS_NOT_INSTALLABLE: + s = pool_id2solvable(pool, source); + printf(" package %s requires %s, but none of the providers can be installed\n", solvable2str(pool, s), dep2str(pool, dep)); + break; + case SOLVER_PROBLEM_SELF_CONFLICT: + s = pool_id2solvable(pool, source); + printf(" package %s conflicts with %s provided by itself\n", solvable2str(pool, s), dep2str(pool, dep)); + break; + } + } + } + } +#if 0 + else + { + if (!strcmp(id2str(pool, s->name), "libusb-compat-devel")) + { + solver_printdecisions(solv); + } + } +#endif + solver_free(solv); + } + exit(status); +} -- 2.7.4