summaryrefslogtreecommitdiff
path: root/src/solver.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/solver.c')
-rw-r--r--src/solver.c699
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)
{