diff options
Diffstat (limited to 'src/solver.c')
-rw-r--r-- | src/solver.c | 699 |
1 files changed, 90 insertions, 609 deletions
diff --git a/src/solver.c b/src/solver.c index 037b33d..6405f4a 100644 --- a/src/solver.c +++ b/src/solver.c @@ -31,82 +31,6 @@ #define RULES_BLOCK 63 -static Id -autouninstall(Solver *solv, Id *problem) -{ - Pool *pool = solv->pool; - int i; - int lastfeature = 0, lastupdate = 0; - Id v; - Id extraflags = -1; - Map *m = 0; - - if (!solv->allowuninstall && !solv->allowuninstall_all) - { - if (!solv->allowuninstallmap.size) - return 0; /* why did we get called? */ - m = &solv->allowuninstallmap; - } - for (i = 0; (v = problem[i]) != 0; i++) - { - if (v < 0) - extraflags &= solv->job.elements[-v - 1]; - if (v >= solv->updaterules && v < solv->updaterules_end) - { - Rule *r; - if (m && !MAPTST(m, v - solv->updaterules)) - continue; - /* check if identical to feature rule, we don't like that (except for orphans) */ - r = solv->rules + solv->featurerules + (v - solv->updaterules); - if (!r->p) - { - /* update rule == feature rule */ - if (v > lastfeature) - lastfeature = v; - /* prefer orphaned packages in dup mode */ - if (solv->keep_orphans) - { - r = solv->rules + v; - if (!r->d && !r->w2 && r->p == (solv->installed->start + (v - solv->updaterules))) - { - lastfeature = v; - lastupdate = 0; - break; - } - } - continue; - } - if (v > lastupdate) - lastupdate = v; - } - } - if (!lastupdate && !lastfeature) - return 0; - v = lastupdate ? lastupdate : lastfeature; - POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "allowuninstall disabling "); - solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + v); - solver_disableproblem(solv, v); - if (extraflags != -1 && (extraflags & SOLVER_CLEANDEPS) != 0 && solv->cleandepsmap.size) - { - /* add the package to the updatepkgs list, this will automatically turn - * on cleandeps mode */ - Id p = solv->rules[v].p; - if (!solv->cleandeps_updatepkgs) - { - solv->cleandeps_updatepkgs = solv_calloc(1, sizeof(Queue)); - queue_init(solv->cleandeps_updatepkgs); - } - if (p > 0) - { - int oldupdatepkgscnt = solv->cleandeps_updatepkgs->count; - queue_pushunique(solv->cleandeps_updatepkgs, p); - if (solv->cleandeps_updatepkgs->count != oldupdatepkgscnt) - solver_disablepolicyrules(solv); - } - } - return v; -} - /************************************************************************/ /* @@ -164,17 +88,18 @@ enabledisablelearntrules(Solver *solv) * If we find a conflict, disable rules and add them to problem queue. */ -static void -makeruledecisions(Solver *solv) +static int +makeruledecisions(Solver *solv, int disablerules) { Pool *pool = solv->pool; - int i, ri, ii; + int i, ri, ii, ori; Rule *r, *rr; Id v, vv; int decisionstart; int record_proof = 1; int oldproblemcount; int havedisabled = 0; + int doautouninstall; /* The system solvable is always installed first */ assert(solv->decisionq.count == 0); @@ -222,7 +147,7 @@ makeruledecisions(Solver *solv) if (!solv->decisionmap[vv]) /* if not yet decided */ { queue_push(&solv->decisionq, v); - queue_push(&solv->decisionq_why, r - solv->rules); + queue_push(&solv->decisionq_why, ri); solv->decisionmap[vv] = v > 0 ? 1 : -1; IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE) { @@ -254,14 +179,13 @@ makeruledecisions(Solver *solv) /* conflict with a learnt rule */ /* can happen when packages cannot be installed for multiple reasons. */ /* we disable the learnt rule in this case */ - /* (XXX: we should really call analyze_unsolvable_rule here!) */ + /* (XXX: we should really do something like analyze_unsolvable_rule here!) */ solver_disablerule(solv, r); continue; } POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "ANALYZE UNSOLVABLE ASSERTION ----------------------\n"); - IF_POOLDEBUG (SOLV_DEBUG_UNSOLVABLE) - solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + ri); + assert(ri >= solv->pkgrules_end); /* must not have a conflict in the pkg rules! */ /* * find the decision which is the "opposite" of the rule @@ -270,136 +194,94 @@ makeruledecisions(Solver *solv) if (solv->decisionq.elements[i] == -v) break; assert(i < solv->decisionq.count); /* assert that we found it */ - oldproblemcount = solv->problems.count; - - /* - * conflict with system solvable ? - */ if (v == -SYSTEMSOLVABLE) + ori = 0; + else { - if (record_proof) - { - queue_push(&solv->problems, solv->learnt_pool.count); - queue_push(&solv->learnt_pool, ri); - queue_push(&solv->learnt_pool, 0); - } - else - queue_push(&solv->problems, 0); - POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflict with system solvable, disabling rule #%d\n", ri); - if (ri >= solv->jobrules && ri < solv->jobrules_end) - v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1); - else - v = ri; - queue_push(&solv->problems, v); - queue_push(&solv->problems, 0); - if (v >= solv->featurerules && v < solv->updaterules_end) - { - if (solv->allowuninstall || solv->allowuninstall_all || solv->allowuninstallmap.size) - if (autouninstall(solv, solv->problems.elements + oldproblemcount + 1) != 0) - { - solv->problems.count = oldproblemcount; - havedisabled = 1; - break; /* start over */ - } - } - solver_disableproblem(solv, v); - havedisabled = 1; - break; /* start over */ + ori = solv->decisionq_why.elements[i]; /* the conflicting rule */ + assert(ori > 0); } - assert(solv->decisionq_why.elements[i] > 0); - IF_POOLDEBUG (SOLV_DEBUG_UNSOLVABLE) - solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + solv->decisionq_why.elements[i]); - /* - * conflict with a pkg rule ? - */ - if (solv->decisionq_why.elements[i] < solv->pkgrules_end) + * record the problem + */ + doautouninstall = 0; + oldproblemcount = solv->problems.count; + queue_push(&solv->problems, 0); /* start problem */ + if (ori < solv->pkgrules_end) { - if (record_proof) + /* easy: conflict with system solvable or pkg rule */ + assert(v > 0 || v == -SYSTEMSOLVABLE); + IF_POOLDEBUG (SOLV_DEBUG_UNSOLVABLE) { - queue_push(&solv->problems, solv->learnt_pool.count); - queue_push(&solv->learnt_pool, ri); - queue_push(&solv->learnt_pool, solv->decisionq_why.elements[i]); - queue_push(&solv->learnt_pool, 0); + if (ori) + POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflict with pkg rule, disabling rule #%d\n", ri); + else + POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflict with system solvable, disabling rule #%d\n", ri); + solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + ri); + if (ori) + solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + ori); } - else - queue_push(&solv->problems, 0); - assert(v > 0 || v == -SYSTEMSOLVABLE); - POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflict with pkg rule, disabling rule #%d\n", ri); - if (ri >= solv->jobrules && ri < solv->jobrules_end) - v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1); - else - v = ri; - queue_push(&solv->problems, v); - queue_push(&solv->problems, 0); - if (v >= solv->featurerules && v < solv->updaterules_end) + solver_recordproblem(solv, ri); + if (ri >= solv->featurerules && ri < solv->updaterules_end) + doautouninstall = 1; + } + else + { + POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflicting update/job assertions over literal %d\n", vv); + /* + * push all of our rules (can only be feature or job rules) + * asserting this literal on the problem stack + */ + for (i = solv->pkgrules_end, rr = solv->rules + i; i < solv->learntrules; i++, rr++) { - if (solv->allowuninstall || solv->allowuninstall_all || solv->allowuninstallmap.size) - if (autouninstall(solv, solv->problems.elements + oldproblemcount + 1) != 0) - { - solv->problems.count = oldproblemcount; - havedisabled = 1; - break; /* start over */ - } + if (rr->d < 0 /* disabled */ + || rr->w2) /* or no assertion */ + continue; + if (rr->p != vv /* not affecting the literal */ + && rr->p != -vv) + continue; + if (solv->weakrulemap.size && MAPTST(&solv->weakrulemap, i)) /* weak: silently ignore */ + continue; + + POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, " - disabling rule #%d\n", i); + solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + i); + solver_recordproblem(solv, i); + if (i >= solv->featurerules && i < solv->updaterules_end) + doautouninstall = 1; } - solver_disableproblem(solv, v); - havedisabled = 1; - break; /* start over */ } + queue_push(&solv->problems, 0); /* finish problem */ - /* - * conflict with another job or update/feature rule - */ + /* try autouninstall if requested */ + if (doautouninstall) + { + if (solv->allowuninstall || solv->allowuninstall_all || solv->allowuninstallmap.size) + if (solver_autouninstall(solv, oldproblemcount) != 0) + { + solv->problems.count = oldproblemcount; + havedisabled = 1; + break; /* start over */ + } + } - /* record proof */ + /* record the proof if requested */ if (record_proof) { - queue_push(&solv->problems, solv->learnt_pool.count); + solv->problems.elements[oldproblemcount] = solv->learnt_pool.count; queue_push(&solv->learnt_pool, ri); - queue_push(&solv->learnt_pool, solv->decisionq_why.elements[i]); + if (ori) + queue_push(&solv->learnt_pool, ori); queue_push(&solv->learnt_pool, 0); } - else - queue_push(&solv->problems, 0); - POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflicting update/job assertions over literal %d\n", vv); - - /* - * push all of our rules (can only be feature or job rules) - * asserting this literal on the problem stack - */ - for (i = solv->featurerules, rr = solv->rules + i; i < solv->learntrules; i++, rr++) + if (!disablerules) { - if (rr->d < 0 /* disabled */ - || rr->w2) /* or no assertion */ - continue; - if (rr->p != vv /* not affecting the literal */ - && rr->p != -vv) - continue; - if (solv->weakrulemap.size && MAPTST(&solv->weakrulemap, i)) /* weak: silently ignore */ - continue; - - POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, " - disabling rule #%d\n", i); - solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + i); - - v = i; - if (i >= solv->jobrules && i < solv->jobrules_end) - v = -(solv->ruletojob.elements[i - solv->jobrules] + 1); - queue_push(&solv->problems, v); + POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "UNSOLVABLE\n"); + return -1; } - queue_push(&solv->problems, 0); - - if (solv->allowuninstall || solv->allowuninstall_all || solv->allowuninstallmap.size) - if (autouninstall(solv, solv->problems.elements + oldproblemcount + 1) != 0) - { - solv->problems.count = oldproblemcount; - havedisabled = 1; - break; /* start over */ - } - - for (i = oldproblemcount + 1; i < solv->problems.count - 1; i++) - solver_disableproblem(solv, solv->problems.elements[i]); + /* disable all problem rules */ + solver_disableproblemset(solv, oldproblemcount); havedisabled = 1; break; /* start over */ } @@ -444,21 +326,15 @@ makeruledecisions(Solver *solv) continue; POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "assertion conflict, but I am weak, disabling "); - solver_printrule(solv, SOLV_DEBUG_UNSOLVABLE, r); - - if (ri >= solv->jobrules && ri < solv->jobrules_end) - v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1); - else - v = ri; - solver_disableproblem(solv, v); - if (v < 0) - solver_reenablepolicyrules(solv, -v); + solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, r); + solver_fixproblem(solv, ri); havedisabled = 1; break; /* start over */ } if (ii == solv->ruleassertions.count) break; /* finished! */ } + return 1; /* the new level */ } @@ -1013,36 +889,9 @@ analyze_unsolvable_rule(Solver *solv, Rule *r, Queue *weakq, Map *rseen) } if (solv->weakrulemap.size && MAPTST(&solv->weakrulemap, why) && weakq) queue_push(weakq, why); - /* do not add pkg rules to problem */ - if (why < solv->pkgrules_end) - return; - /* turn rule into problem */ - if (why >= solv->jobrules && why < solv->jobrules_end) - why = -(solv->ruletojob.elements[why - solv->jobrules] + 1); - /* normalize dup/infarch rules */ - if (why > solv->infarchrules && why < solv->infarchrules_end) - { - Id name = pool->solvables[-solv->rules[why].p].name; - while (why > solv->infarchrules && pool->solvables[-solv->rules[why - 1].p].name == name) - why--; - } - if (why > solv->duprules && why < solv->duprules_end) - { - Id name = pool->solvables[-solv->rules[why].p].name; - while (why > solv->duprules && pool->solvables[-solv->rules[why - 1].p].name == name) - why--; - } - - /* return if problem already countains our rule */ - if (solv->problems.count) - { - for (i = solv->problems.count - 1; i >= 0; i--) - if (solv->problems.elements[i] == 0) /* end of last problem reached? */ - break; - else if (solv->problems.elements[i] == why) - return; - } - queue_push(&solv->problems, why); + /* add non-pkg rules to problem and disable */ + if (why >= solv->pkgrules_end) + solver_recordproblem(solv, why); } @@ -1149,24 +998,18 @@ analyze_unsolvable(Solver *solv, Rule *cr, int disablerules) return 0; } queue_free(&weakq); - if (lastweak >= solv->jobrules && lastweak < solv->jobrules_end) - v = -(solv->ruletojob.elements[lastweak - solv->jobrules] + 1); - else - v = lastweak; POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "disabling "); solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + lastweak); if (lastweak >= solv->choicerules && lastweak < solv->choicerules_end) solver_disablechoicerules(solv, solv->rules + lastweak); - solver_disableproblem(solv, v); - if (v < 0) - solver_reenablepolicyrules(solv, -v); + solver_fixproblem(solv, lastweak); solver_reset(solv); return 0; } queue_free(&weakq); if (solv->allowuninstall || solv->allowuninstall_all || solv->allowuninstallmap.size) - if (autouninstall(solv, solv->problems.elements + oldproblemcount + 1) != 0) + if (solver_autouninstall(solv, oldproblemcount) != 0) { solv->problems.count = oldproblemcount; solv->learnt_pool.count = oldlearntpoolcount; @@ -1184,8 +1027,7 @@ analyze_unsolvable(Solver *solv, Rule *cr, int disablerules) /* + 2: index + trailing zero */ if (disablerules && oldproblemcount + 2 < solv->problems.count) { - for (i = oldproblemcount + 1; i < solv->problems.count - 1; i++) - solver_disableproblem(solv, solv->problems.elements[i]); + solver_disableproblemset(solv, oldproblemcount); /* XXX: might want to enable all weak rules again */ solver_reset(solv); return 0; @@ -2672,13 +2514,9 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) { if (level < 0) break; - makeruledecisions(solv); - level = 1; - if (!disablerules && solv->problems.count) - { - level = -1; - break; - } + level = makeruledecisions(solv, disablerules); + if (level < 0) + break; POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "initial propagate (propagate_index: %d; size decisionq: %d)...\n", solv->propagate_index, solv->decisionq.count); if ((r = propagate(solv, level)) != 0) { @@ -3494,7 +3332,6 @@ solver_solve(Solver *solv, Queue *job) deduceq2addedmap(solv, &addedmap); if (solv->nrules != initialnrules) solver_shrinkrules(solv, initialnrules); - solv->nrules = initialnrules; solv->lastpkgrule = 0; solv->pkgrules_end = 0; @@ -3588,7 +3425,7 @@ solver_solve(Solver *solv, Queue *job) } break; case SOLVER_DROP_ORPHANED: - if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid)) + if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && installed && what == installed->repoid)) solv->droporphanedmap_all = 1; FOR_JOB_SELECT(p, pp, select, what) { @@ -4021,18 +3858,7 @@ solver_solve(Solver *solv, Queue *job) /* now create infarch and dup rules */ if (!solv->noinfarchcheck) - { - solver_addinfarchrules(solv, &addedmap); -#if 0 - if (pool->implicitobsoleteusescolors) - { - /* currently doesn't work well with infarch rules, so make - * them weak */ - for (i = solv->infarchrules; i < solv->infarchrules_end; i++) - queue_push(&solv->weakruleq, i); - } -#endif - } + solver_addinfarchrules(solv, &addedmap); else solv->infarchrules = solv->infarchrules_end = solv->nrules; @@ -4049,7 +3875,7 @@ solver_solve(Solver *solv, Queue *job) if (solv->bestupdatemap_all || solv->bestupdatemap.size || hasbestinstalljob) solver_addbestrules(solv, hasbestinstalljob); else - solv->bestrules = solv->bestrules_end = solv->nrules; + solv->bestrules = solv->bestrules_end = solv->bestrules_up = solv->nrules; if (needduprules) solver_freedupmaps(solv); /* no longer needed */ @@ -4079,7 +3905,7 @@ solver_solve(Solver *solv, Queue *job) map_free(&installcandidatemap); queue_free(&q); - POOL_DEBUG(SOLV_DEBUG_STATS, "%d pkg rules, 2 * %d update rules, %d job rules, %d infarch rules, %d dup rules, %d choice rules, %d best rules\n", solv->pkgrules_end - 1, solv->updaterules_end - solv->updaterules, solv->jobrules_end - solv->jobrules, solv->infarchrules_end - solv->infarchrules, solv->duprules_end - solv->duprules, solv->choicerules_end - solv->choicerules, solv->bestrules_end - solv->bestrules); + POOL_DEBUG(SOLV_DEBUG_STATS, "%d pkg rules, 2 * %d update rules, %d job rules, %d infarch rules, %d dup rules, %d choice rules, %d best rules, %d yumobs rules\n", solv->pkgrules_end - 1, solv->updaterules_end - solv->updaterules, solv->jobrules_end - solv->jobrules, solv->infarchrules_end - solv->infarchrules, solv->duprules_end - solv->duprules, solv->choicerules_end - solv->choicerules, solv->bestrules_end - solv->bestrules, solv->yumobsrules_end - solv->yumobsrules); POOL_DEBUG(SOLV_DEBUG_STATS, "overall rule memory used: %d K\n", solv->nrules * (int)sizeof(Rule) / 1024); /* create weak map */ @@ -4716,351 +4542,6 @@ pool_isemptyupdatejob(Pool *pool, Id how, Id what) return 1; } -static int -get_userinstalled_cmp(const void *ap, const void *bp, void *dp) -{ - return *(Id *)ap - *(Id *)bp; -} - -static int -get_userinstalled_cmp_names(const void *ap, const void *bp, void *dp) -{ - Pool *pool = dp; - return strcmp(pool_id2str(pool, *(Id *)ap), pool_id2str(pool, *(Id *)bp)); -} - -static int -get_userinstalled_cmp_namearch(const void *ap, const void *bp, void *dp) -{ - Pool *pool = dp; - int r; - r = strcmp(pool_id2str(pool, ((Id *)ap)[0]), pool_id2str(pool, ((Id *)bp)[0])); - if (r) - return r; - return strcmp(pool_id2str(pool, ((Id *)ap)[1]), pool_id2str(pool, ((Id *)bp)[1])); -} - -static void -get_userinstalled_sort_uniq(Pool *pool, Queue *q, int flags) -{ - Id lastp = -1, lasta = -1; - int i, j; - if (q->count < ((flags & GET_USERINSTALLED_NAMEARCH) ? 4 : 2)) - return; - if ((flags & GET_USERINSTALLED_NAMEARCH) != 0) - solv_sort(q->elements, q->count / 2, 2 * sizeof(Id), get_userinstalled_cmp_namearch, pool); - else if ((flags & GET_USERINSTALLED_NAMES) != 0) - solv_sort(q->elements, q->count, sizeof(Id), get_userinstalled_cmp_names, pool); - else - solv_sort(q->elements, q->count, sizeof(Id), get_userinstalled_cmp, 0); - if ((flags & GET_USERINSTALLED_NAMEARCH) != 0) - { - for (i = j = 0; i < q->count; i += 2) - if (q->elements[i] != lastp || q->elements[i + 1] != lasta) - { - q->elements[j++] = lastp = q->elements[i]; - q->elements[j++] = lasta = q->elements[i + 1]; - } - } - else - { - for (i = j = 0; i < q->count; i++) - if (q->elements[i] != lastp) - q->elements[j++] = lastp = q->elements[i]; - } - queue_truncate(q, j); -} - -static void -namearch2solvables(Pool *pool, Queue *q, Queue *qout, int job) -{ - int i; - if (!pool->installed) - return; - for (i = 0; i < q->count; i += 2) - { - Id p, pp, name = q->elements[i], arch = q->elements[i + 1]; - FOR_PROVIDES(p, pp, name) - { - Solvable *s = pool->solvables + p; - if (s->repo != pool->installed || s->name != name || (arch && s->arch != arch)) - continue; - if (job) - queue_push(qout, job); - queue_push(qout, p); - } - } -} - -void -solver_get_userinstalled(Solver *solv, Queue *q, int flags) -{ - Pool *pool = solv->pool; - Id p, p2, pp; - Solvable *s; - Repo *installed = solv->installed; - int i, j; - Map userinstalled; - - map_init(&userinstalled, 0); - queue_empty(q); - /* first process jobs */ - for (i = 0; i < solv->job.count; i += 2) - { - Id how = solv->job.elements[i]; - Id what, select; - if (installed && (how & SOLVER_JOBMASK) == SOLVER_USERINSTALLED) - { - if (!userinstalled.size) - map_grow(&userinstalled, installed->end - installed->start); - what = solv->job.elements[i + 1]; - select = how & SOLVER_SELECTMASK; - if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid)) - { - FOR_REPO_SOLVABLES(installed, p, s) - MAPSET(&userinstalled, p - installed->start); - } - FOR_JOB_SELECT(p, pp, select, what) - if (pool->solvables[p].repo == installed) - MAPSET(&userinstalled, p - installed->start); - continue; - } - if ((how & SOLVER_JOBMASK) != SOLVER_INSTALL) - continue; - if ((how & SOLVER_NOTBYUSER) != 0) - continue; - what = solv->job.elements[i + 1]; - select = how & SOLVER_SELECTMASK; - FOR_JOB_SELECT(p, pp, select, what) - if (solv->decisionmap[p] > 0) - { - queue_push(q, p); -#ifdef ENABLE_LINKED_PKGS - if (has_package_link(pool, pool->solvables + p)) - { - int j; - Queue lq; - queue_init(&lq); - find_package_link(pool, pool->solvables + p, 0, &lq, 0, 0); - for (j = 0; j < lq.count; j++) - if (solv->decisionmap[lq.elements[j]] > 0) - queue_push(q, lq.elements[j]); - } -#endif - } - } - /* now process updates of userinstalled packages */ - if (installed && userinstalled.size) - { - for (i = 1; i < solv->decisionq.count; i++) - { - p = solv->decisionq.elements[i]; - if (p <= 0) - continue; - s = pool->solvables + p; - if (!s->repo) - continue; - if (s->repo == installed) - { - if (MAPTST(&userinstalled, p - installed->start)) - queue_push(q, p); - continue; - } - /* new package, check if we replace a userinstalled one */ - FOR_PROVIDES(p2, pp, s->name) - { - Solvable *ps = pool->solvables + p2; - if (p2 == p || ps->repo != installed || !MAPTST(&userinstalled, p2 - installed->start)) - continue; - if (!pool->implicitobsoleteusesprovides && s->name != ps->name) - continue; - if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps)) - continue; - queue_push(q, p); - break; - } - if (!p2 && s->repo != installed && s->obsoletes) - { - Id obs, *obsp = s->repo->idarraydata + s->obsoletes; - while ((obs = *obsp++) != 0) - { - FOR_PROVIDES(p2, pp, obs) - { - Solvable *ps = pool->solvables + p2; - if (p2 == p || ps->repo != installed || !MAPTST(&userinstalled, p2 - installed->start)) - continue; - if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs)) - continue; - if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps)) - continue; - queue_push(q, p); - break; - } - if (p2) - break; - } - } - } - } - map_free(&userinstalled); - - /* convert to desired output format */ - if ((flags & GET_USERINSTALLED_NAMEARCH) != 0) - { - int qcount = q->count; - queue_insertn(q, 0, qcount, 0); - for (i = j = 0; i < qcount; i++) - { - s = pool->solvables + q->elements[i + qcount]; - q->elements[j++] = s->name; - q->elements[j++] = s->arch; - } - } - else if ((flags & GET_USERINSTALLED_NAMES) != 0) - { - for (i = 0; i < q->count; i++) - { - s = pool->solvables + q->elements[i]; - q->elements[i] = s->name; - } - } - /* sort and unify */ - get_userinstalled_sort_uniq(pool, q, flags); - - /* invert if asked for */ - if ((flags & GET_USERINSTALLED_INVERTED) != 0) - { - /* first generate queue with all installed packages */ - Queue invq; - queue_init(&invq); - for (i = 1; i < solv->decisionq.count; i++) - { - p = solv->decisionq.elements[i]; - if (p <= 0) - continue; - s = pool->solvables + p; - if (!s->repo) - continue; - if ((flags & GET_USERINSTALLED_NAMEARCH) != 0) - queue_push2(&invq, s->name, s->arch); - else if ((flags & GET_USERINSTALLED_NAMES) != 0) - queue_push(&invq, s->name); - else - queue_push(&invq, p); - } - /* push q on invq, just in case... */ - queue_insertn(&invq, invq.count, q->count, q->elements); - get_userinstalled_sort_uniq(pool, &invq, flags); - /* subtract queues (easy as they are sorted and invq is a superset of q) */ - if ((flags & GET_USERINSTALLED_NAMEARCH) != 0) - { - if (q->count) - { - for (i = j = 0; i < invq.count; i += 2) - if (invq.elements[i] == q->elements[j] && invq.elements[i + 1] == q->elements[j + 1]) - { - invq.elements[i] = invq.elements[i + 1] = 0; - j += 2; - if (j >= q->count) - break; - } - queue_empty(q); - } - for (i = 0; i < invq.count; i += 2) - if (invq.elements[i]) - queue_push2(q, invq.elements[i], invq.elements[i + 1]); - } - else - { - if (q->count) - { - for (i = j = 0; i < invq.count; i++) - if (invq.elements[i] == q->elements[j]) - { - invq.elements[i] = 0; - if (++j >= q->count) - break; - } - queue_empty(q); - } - for (i = 0; i < invq.count; i++) - if (invq.elements[i]) - queue_push(q, invq.elements[i]); - } - queue_free(&invq); - } -} - -void -pool_add_userinstalled_jobs(Pool *pool, Queue *q, Queue *job, int flags) -{ - int i; - - if ((flags & GET_USERINSTALLED_INVERTED) != 0) - { - Queue invq; - Id p, lastid; - Solvable *s; - int bad; - if (!pool->installed) - return; - queue_init(&invq); - if ((flags & GET_USERINSTALLED_NAMEARCH) != 0) - flags &= ~GET_USERINSTALLED_NAMES; /* just in case */ - FOR_REPO_SOLVABLES(pool->installed, p, s) - queue_push(&invq, flags & GET_USERINSTALLED_NAMES ? s->name : p); - if ((flags & GET_USERINSTALLED_NAMEARCH) != 0) - { - /* for namearch we convert to packages */ - namearch2solvables(pool, q, &invq, 0); - get_userinstalled_sort_uniq(pool, &invq, flags); - namearch2solvables(pool, q, &invq, 0); - flags = 0; - } - else - { - queue_insertn(&invq, invq.count, q->count, q->elements); - get_userinstalled_sort_uniq(pool, &invq, flags); - /* now the fun part, add q again, sort, and remove all dups */ - queue_insertn(&invq, invq.count, q->count, q->elements); - } - if (invq.count > 1) - { - if ((flags & GET_USERINSTALLED_NAMES) != 0) - solv_sort(invq.elements, invq.count, sizeof(Id), get_userinstalled_cmp_names, pool); - else - solv_sort(invq.elements, invq.count, sizeof(Id), get_userinstalled_cmp, 0); - } - lastid = -1; - bad = 1; - for (i = 0; i < invq.count; i++) - { - if (invq.elements[i] == lastid) - { - bad = 1; - continue; - } - if (!bad) - queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), lastid); - bad = 0; - lastid = invq.elements[i]; - } - if (!bad) - queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), lastid); - queue_free(&invq); - } - else - { - if (flags & GET_USERINSTALLED_NAMEARCH) - namearch2solvables(pool, q, job, SOLVER_USERINSTALLED | SOLVER_SOLVABLE); - else - { - for (i = 0; i < q->count; i++) - queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), q->elements[i]); - } - } -} - int solver_alternatives_count(Solver *solv) { |