diff options
author | Michael Schroeder <mls@suse.de> | 2008-08-29 18:31:45 +0000 |
---|---|---|
committer | Michael Schroeder <mls@suse.de> | 2008-08-29 18:31:45 +0000 |
commit | 2a270f741c5123d4aa7ec409be09da5498d754a5 (patch) | |
tree | 47457df0f45a1fb86fcdf2903011adc7bf3baff1 /src | |
parent | e39167fb292391ba3ae555a2ce5b902be025d981 (diff) | |
download | libsolv-2a270f741c5123d4aa7ec409be09da5498d754a5.tar.gz libsolv-2a270f741c5123d4aa7ec409be09da5498d754a5.tar.bz2 libsolv-2a270f741c5123d4aa7ec409be09da5498d754a5.zip |
- new job commands, now combinded from job type and select type
- support for distupgrade mode
Diffstat (limited to 'src')
-rw-r--r-- | src/policy.c | 8 | ||||
-rw-r--r-- | src/pool.c | 4 | ||||
-rw-r--r-- | src/pool.h | 1 | ||||
-rw-r--r-- | src/solvable.c | 36 | ||||
-rw-r--r-- | src/solver.c | 466 | ||||
-rw-r--r-- | src/solver.h | 63 | ||||
-rw-r--r-- | src/solverdebug.c | 99 | ||||
-rw-r--r-- | src/solverdebug.h | 2 |
8 files changed, 403 insertions, 276 deletions
diff --git a/src/policy.c b/src/policy.c index ffc8233..c6f9a10 100644 --- a/src/policy.c +++ b/src/policy.c @@ -299,7 +299,7 @@ prune_to_best_version(Solver *solv, Queue *plist) } } - if (best == ID_NULL) + if (!best) best = plist->elements[0]; plist->elements[j++] = best; @@ -461,7 +461,11 @@ policy_findupdatepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all) continue; queue_push(qs, p); } - if (solv->noupdateprovide && solv->obsoletes && solv->obsoletes[n - solv->installed->start]) + /* if we have found some valid candidates and noupdateprovide is not set, we're + done. otherwise we fallback to all obsoletes */ + if (!solv->noupdateprovide && qs->count) + return; + if (solv->obsoletes && solv->obsoletes[n - solv->installed->start]) { for (pp = solv->obsoletes_data + solv->obsoletes[n - solv->installed->start]; (p = *pp++) != 0;) { @@ -376,8 +376,8 @@ pool_queuetowhatprovides(Pool *pool, Queue *q) Offset off; int count = q->count; - if (count == 0) /* queue empty -> ID_EMPTY */ - return ID_EMPTY; + if (count == 0) /* queue empty -> 1 */ + return 1; /* extend whatprovidesdata if needed, +1 for ID_NULL-termination */ if (pool->whatprovidesdataleft < count + 1) @@ -178,6 +178,7 @@ int solvable_lookup_void(Solvable *s, Id keyname); char * solvable_get_location(Solvable *s, unsigned int *medianrp); const unsigned char *solvable_lookup_bin_checksum(Solvable *s, Id keyname, Id *typep); const char *solvable_lookup_checksum(Solvable *s, Id keyname, Id *typep); +int solvable_identical(Pool *pool, Solvable *s1, Solvable *s2); int solvable_trivial_installable_map(Solvable *s, Map *installedmap, Map *conflictsmap); int solvable_trivial_installable_repo(Solvable *s, struct _Repo *installed); diff --git a/src/solvable.c b/src/solvable.c index 5f79c70..c17fe25 100644 --- a/src/solvable.c +++ b/src/solvable.c @@ -604,3 +604,39 @@ pool_create_state_maps(Pool *pool, Queue *installed, Map *installedmap, Map *con } } +int +solvable_identical(Pool *pool, Solvable *s1, Solvable *s2) +{ + unsigned int bt1, bt2; + Id rq1, rq2; + Id *reqp; + + if (s1->name != s2->name) + return 0; + if (s1->arch != s2->arch) + return 0; + if (s1->evr != s2->evr) + return 0; + if (s1->vendor != s2->vendor) + return 0; + + /* first tests passed, try requires */ + rq1 = rq2 = 0; + if (s1->requires) + for (reqp = s1->repo->idarraydata + s1->requires; *reqp; reqp++) + rq1 ^= *reqp++; + if (s2->requires) + for (reqp = s2->repo->idarraydata + s2->requires; *reqp; reqp++) + rq2 ^= *reqp++; + if (rq1 != rq2) + return 0; + + /* looking good, try some fancier stuff */ + bt1 = solvable_lookup_num(s1, SOLVABLE_BUILDTIME, 0); + bt2 = solvable_lookup_num(s2, SOLVABLE_BUILDTIME, 0); + if (bt1 && bt2 && bt1 != bt2) + return 0; + + /* might also look up the package checksum here */ + return 1; +} diff --git a/src/solver.c b/src/solver.c index 4354511..2d50e63 100644 --- a/src/solver.c +++ b/src/solver.c @@ -651,7 +651,7 @@ makeruledecisions(Solver *solv) disableproblem(solv, v); continue; } - + assert(solv->decisionq_why.elements[i]); /* @@ -856,7 +856,7 @@ enableweakrules(Solver *solv) /* FIXME: bad code ahead, replace as soon as possible */ -/* FIXME: should probably look at SOLVER_INSTALL_SOLVABLE_ONE_OF */ +/* FIXME: should probably look at SOLVER_INSTALL|SOLVABLE_ONE_OF */ /*------------------------------------------------------------------- * disable update rules @@ -867,7 +867,7 @@ disableupdaterules(Solver *solv, Queue *job, int jobidx) { Pool *pool = solv->pool; int i, j; - Id how, what, p, *pp; + Id how, select, what, p, *pp; Solvable *s; Repo *installed; Rule *r; @@ -879,13 +879,15 @@ disableupdaterules(Solver *solv, Queue *job, int jobidx) if (jobidx != -1) { - how = job->elements[jobidx] & ~SOLVER_WEAK; - switch(how) + how = job->elements[jobidx]; + select = how & SOLVER_SELECTMASK; + switch (how & SOLVER_JOBMASK) { - case SOLVER_INSTALL_SOLVABLE: - case SOLVER_ERASE_SOLVABLE: - case SOLVER_ERASE_SOLVABLE_NAME: - case SOLVER_ERASE_SOLVABLE_PROVIDES: + case SOLVER_ERASE: + break; + case SOLVER_INSTALL: + if (select != SOLVER_SOLVABLE) + return; break; default: return; @@ -902,14 +904,19 @@ disableupdaterules(Solver *solv, Queue *job, int jobidx) if (j == lastjob) continue; lastjob = j; - how = job->elements[j] & ~SOLVER_WEAK; + how = job->elements[j]; what = job->elements[j + 1]; - switch(how) + select = how & SOLVER_SELECTMASK; + switch (how & SOLVER_JOBMASK) { - case SOLVER_INSTALL_SOLVABLE: /* install specific solvable */ + case SOLVER_INSTALL: + if (select != SOLVER_SOLVABLE) + break; s = pool->solvables + what; if (solv->noobsoletes.size && MAPTST(&solv->noobsoletes, what)) break; + if (s->repo == installed) + break; if (s->obsoletes) { Id obs, *obsp; @@ -932,20 +939,10 @@ disableupdaterules(Solver *solv, Queue *job, int jobidx) MAPSET(&solv->noupdate, p - installed->start); } break; - case SOLVER_ERASE_SOLVABLE: - s = pool->solvables + what; - if (s->repo == installed) - MAPSET(&solv->noupdate, what - installed->start); - break; - case SOLVER_ERASE_SOLVABLE_NAME: /* remove by capability */ - case SOLVER_ERASE_SOLVABLE_PROVIDES: - FOR_PROVIDES(p, pp, what) - { - if (how == SOLVER_ERASE_SOLVABLE_NAME && !pool_match_nevr(pool, pool->solvables + p, what)) - continue; - if (pool->solvables[p].repo == installed) - MAPSET(&solv->noupdate, p - installed->start); - } + case SOLVER_ERASE: + FOR_JOB_SELECT(p, pp, select, what) + if (pool->solvables[p].repo == installed) + MAPSET(&solv->noupdate, p - installed->start); break; default: break; @@ -957,12 +954,17 @@ disableupdaterules(Solver *solv, Queue *job, int jobidx) { /* we just disabled job #jobidx. enable all update rules * that aren't disabled by the remaining job rules */ - how = job->elements[jobidx] & ~SOLVER_WEAK; + how = job->elements[jobidx]; what = job->elements[jobidx + 1]; - switch(how) + select = how & SOLVER_SELECTMASK; + switch (how & SOLVER_JOBMASK) { - case SOLVER_INSTALL_SOLVABLE: + case SOLVER_INSTALL: + if (select != SOLVER_SOLVABLE) + break; s = pool->solvables + what; + if (s->repo == installed) + break; if (s->obsoletes) { Id obs, *obsp; @@ -1006,28 +1008,9 @@ disableupdaterules(Solver *solv, Queue *job, int jobidx) } } break; - case SOLVER_ERASE_SOLVABLE: - s = pool->solvables + what; - if (s->repo != installed) - break; - if (MAPTST(&solv->noupdate, what - installed->start)) - break; - r = solv->rules + solv->updaterules + (what - installed->start); - if (r->d >= 0) - break; - enablerule(solv, r); - IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS) - { - POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "@@@ re-enabling "); - solver_printrule(solv, SAT_DEBUG_SOLUTIONS, r); - } - break; - case SOLVER_ERASE_SOLVABLE_NAME: /* remove by capability */ - case SOLVER_ERASE_SOLVABLE_PROVIDES: - FOR_PROVIDES(p, pp, what) + case SOLVER_ERASE: + FOR_JOB_SELECT(p, pp, select, what) { - if (how == SOLVER_ERASE_SOLVABLE_NAME && !pool_match_nevr(pool, pool->solvables + p, what)) - continue; if (pool->solvables[p].repo != installed) continue; if (MAPTST(&solv->noupdate, p - installed->start)) @@ -1415,6 +1398,35 @@ addrpmrulesforupdaters(Solver *solv, Solvable *s, Map *m, int allow_all) POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforupdaters -----\n"); } +static Id +finddistupgradepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all) +{ + Pool *pool = solv->pool; + int i; + + policy_findupdatepackages(solv, s, qs, allow_all); + if (!qs->count) + { + if (allow_all) + return 0; + policy_findupdatepackages(solv, s, qs, 1); + if (!qs->count) + return 0; + qs->count = 0; + return -SYSTEMSOLVABLE; + } + if (allow_all) + return s - pool->solvables; + /* check if it is ok to keep the installed package */ + for (i = 0; i < qs->count; i++) + { + Solvable *ns = pool->solvables + qs->elements[i]; + if (s->evr == ns->evr && solvable_identical(pool, s, ns)) + return s - pool->solvables; + } + /* nope, it must be some other package */ + return queue_shift(qs); +} /*------------------------------------------------------------------- * @@ -1429,21 +1441,21 @@ addupdaterule(Solver *solv, Solvable *s, int allow_all) { /* installed packages get a special upgrade allowed rule */ Pool *pool = solv->pool; - Id d; + Id p, d; Queue qs; Id qsbuf[64]; POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addupdaterule -----\n"); - queue_init_buffer(&qs, qsbuf, sizeof(qsbuf)/sizeof(*qsbuf)); - /* find update candidates for 's' */ - policy_findupdatepackages(solv, s, &qs, allow_all); - if (qs.count == 0) /* no updaters found */ - d = 0; /* assertion (keep installed) */ + p = s - pool->solvables; + /* find update candidates for 's' */ + if (solv->distupgrade) + p = finddistupgradepackages(solv, s, &qs, allow_all); else - d = pool_queuetowhatprovides(pool, &qs); /* intern computed queue */ + policy_findupdatepackages(solv, s, &qs, allow_all); + d = qs.count ? pool_queuetowhatprovides(pool, &qs) : 0; queue_free(&qs); - addrule(solv, s - pool->solvables, d); /* allow update of s */ + addrule(solv, p, d); /* allow update of s */ POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addupdaterule end -----\n"); } @@ -1812,7 +1824,7 @@ l1retry: goto l1retry; } why = solv->decisionq_why.elements[idx]; - if (!why) /* just in case, maye for SYSTEMSOLVABLE */ + if (!why) /* just in case, maybe for SYSTEMSOLVABLE */ goto l1retry; c = solv->rules + why; } @@ -2261,6 +2273,7 @@ solver_create(Pool *pool, Repo *installed) queue_init(&solv->problems); queue_init(&solv->suggestions); queue_init(&solv->recommendations); + queue_init(&solv->orphaned); queue_init(&solv->learnt_why); queue_init(&solv->learnt_pool); queue_init(&solv->branches); @@ -2298,6 +2311,7 @@ solver_free(Solver *solv) queue_free(&solv->problems); queue_free(&solv->suggestions); queue_free(&solv->recommendations); + queue_free(&solv->orphaned); queue_free(&solv->branches); queue_free(&solv->covenantq); queue_free(&solv->weakruleq); @@ -2414,6 +2428,7 @@ run_solver(Solver *solv, int disablerules, int doweak) } if (l || !dq.count) continue; + /* prune to installed if not updating */ if (!solv->updatesystem && solv->installed && dq.count > 1) { int j, k; @@ -2490,7 +2505,7 @@ run_solver(Solver *solv, int disablerules, int doweak) for (i = solv->installed->start, r = solv->rules + solv->updaterules; i < solv->installed->end; i++, r++) { Rule *rr; - Id d; + Id inst; s = pool->solvables + i; /* skip if not installed (can't update) */ @@ -2505,42 +2520,34 @@ run_solver(Solver *solv, int disablerules, int doweak) continue; queue_empty(&dq); + 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; - d = (rr->d < 0) ? -rr->d - 1 : rr->d; - if (d == 0) - { - if (!rr->w2 || solv->decisionmap[rr->w2] > 0) - continue; - /* decide w2 if yet undecided */ - if (solv->decisionmap[rr->w2] == 0) - queue_push(&dq, rr->w2); - } - else + if (rr->p <= 0) + continue; + + FOR_RULELITERALS(p, dp, rr) { - dp = pool->whatprovidesdata + d; - while ((p = *dp++) != 0) - { - if (solv->decisionmap[p] > 0) - break; - /* decide p if yet undecided */ - if (solv->decisionmap[p] == 0) - queue_push(&dq, p); - } - if (p) - continue; + if (solv->decisionmap[p] > 0) + break; + if (solv->decisionmap[p] == 0) + queue_push(&dq, p); } - if (!dq.count && solv->decisionmap[i] != 0) + if (p || !dq.count) /* already fulfilled or empty */ continue; + if (dq.elements[0] == i) + inst = queue_shift(&dq); + else + inst = 0; olevel = level; /* FIXME: it is handled a bit different because we do not want * to have it pruned just because it is not recommened. - * we should not prune installed packages instead + * we should not prune installed packages instead. */ - level = selectandinstall(solv, level, &dq, (solv->decisionmap[i] ? 0 : i), disablerules); + level = selectandinstall(solv, level, &dq, inst, disablerules); if (level == 0) { queue_free(&dq); @@ -2746,6 +2753,37 @@ run_solver(Solver *solv, int disablerules, int doweak) } } + if (solv->distupgrade && solv->installed) + { + /* let's see if we can install some unsupported package */ + int ri; + POOL_DEBUG(SAT_DEBUG_STATS, "deciding unsupported packages\n"); + for (i = solv->installed->start, ri = 0; i < solv->installed->end; i++, ri++) + { + s = pool->solvables + i; + if (s->repo != solv->installed) + continue; + if (solv->decisionmap[i]) + continue; + if (!solv->rules[solv->updaterules + ri].p && !solv->rules[solv->featurerules + ri].p) + break; + } + if (i < solv->installed->end) + { + if (solv->distupgrade_removeunsupported) + { + POOL_DEBUG(SAT_DEBUG_STATS, "removing unsupported %s\n", solvable2str(pool, pool->solvables + i)); + level = setpropagatelearn(solv, level, -i, 0); + } + else + { + POOL_DEBUG(SAT_DEBUG_STATS, "keeping unsupported %s\n", solvable2str(pool, pool->solvables + i)); + level = setpropagatelearn(solv, level, i, 0); + } + continue; + } + } + if (solv->solution_callback) { solv->solution_callback(solv, solv->solution_callback_data); @@ -3102,11 +3140,19 @@ problems_to_solutions(Solver *solv, Queue *job) Id p, d, *dp, rp = 0; Rule *rr; p = solv->installed->start + (why - solv->updaterules); - if (solv->decisionmap[p] > 0) - continue; /* false alarm, turned out we can keep the package */ rr = solv->rules + solv->featurerules + (why - solv->updaterules); if (!rr->p) rr = solv->rules + why; + if (solv->distupgrade && solv->rules[why].p != p && solv->decisionmap[p] > 0) + { + /* distupgrade case, allow to keep old package */ + queue_push(&solutions, p); + queue_push(&solutions, p); + nsol++; + continue; + } + if (solv->decisionmap[p] > 0) + continue; /* false alarm, turned out we can keep the package */ if (rr->w2) { d = rr->d < 0 ? -rr->d - 1 : rr->d; @@ -3258,7 +3304,7 @@ solver_problemruleinfo(Solver *solv, Queue *job, Id rid, Id *depp, Id *sourcep, *sourcep = p; *targetp = job->elements[p]; d = r->d < 0 ? -r->d - 1 : r->d; - if (d == 0 && r->w2 == 0 && r->p == -SYSTEMSOLVABLE && job->elements[p] != SOLVER_INSTALL_SOLVABLE_ONE_OF) + if (d == 0 && r->w2 == 0 && r->p == -SYSTEMSOLVABLE && (job->elements[p] & SOLVER_SELECTMASK) != SOLVER_SOLVABLE_ONE_OF) return SOLVER_PROBLEM_JOB_NOTHING_PROVIDES_DEP; return SOLVER_PROBLEM_JOB_RULE; } @@ -3776,7 +3822,7 @@ weaken_solvable_deps(Solver *solv, Id p) int i; Rule *r; - for (i = 1, r = solv->rules + i; i < solv->featurerules; i++, r++) + for (i = 1, r = solv->rules + i; i < solv->rpmrules_end; i++, r++) { if (r->p != -p) continue; @@ -3804,19 +3850,25 @@ solver_solve(Solver *solv, Queue *job) int oldnrules; Map addedmap; /* '1' == have rpm-rules for solvable */ Map installcandidatemap; - Id how, what, name, weak, p, *pp, d; + Id how, what, select, name, weak, p, *pp, d; Queue q, redoq; Solvable *s; int goterase; Rule *r; + POOL_DEBUG(SAT_DEBUG_STATS, "solver started\n"); + POOL_DEBUG(SAT_DEBUG_STATS, "fixsystem=%d updatesystem=%d dosplitprovides=%d, noupdateprovide=%d\n", solv->fixsystem, solv->updatesystem, solv->dosplitprovides, solv->noupdateprovide); + POOL_DEBUG(SAT_DEBUG_STATS, "distupgrade=%d distupgrade_removeunsupported=%d\n", solv->distupgrade, solv->distupgrade_removeunsupported); + POOL_DEBUG(SAT_DEBUG_STATS, "allowuninstall=%d, allowdowngrade=%d, allowarchchange=%d, allowvendorchange=%d\n", solv->allowuninstall, solv->allowdowngrade, solv->allowarchchange, solv->allowvendorchange); + POOL_DEBUG(SAT_DEBUG_STATS, "promoteepoch=%d, allowvirtualconflicts=%d, allowselfconflicts=%d\n", pool->promoteepoch, solv->allowvirtualconflicts, solv->allowselfconflicts); + POOL_DEBUG(SAT_DEBUG_STATS, "obsoleteusesprovides=%d, implicitobsoleteusesprovides=%d\n", solv->obsoleteusesprovides, solv->implicitobsoleteusesprovides); + POOL_DEBUG(SAT_DEBUG_STATS, "dontinstallrecommended=%d, ignorealreadyrecommended=%d, dontshowinstalledrecommended=%d\n", solv->dontinstallrecommended, solv->ignorealreadyrecommended, solv->dontshowinstalledrecommended); /* create whatprovides if not already there */ if (!pool->whatprovides) pool_createwhatprovides(pool); /* create obsolete index if needed */ - if (solv->noupdateprovide) - create_obsolete_index(solv); + create_obsolete_index(solv); /* * create basic rule set of all involved packages @@ -3828,29 +3880,14 @@ solver_solve(Solver *solv, Queue *job) for (i = 0; i < job->count; i += 2) { how = job->elements[i] & ~SOLVER_WEAK; + if ((how & SOLVER_JOBMASK) != SOLVER_NOOBSOLETES) + continue; what = job->elements[i + 1]; - switch(how) - { - case SOLVER_NOOBSOLETES_SOLVABLE: - case SOLVER_NOOBSOLETES_SOLVABLE_NAME: - case SOLVER_NOOBSOLETES_SOLVABLE_PROVIDES: - if (!solv->noobsoletes.size) - map_init(&solv->noobsoletes, pool->nsolvables); - if (how == SOLVER_NOOBSOLETES_SOLVABLE) - { - MAPSET(&solv->noobsoletes, what); - break; - } - FOR_PROVIDES(p, pp, what) - { - if (how == SOLVER_NOOBSOLETES_SOLVABLE_NAME && !pool_match_nevr(pool, pool->solvables + p, what)) - continue; - MAPSET(&solv->noobsoletes, p); - } - break; - default: - break; - } + select = how & SOLVER_SELECTMASK; + if (!solv->noobsoletes.size) + map_init(&solv->noobsoletes, pool->nsolvables); + FOR_JOB_SELECT(p, pp, select, what) + MAPSET(&solv->noobsoletes, p); } map_init(&addedmap, pool->nsolvables); @@ -3893,34 +3930,23 @@ solver_solve(Solver *solv, Queue *job) oldnrules = solv->nrules; for (i = 0; i < job->count; i += 2) { - how = job->elements[i] & ~SOLVER_WEAK; + how = job->elements[i]; what = job->elements[i + 1]; + select = how & SOLVER_SELECTMASK; - switch(how) + switch (how & SOLVER_JOBMASK) { - case SOLVER_INSTALL_SOLVABLE: - MAPSET(&installcandidatemap, what); - addrpmrulesforsolvable(solv, pool->solvables + what, &addedmap); - break; - case SOLVER_INSTALL_SOLVABLE_NAME: - case SOLVER_INSTALL_SOLVABLE_PROVIDES: - FOR_PROVIDES(p, pp, what) + case SOLVER_INSTALL: + FOR_JOB_SELECT(p, pp, select, what) { - /* if by name, ensure that the name matches */ - if (how == SOLVER_INSTALL_SOLVABLE_NAME && !pool_match_nevr(pool, pool->solvables + p, what)) - continue; MAPSET(&installcandidatemap, p); addrpmrulesforsolvable(solv, pool->solvables + p, &addedmap); } break; - case SOLVER_INSTALL_SOLVABLE_UPDATE: - /* dont allow downgrade */ - addrpmrulesforupdaters(solv, pool->solvables + what, &addedmap, 0); - break; - case SOLVER_INSTALL_SOLVABLE_ONE_OF: - pp = pool->whatprovidesdata + what; - while ((p = *pp++) != 0) - addrpmrulesforsolvable(solv, pool->solvables + p, &addedmap); + case SOLVER_UPDATE: + /* FIXME: semantics? */ + FOR_JOB_SELECT(p, pp, select, what) + addrpmrulesforupdaters(solv, pool->solvables + what, &addedmap, 0); break; } } @@ -4003,7 +4029,7 @@ solver_solve(Solver *solv, Queue *job) * Add update rules for installed solvables * * almost identical to feature rules - * except that downgrades are allowed + * except that downgrades/archchanges/vendorchanges are not allowed */ POOL_DEBUG(SAT_DEBUG_SCHUBI, "*** Add update rules ***\n"); @@ -4021,22 +4047,28 @@ solver_solve(Solver *solv, Queue *job) addrule(solv, 0, 0); /* create dummy rule */ continue; } - - addupdaterule(solv, s, 0); /* allowall = 0: downgrades allowed */ - + addupdaterule(solv, s, 0); /* allowall = 0: downgrades not allowed */ /* * check for and remove duplicate */ - r = solv->rules + solv->nrules - 1; /* r: update rule */ sr = r - (installed->end - installed->start); /* sr: feature rule */ + /* it's orphaned if there is no feature rule or the feature rule + * consists just of the installed package */ + if (!sr->p || (sr->p == i && !sr->d && !sr->w2)) + queue_push(&solv->orphaned, i); + if (!r->p) + { + assert(!sr->p); /* can't have feature rule and no update rule */ + continue; + } unifyrules_sortcmp_data = pool; if (!unifyrules_sortcmp(r, sr)) { /* identical rule, kill unneeded rule */ if (solv->allowuninstall) { - /* keep feature rule */ + /* keep feature rule, make it weak */ memset(r, 0, sizeof(*r)); queue_push(&solv->weakruleq, sr - solv->rules); } @@ -4072,101 +4104,77 @@ solver_solve(Solver *solv, Queue *job) { oldnrules = solv->nrules; - how = job->elements[i] & ~SOLVER_WEAK; - weak = job->elements[i] & SOLVER_WEAK; + how = job->elements[i]; what = job->elements[i + 1]; - switch(how) + weak = how & SOLVER_WEAK; + select = how & SOLVER_SELECTMASK; + switch (how & SOLVER_JOBMASK) { - case SOLVER_INSTALL_SOLVABLE: /* install specific solvable */ - s = pool->solvables + what; - POOL_DEBUG(SAT_DEBUG_JOB, "job: %sinstall solvable %s\n", weak ? "weak " : "", solvable2str(pool, s)); - addrule(solv, what, 0); /* install by Id */ + case SOLVER_INSTALL: + POOL_DEBUG(SAT_DEBUG_JOB, "job: %sinstall %s\n", weak ? "weak " : "", solver_select2str(solv, select, what)); + if (select == SOLVER_SOLVABLE) + { + p = what; + d = 0; + } + else + { + queue_empty(&q); + FOR_JOB_SELECT(p, pp, select, what) + queue_push(&q, p); + if (!q.count) + { + /* no candidate found, make this an impossible rule */ + queue_push(&q, -SYSTEMSOLVABLE); + } + p = queue_shift(&q); /* get first candidate */ + d = !q.count ? 0 : pool_queuetowhatprovides(pool, &q); /* internalize */ + } + addrule(solv, p, d); /* add install rule */ queue_push(&solv->ruletojob, i); if (weak) queue_push(&solv->weakruleq, solv->nrules - 1); break; - case SOLVER_ERASE_SOLVABLE: - s = pool->solvables + what; - POOL_DEBUG(SAT_DEBUG_JOB, "job: %serase solvable %s\n", weak ? "weak " : "", solvable2str(pool, s)); - name = s->name; - if (solv->installed && s->repo == solv->installed) + case SOLVER_ERASE: + POOL_DEBUG(SAT_DEBUG_JOB, "job: %serase %s\n", weak ? "weak " : "", solver_select2str(solv, select, what)); + if (select == SOLVER_SOLVABLE && solv->installed && pool->solvables[what].repo == solv->installed) { - FOR_PROVIDES(p, pp, s->name) + /* special case for "erase a specific solvable": we also + * erase all other solvables with that name, so that they + * don't get picked up as replacement */ + name = pool->solvables[what].name; + FOR_PROVIDES(p, pp, name) { + if (p == what) + continue; s = pool->solvables + p; if (s->name != name) continue; - if (p != what) - { - /* keep other versions installed */ - if (s->repo == solv->installed) - continue; - /* keep installcandidates of other jobs */ - if (MAPTST(&installcandidatemap, p)) - continue; - } + /* keep other versions installed */ + if (s->repo == solv->installed) + continue; + /* keep installcandidates of other jobs */ + if (MAPTST(&installcandidatemap, p)) + continue; addrule(solv, -p, 0); /* remove by Id */ queue_push(&solv->ruletojob, i); if (weak) queue_push(&solv->weakruleq, solv->nrules - 1); } } - else + FOR_JOB_SELECT(p, pp, select, what) { - addrule(solv, -what, 0); /* remove by Id */ + addrule(solv, -p, 0); queue_push(&solv->ruletojob, i); if (weak) queue_push(&solv->weakruleq, solv->nrules - 1); } break; - case SOLVER_INSTALL_SOLVABLE_NAME: /* install by capability */ - case SOLVER_INSTALL_SOLVABLE_PROVIDES: - if (how == SOLVER_INSTALL_SOLVABLE_NAME) - POOL_DEBUG(SAT_DEBUG_JOB, "job: %sinstall name %s\n", weak ? "weak " : "", dep2str(pool, what)); - if (how == SOLVER_INSTALL_SOLVABLE_PROVIDES) - POOL_DEBUG(SAT_DEBUG_JOB, "job: %sinstall provides %s\n", weak ? "weak " : "", dep2str(pool, what)); - queue_empty(&q); - FOR_PROVIDES(p, pp, what) - { - /* if by name, ensure that the name matches */ - if (how == SOLVER_INSTALL_SOLVABLE_NAME && !pool_match_nevr(pool, pool->solvables + p, what)) - continue; - queue_push(&q, p); - } - if (!q.count) - { - /* no provider, make this an impossible rule */ - queue_push(&q, -SYSTEMSOLVABLE); - } - p = queue_shift(&q); /* get first provider */ - if (!q.count) - d = 0; /* single provider ? -> make assertion */ - else - d = pool_queuetowhatprovides(pool, &q); /* get all providers */ - addrule(solv, p, d); /* add 'requires' rule */ - queue_push(&solv->ruletojob, i); - if (weak) - queue_push(&solv->weakruleq, solv->nrules - 1); - break; - case SOLVER_ERASE_SOLVABLE_NAME: /* remove by capability */ - case SOLVER_ERASE_SOLVABLE_PROVIDES: - if (how == SOLVER_ERASE_SOLVABLE_NAME) - POOL_DEBUG(SAT_DEBUG_JOB, "job: %serase name %s\n", weak ? "weak " : "", dep2str(pool, what)); - if (how == SOLVER_ERASE_SOLVABLE_PROVIDES) - POOL_DEBUG(SAT_DEBUG_JOB, "job: %serase provides %s\n", weak ? "weak " : "", dep2str(pool, what)); - FOR_PROVIDES(p, pp, what) - { - /* if by name, ensure that the name matches */ - if (how == SOLVER_ERASE_SOLVABLE_NAME && !pool_match_nevr(pool, pool->solvables + p, what)) - continue; - addrule(solv, -p, 0); /* add 'remove' rule */ - queue_push(&solv->ruletojob, i); - if (weak) - queue_push(&solv->weakruleq, solv->nrules - 1); - } - break; - case SOLVER_INSTALL_SOLVABLE_UPDATE: /* find update for solvable */ + case SOLVER_UPDATE: + POOL_DEBUG(SAT_DEBUG_JOB, "job: %supdate %s\n", weak ? "weak " : "", solver_select2str(solv, select, what)); + if (select != SOLVER_SOLVABLE) + break; s = pool->solvables + what; POOL_DEBUG(SAT_DEBUG_JOB, "job: %supdate %s\n", weak ? "weak " : "", solvable2str(pool, s)); addupdaterule(solv, s, 0); @@ -4174,28 +4182,32 @@ solver_solve(Solver *solv, Queue *job) if (weak) queue_push(&solv->weakruleq, solv->nrules - 1); break; - case SOLVER_INSTALL_SOLVABLE_ONE_OF: - POOL_DEBUG(SAT_DEBUG_JOB, "job: %sone of\n", weak ? "weak " : ""); - for (pp = pool->whatprovidesdata + what; *pp; pp++) - POOL_DEBUG(SAT_DEBUG_JOB, " %s\n", solvable2str(pool, pool->solvables + *pp)); - addrule(solv, -SYSTEMSOLVABLE, what); - queue_push(&solv->ruletojob, i); - if (weak) - queue_push(&solv->weakruleq, solv->nrules - 1); - break; - case SOLVER_WEAKEN_SOLVABLE_DEPS: + case SOLVER_WEAKENDEPS: + POOL_DEBUG(SAT_DEBUG_JOB, "job: %sweaken deps %s\n", weak ? "weak " : "", solver_select2str(solv, select, what)); + if (select != SOLVER_SOLVABLE) + break; s = pool->solvables + what; - POOL_DEBUG(SAT_DEBUG_JOB, "job: weaken deps %s\n", solvable2str(pool, s)); weaken_solvable_deps(solv, what); break; - case SOLVER_NOOBSOLETES_SOLVABLE: - POOL_DEBUG(SAT_DEBUG_JOB, "job: no obsolete %s\n", solvable2str(pool, pool->solvables + what)); + case SOLVER_NOOBSOLETES: + POOL_DEBUG(SAT_DEBUG_JOB, "job: %sno obsolete %s\n", weak ? "weak " : "", solver_select2str(solv, select, what)); break; - case SOLVER_NOOBSOLETES_SOLVABLE_NAME: - POOL_DEBUG(SAT_DEBUG_JOB, "job: no obsolete name %s\n", dep2str(pool, what)); + case SOLVER_LOCK: + POOL_DEBUG(SAT_DEBUG_JOB, "job: %slock %s\n", weak ? "weak " : "", solver_select2str(solv, select, what)); + FOR_JOB_SELECT(p, pp, select, what) + { + s = pool->solvables + p; + if (installed && s->repo == installed) + addrule(solv, p, 0); + else + addrule(solv, -p, 0); + queue_push(&solv->ruletojob, i); + if (weak) + queue_push(&solv->weakruleq, solv->nrules - 1); + } break; - case SOLVER_NOOBSOLETES_SOLVABLE_PROVIDES: - POOL_DEBUG(SAT_DEBUG_JOB, "job: no obsolete provides %s\n", dep2str(pool, what)); + default: + POOL_DEBUG(SAT_DEBUG_JOB, "job: unknown job\n"); break; } diff --git a/src/solver.h b/src/solver.h index 4751394..13366a3 100644 --- a/src/solver.h +++ b/src/solver.h @@ -126,6 +126,7 @@ typedef struct solver { Queue problems; /* index of conflicting rules, < 0 for job rules */ Queue recommendations; /* recommended packages */ Queue suggestions; /* suggested packages */ + Queue orphaned; /* orphaned packages */ int stats_learned; /* statistic */ int stats_unsolvable; /* statistic */ @@ -157,6 +158,10 @@ typedef struct solver { int ignorealreadyrecommended; /* true: ignore recommended packages that were already recommended by the installed packages */ int dontshowinstalledrecommended; /* true: do not show recommended packages that are already installed */ + /* distupgrade also needs updatesystem and dosplitprovides */ + int distupgrade; + int distupgrade_removeunsupported; + /* Callbacks for defining the bahaviour of the SAT solver */ /* Finding best candidate @@ -208,24 +213,39 @@ typedef struct solver { * queue commands */ -typedef enum { - SOLVCMD_NULL=0, - SOLVER_INSTALL_SOLVABLE, - SOLVER_ERASE_SOLVABLE, - SOLVER_INSTALL_SOLVABLE_NAME, - SOLVER_ERASE_SOLVABLE_NAME, - SOLVER_INSTALL_SOLVABLE_PROVIDES, - SOLVER_ERASE_SOLVABLE_PROVIDES, - SOLVER_INSTALL_SOLVABLE_UPDATE, - SOLVER_INSTALL_SOLVABLE_ONE_OF, - SOLVER_WEAKEN_SOLVABLE_DEPS, - SOLVER_NOOBSOLETES_SOLVABLE, - SOLVER_NOOBSOLETES_SOLVABLE_NAME, - SOLVER_NOOBSOLETES_SOLVABLE_PROVIDES, - - /* flags */ - SOLVER_WEAK = 0x100, -} SolverCmd; +#define SOLVER_SOLVABLE 0x01 +#define SOLVER_SOLVABLE_NAME 0x02 +#define SOLVER_SOLVABLE_PROVIDES 0x03 +#define SOLVER_SOLVABLE_ONE_OF 0x04 + +#define SOLVER_SELECTMASK 0xff + +#define SOLVER_INSTALL 0x0100 +#define SOLVER_ERASE 0x0200 +#define SOLVER_UPDATE 0x0300 +#define SOLVER_WEAKENDEPS 0x0400 +#define SOLVER_NOOBSOLETES 0x0500 +#define SOLVER_LOCK 0x0600 + +#define SOLVER_JOBMASK 0xff00 + +#define SOLVER_WEAK 0x010000 + +/* old API compatibility, do not use in new code */ +#if 1 +#define SOLVER_INSTALL_SOLVABLE (SOLVER_INSTALL|SOLVER_SOLVABLE) +#define SOLVER_ERASE_SOLVABLE (SOLVER_ERASE|SOLVER_SOLVABLE) +#define SOLVER_INSTALL_SOLVABLE_NAME (SOLVER_INSTALL|SOLVER_SOLVABLE_NAME) +#define SOLVER_ERASE_SOLVABLE_NAME (SOLVER_ERASE|SOLVER_SOLVABLE_NAME) +#define SOLVER_INSTALL_SOLVABLE_PROVIDES (SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES) +#define SOLVER_ERASE_SOLVABLE_PROVIDES (SOLVER_ERASE|SOLVER_SOLVABLE_PROVIDES) +#define SOLVER_INSTALL_SOLVABLE_UPDATE (SOLVER_UPDATE|SOLVER_SOLVABLE) +#define SOLVER_INSTALL_SOLVABLE_ONE_OF (SOLVER_INSTALL|SOLVER_SOLVABLE_ONE_OF) +#define SOLVER_WEAKEN_SOLVABLE_DEPS (SOLVER_WEAKENDEPS|SOLVER_SOLVABLE) +#define SOLVER_NOOBSOLETES_SOLVABLE (SOLVER_NOOBSOLETES|SOLVER_SOLVABLE) +#define SOLVER_NOOBSOLETES_SOLVABLE_NAME (SOLVER_NOOBSOLETES|SOLVER_SOLVABLE_NAME) +#define SOLVER_NOOBSOLETES_SOLVABLE_PROVIDES (SOLVER_NOOBSOLETES|SOLVER_SOLVABLE_PROVIDES) +#endif typedef enum { SOLVER_PROBLEM_UPDATE_RULE, @@ -325,6 +345,13 @@ solver_create_state_maps(Solver *solv, Map *installedmap, Map *conflictsmap) dp = !l ? &r->w2 : pool->whatprovidesdata + l, \ l = r->p; l; l = (dp != &r->w2 + 1 ? *dp++ : 0)) +#define FOR_JOB_SELECT(p, pp, select, what) \ + for (pp = (select == SOLVER_SOLVABLE ? pool->whatprovidesdata : \ + select == SOLVER_SOLVABLE_ONE_OF ? pool->whatprovidesdata + what : \ + pool_whatprovides(pool, what)), \ + p = (select == SOLVER_SOLVABLE ? what : *pp++) ; p ; p = *pp++) \ + if (select != SOLVER_SOLVABLE_NAME || pool_match_nevr(pool, pool->solvables + p, what)) + #ifdef __cplusplus } #endif diff --git a/src/solverdebug.c b/src/solverdebug.c index 84166de..2e314cf 100644 --- a/src/solverdebug.c +++ b/src/solverdebug.c @@ -18,6 +18,7 @@ #include <assert.h> #include "solver.h" +#include "solverdebug.h" #include "bitmap.h" #include "pool.h" #include "util.h" @@ -362,6 +363,19 @@ solver_printdecisions(Solver *solv) } POOL_DEBUG(SAT_DEBUG_RESULT, "\n"); } + if (solv->orphaned.count) + { + POOL_DEBUG(SAT_DEBUG_RESULT, "orphaned packages:\n"); + for (i = 0; i < solv->orphaned.count; i++) + { + s = pool->solvables + solv->orphaned.elements[i]; + if (solv->decisionmap[solv->orphaned.elements[i]] > 0) + POOL_DEBUG(SAT_DEBUG_RESULT, " %s (kept)\n", solvable2str(pool, s)); + else + POOL_DEBUG(SAT_DEBUG_RESULT, " %s (erased)\n", solvable2str(pool, s)); + } + POOL_DEBUG(SAT_DEBUG_RESULT, "\n"); + } } void @@ -427,7 +441,7 @@ solver_printsolutions(Solver *solv, Queue *job) { Pool *pool = solv->pool; int pcnt; - Id p, rp, how, what; + Id p, rp, how, what, select; Id problem, solution, element; Solvable *s, *sd; @@ -451,37 +465,30 @@ solver_printsolutions(Solver *solv, Queue *job) /* job, rp is index into job queue */ how = job->elements[rp - 1] & ~SOLVER_WEAK; what = job->elements[rp]; - switch (how) + select = how & SOLVER_SELECTMASK; + switch (how & SOLVER_JOBMASK) { - case SOLVER_INSTALL_SOLVABLE: - s = pool->solvables + what; - if (solv->installed && s->repo == solv->installed) - POOL_DEBUG(SAT_DEBUG_RESULT, "- do not keep %s installed\n", solvable2str(pool, s)); + 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)); + else if (select == SOLVER_SOLVABLE_PROVIDES) + POOL_DEBUG(SAT_DEBUG_RESULT, "- do not install a solvable %s\n", solver_select2str(solv, select, what)); else - POOL_DEBUG(SAT_DEBUG_RESULT, "- do not install %s\n", solvable2str(pool, s)); + POOL_DEBUG(SAT_DEBUG_RESULT, "- do not install %s\n", solver_select2str(solv, select, what)); break; - case SOLVER_ERASE_SOLVABLE: - s = pool->solvables + what; - if (solv->installed && s->repo == solv->installed) - POOL_DEBUG(SAT_DEBUG_RESULT, "- do not deinstall %s\n", solvable2str(pool, s)); + 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)); + else if (select == SOLVER_SOLVABLE_PROVIDES) + POOL_DEBUG(SAT_DEBUG_RESULT, "- do not deinstall all solvables %s\n", solver_select2str(solv, select, what)); else - POOL_DEBUG(SAT_DEBUG_RESULT, "- do not forbid installation of %s\n", solvable2str(pool, s)); + POOL_DEBUG(SAT_DEBUG_RESULT, "- do not deinstall %s\n", solver_select2str(solv, select, what)); break; - case SOLVER_INSTALL_SOLVABLE_NAME: - POOL_DEBUG(SAT_DEBUG_RESULT, "- do not install %s\n", dep2str(pool, what)); + case SOLVER_UPDATE: + POOL_DEBUG(SAT_DEBUG_RESULT, "- do not install most recent version of %s\n", solver_select2str(solv, select, what)); break; - case SOLVER_ERASE_SOLVABLE_NAME: - POOL_DEBUG(SAT_DEBUG_RESULT, "- do not deinstall %s\n", dep2str(pool, what)); - break; - case SOLVER_INSTALL_SOLVABLE_PROVIDES: - POOL_DEBUG(SAT_DEBUG_RESULT, "- do not install a solvable providing %s\n", dep2str(pool, what)); - break; - case SOLVER_ERASE_SOLVABLE_PROVIDES: - POOL_DEBUG(SAT_DEBUG_RESULT, "- do not deinstall all solvables providing %s\n", dep2str(pool, what)); - break; - case SOLVER_INSTALL_SOLVABLE_UPDATE: - s = pool->solvables + what; - POOL_DEBUG(SAT_DEBUG_RESULT, "- do not install most recent version of %s\n", solvable2str(pool, s)); + case SOLVER_LOCK: + POOL_DEBUG(SAT_DEBUG_RESULT, "- do not lock %s\n", solver_select2str(solv, select, what)); break; default: POOL_DEBUG(SAT_DEBUG_RESULT, "- do something different\n"); @@ -493,7 +500,11 @@ solver_printsolutions(Solver *solv, Queue *job) /* policy, replace p with rp */ s = pool->solvables + p; sd = rp ? pool->solvables + rp : 0; - if (sd) + if (s == sd && solv->distupgrade) + { + POOL_DEBUG(SAT_DEBUG_RESULT, "- keep obsolete %s\n", solvable2str(pool, s)); + } + else if (sd) { int gotone = 0; if (!solv->allowdowngrade && evrcmp(pool, s->evr, sd->evr, EVRCMP_MATCH_RELEASE) > 0) @@ -564,3 +575,37 @@ solver_printtrivial(Solver *solv) queue_free(&in); queue_free(&out); } + +const char * +solver_select2str(Solver *solv, Id select, Id what) +{ + Pool *pool = solv->pool; + const char *s; + char *b; + if (select == SOLVER_SOLVABLE) + return solvable2str(pool, pool->solvables + what); + if (select == SOLVER_SOLVABLE_NAME) + return dep2str(pool, what); + if (select == SOLVER_SOLVABLE_PROVIDES) + { + s = dep2str(pool, what); + b = pool_alloctmpspace(pool, 11 + strlen(s)); + sprintf(b, "providing %s", s); + return b; + } + if (select == SOLVER_SOLVABLE_ONE_OF) + { + Id p; + char *b2; + b = ""; + while ((p = pool->whatprovidesdata[what++]) != 0) + { + s = solvable2str(pool, pool->solvables + p); + b2 = pool_alloctmpspace(pool, strlen(b) + strlen(s) + 3); + sprintf(b2, "%s, %s", b, s); + b = b2; + } + return *b ? b + 2 : "nothing"; + } + return "unknown job select"; +} diff --git a/src/solverdebug.h b/src/solverdebug.h index cb90fdb..2b8493b 100644 --- a/src/solverdebug.h +++ b/src/solverdebug.h @@ -27,6 +27,8 @@ extern void solver_printdecisions(Solver *solv); extern void solver_printprobleminfo(Solver *solv, Queue *job, Id problem); extern void solver_printsolutions(Solver *solv, Queue *job); extern void solver_printtrivial(Solver *solv); +extern const char *solver_select2str(Solver *solv, Id select, Id what); + #endif /* SATSOLVER_SOLVERDEBUG_H */ |