From 87326c4b51d988fdd8c337e65de9535a6b0ba408 Mon Sep 17 00:00:00 2001 From: Michael Schroeder Date: Wed, 13 May 2009 16:31:28 +0200 Subject: [PATCH] - start transaction ordering --- src/CMakeLists.txt | 5 +- src/solver.c | 417 ++++++++----------------------- src/solver.h | 28 +-- src/solverdebug.c | 56 ++--- src/transaction.c | 690 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/transaction.h | 55 ++++ tools/CMakeLists.txt | 4 + tools/patchcheck.c | 487 ++++++++++++++++++++++++++++++++++++ tools/repo_rpmmd.c | 4 +- 9 files changed, 1365 insertions(+), 381 deletions(-) create mode 100644 src/transaction.c create mode 100644 src/transaction.h create mode 100644 tools/patchcheck.c diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0a56baa..a74bf8c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,7 +2,8 @@ SET(libsatsolver_SRCS bitmap.c poolarch.c poolvendor.c poolid.c strpool.c dirpool.c solver.c solverdebug.c repo_solv.c repo_helix.c evr.c pool.c - queue.c repo.c repodata.c repopage.c util.c policy.c solvable.c) + queue.c repo.c repodata.c repopage.c util.c policy.c solvable.c + transaction.c) ADD_LIBRARY(satsolver STATIC ${libsatsolver_SRCS}) @@ -10,7 +11,7 @@ SET(libsatsolver_HEADERS bitmap.h evr.h hash.h policy.h poolarch.h poolvendor.h pool.h poolid.h pooltypes.h queue.h solvable.h solver.h solverdebug.h repo.h repodata.h repopage.h repo_solv.h repo_helix.h util.h - strpool.h dirpool.h knownid.h) + strpool.h dirpool.h knownid.h transaction.h) SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") diff --git a/src/solver.c b/src/solver.c index 2329f19..5c8f997 100644 --- a/src/solver.c +++ b/src/solver.c @@ -140,8 +140,6 @@ dep_possible(Solver *solv, Id dep, Map *m) * - unify rules, remove duplicates */ -static Pool *unifyrules_sortcmp_data; - /*------------------------------------------------------------------- * * compare rules for unification sort @@ -149,9 +147,9 @@ static Pool *unifyrules_sortcmp_data; */ static int -unifyrules_sortcmp(const void *ap, const void *bp) +unifyrules_sortcmp(const void *ap, const void *bp, void *dp) { - Pool *pool = unifyrules_sortcmp_data; + Pool *pool = dp; Rule *a = (Rule *)ap; Rule *b = (Rule *)bp; Id *ad, *bd; @@ -206,8 +204,7 @@ unifyrules(Solver *solv) POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- unifyrules -----\n"); /* sort rules first */ - unifyrules_sortcmp_data = solv->pool; - qsort(solv->rules + 1, solv->nrules - 1, sizeof(Rule), unifyrules_sortcmp); + sat_sort(solv->rules + 1, solv->nrules - 1, sizeof(Rule), unifyrules_sortcmp, solv->pool); /* prune rules * i = unpruned @@ -216,7 +213,7 @@ unifyrules(Solver *solv) jr = 0; for (i = j = 1, ir = solv->rules + i; i < solv->nrules; i++, ir++) { - if (jr && !unifyrules_sortcmp(ir, jr)) + if (jr && !unifyrules_sortcmp(ir, jr, pool)) continue; /* prune! */ jr = solv->rules + j++; /* keep! */ if (ir != jr) @@ -1409,7 +1406,7 @@ addrpmrulesforsolvable(Solver *solv, Solvable *s, Map *m) { POOL_DEBUG(SAT_DEBUG_RULE_CREATION," %s requires %s\n", solvable2str(pool, s), dep2str(pool, req)); for (i = 0; dp[i]; i++) - POOL_DEBUG(SAT_DEBUG_RULE_CREATION, " provided by %s\n", solvable2str(pool, pool->solvables + dp[i])); + POOL_DEBUG(SAT_DEBUG_RULE_CREATION, " provided by %s\n", solvid2str(pool, dp[i])); } /* add 'requires' dependency */ @@ -1974,9 +1971,9 @@ propagate(Solver *solv, int level) IF_POOLDEBUG (SAT_DEBUG_PROPAGATE) { if (p > 0) - POOL_DEBUG(SAT_DEBUG_PROPAGATE, " -> move w%d to %s\n", (pkg == r->w1 ? 1 : 2), solvable2str(pool, pool->solvables + p)); + POOL_DEBUG(SAT_DEBUG_PROPAGATE, " -> move w%d to %s\n", (pkg == r->w1 ? 1 : 2), solvid2str(pool, p)); else - POOL_DEBUG(SAT_DEBUG_PROPAGATE," -> move w%d to !%s\n", (pkg == r->w1 ? 1 : 2), solvable2str(pool, pool->solvables - p)); + POOL_DEBUG(SAT_DEBUG_PROPAGATE," -> move w%d to !%s\n", (pkg == r->w1 ? 1 : 2), solvid2str(pool, -p)); } *rp = *next_rp; @@ -2022,11 +2019,10 @@ propagate(Solver *solv, int level) IF_POOLDEBUG (SAT_DEBUG_PROPAGATE) { - Solvable *s = pool->solvables + (other_watch > 0 ? other_watch : -other_watch); if (other_watch > 0) - POOL_DEBUG(SAT_DEBUG_PROPAGATE, " -> decided to install %s\n", solvable2str(pool, s)); + POOL_DEBUG(SAT_DEBUG_PROPAGATE, " -> decided to install %s\n", solvid2str(pool, other_watch)); else - POOL_DEBUG(SAT_DEBUG_PROPAGATE, " -> decided to conflict %s\n", solvable2str(pool, s)); + POOL_DEBUG(SAT_DEBUG_PROPAGATE, " -> decided to conflict %s\n", solvid2str(pool, -other_watch)); } } /* foreach rule involving 'pkg' */ @@ -2572,7 +2568,7 @@ selectandinstall(Solver *solv, int level, Queue *dq, int disablerules, Id ruleid } p = dq->elements[0]; - POOL_DEBUG(SAT_DEBUG_POLICY, "installing %s\n", solvable2str(pool, pool->solvables + p)); + POOL_DEBUG(SAT_DEBUG_POLICY, "installing %s\n", solvid2str(pool, p)); return setpropagatelearn(solv, level, p, disablerules, ruleid); } @@ -2675,6 +2671,7 @@ solver_free(Solver *solv) sat_free(solv->obsoletes); sat_free(solv->obsoletes_data); sat_free(solv->multiversionupdaters); + sat_free(solv->transaction_installed); sat_free(solv); } @@ -2899,7 +2896,7 @@ run_solver(Solver *solv, int disablerules, int doweak) if (solv->decisionmap[i] == 0) { olevel = level; - POOL_DEBUG(SAT_DEBUG_POLICY, "keeping %s\n", solvable2str(pool, pool->solvables + i)); + POOL_DEBUG(SAT_DEBUG_POLICY, "keeping %s\n", solvid2str(pool, i)); level = setpropagatelearn(solv, level, i, disablerules, r - solv->rules); if (level == 0) { @@ -3004,7 +3001,7 @@ run_solver(Solver *solv, int disablerules, int doweak) queue_free(&dqs); return; } - if (level < systemlevel) + if (level < systemlevel || level == 1) break; n = 0; } /* for(), decide */ @@ -3153,9 +3150,9 @@ run_solver(Solver *solv, int disablerules, int doweak) /* simple case, just one package. no need to choose */ p = dq.elements[0]; if (dqs.count) - POOL_DEBUG(SAT_DEBUG_POLICY, "installing supplemented %s\n", solvable2str(pool, pool->solvables + p)); + POOL_DEBUG(SAT_DEBUG_POLICY, "installing supplemented %s\n", solvid2str(pool, p)); else - POOL_DEBUG(SAT_DEBUG_POLICY, "installing recommended %s\n", solvable2str(pool, pool->solvables + p)); + POOL_DEBUG(SAT_DEBUG_POLICY, "installing recommended %s\n", solvid2str(pool, p)); queue_push(&solv->recommendations, p); level = setpropagatelearn(solv, level, p, 0, 0); continue; @@ -3173,7 +3170,7 @@ run_solver(Solver *solv, int disablerules, int doweak) p = dqs.elements[i]; if (solv->decisionmap[p] || !MAPTST(&dqmap, p)) continue; - POOL_DEBUG(SAT_DEBUG_POLICY, "installing supplemented %s\n", solvable2str(pool, pool->solvables + p)); + POOL_DEBUG(SAT_DEBUG_POLICY, "installing supplemented %s\n", solvid2str(pool, p)); queue_push(&solv->recommendations, p); olevel = level; level = setpropagatelearn(solv, level, p, 0, 0); @@ -3224,7 +3221,7 @@ run_solver(Solver *solv, int disablerules, int doweak) queue_push(&solv->branches, -level); } p = dq.elements[0]; - POOL_DEBUG(SAT_DEBUG_POLICY, "installing recommended %s\n", solvable2str(pool, pool->solvables + p)); + POOL_DEBUG(SAT_DEBUG_POLICY, "installing recommended %s\n", solvid2str(pool, p)); queue_push(&solv->recommendations, p); olevel = level; level = setpropagatelearn(solv, level, p, 0, 0); @@ -3251,7 +3248,7 @@ run_solver(Solver *solv, int disablerules, int doweak) p = dq.elements[i]; break; } - POOL_DEBUG(SAT_DEBUG_POLICY, "installing recommended %s\n", solvable2str(pool, pool->solvables + p)); + POOL_DEBUG(SAT_DEBUG_POLICY, "installing recommended %s\n", solvid2str(pool, p)); queue_push(&solv->recommendations, p); level = setpropagatelearn(solv, level, p, 0, 0); continue; @@ -3273,12 +3270,12 @@ run_solver(Solver *solv, int disablerules, int doweak) olevel = level; if (solv->distupgrade_removeunsupported) { - POOL_DEBUG(SAT_DEBUG_STATS, "removing unsupported %s\n", solvable2str(pool, pool->solvables + p)); + POOL_DEBUG(SAT_DEBUG_STATS, "removing unsupported %s\n", solvid2str(pool, p)); level = setpropagatelearn(solv, level, -p, 0, 0); } else { - POOL_DEBUG(SAT_DEBUG_STATS, "keeping unsupported %s\n", solvable2str(pool, pool->solvables + p)); + POOL_DEBUG(SAT_DEBUG_STATS, "keeping unsupported %s\n", solvid2str(pool, p)); level = setpropagatelearn(solv, level, p, 0, 0); installedone = 1; } @@ -3302,7 +3299,7 @@ run_solver(Solver *solv, int disablerules, int doweak) if (solv->branches.elements[i - 1] < 0) break; p = solv->branches.elements[i]; - POOL_DEBUG(SAT_DEBUG_STATS, "branching with %s\n", solvable2str(pool, pool->solvables + p)); + POOL_DEBUG(SAT_DEBUG_STATS, "branching with %s\n", solvid2str(pool, p)); queue_empty(&dq); for (j = i + 1; j < solv->branches.count; j++) queue_push(&dq, solv->branches.elements[j]); @@ -3351,7 +3348,7 @@ run_solver(Solver *solv, int disablerules, int doweak) /* kill old solvable so that we do not loop */ p = solv->branches.elements[lasti]; solv->branches.elements[lasti] = 0; - POOL_DEBUG(SAT_DEBUG_STATS, "minimizing %d -> %d with %s\n", solv->decisionmap[p], lastl, solvable2str(pool, pool->solvables + p)); + POOL_DEBUG(SAT_DEBUG_STATS, "minimizing %d -> %d with %s\n", solv->decisionmap[p], lastl, solvid2str(pool, p)); minimizationsteps++; level = lastl; @@ -3562,11 +3559,10 @@ refine_suggestion(Solver *solv, Queue *job, Id *problem, Id sug, Queue *refined, * make essential job rules last */ -Queue *problems_sort_data; - static int -problems_sortcmp(const void *ap, const void *bp) +problems_sortcmp(const void *ap, const void *bp, void *dp) { + Queue *job = dp; Id a = *(Id *)ap, b = *(Id *)bp; if (a < 0 && b > 0) return 1; @@ -3574,7 +3570,6 @@ problems_sortcmp(const void *ap, const void *bp) return -1; if (a < 0 && b < 0) { - Queue *job = problems_sort_data; int af = job->elements[-a - 1] & SOLVER_ESSENTIAL; int bf = job->elements[-b - 1] & SOLVER_ESSENTIAL; int x = af - bf; @@ -3694,6 +3689,36 @@ convertsolution(Solver *solv, Id why, Queue *solutionq) } /* + * convert problem data into a form usable for refining. + * Returns the number of problems. + */ +int +prepare_solutions(Solver *solv) +{ + int i, j = 1, idx = 1; + + if (!solv->problems.count) + return 0; + queue_push(&solv->solutions, 0); + queue_push(&solv->solutions, -1); /* unrefined */ + for (i = 1; i < solv->problems.count; i++) + { + Id p = solv->problems.elements[i]; + queue_push(&solv->solutions, p); + if (p) + continue; + solv->problems.elements[j++] = idx; + if (i + 1 >= solv->problems.count) + break; + solv->problems.elements[j++] = solv->problems.elements[++i]; /* copy proofidx */ + idx = solv->solutions.count; + queue_push(&solv->solutions, -1); + } + solv->problems.count = j; + return j / 2; +} + +/* * refine the simple solution rule list provided by * the solver into multiple lists of job modifiers. */ @@ -3733,9 +3758,8 @@ create_solutions(Solver *solv, int probnr, int solidx) break; queue_push(&problem, v); } - problems_sort_data = &solv->job; if (problem.count > 1) - qsort(problem.elements, problem.count, sizeof(Id), problems_sortcmp); + sat_sort(problem.elements, problem.count, sizeof(Id), problems_sortcmp, &solv->job); queue_push(&problem, 0); /* mark end for refine_suggestion */ problem.count--; #if 0 @@ -3926,14 +3950,13 @@ findproblemrule_internal(Solver *solv, Id idx, Id *reqrp, Id *conrp, Id *sysrp, *sysrp = lsysr; } - -/*------------------------------------------------------------------- - * +/* * find problem rule * * search for a rule that describes the problem to the - * user. A pretty hopeless task, actually. We currently - * prefer simple requires. + * user. Actually a pretty hopeless task that may leave the user + * puzzled. To get all of the needed information use + * solver_findallproblemrules() instead. */ Id @@ -3944,16 +3967,18 @@ solver_findproblemrule(Solver *solv, Id problem) reqr = conr = sysr = jobr = 0; findproblemrule_internal(solv, idx, &reqr, &conr, &sysr, &jobr); if (reqr) - return reqr; + return reqr; /* some requires */ if (conr) - return conr; + return conr; /* some conflict */ if (sysr) - return sysr; + return sysr; /* an update rule */ if (jobr) - return jobr; + return jobr; /* a user request */ assert(0); } +/*-------------------------------------------------------------------*/ + static void findallproblemrules_internal(Solver *solv, Id idx, Queue *rules) { @@ -3969,6 +3994,14 @@ findallproblemrules_internal(Solver *solv, Id idx, Queue *rules) } } +/* + * find all problem rule + * + * return all rules that lead to the problem. This gives the user + * all of the information to understand the problem, but the result + * can be a large number of rules. + */ + void solver_findallproblemrules(Solver *solv, Id problem, Queue *rules) { @@ -3981,9 +4014,10 @@ solver_findallproblemrules(Solver *solv, Id problem, Queue *rules) * * create reverse obsoletes map for installed solvables * - * for each installed solvable find which packages with *different* names + * For each installed solvable find which packages with *different* names * obsolete the solvable. - * this index is used in policy_findupdatepackages if noupdateprovide is set. + * This index is used in policy_findupdatepackages if noupdateprovide is + * set. */ static void @@ -3993,11 +4027,12 @@ create_obsolete_index(Solver *solv) Solvable *s; Repo *installed = solv->installed; Id p, pp, obs, *obsp, *obsoletes, *obsoletes_data; - int i, n; + int i, n, cnt; - if (!installed || !installed->nsolvables) + if (!installed || installed->start == installed->end) return; - solv->obsoletes = obsoletes = sat_calloc(installed->end - installed->start, sizeof(Id)); + cnt = installed->end - installed->start; + solv->obsoletes = obsoletes = sat_calloc(cnt, sizeof(Id)); for (i = 1; i < pool->nsolvables; i++) { s = pool->solvables + i; @@ -4021,7 +4056,7 @@ create_obsolete_index(Solver *solv) } } n = 0; - for (i = 0; i < installed->nsolvables; i++) + for (i = 0; i < cnt; i++) if (obsoletes[i]) { n += obsoletes[i] + 1; @@ -4090,7 +4125,7 @@ removedisabledconflicts(Solver *solv, Queue *removed) if (r->d < 0 && decisionmap[-p]) { /* rule is now disabled, remove from decisionmap */ - POOL_DEBUG(SAT_DEBUG_SCHUBI, "removing conflict for package %s[%d]\n", solvable2str(pool, pool->solvables - p), -p); + POOL_DEBUG(SAT_DEBUG_SCHUBI, "removing conflict for package %s[%d]\n", solvid2str(pool, -p), -p); queue_push(removed, -p); queue_push(removed, decisionmap[-p]); decisionmap[-p] = 0; @@ -4153,7 +4188,7 @@ removedisabledconflicts(Solver *solv, Queue *removed) } if (new) { - POOL_DEBUG(SAT_DEBUG_SCHUBI, "re-conflicting package %s[%d]\n", solvable2str(pool, pool->solvables - new), -new); + POOL_DEBUG(SAT_DEBUG_SCHUBI, "re-conflicting package %s[%d]\n", solvid2str(pool, -new), -new); decisionmap[-new] = -1; new = 0; n = 0; /* redo all rules */ @@ -4594,240 +4629,6 @@ findrecommendedsuggested(Solver *solv) } -Solver *obsq_sortcmp_data; - -static int -obsq_sortcmp(const void *ap, const void *bp) -{ - Id a, b, oa, ob; - Solver *solv = obsq_sortcmp_data; - Pool *pool = solv->pool; - Solvable *s, *oas, *obs; - int r; - - a = ((Id *)ap)[0]; - oa = ((Id *)ap)[1]; - b = ((Id *)bp)[0]; - ob = ((Id *)bp)[1]; - if (a != b) - return a - b; - if (oa == ob) - return 0; - s = pool->solvables + a; - oas = pool->solvables + oa; - obs = pool->solvables + ob; - if (oas->name != obs->name) - { - if (oas->name == s->name) - return -1; - if (obs->name == s->name) - return 1; - return strcmp(id2str(pool, oas->name), id2str(pool, obs->name)); - } - r = evrcmp(pool, oas->evr, obs->evr, EVRCMP_COMPARE); - if (r) - return -r; /* highest version first */ - return oa - ob; -} - -void -solver_transaction_info(Solver *solv, Id p, Queue *out) -{ - Pool *pool = solv->pool; - Solvable *s = pool->solvables + p; - Queue *ti = &solv->transaction_info; - int i; - - queue_empty(out); - if (p <= 0 || !s->repo) - return; - if (s->repo == solv->installed) - { - /* find which packages obsolete us */ - for (i = 0; i < ti->count; i += 2) - if (ti->elements[i + 1] == p) - { - queue_push(out, p); - queue_push(out, ti->elements[i]); - } - if (out->count > 2) - { - /* sort obsoleters */ - obsq_sortcmp_data = solv; - qsort(out->elements, out->count / 2, 2 * sizeof(Id), obsq_sortcmp); - } - for (i = 0; i < out->count; i += 2) - out->elements[i] = out->elements[i / 2 + 1]; - out->count /= 2; - } - else - { - /* find the packages we obsolete */ - for (i = 0; i < ti->count; i += 2) - { - if (ti->elements[i] == p) - queue_push(out, ti->elements[i + 1]); - else if (out->count) - break; - } - } -} - -Id -solver_transaction_pkg(Solver *solv, Id p) -{ - Queue ti; - Id tibuf[5]; - - queue_init_buffer(&ti, tibuf, sizeof(tibuf)/sizeof(*tibuf)); - solver_transaction_info(solv, p, &ti); - p = ti.count ? ti.elements[0] : 0; - queue_free(&ti); - return p; -} - -static void -create_transaction(Solver *solv) -{ - Pool *pool = solv->pool; - Repo *installed = solv->installed; - Queue *ti = &solv->transaction_info; - int i, j, r, noobs; - Id p, p2, pp2; - Solvable *s, *s2; - - queue_empty(&solv->transaction); - queue_empty(ti); - - /* first create obsoletes index */ - if (installed) - { - for (i = 0; i < solv->decisionq.count; i++) - { - p = solv->decisionq.elements[i]; - if (p <= 0 || p == SYSTEMSOLVABLE) - continue; - s = pool->solvables + p; - if (s->repo == installed) - continue; - noobs = solv->noobsoletes.size && MAPTST(&solv->noobsoletes, p); - FOR_PROVIDES(p2, pp2, s->name) - { - if (solv->decisionmap[p2] > 0) - continue; - s2 = pool->solvables + p2; - if (s2->repo != installed) - continue; - if (noobs && (s->name != s2->name || s->evr != s2->evr || s->arch != s2->arch)) - continue; - if (!solv->implicitobsoleteusesprovides && s->name != s2->name) - continue; - queue_push(ti, p); - queue_push(ti, p2); - } - if (s->obsoletes && !noobs) - { - Id obs, *obsp = s->repo->idarraydata + s->obsoletes; - while ((obs = *obsp++) != 0) - { - FOR_PROVIDES(p2, pp2, obs) - { - s2 = pool->solvables + p2; - if (s2->repo != installed) - continue; - if (!solv->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p2, obs)) - continue; - queue_push(ti, p); - queue_push(ti, p2); - } - } - } - } - obsq_sortcmp_data = solv; - qsort(ti->elements, ti->count / 2, 2 * sizeof(Id), obsq_sortcmp); - /* now unify */ - for (i = j = 0; i < ti->count; i += 2) - { - if (j && ti->elements[i] == ti->elements[j - 2] && ti->elements[i + 1] == ti->elements[j - 1]) - continue; - ti->elements[j++] = ti->elements[i]; - ti->elements[j++] = ti->elements[i + 1]; - } - ti->count = j; - } - - if (installed) - { - FOR_REPO_SOLVABLES(installed, p, s) - { - if (solv->decisionmap[p] > 0) - continue; - p2 = solver_transaction_pkg(solv, p); - if (!p2) - queue_push(&solv->transaction, SOLVER_TRANSACTION_ERASE); - else - { - s2 = pool->solvables + p2; - if (s->name == s2->name) - { - if (s->evr == s2->evr && solvable_identical(s, s2)) - queue_push(&solv->transaction, SOLVER_TRANSACTION_REINSTALLED); - else - { - r = evrcmp(pool, s->evr, s2->evr, EVRCMP_COMPARE); - if (r < 0) - queue_push(&solv->transaction, SOLVER_TRANSACTION_UPGRADED); - else if (r > 0) - queue_push(&solv->transaction, SOLVER_TRANSACTION_DOWNGRADED); - else - queue_push(&solv->transaction, SOLVER_TRANSACTION_CHANGED); - } - } - else - queue_push(&solv->transaction, SOLVER_TRANSACTION_OBSOLETED); - } - queue_push(&solv->transaction, p); - } - } - for (i = 0; i < solv->decisionq.count; i++) - { - p = solv->decisionq.elements[i]; - if (p < 0 || p == SYSTEMSOLVABLE) - continue; - s = pool->solvables + p; - if (solv->installed && s->repo == solv->installed) - continue; - noobs = solv->noobsoletes.size && MAPTST(&solv->noobsoletes, p); - p2 = solver_transaction_pkg(solv, p); - if (noobs) - queue_push(&solv->transaction, p2 ? SOLVER_TRANSACTION_MULTIREINSTALL : SOLVER_TRANSACTION_MULTIINSTALL); - else if (!p2) - queue_push(&solv->transaction, SOLVER_TRANSACTION_INSTALL); - else - { - s2 = pool->solvables + p2; - if (s->name == s2->name) - { - if (s->evr == s2->evr && solvable_identical(s, s2)) - queue_push(&solv->transaction, SOLVER_TRANSACTION_REINSTALL); - else - { - r = evrcmp(pool, s->evr, s2->evr, EVRCMP_COMPARE); - if (r > 0) - queue_push(&solv->transaction, SOLVER_TRANSACTION_UPGRADE); - else if (r < 0) - queue_push(&solv->transaction, SOLVER_TRANSACTION_DOWNGRADE); - else - queue_push(&solv->transaction, SOLVER_TRANSACTION_CHANGE); - } - } - else - queue_push(&solv->transaction, SOLVER_TRANSACTION_RENAME); - } - queue_push(&solv->transaction, p); - } -} - /* * * solve job queue @@ -5072,8 +4873,7 @@ solver_solve(Solver *solv, Queue *job) assert(solv->distupgrade && !sr->p); continue; } - unifyrules_sortcmp_data = pool; - if (!unifyrules_sortcmp(r, sr)) + if (!unifyrules_sortcmp(r, sr, pool)) { /* identical rule, kill unneeded one */ if (solv->allowuninstall) @@ -5259,10 +5059,10 @@ solver_solve(Solver *solv, Queue *job) solv->duprules = solv->duprules_end = solv->nrules; - /* all rules created - * -------------------------------------------------------------- - * prepare for solving - */ + /* all rules created + * -------------------------------------------------------------- + * prepare for solving + */ /* free unneeded memory */ map_free(&addedmap); @@ -5315,33 +5115,14 @@ solver_solve(Solver *solv, Queue *job) findrecommendedsuggested(solv); /* - * if unsolvable, prepare solution queue + * prepare solution queue if there were problems */ - if (solv->problems.count) - { - int j = 1, idx = 1; - queue_push(&solv->solutions, 0); - queue_push(&solv->solutions, -1); /* unrefined */ - for (i = 1; i < solv->problems.count; i++) - { - Id p = solv->problems.elements[i]; - queue_push(&solv->solutions, p); - if (p) - continue; - solv->problems.elements[j++] = idx; - if (i + 1 >= solv->problems.count) - break; - solv->problems.elements[j++] = solv->problems.elements[++i]; /* copy proofidx */ - idx = solv->solutions.count; - queue_push(&solv->solutions, -1); - } - solv->problems.count = j; - } + prepare_solutions(solv); /* * finally prepare transaction info */ - create_transaction(solv); + solver_create_transaction(solv); POOL_DEBUG(SAT_DEBUG_STATS, "final solver statistics: %d problems, %d learned rules, %d unsolvable\n", solv->problems.count / 2, solv->stats_learned, solv->stats_unsolvable); POOL_DEBUG(SAT_DEBUG_STATS, "solver_solve took %d ms\n", sat_timems(solve_start)); @@ -5465,7 +5246,7 @@ solver_find_involved(Solver *solv, Queue *installedq, Solvable *ts, Queue *q) if (MAPTST(&im, p)) { #if FIND_INVOLVED_DEBUG - printf("%s requires %s\n", solvable2str(pool, pool->solvables + ip), solvable2str(pool, pool->solvables + p)); + printf("%s requires %s\n", solvid2str(pool, ip), solvid2str(pool, p)); #endif queue_push(&iq, p); } @@ -5488,7 +5269,7 @@ solver_find_involved(Solver *solv, Queue *installedq, Solvable *ts, Queue *q) if (MAPTST(&im, p)) { #if FIND_INVOLVED_DEBUG - printf("%s recommends %s\n", solvable2str(pool, pool->solvables + ip), solvable2str(pool, pool->solvables + p)); + printf("%s recommends %s\n", solvid2str(pool, ip), solvid2str(pool, p)); #endif queue_push(&iq, p); } @@ -5514,7 +5295,7 @@ solver_find_involved(Solver *solv, Queue *installedq, Solvable *ts, Queue *q) if (sup) { #if FIND_INVOLVED_DEBUG - printf("%s supplemented\n", solvable2str(pool, pool->solvables + ip)); + printf("%s supplemented\n", solvid2str(pool, ip)); #endif queue_push(&iq, ip); } @@ -5550,7 +5331,7 @@ solver_find_involved(Solver *solv, Queue *installedq, Solvable *ts, Queue *q) if (p == tp) continue; #if FIND_INVOLVED_DEBUG - printf("%s requires %s\n", solvable2str(pool, pool->solvables + ip), solvable2str(pool, pool->solvables + p)); + printf("%s requires %s\n", solvid2str(pool, ip), solvid2str(pool, p)); #endif MAPSET(&im, p); queue_push(&iq, p); @@ -5570,7 +5351,7 @@ solver_find_involved(Solver *solv, Queue *installedq, Solvable *ts, Queue *q) if (p == tp) continue; #if FIND_INVOLVED_DEBUG - printf("%s recommends %s\n", solvable2str(pool, pool->solvables + ip), solvable2str(pool, pool->solvables + p)); + printf("%s recommends %s\n", solvid2str(pool, ip), solvid2str(pool, p)); #endif MAPSET(&im, p); queue_push(&iq, p); @@ -5598,7 +5379,7 @@ solver_find_involved(Solver *solv, Queue *installedq, Solvable *ts, Queue *q) if (sup) { #if FIND_INVOLVED_DEBUG - printf("%s supplemented\n", solvable2str(pool, pool->solvables + ip)); + printf("%s supplemented\n", solvid2str(pool, ip)); #endif MAPSET(&im, ip); queue_push(&iq, ip); @@ -5707,7 +5488,7 @@ addrpmruleinfo(Solver *solv, Id p, Id d, int type, Id dep) } static int -solver_allruleinfos_cmp(const void *ap, const void *bp) +solver_allruleinfos_cmp(const void *ap, const void *bp, void *dp) { const Id *a = ap, *b = bp; int r; @@ -5758,7 +5539,7 @@ solver_allruleinfos(Solver *solv, Id rid, Queue *rq) /* now sort & unify em */ if (!rq->count) return 0; - qsort(rq->elements, rq->count / 4, 4 * sizeof(Id), solver_allruleinfos_cmp); + sat_sort(rq->elements, rq->count / 4, 4 * sizeof(Id), solver_allruleinfos_cmp, 0); /* throw out identical entries */ for (i = j = 0; i < rq->count; i += 4) { diff --git a/src/solver.h b/src/solver.h index c271591..5330d3a 100644 --- a/src/solver.h +++ b/src/solver.h @@ -22,6 +22,7 @@ extern "C" { #include "repo.h" #include "queue.h" #include "bitmap.h" +#include "transaction.h" /* * Callback definitions in order to "overwrite" the policies by an external application. */ @@ -57,14 +58,15 @@ typedef struct rule { Id n1, n2; /* next rules in linked list, corresponding to w1,w2 */ } Rule; -struct solver; +struct _Solver; -typedef struct solver { +typedef struct _Solver { Pool *pool; Queue job; /* copy of the job we're solving */ Queue transaction; /* solver result */ Queue transaction_info; /* transaction obsoletes info */ + Id *transaction_installed; /* data for installed packages */ Repo *installed; /* copy of pool->installed */ @@ -130,7 +132,7 @@ typedef struct solver { Queue learnt_pool; Queue branches; - int (*solution_callback)(struct solver *solv, void *data); + int (*solution_callback)(struct _Solver *solv, void *data); void *solution_callback_data; int propagate_index; /* index into decisionq for non-propagated decisions */ @@ -328,29 +330,9 @@ typedef enum { #define SOLVER_SOLUTION_DISTUPGRADE (-1) #define SOLVER_SOLUTION_INFARCH (-2) -#define SOLVER_TRANSACTION_ERASE 0x10 -#define SOLVER_TRANSACTION_REINSTALLED 0x11 -#define SOLVER_TRANSACTION_DOWNGRADED 0x12 -#define SOLVER_TRANSACTION_CHANGED 0x13 -#define SOLVER_TRANSACTION_UPGRADED 0x14 -#define SOLVER_TRANSACTION_OBSOLETED 0x15 - -#define SOLVER_TRANSACTION_INSTALL 0x20 -#define SOLVER_TRANSACTION_REINSTALL 0x21 -#define SOLVER_TRANSACTION_DOWNGRADE 0x22 -#define SOLVER_TRANSACTION_CHANGE 0x23 -#define SOLVER_TRANSACTION_UPGRADE 0x24 -#define SOLVER_TRANSACTION_RENAME 0x25 - -#define SOLVER_TRANSACTION_MULTIINSTALL 0x30 -#define SOLVER_TRANSACTION_MULTIREINSTALL 0x31 - - extern Solver *solver_create(Pool *pool); extern void solver_free(Solver *solv); extern void solver_solve(Solver *solv, Queue *job); -extern void solver_transaction_info(Solver *solv, Id p, Queue *info); -extern Id solver_transaction_pkg(Solver *solv, Id p); extern int solver_dep_installed(Solver *solv, Id dep); extern int solver_splitprovides(Solver *solv, Id dep); diff --git a/src/solverdebug.c b/src/solverdebug.c index 1b74e1e..6bfc2a3 100644 --- a/src/solverdebug.c +++ b/src/solverdebug.c @@ -297,7 +297,7 @@ solver_printdecisions(Solver *solv) POOL_DEBUG(SAT_DEBUG_RESULT, " change %s", solvable2str(pool, s)); break; case SOLVER_TRANSACTION_UPGRADE: - case SOLVER_TRANSACTION_RENAME: + case SOLVER_TRANSACTION_REPLACE: POOL_DEBUG(SAT_DEBUG_RESULT, " upgrade %s", solvable2str(pool, s)); break; case SOLVER_TRANSACTION_ERASE: @@ -316,13 +316,13 @@ solver_printdecisions(Solver *solv) case SOLVER_TRANSACTION_DOWNGRADE: case SOLVER_TRANSACTION_CHANGE: case SOLVER_TRANSACTION_UPGRADE: - case SOLVER_TRANSACTION_RENAME: - solver_transaction_info(solv, solv->transaction.elements[i + 1], &iq); + case SOLVER_TRANSACTION_REPLACE: + solver_transaction_all_pkgs(solv, solv->transaction.elements[i + 1], &iq); if (iq.count) { POOL_DEBUG(SAT_DEBUG_RESULT, " (obsoletes"); for (j = 0; j < iq.count; j++) - POOL_DEBUG(SAT_DEBUG_RESULT, " %s", solvable2str(pool, pool->solvables + iq.elements[j])); + POOL_DEBUG(SAT_DEBUG_RESULT, " %s", solvid2str(pool, iq.elements[j])); POOL_DEBUG(SAT_DEBUG_RESULT, ")"); } POOL_DEBUG(SAT_DEBUG_RESULT, "\n"); @@ -393,22 +393,18 @@ solver_printprobleminfo(Solver *solv, Queue *job, Id problem) Pool *pool = solv->pool; Id probr; Id dep, source, target; - Solvable *s, *s2; probr = solver_findproblemrule(solv, problem); switch (solver_problemruleinfo(solv, job, probr, &dep, &source, &target)) { case SOLVER_RULE_DISTUPGRADE: - s = pool_id2solvable(pool, source); - POOL_DEBUG(SAT_DEBUG_RESULT, "%s does not belong to a distupgrade repository\n", solvable2str(pool, s)); + POOL_DEBUG(SAT_DEBUG_RESULT, "%s does not belong to a distupgrade repository\n", solvid2str(pool, source)); return; case SOLVER_RULE_INFARCH: - s = pool_id2solvable(pool, source); - POOL_DEBUG(SAT_DEBUG_RESULT, "%s has inferior architecture\n", solvable2str(pool, s)); + POOL_DEBUG(SAT_DEBUG_RESULT, "%s has inferior architecture\n", solvid2str(pool, source)); return; case SOLVER_RULE_UPDATE: - s = pool_id2solvable(pool, source); - POOL_DEBUG(SAT_DEBUG_RESULT, "problem with installed package %s\n", solvable2str(pool, s)); + POOL_DEBUG(SAT_DEBUG_RESULT, "problem with installed package %s\n", solvid2str(pool, source)); return; case SOLVER_RULE_JOB: POOL_DEBUG(SAT_DEBUG_RESULT, "conflicting requests\n"); @@ -420,40 +416,28 @@ solver_printprobleminfo(Solver *solv, Queue *job, Id problem) POOL_DEBUG(SAT_DEBUG_RESULT, "some dependency problem\n"); return; case SOLVER_RULE_RPM_NOT_INSTALLABLE: - s = pool_id2solvable(pool, source); - POOL_DEBUG(SAT_DEBUG_RESULT, "package %s is not installable\n", solvable2str(pool, s)); + POOL_DEBUG(SAT_DEBUG_RESULT, "package %s is not installable\n", solvid2str(pool, source)); return; case SOLVER_RULE_RPM_NOTHING_PROVIDES_DEP: - s = pool_id2solvable(pool, source); - POOL_DEBUG(SAT_DEBUG_RESULT, "nothing provides %s needed by %s\n", dep2str(pool, dep), solvable2str(pool, s)); + POOL_DEBUG(SAT_DEBUG_RESULT, "nothing provides %s needed by %s\n", dep2str(pool, dep), solvid2str(pool, source)); return; case SOLVER_RULE_RPM_SAME_NAME: - s = pool_id2solvable(pool, source); - s2 = pool_id2solvable(pool, target); - POOL_DEBUG(SAT_DEBUG_RESULT, "cannot install both %s and %s\n", solvable2str(pool, s), solvable2str(pool, s2)); + POOL_DEBUG(SAT_DEBUG_RESULT, "cannot install both %s and %s\n", solvid2str(pool, source), solvid2str(pool, target)); return; case SOLVER_RULE_RPM_PACKAGE_CONFLICT: - s = pool_id2solvable(pool, source); - s2 = pool_id2solvable(pool, target); - POOL_DEBUG(SAT_DEBUG_RESULT, "package %s conflicts with %s provided by %s\n", solvable2str(pool, s), dep2str(pool, dep), solvable2str(pool, s2)); + POOL_DEBUG(SAT_DEBUG_RESULT, "package %s conflicts with %s provided by %s\n", solvid2str(pool, source), dep2str(pool, dep), solvid2str(pool, target)); return; case SOLVER_RULE_RPM_PACKAGE_OBSOLETES: - s = pool_id2solvable(pool, source); - s2 = pool_id2solvable(pool, target); - POOL_DEBUG(SAT_DEBUG_RESULT, "package %s obsoletes %s provided by %s\n", solvable2str(pool, s), dep2str(pool, dep), solvable2str(pool, s2)); + POOL_DEBUG(SAT_DEBUG_RESULT, "package %s obsoletes %s provided by %s\n", solvid2str(pool, source), dep2str(pool, dep), solvid2str(pool, target)); return; case SOLVER_RULE_RPM_IMPLICIT_OBSOLETES: - s = pool_id2solvable(pool, source); - s2 = pool_id2solvable(pool, target); - POOL_DEBUG(SAT_DEBUG_RESULT, "package %s implicitely obsoletes %s provided by %s\n", solvable2str(pool, s), dep2str(pool, dep), solvable2str(pool, s2)); + POOL_DEBUG(SAT_DEBUG_RESULT, "package %s implicitely obsoletes %s provided by %s\n", solvid2str(pool, source), dep2str(pool, dep), solvid2str(pool, target)); return; case SOLVER_RULE_RPM_PACKAGE_REQUIRES: - s = pool_id2solvable(pool, source); - POOL_DEBUG(SAT_DEBUG_RESULT, "package %s requires %s, but none of the providers can be installed\n", solvable2str(pool, s), dep2str(pool, dep)); + POOL_DEBUG(SAT_DEBUG_RESULT, "package %s requires %s, but none of the providers can be installed\n", solvid2str(pool, source), dep2str(pool, dep)); return; case SOLVER_RULE_RPM_SELF_CONFLICT: - s = pool_id2solvable(pool, source); - POOL_DEBUG(SAT_DEBUG_RESULT, "package %s conflicts with %s provided by itself\n", solvable2str(pool, s), dep2str(pool, dep)); + POOL_DEBUG(SAT_DEBUG_RESULT, "package %s conflicts with %s provided by itself\n", solvid2str(pool, source), dep2str(pool, dep)); return; case SOLVER_RULE_UNKNOWN: case SOLVER_RULE_FEATURE: @@ -497,7 +481,7 @@ solver_printsolutions(Solver *solv, Queue *job) { case SOLVER_INSTALL: if (select == SOLVER_SOLVABLE && solv->installed && pool->solvables[what].repo == solv->installed) - POOL_DEBUG(SAT_DEBUG_RESULT, "- do not keep %s installed\n", solvable2str(pool, pool->solvables + what)); + POOL_DEBUG(SAT_DEBUG_RESULT, "- do not keep %s installed\n", solvid2str(pool, what)); else if (select == SOLVER_SOLVABLE_PROVIDES) POOL_DEBUG(SAT_DEBUG_RESULT, "- do not install a solvable %s\n", solver_select2str(solv, select, what)); else @@ -505,7 +489,7 @@ solver_printsolutions(Solver *solv, Queue *job) break; case SOLVER_ERASE: if (select == SOLVER_SOLVABLE && !(solv->installed && pool->solvables[what].repo == solv->installed)) - POOL_DEBUG(SAT_DEBUG_RESULT, "- do not forbid installation of %s\n", solvable2str(pool, pool->solvables + what)); + POOL_DEBUG(SAT_DEBUG_RESULT, "- do not forbid installation of %s\n", solvid2str(pool, what)); else if (select == SOLVER_SOLVABLE_PROVIDES) POOL_DEBUG(SAT_DEBUG_RESULT, "- do not deinstall all solvables %s\n", solver_select2str(solv, select, what)); else @@ -610,7 +594,7 @@ solver_printtrivial(Solver *solv) solver_trivial_installable(solv, &in, &out); POOL_DEBUG(SAT_DEBUG_RESULT, "trivial installable status:\n"); for (i = 0; i < in.count; i++) - POOL_DEBUG(SAT_DEBUG_RESULT, " %s: %d\n", solvable2str(pool, pool->solvables + in.elements[i]), out.elements[i]); + POOL_DEBUG(SAT_DEBUG_RESULT, " %s: %d\n", solvid2str(pool, in.elements[i]), out.elements[i]); POOL_DEBUG(SAT_DEBUG_RESULT, "\n"); queue_free(&in); queue_free(&out); @@ -623,7 +607,7 @@ solver_select2str(Solver *solv, Id select, Id what) const char *s; char *b; if (select == SOLVER_SOLVABLE) - return solvable2str(pool, pool->solvables + what); + return solvid2str(pool, what); if (select == SOLVER_SOLVABLE_NAME) return dep2str(pool, what); if (select == SOLVER_SOLVABLE_PROVIDES) @@ -640,7 +624,7 @@ solver_select2str(Solver *solv, Id select, Id what) b = ""; while ((p = pool->whatprovidesdata[what++]) != 0) { - s = solvable2str(pool, pool->solvables + p); + s = solvid2str(pool, p); b2 = pool_alloctmpspace(pool, strlen(b) + strlen(s) + 3); sprintf(b2, "%s, %s", b, s); b = b2; diff --git a/src/transaction.c b/src/transaction.c new file mode 100644 index 0000000..cf682f3 --- /dev/null +++ b/src/transaction.c @@ -0,0 +1,690 @@ +/* + * Copyright (c) 2007-2009, Novell Inc. + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +/* + * transaction.c + * + * Transaction handling + */ + +#include +#include +#include +#include +#include + +#include "transaction.h" +#include "solver.h" +#include "bitmap.h" +#include "pool.h" +#include "evr.h" +#include "util.h" + +static int +obsq_sortcmp(const void *ap, const void *bp, void *dp) +{ + Id a, b, oa, ob; + Pool *pool = dp; + Solvable *s, *oas, *obs; + int r; + + a = ((Id *)ap)[0]; + oa = ((Id *)ap)[1]; + b = ((Id *)bp)[0]; + ob = ((Id *)bp)[1]; + if (a != b) + return a - b; + if (oa == ob) + return 0; + s = pool->solvables + a; + oas = pool->solvables + oa; + obs = pool->solvables + ob; + if (oas->name != obs->name) + { + if (oas->name == s->name) + return -1; + if (obs->name == s->name) + return 1; + return strcmp(id2str(pool, oas->name), id2str(pool, obs->name)); + } + r = evrcmp(pool, oas->evr, obs->evr, EVRCMP_COMPARE); + if (r) + return -r; /* highest version first */ + return oa - ob; +} + +void +solver_transaction_all_pkgs(Solver *solv, Id p, Queue *pkgs) +{ + Pool *pool = solv->pool; + Solvable *s = pool->solvables + p; + Queue *ti = &solv->transaction_info; + Id q; + int i; + + queue_empty(pkgs); + if (p <= 0 || !s->repo) + return; + if (s->repo == solv->installed) + { + q = solv->transaction_installed[p - solv->installed->start]; + if (!q) + return; + if (q > 0) + { + queue_push(pkgs, q); + return; + } + /* find which packages obsolete us */ + for (i = 0; i < ti->count; i += 2) + if (ti->elements[i + 1] == p) + { + queue_push(pkgs, p); + queue_push(pkgs, ti->elements[i]); + } + /* sort obsoleters */ + if (pkgs->count > 2) + sat_sort(pkgs->elements, pkgs->count / 2, 2 * sizeof(Id), obsq_sortcmp, pool); + for (i = 0; i < pkgs->count; i += 2) + pkgs->elements[i / 2] = pkgs->elements[i + 1]; + pkgs->count /= 2; + } + else + { + /* find the packages we obsolete */ + for (i = 0; i < ti->count; i += 2) + { + if (ti->elements[i] == p) + queue_push(pkgs, ti->elements[i + 1]); + else if (pkgs->count) + break; + } + } +} + +Id +solver_transaction_pkg(Solver *solv, Id p) +{ + Pool *pool = solv->pool; + Solvable *s = pool->solvables + p; + Queue ti; + Id tibuf[5]; + + if (p <= 0 || !s->repo) + return 0; + if (s->repo == solv->installed) + { + p = solv->transaction_installed[p - solv->installed->start]; + return p < 0 ? -p : p; + } + queue_init_buffer(&ti, tibuf, sizeof(tibuf)/sizeof(*tibuf)); + solver_transaction_all_pkgs(solv, p, &ti); + p = ti.count ? ti.elements[0] : 0; + queue_free(&ti); + return p; +} + +/* type filtering, needed if either not all packages are shown + * or replaces are not shown, as otherwise parts of the + * transaction might not be shown to the user */ + +Id +solver_transaction_filter(Solver *solv, Id type, Id p, int flags) +{ + Pool *pool = solv->pool; + Solvable *s = pool->solvables + p; + Queue oq, rq; + Id q; + int i, j, ref = 0; + + if (type == SOLVER_TRANSACTION_ERASE || type == SOLVER_TRANSACTION_INSTALL || type == SOLVER_TRANSACTION_MULTIINSTALL) + return type; + + if (s->repo == pool->installed && (flags & SOLVER_TRANSACTION_SHOW_ACTIVE) == 0) + { + /* erase element */ + if ((flags & SOLVER_TRANSACTION_SHOW_REPLACES) == 0 && type == SOLVER_TRANSACTION_REPLACED) + type = SOLVER_TRANSACTION_ERASE; + return type; + } + if (s->repo != pool->installed && (flags & SOLVER_TRANSACTION_SHOW_ACTIVE) != 0) + { + if ((flags & SOLVER_TRANSACTION_SHOW_REPLACES) == 0 && type == SOLVER_TRANSACTION_REPLACE) + type = SOLVER_TRANSACTION_INSTALL; + return type; + } + + /* most of the time there's only one reference, so check it first */ + q = solver_transaction_pkg(solv, p); + if ((flags & SOLVER_TRANSACTION_SHOW_REPLACES) == 0) + { + Solvable *sq = pool->solvables + q; + if (sq->name != s->name) + { + if (s->repo == pool->installed) + return SOLVER_TRANSACTION_ERASE; + else if (type == SOLVER_TRANSACTION_MULTIREINSTALL) + return SOLVER_TRANSACTION_MULTIINSTALL; + else + return SOLVER_TRANSACTION_INSTALL; + } + } + if (solver_transaction_pkg(solv, q) == p) + return type; + + /* too bad, a miss. check em all */ + queue_init(&oq); + queue_init(&rq); + solver_transaction_all_pkgs(solv, p, &oq); + for (i = 0; i < oq.count; i++) + { + q = oq.elements[i]; + if ((flags & SOLVER_TRANSACTION_SHOW_REPLACES) == 0) + { + Solvable *sq = pool->solvables + q; + if (sq->name != s->name) + continue; + } + /* check if we are referenced? */ + if ((flags & SOLVER_TRANSACTION_SHOW_ALL) != 0) + { + solver_transaction_all_pkgs(solv, q, &rq); + for (j = 0; j < rq.count; j++) + if (rq.elements[j] == p) + { + ref = 1; + break; + } + if (ref) + break; + } + else if (solver_transaction_pkg(solv, q) == p) + { + ref = 1; + break; + } + } + queue_free(&oq); + queue_free(&rq); + + if (!ref) + { + if (s->repo == pool->installed) + type = SOLVER_TRANSACTION_ERASE; + else if (type == SOLVER_TRANSACTION_MULTIREINSTALL) + type = SOLVER_TRANSACTION_MULTIINSTALL; + else + type = SOLVER_TRANSACTION_INSTALL; + } + return type; +} + +static void +create_transaction_info(Solver *solv) +{ + Pool *pool = solv->pool; + Queue *ti = &solv->transaction_info; + Repo *installed = solv->installed; + int i, j, noobs; + Id p, p2, pp2; + Solvable *s, *s2; + + queue_empty(ti); + if (!installed) + return; /* no info needed */ + for (i = 0; i < solv->decisionq.count; i++) + { + p = solv->decisionq.elements[i]; + if (p <= 0 || p == SYSTEMSOLVABLE) + continue; + s = pool->solvables + p; + if (s->repo == installed) + continue; + noobs = solv->noobsoletes.size && MAPTST(&solv->noobsoletes, p); + FOR_PROVIDES(p2, pp2, s->name) + { + if (solv->decisionmap[p2] > 0) + continue; + s2 = pool->solvables + p2; + if (s2->repo != installed) + continue; + if (noobs && (s->name != s2->name || s->evr != s2->evr || s->arch != s2->arch)) + continue; + if (!solv->implicitobsoleteusesprovides && s->name != s2->name) + continue; + queue_push(ti, p); + queue_push(ti, p2); + } + if (s->obsoletes && !noobs) + { + Id obs, *obsp = s->repo->idarraydata + s->obsoletes; + while ((obs = *obsp++) != 0) + { + FOR_PROVIDES(p2, pp2, obs) + { + s2 = pool->solvables + p2; + if (s2->repo != installed) + continue; + if (!solv->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p2, obs)) + continue; + queue_push(ti, p); + queue_push(ti, p2); + } + } + } + } + sat_sort(ti->elements, ti->count / 2, 2 * sizeof(Id), obsq_sortcmp, pool); + /* now unify */ + for (i = j = 0; i < ti->count; i += 2) + { + if (j && ti->elements[i] == ti->elements[j - 2] && ti->elements[i + 1] == ti->elements[j - 1]) + continue; + ti->elements[j++] = ti->elements[i]; + ti->elements[j++] = ti->elements[i + 1]; + } + ti->count = j; + + /* create transaction_installed helper */ + solv->transaction_installed = sat_calloc(installed->end - installed->start, sizeof(Id)); + for (i = 0; i < ti->count; i += 2) + { + j = ti->elements[i + 1] - installed->start; + if (!solv->transaction_installed[j]) + solv->transaction_installed[j] = ti->elements[i]; + else + { + /* more than one package obsoletes us. compare */ + Id q[4]; + if (solv->transaction_installed[j] > 0) + solv->transaction_installed[j] = -solv->transaction_installed[j]; + q[0] = q[2] = ti->elements[i + 1]; + q[1] = ti->elements[i]; + q[3] = -solv->transaction_installed[j]; + if (obsq_sortcmp(q, q + 2, pool) < 0) + solv->transaction_installed[j] = -ti->elements[i]; + } + } +} + + +void +solver_create_transaction(Solver *solv) +{ + Pool *pool = solv->pool; + Repo *installed = solv->installed; + int i, r, noobs; + Id p, p2; + Solvable *s, *s2; + + queue_empty(&solv->transaction); + create_transaction_info(solv); + + if (installed) + { + FOR_REPO_SOLVABLES(installed, p, s) + { + if (solv->decisionmap[p] > 0) + continue; + p2 = solver_transaction_pkg(solv, p); + if (!p2) + queue_push(&solv->transaction, SOLVER_TRANSACTION_ERASE); + else + { + s2 = pool->solvables + p2; + if (s->name == s2->name) + { + if (s->evr == s2->evr && solvable_identical(s, s2)) + queue_push(&solv->transaction, SOLVER_TRANSACTION_REINSTALLED); + else + { + r = evrcmp(pool, s->evr, s2->evr, EVRCMP_COMPARE); + if (r < 0) + queue_push(&solv->transaction, SOLVER_TRANSACTION_UPGRADED); + else if (r > 0) + queue_push(&solv->transaction, SOLVER_TRANSACTION_DOWNGRADED); + else + queue_push(&solv->transaction, SOLVER_TRANSACTION_CHANGED); + } + } + else + queue_push(&solv->transaction, SOLVER_TRANSACTION_REPLACED); + } + queue_push(&solv->transaction, p); + } + } + for (i = 0; i < solv->decisionq.count; i++) + { + p = solv->decisionq.elements[i]; + if (p < 0 || p == SYSTEMSOLVABLE) + continue; + s = pool->solvables + p; + if (solv->installed && s->repo == solv->installed) + continue; + noobs = solv->noobsoletes.size && MAPTST(&solv->noobsoletes, p); + p2 = solver_transaction_pkg(solv, p); + if (noobs) + queue_push(&solv->transaction, p2 ? SOLVER_TRANSACTION_MULTIREINSTALL : SOLVER_TRANSACTION_MULTIINSTALL); + else if (!p2) + queue_push(&solv->transaction, SOLVER_TRANSACTION_INSTALL); + else + { + s2 = pool->solvables + p2; + if (s->name == s2->name) + { + if (s->evr == s2->evr && solvable_identical(s, s2)) + queue_push(&solv->transaction, SOLVER_TRANSACTION_REINSTALL); + else + { + r = evrcmp(pool, s->evr, s2->evr, EVRCMP_COMPARE); + if (r > 0) + queue_push(&solv->transaction, SOLVER_TRANSACTION_UPGRADE); + else if (r < 0) + queue_push(&solv->transaction, SOLVER_TRANSACTION_DOWNGRADE); + else + queue_push(&solv->transaction, SOLVER_TRANSACTION_CHANGE); + } + } + else + queue_push(&solv->transaction, SOLVER_TRANSACTION_REPLACE); + } + queue_push(&solv->transaction, p); + } +} + +#define TYPE_REQ (1<<0) +#define TYPE_PREREQ (1<<1) +#define TYPE_CON (1<<2) +#define TYPE_ERASE (1<<3) + +#define EDGEDATA_BLOCK 127 + +struct transel { + Id p; + Id edges; +}; + +struct orderdata { + Solver *solv; + struct transel *tes; + int ntes; + Id *edgedata; + int nedgedata; +}; + +static void +addedge(struct orderdata *od, Id from, Id to, int type) +{ + Solver *solv = od->solv; + Pool *pool = solv->pool; + Solvable *s; + struct transel *te; + int i; + + // printf("addedge %d %d type %d\n", from, to, type); + s = pool->solvables + from; + if (s->repo == solv->installed && solv->transaction_installed[from - solv->installed->start]) + { + /* passive, map to active */ + if (solv->transaction_installed[from - solv->installed->start] > 0) + from = solv->transaction_installed[from - solv->installed->start]; + else + { + Queue ti; + Id tibuf[5]; + queue_init_buffer(&ti, tibuf, sizeof(tibuf)/sizeof(*tibuf)); + solver_transaction_all_pkgs(solv, from, &ti); + for (i = 0; i < ti.count; i++) + addedge(od, ti.elements[i], to, type); + queue_free(&ti); + } + return; + } + s = pool->solvables + to; + if (s->repo == solv->installed && solv->transaction_installed[to - solv->installed->start]) + { + /* passive, map to active */ + if (solv->transaction_installed[to - solv->installed->start] > 0) + to = solv->transaction_installed[to - solv->installed->start]; + else + { + Queue ti; + Id tibuf[5]; + queue_init_buffer(&ti, tibuf, sizeof(tibuf)/sizeof(*tibuf)); + solver_transaction_all_pkgs(solv, to, &ti); + for (i = 0; i < ti.count; i++) + addedge(od, from, ti.elements[i], type); + queue_free(&ti); + return; + } + } + + /* map target to te num */ + for (i = 1, te = od->tes + i; i < od->ntes; i++, te++) + if (te->p == to) + break; + if (i == od->ntes) + return; + to = i; + + for (i = 1, te = od->tes + i; i < od->ntes; i++, te++) + if (te->p == from) + break; + if (i == od->ntes) + return; + + if (i == to) + return; /* no edges to ourselfes */ + + // printf("edge %d -> %d type %x\n", i, to, type); + + for (i = te->edges; od->edgedata[i]; i += 2) + if (od->edgedata[i] == to) + break; + if (od->edgedata[i]) + { + od->edgedata[i + 1] |= type; + return; + } + if (i + 1 == od->nedgedata) + { + // printf("tail add %d\n", i - te->edges); + if (!i) + te->edges = ++i; + od->edgedata = sat_extend(od->edgedata, od->nedgedata, 3, sizeof(Id), EDGEDATA_BLOCK); + } + else + { + // printf("extend %d\n", i - te->edges); + od->edgedata = sat_extend(od->edgedata, od->nedgedata, 3 + (i - te->edges), sizeof(Id), EDGEDATA_BLOCK); + if (i > te->edges) + memcpy(od->edgedata + od->nedgedata, od->edgedata + te->edges, sizeof(Id) * (i - te->edges)); + i = od->nedgedata + (i - te->edges); + te->edges = od->nedgedata; + } + od->edgedata[i] = to; + od->edgedata[i + 1] = type; + od->edgedata[i + 2] = 0; + od->nedgedata = i + 3; +} + +void +solver_order_transaction(Solver *solv) +{ + Pool *pool = solv->pool; + Queue *tr = &solv->transaction; + Repo *installed = solv->installed; + Id type, p; + Solvable *s, *s2; + Id req, *reqp, con, *conp; + Id p2, pp2; + int i, j, pre, numte, numedge; + struct orderdata od; + struct transel *te; + + /* create a transaction element for every active component */ + numte = 0; + for (i = 0; i < tr->count; i += 2) + { + p = tr->elements[i + 1]; + s = pool->solvables + p; + if (s->repo != installed || !solv->transaction_installed[p - solv->installed->start]) + numte++; + } + if (!numte) + return; /* nothing to do... */ + + + printf("numte = %d\n", numte); + numte++; /* leave first one zero */ + od.solv = solv; + od.ntes = numte; + od.tes = sat_calloc(numte, sizeof(*od.tes)); + od.edgedata = sat_extend(0, 0, 1, sizeof(Id), EDGEDATA_BLOCK); + od.edgedata[0] = 0; + od.nedgedata = 1; + + for (i = 0, te = od.tes + 1; i < tr->count; i += 2) + { + p = tr->elements[i + 1]; + s = pool->solvables + p; + if (s->repo == installed && solv->transaction_installed[p - solv->installed->start]) + continue; + te->p = p; + te++; + } + + /* create dependency graph */ + for (i = 0; i < tr->count; i += 2) + { + type = tr->elements[i]; + p = tr->elements[i + 1]; + s = pool->solvables + p; + if (s->requires) + { + reqp = s->repo->idarraydata + s->requires; + pre = TYPE_REQ; + while ((req = *reqp++) != 0) + { + int eraseonly = 0; + if (req == SOLVABLE_PREREQMARKER) + { + pre = TYPE_PREREQ; + continue; + } +#if 1 + if (s->repo == installed && pre != TYPE_PREREQ) + continue; +#endif + FOR_PROVIDES(p2, pp2, req) + { + if (p2 == p) + continue; + s2 = pool->solvables + p2; + if (!s2->repo) + continue; + if (s2->repo == installed && solv->decisionmap[p2] > 0) + continue; + if (s2->repo != installed && solv->decisionmap[p2] < 0) + continue; /* not interesting */ + if (s->repo == installed) + { + /* we're uninstalling s */ + if (s2->repo == installed) + { + if (eraseonly == 0) + eraseonly = 1; + } + if (s2->repo != installed) + { + /* update p2 before erasing p */ +#if 1 + addedge(&od, p, p2, pre); +#endif + eraseonly = -1; + } + } + else + { + /* install p2 before installing p */ + if (s2->repo != installed) + addedge(&od, p, p2, pre); + } + } + if (eraseonly == 1) + { + printf("eraseonlyedge for %s req %s\n", solvable2str(pool, s), dep2str(pool, req)); + /* need edges to uninstalled pkgs */ +#if 1 + FOR_PROVIDES(p2, pp2, req) + { + if (p2 == p) + continue; + s2 = pool->solvables + p2; + if (!s2->repo || s2->repo != installed) + continue; + if (solv->decisionmap[p2] > 0) + continue; +#if 0 + addedge(&od, p2, p, pre); +#else + addedge(&od, p2, p, TYPE_ERASE); +#endif + } +#endif + } + } + } + if (s->conflicts) + { + conp = s->repo->idarraydata + s->conflicts; + while ((con = *conp++) != 0) + { +#if 1 + FOR_PROVIDES(p2, pp2, con) + { + if (p2 == p) + continue; + s2 = pool->solvables + p2; + if (!s2->repo) + continue; + if (s->repo == installed) + { + if (s2->repo != installed && solv->decisionmap[p2] >= 0) + { + /* deinstall p before installing p2 */ + addedge(&od, p2, p, TYPE_CON); + } + } + else + { + if (s2->repo == installed && solv->decisionmap[p2] < 0) + { + /* deinstall p2 before installing p */ +#if 1 + addedge(&od, p, p2, TYPE_CON); +#endif + } + } + + } +#endif + } + } + } + numedge = 0; + for (i = 1, te = od.tes + i; i < numte; i++, te++) + { + printf("TE #%d, %d(%s)\n", i, te->p, solvid2str(pool, te->p)); + for (j = te->edges; od.edgedata[j]; j += 2) + { + struct transel *te2 = od.tes + od.edgedata[j]; + printf(" depends %x on TE %d, %d(%s)\n", od.edgedata[j + 1], od.edgedata[j], te2->p, solvid2str(pool, te2->p)); + numedge++; + } + } + printf("TEs: %d, Edges: %d, Space: %d\n", numte - 1, numedge, od.nedgedata / 2); +} diff --git a/src/transaction.h b/src/transaction.h new file mode 100644 index 0000000..25a7967 --- /dev/null +++ b/src/transaction.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2007-2009, Novell Inc. + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +/* + * transaction.h + * + */ + +#ifndef SATSOLVER_TRANSACTION_H +#define SATSOLVER_TRANSACTION_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "pooltypes.h" +#include "queue.h" + +struct _Solver; + +#define SOLVER_TRANSACTION_ERASE 0x10 +#define SOLVER_TRANSACTION_REINSTALLED 0x11 +#define SOLVER_TRANSACTION_DOWNGRADED 0x12 +#define SOLVER_TRANSACTION_CHANGED 0x13 +#define SOLVER_TRANSACTION_UPGRADED 0x14 +#define SOLVER_TRANSACTION_REPLACED 0x15 + +#define SOLVER_TRANSACTION_INSTALL 0x20 +#define SOLVER_TRANSACTION_REINSTALL 0x21 +#define SOLVER_TRANSACTION_DOWNGRADE 0x22 +#define SOLVER_TRANSACTION_CHANGE 0x23 +#define SOLVER_TRANSACTION_UPGRADE 0x24 +#define SOLVER_TRANSACTION_REPLACE 0x25 + +#define SOLVER_TRANSACTION_MULTIINSTALL 0x30 +#define SOLVER_TRANSACTION_MULTIREINSTALL 0x31 + +#define SOLVER_TRANSACTION_SHOW_ACTIVE (1 << 0) +#define SOLVER_TRANSACTION_SHOW_ALL (1 << 1) +#define SOLVER_TRANSACTION_SHOW_REPLACES (1 << 2) + +extern void solver_create_transaction(struct _Solver *solv); +extern void solver_transaction_all_pkgs(struct _Solver *solv, Id p, Queue *pkgs); +extern Id solver_transaction_pkg(struct _Solver *solv, Id p); +extern Id solver_transaction_filter(struct _Solver *solv, Id type, Id p, int mode); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 7fca8f3..5f20cf0 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -47,6 +47,10 @@ 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}) +SET(patchcheck_SOURCES patchcheck.c repo_rpmmd.c repo_susetags.c repo_updateinfoxml.c) +ADD_EXECUTABLE(patchcheck ${patchcheck_SOURCES}) +TARGET_LINK_LIBRARIES(patchcheck satsolver ${EXPAT_LIBRARY} ${ZLIB_LIBRARY}) + ADD_EXECUTABLE( dumpsolv dumpsolv.c ) TARGET_LINK_LIBRARIES( dumpsolv satsolver) diff --git a/tools/patchcheck.c b/tools/patchcheck.c new file mode 100644 index 0000000..e24d88d --- /dev/null +++ b/tools/patchcheck.c @@ -0,0 +1,487 @@ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include + +#include "pool.h" +#include "evr.h" +#include "poolarch.h" +#include "repo_solv.h" +#include "repo_susetags.h" +#include "repo_updateinfoxml.h" +#include "repo_rpmmd.h" +#include "solver.h" +#include "solverdebug.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); +} + +void +showproblems(Solver *solv, Solvable *s, Queue *cand, Queue *badguys) +{ + Pool *pool = solv->pool; + Queue rids, rinfo; + Id problem = 0; + int jj; + int rerun = 0; + + queue_init(&rids); + queue_init(&rinfo); + printf("can't install %s:\n", solvable2str(pool, s)); + while ((problem = solver_next_problem(solv, problem)) != 0) + { + solver_findallproblemrules(solv, problem, &rids); + for (jj = 0; jj < rids.count; jj++) + { + Id probr = rids.elements[jj]; + int k, l; + + queue_empty(&rinfo); + solver_allruleinfos(solv, probr, &rinfo); + for (k = 0; k < rinfo.count; k += 4) + { + Id dep, source, target; + source = rinfo.elements[k + 1]; + target = rinfo.elements[k + 2]; + dep = rinfo.elements[k + 3]; + switch (rinfo.elements[k]) + { + case SOLVER_PROBLEM_DISTUPGRADE_RULE: + break; + case SOLVER_PROBLEM_INFARCH_RULE: + printf(" %s has inferior architecture\n", solvid2str(pool, source)); + break; + case SOLVER_PROBLEM_UPDATE_RULE: + printf(" update rule for %s\n", solvid2str(pool, source)); + if (badguys) + queue_pushunique(badguys, source); + if (!cand) + break; + /* only drop update problem packages from cand so that we see all problems of this patch */ + for (l = 0; l < cand->count; l++) + if (cand->elements[l] == source || cand->elements[l] == -source) + break; + if (l == cand->count) + break; + if (!rerun) + { + for (l = 0; l < cand->count; l++) + if (cand->elements[l] < 0) + cand->elements[l] = -cand->elements[l]; + rerun = 1; + } + for (l = 0; l < cand->count; l++) + if (cand->elements[l] == source) + { + cand->elements[l] = -source; + } + 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: + printf(" package %s is not installable\n", solvid2str(pool, source)); + break; + case SOLVER_PROBLEM_NOTHING_PROVIDES_DEP: + printf(" nothing provides %s needed by %s\n", dep2str(pool, dep), solvid2str(pool, source)); + 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", solvid2str(pool, rp)); + } + } + break; + case SOLVER_PROBLEM_SAME_NAME: + printf(" cannot install both %s and %s\n", solvid2str(pool, source), solvid2str(pool, target)); + break; + case SOLVER_PROBLEM_PACKAGE_CONFLICT: + printf(" package %s conflicts with %s provided by %s\n", solvid2str(pool, source), dep2str(pool, dep), solvid2str(pool, target)); + break; + case SOLVER_PROBLEM_PACKAGE_OBSOLETES: + printf(" package %s obsoletes %s provided by %s\n", solvid2str(pool, source), dep2str(pool, dep), solvid2str(pool, target)); + break; + case SOLVER_PROBLEM_DEP_PROVIDERS_NOT_INSTALLABLE: + printf(" package %s requires %s, but none of the providers can be installed\n", solvid2str(pool, source), dep2str(pool, dep)); + break; + case SOLVER_PROBLEM_SELF_CONFLICT: + printf(" package %s conflicts with %s provided by itself\n", solvid2str(pool, source), dep2str(pool, dep)); + break; + } + } + } + } + queue_free(&rids); + queue_free(&rinfo); +} + +void +toinst(Solver *solv, Repo *repo, Repo *instrepo) +{ + Pool *pool = solv->pool; + int k; + Id p; + + for (k = 0; k < solv->decisionq.count; k++) + { + p = solv->decisionq.elements[k]; + if (p < 0 || p == SYSTEMSOLVABLE) + continue; + /* oh my! */ + pool->solvables[p].repo = instrepo; + } +} + +void +frominst(Solver *solv, Repo *repo, Repo *instrepo) +{ + Pool *pool = solv->pool; + int k; + + for (k = 1; k < pool->nsolvables; k++) + if (pool->solvables[k].repo == instrepo) + pool->solvables[k].repo = repo; +} + +int +main(int argc, char **argv) +{ + Pool *pool; + char *arch, *mypatch; + const char *pname; + int l; + FILE *fp; + int i, j; + Queue job; + Queue cand; + Queue badguys; + Id pid, p, pp; + Id con, *conp; + Solver *solv; + Repo *repo, *instrepo; + int status = 0; + int tests = 0; + int updatestart = 0; + + arch = argv[1]; + pool = pool_create(); + pool_setarch(pool, arch); + mypatch = argv[2]; + + repo = repo_create(pool, 0); + instrepo = repo_create(pool, 0); + for (i = 3; i < argc; i++) + { + if (!strcmp(argv[i], "--updaterepos")) + { + updatestart = 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); + } + 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 (l >= 17 && !strcmp(argv[i] + l - 17, "updateinfo.xml.gz")) + { + repo_add_updateinfoxml(repo, fp, 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); + } + + /* bad hack ahead: clone repo */ + instrepo->idarraydata = repo->idarraydata; + instrepo->start = repo->start; + instrepo->end = repo->end; + instrepo->nsolvables = repo->nsolvables; /* sic! */ + pool_set_installed(pool, instrepo); + + pool_addfileprovides(pool); + pool_createwhatprovides(pool); + + queue_init(&job); + queue_init(&cand); + queue_init(&badguys); + +#if 0 + pool_setdebuglevel(pool, 2); +#endif + + for (pid = 1; pid < pool->nsolvables; pid++) + { + Solvable *s = pool->solvables + pid; + if (!s->repo) + continue; + if (!pool_installable(pool, s)) + continue; + pname = id2str(pool, s->name); + if (strncmp(pname, "patch:", 6) != 0) + continue; + if (*mypatch) + { + if (strncmp(mypatch, pname + 6, strlen(pname + 6)) != 0) + continue; + if (strcmp(mypatch, pname + 6) != 0) + { + l = strlen(pname + 6); + if (mypatch[l] != '-') + continue; + if (strcmp(mypatch + l + 1, id2str(pool, s->evr)) != 0) + continue; + } + } + else + { + FOR_PROVIDES(p, pp, s->name) + { + Solvable *s2 = pool->solvables + p; + if (evrcmp(pool, s->evr, s2->evr, EVRCMP_COMPARE) < 0) + break; + } + if (p) + continue; /* found a newer one */ + } + tests++; + if (!s->conflicts) + continue; + +#if 0 + printf("testing patch %s-%s\n", pname + 6, id2str(pool, s->evr)); +#endif + + /* Test 1: are all old patches included */ + FOR_PROVIDES(p, pp, s->name) + { + Solvable *s2 = pool->solvables + p; + Id con2, *conp2; + int shown = 0; + + if (evrcmp(pool, s->evr, s2->evr, EVRCMP_COMPARE) <= 0) + continue; + if (!s2->conflicts) + continue; + conp2 = s2->repo->idarraydata + s2->conflicts; + while ((con2 = *conp2++) != 0) + { + Reldep *rd2; + if (!ISRELDEP(con2)) + continue; + rd2 = GETRELDEP(pool, con2); + conp = s->repo->idarraydata + s->conflicts; + while ((con = *conp++) != 0) + { + Reldep *rd; + if (!ISRELDEP(con)) + continue; + rd = GETRELDEP(pool, con); + if (rd->name == rd2->name) + break; + } + if (!con) + { + if (!shown++) + printf("%s:\n", solvable2str(pool, s)); + printf(" %s contained %s\n", solvable2str(pool, s2), dep2str(pool, rd2->name)); + } + } + } + + /* Test 2: are the packages installable */ + conp = s->repo->idarraydata + s->conflicts; + while ((con = *conp++) != 0) + { + FOR_PROVIDES(p, pp, con) + { + queue_empty(&job); + queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_WEAK); + queue_push(&job, p); + + /* also set up some minimal system */ + queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES|SOLVER_WEAK); + queue_push(&job, str2id(pool, "rpm", 1)); + queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES|SOLVER_WEAK); + queue_push(&job, str2id(pool, "aaa_base", 1)); + + solv = solver_create(pool); + solv->dontinstallrecommended = 1; + solv = solver_create(pool); + solver_solve(solv, &job); + toinst(solv, repo, instrepo); + solver_free(solv); + queue_empty(&job); + for (i = 1; i < updatestart; i++) + { + if (pool->solvables[i].repo != repo || i == pid) + continue; + queue_push(&job, SOLVER_ERASE|SOLVER_SOLVABLE); + queue_push(&job, i); + } + queue_push(&job, SOLVER_INSTALL_SOLVABLE); + queue_push(&job, pid); + solv = solver_create(pool); + solv->dontinstallrecommended = 1; + solver_solve(solv, &job); + if (solv->problems.count) + { + status = 1; + showproblems(solv, s, 0, 0); + } + frominst(solv, repo, instrepo); + solver_free(solv); + } + } + + if (0) + continue; + + /* Test 3: can we upgrade all packages? */ + queue_empty(&cand); + queue_empty(&badguys); + for (p = 1; p < pool->nsolvables; p++) + { + Solvable *s = pool->solvables + p; + if (!s->repo) + continue; + if (strchr(id2str(pool, s->name), ':')) + continue; /* only packages, please */ + if (!pool_installable(pool, s)) + continue; + queue_push(&cand, p); + } + while (cand.count) + { + solv = solver_create(pool); + solv->dontinstallrecommended = 1; + solv = solver_create(pool); + queue_empty(&job); + for (i = 0; i < badguys.count; i++) + { + queue_push(&job, SOLVER_ERASE|SOLVER_SOLVABLE|SOLVER_WEAK); + queue_push(&job, badguys.elements[i]); + } + conp = s->repo->idarraydata + s->conflicts; + while ((con = *conp++) != 0) + { + queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES|SOLVER_WEAK); + queue_push(&job, con); + } + for (i = 0; i < cand.count; i++) + { + p = cand.elements[i]; + queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_WEAK); + queue_push(&job, p); + } + solver_solve(solv, &job); +#if 0 + solver_printdecisions(solv); +#endif + /* put packages into installed repo and prune them from cand */ + toinst(solv, repo, instrepo); + for (i = 0; i < cand.count; i++) + { + p = cand.elements[i]; + if (p > 0 && solv->decisionmap[p] > 0) + cand.elements[i] = -p; /* drop candidate */ + } + solver_free(solv); + + /* now the interesting part: test patch */ + queue_empty(&job); +#if 0 + for (i = 1; i < updatestart; i++) + { + if (pool->solvables[i].repo != repo || i == pid) + continue; + queue_push(&job, SOLVER_ERASE|SOLVER_SOLVABLE); + queue_push(&job, i); + } +#endif + queue_push(&job, SOLVER_INSTALL_SOLVABLE); + queue_push(&job, pid); + solv = solver_create(pool); + solv->dontinstallrecommended = 1; + solver_solve(solv, &job); + + if (solv->problems.count) + { + status = 1; + showproblems(solv, s, &cand, &badguys); + } + frominst(solv, repo, instrepo); + solver_free(solv); + /* now drop all negative elements from cand */ + for (i = j = 0; i < cand.count; i++) + { + if (cand.elements[i] < 0) + continue; + cand.elements[j++] = cand.elements[i]; + } + if (i == j) + break; /* no progress */ + cand.count = j; + } + } + exit(status); +} diff --git a/tools/repo_rpmmd.c b/tools/repo_rpmmd.c index 867c026..eed0ab1 100644 --- a/tools/repo_rpmmd.c +++ b/tools/repo_rpmmd.c @@ -269,7 +269,7 @@ langtag(struct parsedata *pd, Id tag, const char *language) } static int -id3_cmp (const void *v1, const void *v2) +id3_cmp (const void *v1, const void *v2, void *dp) { Id *i1 = (Id*)v1; Id *i2 = (Id*)v2; @@ -284,7 +284,7 @@ commit_diskusage (struct parsedata *pd, unsigned handle) /* Now sort in dirid order. This ensures that parents come before their children. */ if (pd->ndirs > 1) - qsort(pd->dirs, pd->ndirs, sizeof (pd->dirs[0]), id3_cmp); + sat_sort(pd->dirs, pd->ndirs, sizeof (pd->dirs[0]), id3_cmp, 0); /* Substract leaf numbers from all parents to make the numbers non-cumulative. This must be done post-order (i.e. all leafs adjusted before parents). We ensure this by starting at the end of -- 2.7.4