trivial_installable: check vendor of affected package to see if a patch should be...
[platform/upstream/libsolv.git] / src / solver.c
1 /*
2  * Copyright (c) 2007-2008, Novell Inc.
3  *
4  * This program is licensed under the BSD license, read LICENSE.BSD
5  * for further information
6  */
7
8 /*
9  * solver.c
10  *
11  * SAT based dependency solver
12  */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <string.h>
18 #include <assert.h>
19
20 #include "solver.h"
21 #include "solver_private.h"
22 #include "bitmap.h"
23 #include "pool.h"
24 #include "util.h"
25 #include "policy.h"
26 #include "poolarch.h"
27 #include "solverdebug.h"
28
29 #define RULES_BLOCK 63
30
31 /********************************************************************
32  *
33  * dependency check helpers
34  *
35  */
36
37 /*-------------------------------------------------------------------
38  * handle split provides
39  *
40  * a splitprovides dep looks like
41  *     namespace:splitprovides(pkg REL_WITH path)
42  * and is only true if pkg is installed and contains the specified path.
43  * we also make sure that pkg is selected for an update, otherwise the
44  * update would always be forced onto the user.
45  */
46 int
47 solver_splitprovides(Solver *solv, Id dep)
48 {
49   Pool *pool = solv->pool;
50   Id p, pp;
51   Reldep *rd;
52   Solvable *s;
53
54   if (!solv->dosplitprovides || !solv->installed || (!solv->updatemap_all && !solv->updatemap.size))
55     return 0;
56   if (!ISRELDEP(dep))
57     return 0;
58   rd = GETRELDEP(pool, dep);
59   if (rd->flags != REL_WITH)
60     return 0;
61   FOR_PROVIDES(p, pp, dep)
62     {
63       /* here we have packages that provide the correct name and contain the path,
64        * now do extra filtering */
65       s = pool->solvables + p;
66       if (s->repo == solv->installed && s->name == rd->name &&
67           (solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, p - solv->installed->start))))
68         return 1;
69     }
70   return 0;
71 }
72
73
74 /*-------------------------------------------------------------------
75  * solver_dep_installed
76  */
77
78 int
79 solver_dep_installed(Solver *solv, Id dep)
80 {
81 #if 0
82   Pool *pool = solv->pool;
83   Id p, pp;
84
85   if (ISRELDEP(dep))
86     {
87       Reldep *rd = GETRELDEP(pool, dep);
88       if (rd->flags == REL_AND)
89         {
90           if (!solver_dep_installed(solv, rd->name))
91             return 0;
92           return solver_dep_installed(solv, rd->evr);
93         }
94       if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_INSTALLED)
95         return solver_dep_installed(solv, rd->evr);
96     }
97   FOR_PROVIDES(p, pp, dep)
98     {
99       if (p == SYSTEMSOLVABLE || (solv->installed && pool->solvables[p].repo == solv->installed))
100         return 1;
101     }
102 #endif
103   return 0;
104 }
105
106 /* mirrors solver_dep_installed, but returns 2 if a
107  * dependency listed in solv->installsuppdepq was involved */
108 static int
109 solver_check_installsuppdepq_dep(Solver *solv, Id dep)
110 {
111   Pool *pool = solv->pool;
112   Id p, pp;
113   Queue *q;
114
115   if (ISRELDEP(dep))
116     {
117       Reldep *rd = GETRELDEP(pool, dep);
118       if (rd->flags == REL_AND)
119         {
120           int r2, r1 = solver_check_installsuppdepq_dep(solv, rd->name);
121           if (!r1)
122             return 0;
123           r2 = solver_check_installsuppdepq_dep(solv, rd->evr);
124           if (!r2)
125             return 0;
126           return r1 == 2 || r2 == 2 ? 2 : 1;
127         }
128       if (rd->flags == REL_OR)
129         {
130           int r2, r1 = solver_check_installsuppdepq_dep(solv, rd->name);
131           r2 = solver_check_installsuppdepq_dep(solv, rd->evr);
132           if (!r1 && !r2)
133             return 0;
134           return r1 == 2 || r2 == 2 ? 2 : 1;
135         }
136       if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES)
137         return solver_splitprovides(solv, rd->evr);
138       if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_INSTALLED)
139         return solver_dep_installed(solv, rd->evr);
140       if (rd->flags == REL_NAMESPACE && (q = solv->installsuppdepq) != 0)
141         {
142           int i;
143           for (i = 0; i < q->count; i++)
144             if (q->elements[i] == dep || q->elements[i] == rd->name)
145               return 2;
146         }
147     }
148   FOR_PROVIDES(p, pp, dep)
149     if (solv->decisionmap[p] > 0)
150       return 1;
151   return 0;
152 }
153
154 static int
155 solver_check_installsuppdepq(Solver *solv, Solvable *s)
156 {
157   Id sup, *supp;
158   supp = s->repo->idarraydata + s->supplements;
159   while ((sup = *supp++) != 0)
160     if (solver_check_installsuppdepq_dep(solv, sup) == 2)
161       return 1;
162   return 0;
163 }
164
165 static Id
166 autouninstall(Solver *solv, Id *problem)
167 {
168   Pool *pool = solv->pool;
169   int i;
170   int lastfeature = 0, lastupdate = 0;
171   Id v;
172   Id extraflags = -1;
173
174   for (i = 0; (v = problem[i]) != 0; i++)
175     {
176       if (v < 0)
177         extraflags &= solv->job.elements[-v - 1];
178       if (v >= solv->featurerules && v < solv->featurerules_end)
179         if (v > lastfeature)
180           lastfeature = v;
181       if (v >= solv->updaterules && v < solv->updaterules_end)
182         {
183           /* check if identical to feature rule */
184           Id p = solv->rules[v].p;
185           if (p <= 0)
186             continue;
187           Rule *r = solv->rules + solv->featurerules + (p - solv->installed->start);
188           if (!r->p)
189             {
190               /* update rule == feature rule */
191               if (v > lastfeature)
192                 lastfeature = v;
193               continue;
194             }
195           if (v > lastupdate)
196             lastupdate = v;
197         }
198     }
199   if (!lastupdate && !lastfeature)
200     return 0;
201   v = lastupdate ? lastupdate : lastfeature;
202   POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "allowuninstall disabling ");
203   solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + v);
204   solver_disableproblem(solv, v);
205   if (extraflags != -1 && (extraflags & SOLVER_CLEANDEPS) != 0 && solv->cleandepsmap.size)
206     {
207       /* add the package to the updatepkgs list, this will automatically turn
208        * on cleandeps mode */
209       Id p = solv->rules[v].p;
210       if (!solv->cleandeps_updatepkgs)
211         {
212           solv->cleandeps_updatepkgs = solv_calloc(1, sizeof(Queue));
213           queue_init(solv->cleandeps_updatepkgs);
214         }
215       if (p > 0)
216         {
217           int oldupdatepkgscnt = solv->cleandeps_updatepkgs->count;
218           queue_pushunique(solv->cleandeps_updatepkgs, p);
219           if (solv->cleandeps_updatepkgs->count != oldupdatepkgscnt)
220             solver_disablepolicyrules(solv);
221         }
222     }
223   return v;
224 }
225
226 /************************************************************************/
227
228 /*
229  * enable/disable learnt rules 
230  *
231  * we have enabled or disabled some of our rules. We now reenable all
232  * of our learnt rules except the ones that were learnt from rules that
233  * are now disabled.
234  */
235 static void
236 enabledisablelearntrules(Solver *solv)
237 {
238   Pool *pool = solv->pool;
239   Rule *r;
240   Id why, *whyp;
241   int i;
242
243   POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "enabledisablelearntrules called\n");
244   for (i = solv->learntrules, r = solv->rules + i; i < solv->nrules; i++, r++)
245     {
246       whyp = solv->learnt_pool.elements + solv->learnt_why.elements[i - solv->learntrules];
247       while ((why = *whyp++) != 0)
248         {
249           assert(why > 0 && why < i);
250           if (solv->rules[why].d < 0)
251             break;
252         }
253       /* why != 0: we found a disabled rule, disable the learnt rule */
254       if (why && r->d >= 0)
255         {
256           IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
257             {
258               POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "disabling ");
259               solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r);
260             }
261           solver_disablerule(solv, r);
262         }
263       else if (!why && r->d < 0)
264         {
265           IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
266             {
267               POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "re-enabling ");
268               solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r);
269             }
270           solver_enablerule(solv, r);
271         }
272     }
273 }
274
275
276 /*
277  * make assertion rules into decisions
278  * 
279  * Go through rules and add direct assertions to the decisionqueue.
280  * If we find a conflict, disable rules and add them to problem queue.
281  */
282
283 static void
284 makeruledecisions(Solver *solv)
285 {
286   Pool *pool = solv->pool;
287   int i, ri, ii;
288   Rule *r, *rr;
289   Id v, vv;
290   int decisionstart;
291   int record_proof = 1;
292   int oldproblemcount;
293   int havedisabled = 0;
294
295   /* The system solvable is always installed first */
296   assert(solv->decisionq.count == 0);
297   queue_push(&solv->decisionq, SYSTEMSOLVABLE);
298   queue_push(&solv->decisionq_why, 0);
299   solv->decisionmap[SYSTEMSOLVABLE] = 1;        /* installed at level '1' */
300
301   decisionstart = solv->decisionq.count;
302   for (;;)
303     {
304       /* if we needed to re-run, back up decisions to decisionstart */
305       while (solv->decisionq.count > decisionstart)
306         {
307           v = solv->decisionq.elements[--solv->decisionq.count];
308           --solv->decisionq_why.count;
309           vv = v > 0 ? v : -v;
310           solv->decisionmap[vv] = 0;
311         }
312
313       /* note that the ruleassertions queue is ordered */
314       for (ii = 0; ii < solv->ruleassertions.count; ii++)
315         {
316           ri = solv->ruleassertions.elements[ii];
317           r = solv->rules + ri;
318             
319           if (havedisabled && ri >= solv->learntrules)
320             {
321               /* just started with learnt rule assertions. If we have disabled
322                * some rules, adapt the learnt rule status */
323               enabledisablelearntrules(solv);
324               havedisabled = 0;
325             }
326             
327           if (r->d < 0 || !r->p || r->w2)       /* disabled, dummy or no assertion */
328             continue;
329
330           /* do weak rules in phase 2 */
331           if (ri < solv->learntrules && MAPTST(&solv->weakrulemap, ri))
332             continue;
333
334           v = r->p;
335           vv = v > 0 ? v : -v;
336             
337           if (!solv->decisionmap[vv])          /* if not yet decided */
338             {
339               queue_push(&solv->decisionq, v);
340               queue_push(&solv->decisionq_why, r - solv->rules);
341               solv->decisionmap[vv] = v > 0 ? 1 : -1;
342               IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
343                 {
344                   Solvable *s = solv->pool->solvables + vv;
345                   if (v < 0)
346                     POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "conflicting %s (assertion)\n", pool_solvable2str(solv->pool, s));
347                   else
348                     POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "installing  %s (assertion)\n", pool_solvable2str(solv->pool, s));
349                 }
350               continue;
351             }
352
353           /* check against previous decision: is there a conflict? */
354           if (v > 0 && solv->decisionmap[vv] > 0)    /* ok to install */
355             continue;
356           if (v < 0 && solv->decisionmap[vv] < 0)    /* ok to remove */
357             continue;
358             
359           /*
360            * found a conflict!
361            * 
362            * The rule (r) we're currently processing says something
363            * different (v = r->p) than a previous decision (decisionmap[abs(v)])
364            * on this literal
365            */
366             
367           if (ri >= solv->learntrules)
368             {
369               /* conflict with a learnt rule */
370               /* can happen when packages cannot be installed for multiple reasons. */
371               /* we disable the learnt rule in this case */
372               /* (XXX: we should really call analyze_unsolvable_rule here!) */
373               solver_disablerule(solv, r);
374               continue;
375             }
376             
377           /*
378            * find the decision which is the "opposite" of the rule
379            */
380           for (i = 0; i < solv->decisionq.count; i++)
381             if (solv->decisionq.elements[i] == -v)
382               break;
383           assert(i < solv->decisionq.count);         /* assert that we found it */
384           oldproblemcount = solv->problems.count;
385             
386           /*
387            * conflict with system solvable ?
388            */
389           if (v == -SYSTEMSOLVABLE)
390             {
391               if (record_proof)
392                 {
393                   queue_push(&solv->problems, solv->learnt_pool.count);
394                   queue_push(&solv->learnt_pool, ri);
395                   queue_push(&solv->learnt_pool, 0);
396                 }
397               else
398                 queue_push(&solv->problems, 0);
399               POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflict with system solvable, disabling rule #%d\n", ri);
400               if  (ri >= solv->jobrules && ri < solv->jobrules_end)
401                 v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1);
402               else
403                 v = ri;
404               queue_push(&solv->problems, v);
405               queue_push(&solv->problems, 0);
406               if (solv->allowuninstall && v >= solv->featurerules && v < solv->updaterules_end)
407                 solv->problems.count = oldproblemcount;
408               solver_disableproblem(solv, v);
409               havedisabled = 1;
410               break;    /* start over */
411             }
412
413           assert(solv->decisionq_why.elements[i] > 0);
414
415           /*
416            * conflict with an rpm rule ?
417            */
418           if (solv->decisionq_why.elements[i] < solv->rpmrules_end)
419             {
420               if (record_proof)
421                 {
422                   queue_push(&solv->problems, solv->learnt_pool.count);
423                   queue_push(&solv->learnt_pool, ri);
424                   queue_push(&solv->learnt_pool, solv->decisionq_why.elements[i]);
425                   queue_push(&solv->learnt_pool, 0);
426                 }
427               else
428                 queue_push(&solv->problems, 0);
429               assert(v > 0 || v == -SYSTEMSOLVABLE);
430               POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflict with rpm rule, disabling rule #%d\n", ri);
431               if (ri >= solv->jobrules && ri < solv->jobrules_end)
432                 v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1);
433               else
434                 v = ri;
435               queue_push(&solv->problems, v);
436               queue_push(&solv->problems, 0);
437               if (solv->allowuninstall && v >= solv->featurerules && v < solv->updaterules_end)
438                 solv->problems.count = oldproblemcount;
439               solver_disableproblem(solv, v);
440               havedisabled = 1;
441               break;    /* start over */
442             }
443
444           /*
445            * conflict with another job or update/feature rule
446            */
447             
448           /* record proof */
449           if (record_proof)
450             {
451               queue_push(&solv->problems, solv->learnt_pool.count);
452               queue_push(&solv->learnt_pool, ri);
453               queue_push(&solv->learnt_pool, solv->decisionq_why.elements[i]);
454               queue_push(&solv->learnt_pool, 0);
455             }
456           else
457             queue_push(&solv->problems, 0);
458
459           POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflicting update/job assertions over literal %d\n", vv);
460
461           /*
462            * push all of our rules (can only be feature or job rules)
463            * asserting this literal on the problem stack
464            */
465           for (i = solv->featurerules, rr = solv->rules + i; i < solv->learntrules; i++, rr++)
466             {
467               if (rr->d < 0                          /* disabled */
468                   || rr->w2)                         /*  or no assertion */
469                 continue;
470               if (rr->p != vv                        /* not affecting the literal */
471                   && rr->p != -vv)
472                 continue;
473               if (MAPTST(&solv->weakrulemap, i))     /* weak: silently ignore */
474                 continue;
475                 
476               POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, " - disabling rule #%d\n", i);
477               solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + i);
478                 
479               v = i;
480               if (i >= solv->jobrules && i < solv->jobrules_end)
481                 v = -(solv->ruletojob.elements[i - solv->jobrules] + 1);
482               queue_push(&solv->problems, v);
483             }
484           queue_push(&solv->problems, 0);
485
486           if (solv->allowuninstall && (v = autouninstall(solv, solv->problems.elements + oldproblemcount + 1)) != 0)
487             solv->problems.count = oldproblemcount;
488
489           for (i = oldproblemcount + 1; i < solv->problems.count - 1; i++)
490             solver_disableproblem(solv, solv->problems.elements[i]);
491           havedisabled = 1;
492           break;        /* start over */
493         }
494       if (ii < solv->ruleassertions.count)
495         continue;
496
497       /*
498        * phase 2: now do the weak assertions
499        */
500       for (ii = 0; ii < solv->ruleassertions.count; ii++)
501         {
502           ri = solv->ruleassertions.elements[ii];
503           r = solv->rules + ri;
504           if (r->d < 0 || r->w2)                         /* disabled or no assertion */
505             continue;
506           if (ri >= solv->learntrules || !MAPTST(&solv->weakrulemap, ri))       /* skip non-weak */
507             continue;
508           v = r->p;
509           vv = v > 0 ? v : -v;
510
511           if (!solv->decisionmap[vv])          /* if not yet decided */
512             {
513               queue_push(&solv->decisionq, v);
514               queue_push(&solv->decisionq_why, r - solv->rules);
515               solv->decisionmap[vv] = v > 0 ? 1 : -1;
516               IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
517                 {
518                   Solvable *s = solv->pool->solvables + vv;
519                   if (v < 0)
520                     POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "conflicting %s (weak assertion)\n", pool_solvable2str(solv->pool, s));
521                   else
522                     POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "installing  %s (weak assertion)\n", pool_solvable2str(solv->pool, s));
523                 }
524               continue;
525             }
526           /* check against previous decision: is there a conflict? */
527           if (v > 0 && solv->decisionmap[vv] > 0)
528             continue;
529           if (v < 0 && solv->decisionmap[vv] < 0)
530             continue;
531             
532           POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "assertion conflict, but I am weak, disabling ");
533           solver_printrule(solv, SOLV_DEBUG_UNSOLVABLE, r);
534
535           if (ri >= solv->jobrules && ri < solv->jobrules_end)
536             v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1);
537           else
538             v = ri;
539           solver_disableproblem(solv, v);
540           if (v < 0)
541             solver_reenablepolicyrules(solv, -v);
542           havedisabled = 1;
543           break;        /* start over */
544         }
545       if (ii == solv->ruleassertions.count)
546         break;  /* finished! */
547     }
548 }
549
550
551 /********************************************************************/
552 /* watches */
553
554
555 /*-------------------------------------------------------------------
556  * makewatches
557  *
558  * initial setup for all watches
559  */
560
561 static void
562 makewatches(Solver *solv)
563 {
564   Rule *r;
565   int i;
566   int nsolvables = solv->pool->nsolvables;
567
568   solv_free(solv->watches);
569                                        /* lower half for removals, upper half for installs */
570   solv->watches = solv_calloc(2 * nsolvables, sizeof(Id));
571 #if 1
572   /* do it reverse so rpm rules get triggered first (XXX: obsolete?) */
573   for (i = 1, r = solv->rules + solv->nrules - 1; i < solv->nrules; i++, r--)
574 #else
575   for (i = 1, r = solv->rules + 1; i < solv->nrules; i++, r++)
576 #endif
577     {
578       if (!r->w2)               /* assertions do not need watches */
579         continue;
580
581       /* see addwatches_rule(solv, r) */
582       r->n1 = solv->watches[nsolvables + r->w1];
583       solv->watches[nsolvables + r->w1] = r - solv->rules;
584
585       r->n2 = solv->watches[nsolvables + r->w2];
586       solv->watches[nsolvables + r->w2] = r - solv->rules;
587     }
588 }
589
590
591 /*-------------------------------------------------------------------
592  *
593  * add watches (for a new learned rule)
594  * sets up watches for a single rule
595  * 
596  * see also makewatches() above.
597  */
598
599 static inline void
600 addwatches_rule(Solver *solv, Rule *r)
601 {
602   int nsolvables = solv->pool->nsolvables;
603
604   r->n1 = solv->watches[nsolvables + r->w1];
605   solv->watches[nsolvables + r->w1] = r - solv->rules;
606
607   r->n2 = solv->watches[nsolvables + r->w2];
608   solv->watches[nsolvables + r->w2] = r - solv->rules;
609 }
610
611
612 /********************************************************************/
613 /*
614  * rule propagation
615  */
616
617
618 /* shortcuts to check if a literal (positive or negative) assignment
619  * evaluates to 'true' or 'false'
620  */
621 #define DECISIONMAP_TRUE(p) ((p) > 0 ? (decisionmap[p] > 0) : (decisionmap[-p] < 0))
622 #define DECISIONMAP_FALSE(p) ((p) > 0 ? (decisionmap[p] < 0) : (decisionmap[-p] > 0))
623 #define DECISIONMAP_UNDEF(p) (decisionmap[(p) > 0 ? (p) : -(p)] == 0)
624
625 /*-------------------------------------------------------------------
626  * 
627  * propagate
628  *
629  * make decision and propagate to all rules
630  * 
631  * Evaluate each term affected by the decision (linked through watches).
632  * If we find unit rules we make new decisions based on them.
633  * 
634  * return : 0 = everything is OK
635  *          rule = conflict found in this rule
636  */
637
638 static Rule *
639 propagate(Solver *solv, int level)
640 {
641   Pool *pool = solv->pool;
642   Id *rp, *next_rp;           /* rule pointer, next rule pointer in linked list */
643   Rule *r;                    /* rule */
644   Id p, pkg, other_watch;
645   Id *dp;
646   Id *decisionmap = solv->decisionmap;
647     
648   Id *watches = solv->watches + pool->nsolvables;   /* place ptr in middle */
649
650   POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "----- propagate -----\n");
651
652   /* foreach non-propagated decision */
653   while (solv->propagate_index < solv->decisionq.count)
654     {
655         /*
656          * 'pkg' was just decided
657          * negate because our watches trigger if literal goes FALSE
658          */
659       pkg = -solv->decisionq.elements[solv->propagate_index++];
660         
661       IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
662         {
663           POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "propagate for decision %d level %d\n", -pkg, level);
664           solver_printruleelement(solv, SOLV_DEBUG_PROPAGATE, 0, -pkg);
665         }
666
667       /* foreach rule where 'pkg' is now FALSE */
668       for (rp = watches + pkg; *rp; rp = next_rp)
669         {
670           r = solv->rules + *rp;
671           if (r->d < 0)
672             {
673               /* rule is disabled, goto next */
674               if (pkg == r->w1)
675                 next_rp = &r->n1;
676               else
677                 next_rp = &r->n2;
678               continue;
679             }
680
681           IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
682             {
683               POOL_DEBUG(SOLV_DEBUG_PROPAGATE,"  watch triggered ");
684               solver_printrule(solv, SOLV_DEBUG_PROPAGATE, r);
685             }
686
687             /* 'pkg' was just decided (was set to FALSE)
688              * 
689              *  now find other literal watch, check clause
690              *   and advance on linked list
691              */
692           if (pkg == r->w1)
693             {
694               other_watch = r->w2;
695               next_rp = &r->n1;
696             }
697           else
698             {
699               other_watch = r->w1;
700               next_rp = &r->n2;
701             }
702             
703             /* 
704              * This term is already true (through the other literal)
705              * so we have nothing to do
706              */
707           if (DECISIONMAP_TRUE(other_watch))
708             continue;
709
710             /*
711              * The other literal is FALSE or UNDEF
712              * 
713              */
714             
715           if (r->d)
716             {
717               /* Not a binary clause, try to move our watch.
718                * 
719                * Go over all literals and find one that is
720                *   not other_watch
721                *   and not FALSE
722                * 
723                * (TRUE is also ok, in that case the rule is fulfilled)
724                */
725               if (r->p                                /* we have a 'p' */
726                   && r->p != other_watch              /* which is not watched */
727                   && !DECISIONMAP_FALSE(r->p))        /* and not FALSE */
728                 {
729                   p = r->p;
730                 }
731               else                                    /* go find a 'd' to make 'true' */
732                 {
733                   /* foreach p in 'd'
734                      we just iterate sequentially, doing it in another order just changes the order of decisions, not the decisions itself
735                    */
736                   for (dp = pool->whatprovidesdata + r->d; (p = *dp++) != 0;)
737                     {
738                       if (p != other_watch              /* which is not watched */
739                           && !DECISIONMAP_FALSE(p))     /* and not FALSE */
740                         break;
741                     }
742                 }
743
744               if (p)
745                 {
746                   /*
747                    * if we found some p that is UNDEF or TRUE, move
748                    * watch to it
749                    */
750                   IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
751                     {
752                       if (p > 0)
753                         POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "    -> move w%d to %s\n", (pkg == r->w1 ? 1 : 2), pool_solvid2str(pool, p));
754                       else
755                         POOL_DEBUG(SOLV_DEBUG_PROPAGATE,"    -> move w%d to !%s\n", (pkg == r->w1 ? 1 : 2), pool_solvid2str(pool, -p));
756                     }
757                     
758                   *rp = *next_rp;
759                   next_rp = rp;
760                     
761                   if (pkg == r->w1)
762                     {
763                       r->w1 = p;
764                       r->n1 = watches[p];
765                     }
766                   else
767                     {
768                       r->w2 = p;
769                       r->n2 = watches[p];
770                     }
771                   watches[p] = r - solv->rules;
772                   continue;
773                 }
774               /* search failed, thus all unwatched literals are FALSE */
775                 
776             } /* not binary */
777             
778           /*
779            * unit clause found, set literal other_watch to TRUE
780            */
781
782           if (DECISIONMAP_FALSE(other_watch))      /* check if literal is FALSE */
783             return r;                              /* eek, a conflict! */
784             
785           IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
786             {
787               POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "   unit ");
788               solver_printrule(solv, SOLV_DEBUG_PROPAGATE, r);
789             }
790
791           if (other_watch > 0)
792             decisionmap[other_watch] = level;    /* install! */
793           else
794             decisionmap[-other_watch] = -level;  /* remove! */
795             
796           queue_push(&solv->decisionq, other_watch);
797           queue_push(&solv->decisionq_why, r - solv->rules);
798
799           IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
800             {
801               if (other_watch > 0)
802                 POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "    -> decided to install %s\n", pool_solvid2str(pool, other_watch));
803               else
804                 POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "    -> decided to conflict %s\n", pool_solvid2str(pool, -other_watch));
805             }
806             
807         } /* foreach rule involving 'pkg' */
808         
809     } /* while we have non-decided decisions */
810     
811   POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "----- propagate end-----\n");
812
813   return 0;     /* all is well */
814 }
815
816
817 /********************************************************************/
818 /* Analysis */
819
820 /*-------------------------------------------------------------------
821  * 
822  * analyze
823  *   and learn
824  */
825
826 static int
827 analyze(Solver *solv, int level, Rule *c, int *pr, int *dr, int *whyp)
828 {
829   Pool *pool = solv->pool;
830   Queue r;
831   Id r_buf[4];
832   int rlevel = 1;
833   Map seen;             /* global? */
834   Id d, v, vv, *dp, why;
835   int l, i, idx;
836   int num = 0, l1num = 0;
837   int learnt_why = solv->learnt_pool.count;
838   Id *decisionmap = solv->decisionmap;
839
840   queue_init_buffer(&r, r_buf, sizeof(r_buf)/sizeof(*r_buf));
841
842   POOL_DEBUG(SOLV_DEBUG_ANALYZE, "ANALYZE at %d ----------------------\n", level);
843   map_init(&seen, pool->nsolvables);
844   idx = solv->decisionq.count;
845   for (;;)
846     {
847       IF_POOLDEBUG (SOLV_DEBUG_ANALYZE)
848         solver_printruleclass(solv, SOLV_DEBUG_ANALYZE, c);
849       queue_push(&solv->learnt_pool, c - solv->rules);
850       d = c->d < 0 ? -c->d - 1 : c->d;
851       dp = d ? pool->whatprovidesdata + d : 0;
852       /* go through all literals of the rule */
853       for (i = -1; ; i++)
854         {
855           if (i == -1)
856             v = c->p;
857           else if (d == 0)
858             v = i ? 0 : c->w2;
859           else
860             v = *dp++;
861           if (v == 0)
862             break;
863
864           if (DECISIONMAP_TRUE(v))      /* the one true literal */
865             continue;
866           vv = v > 0 ? v : -v;
867           if (MAPTST(&seen, vv))
868             continue;
869           l = solv->decisionmap[vv];
870           if (l < 0)
871             l = -l;
872           MAPSET(&seen, vv);            /* mark that we also need to look at this literal */
873           if (l == 1)
874             l1num++;                    /* need to do this one in level1 pass */
875           else if (l == level)
876             num++;                      /* need to do this one as well */
877           else
878             {
879               queue_push(&r, v);        /* not level1 or conflict level, add to new rule */
880               if (l > rlevel)
881                 rlevel = l;
882             }
883         }
884 l1retry:
885       if (!num && !--l1num)
886         break;  /* all level 1 literals done */
887
888       /* find the next literal to investigate */
889       /* (as num + l1num > 0, we know that we'll always find one) */
890       for (;;)
891         {
892           assert(idx > 0);
893           v = solv->decisionq.elements[--idx];
894           vv = v > 0 ? v : -v;
895           if (MAPTST(&seen, vv))
896             break;
897         }
898       MAPCLR(&seen, vv);
899
900       if (num && --num == 0)
901         {
902           *pr = -v;     /* so that v doesn't get lost */
903           if (!l1num)
904             break;
905           POOL_DEBUG(SOLV_DEBUG_ANALYZE, "got %d involved level 1 decisions\n", l1num);
906           /* clear non-l1 bits from seen map */
907           for (i = 0; i < r.count; i++)
908             {
909               v = r.elements[i];
910               MAPCLR(&seen, v > 0 ? v : -v);
911             }
912           /* only level 1 marks left in seen map */
913           l1num++;      /* as l1retry decrements it */
914           goto l1retry;
915         }
916
917       why = solv->decisionq_why.elements[idx];
918       if (why <= 0)     /* just in case, maybe for SYSTEMSOLVABLE */
919         goto l1retry;
920       c = solv->rules + why;
921     }
922   map_free(&seen);
923
924   if (r.count == 0)
925     *dr = 0;
926   else if (r.count == 1 && r.elements[0] < 0)
927     *dr = r.elements[0];
928   else
929     *dr = pool_queuetowhatprovides(pool, &r);
930   IF_POOLDEBUG (SOLV_DEBUG_ANALYZE)
931     {
932       POOL_DEBUG(SOLV_DEBUG_ANALYZE, "learned rule for level %d (am %d)\n", rlevel, level);
933       solver_printruleelement(solv, SOLV_DEBUG_ANALYZE, 0, *pr);
934       for (i = 0; i < r.count; i++)
935         solver_printruleelement(solv, SOLV_DEBUG_ANALYZE, 0, r.elements[i]);
936     }
937   /* push end marker on learnt reasons stack */
938   queue_push(&solv->learnt_pool, 0);
939   if (whyp)
940     *whyp = learnt_why;
941   queue_free(&r);
942   solv->stats_learned++;
943   return rlevel;
944 }
945
946
947 /*-------------------------------------------------------------------
948  * 
949  * solver_reset
950  * 
951  * reset all solver decisions
952  * called after rules have been enabled/disabled
953  */
954
955 void
956 solver_reset(Solver *solv)
957 {
958   Pool *pool = solv->pool;
959   int i;
960   Id v;
961
962   /* rewind all decisions */
963   for (i = solv->decisionq.count - 1; i >= 0; i--)
964     {
965       v = solv->decisionq.elements[i];
966       solv->decisionmap[v > 0 ? v : -v] = 0;
967     }
968   solv->decisionq_why.count = 0;
969   solv->decisionq.count = 0;
970   solv->recommends_index = -1;
971   solv->propagate_index = 0;
972   solv->branches.count = 0;
973
974   /* adapt learnt rule status to new set of enabled/disabled rules */
975   enabledisablelearntrules(solv);
976
977   /* redo all assertion rule decisions */
978   makeruledecisions(solv);
979   POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "decisions so far: %d\n", solv->decisionq.count);
980 }
981
982
983 /*-------------------------------------------------------------------
984  * 
985  * analyze_unsolvable_rule
986  *
987  * recursion helper used by analyze_unsolvable
988  */
989
990 static void
991 analyze_unsolvable_rule(Solver *solv, Rule *r, Id *lastweakp, Map *rseen)
992 {
993   Pool *pool = solv->pool;
994   int i;
995   Id why = r - solv->rules;
996
997   IF_POOLDEBUG (SOLV_DEBUG_UNSOLVABLE)
998     solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, r);
999   if (solv->learntrules && why >= solv->learntrules)
1000     {
1001       if (MAPTST(rseen, why - solv->learntrules))
1002         return;
1003       MAPSET(rseen, why - solv->learntrules);
1004       for (i = solv->learnt_why.elements[why - solv->learntrules]; solv->learnt_pool.elements[i]; i++)
1005         if (solv->learnt_pool.elements[i] > 0)
1006           analyze_unsolvable_rule(solv, solv->rules + solv->learnt_pool.elements[i], lastweakp, rseen);
1007       return;
1008     }
1009   if (MAPTST(&solv->weakrulemap, why))
1010     if (!*lastweakp || why > *lastweakp)
1011       *lastweakp = why;
1012   /* do not add rpm rules to problem */
1013   if (why < solv->rpmrules_end)
1014     return;
1015   /* turn rule into problem */
1016   if (why >= solv->jobrules && why < solv->jobrules_end)
1017     why = -(solv->ruletojob.elements[why - solv->jobrules] + 1);
1018   /* normalize dup/infarch rules */
1019   if (why > solv->infarchrules && why < solv->infarchrules_end)
1020     {
1021       Id name = pool->solvables[-solv->rules[why].p].name;
1022       while (why > solv->infarchrules && pool->solvables[-solv->rules[why - 1].p].name == name)
1023         why--;
1024     }
1025   if (why > solv->duprules && why < solv->duprules_end)
1026     {
1027       Id name = pool->solvables[-solv->rules[why].p].name;
1028       while (why > solv->duprules && pool->solvables[-solv->rules[why - 1].p].name == name)
1029         why--;
1030     }
1031
1032   /* return if problem already countains our rule */
1033   if (solv->problems.count)
1034     {
1035       for (i = solv->problems.count - 1; i >= 0; i--)
1036         if (solv->problems.elements[i] == 0)    /* end of last problem reached? */
1037           break;
1038         else if (solv->problems.elements[i] == why)
1039           return;
1040     }
1041   queue_push(&solv->problems, why);
1042 }
1043
1044
1045 /*-------------------------------------------------------------------
1046  * 
1047  * analyze_unsolvable
1048  *
1049  * We know that the problem is not solvable. Record all involved
1050  * rules (i.e. the "proof") into solv->learnt_pool.
1051  * Record the learnt pool index and all non-rpm rules into
1052  * solv->problems. (Our solutions to fix the problems are to
1053  * disable those rules.)
1054  *
1055  * If the proof contains at least one weak rule, we disable the
1056  * last of them.
1057  *
1058  * Otherwise we return 0 if disablerules is not set or disable
1059  * _all_ of the problem rules and return 1.
1060  *
1061  * return: 1 - disabled some rules, try again
1062  *         0 - hopeless
1063  */
1064
1065 static int
1066 analyze_unsolvable(Solver *solv, Rule *cr, int disablerules)
1067 {
1068   Pool *pool = solv->pool;
1069   Rule *r;
1070   Map seen;             /* global to speed things up? */
1071   Map rseen;
1072   Id d, v, vv, *dp, why;
1073   int l, i, idx;
1074   Id *decisionmap = solv->decisionmap;
1075   int oldproblemcount;
1076   int oldlearntpoolcount;
1077   Id lastweak;
1078   int record_proof = 1;
1079
1080   POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "ANALYZE UNSOLVABLE ----------------------\n");
1081   solv->stats_unsolvable++;
1082   oldproblemcount = solv->problems.count;
1083   oldlearntpoolcount = solv->learnt_pool.count;
1084
1085   /* make room for proof index */
1086   /* must update it later, as analyze_unsolvable_rule would confuse
1087    * it with a rule index if we put the real value in already */
1088   queue_push(&solv->problems, 0);
1089
1090   r = cr;
1091   map_init(&seen, pool->nsolvables);
1092   map_init(&rseen, solv->learntrules ? solv->nrules - solv->learntrules : 0);
1093   if (record_proof)
1094     queue_push(&solv->learnt_pool, r - solv->rules);
1095   lastweak = 0;
1096   analyze_unsolvable_rule(solv, r, &lastweak, &rseen);
1097   d = r->d < 0 ? -r->d - 1 : r->d;
1098   dp = d ? pool->whatprovidesdata + d : 0;
1099   for (i = -1; ; i++)
1100     {
1101       if (i == -1)
1102         v = r->p;
1103       else if (d == 0)
1104         v = i ? 0 : r->w2;
1105       else
1106         v = *dp++;
1107       if (v == 0)
1108         break;
1109       if (DECISIONMAP_TRUE(v))  /* the one true literal */
1110           continue;
1111       vv = v > 0 ? v : -v;
1112       l = solv->decisionmap[vv];
1113       if (l < 0)
1114         l = -l;
1115       MAPSET(&seen, vv);
1116     }
1117   idx = solv->decisionq.count;
1118   while (idx > 0)
1119     {
1120       v = solv->decisionq.elements[--idx];
1121       vv = v > 0 ? v : -v;
1122       if (!MAPTST(&seen, vv))
1123         continue;
1124       why = solv->decisionq_why.elements[idx];
1125       assert(why > 0);
1126       if (record_proof)
1127         queue_push(&solv->learnt_pool, why);
1128       r = solv->rules + why;
1129       analyze_unsolvable_rule(solv, r, &lastweak, &rseen);
1130       d = r->d < 0 ? -r->d - 1 : r->d;
1131       dp = d ? pool->whatprovidesdata + d : 0;
1132       for (i = -1; ; i++)
1133         {
1134           if (i == -1)
1135             v = r->p;
1136           else if (d == 0)
1137             v = i ? 0 : r->w2;
1138           else
1139             v = *dp++;
1140           if (v == 0)
1141             break;
1142           if (DECISIONMAP_TRUE(v))      /* the one true literal */
1143               continue;
1144           vv = v > 0 ? v : -v;
1145           l = solv->decisionmap[vv];
1146           if (l < 0)
1147             l = -l;
1148           MAPSET(&seen, vv);
1149         }
1150     }
1151   map_free(&seen);
1152   map_free(&rseen);
1153   queue_push(&solv->problems, 0);       /* mark end of this problem */
1154
1155   if (lastweak)
1156     {
1157       /* disable last weak rule */
1158       solv->problems.count = oldproblemcount;
1159       solv->learnt_pool.count = oldlearntpoolcount;
1160       if (lastweak >= solv->jobrules && lastweak < solv->jobrules_end)
1161         v = -(solv->ruletojob.elements[lastweak - solv->jobrules] + 1);
1162       else
1163         v = lastweak;
1164       POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "disabling ");
1165       solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + lastweak);
1166       if (lastweak >= solv->choicerules && lastweak < solv->choicerules_end)
1167         solver_disablechoicerules(solv, solv->rules + lastweak);
1168       solver_disableproblem(solv, v);
1169       if (v < 0)
1170         solver_reenablepolicyrules(solv, -v);
1171       solver_reset(solv);
1172       return 1;
1173     }
1174
1175   if (solv->allowuninstall && (v = autouninstall(solv, solv->problems.elements + oldproblemcount + 1)) != 0)
1176     {
1177       solv->problems.count = oldproblemcount;
1178       solv->learnt_pool.count = oldlearntpoolcount;
1179       solver_reset(solv);
1180       return 1;
1181     }
1182
1183   /* finish proof */
1184   if (record_proof)
1185     {
1186       queue_push(&solv->learnt_pool, 0);
1187       solv->problems.elements[oldproblemcount] = oldlearntpoolcount;
1188     }
1189
1190   /* + 2: index + trailing zero */
1191   if (disablerules && oldproblemcount + 2 < solv->problems.count)
1192     {
1193       for (i = oldproblemcount + 1; i < solv->problems.count - 1; i++)
1194         solver_disableproblem(solv, solv->problems.elements[i]);
1195       /* XXX: might want to enable all weak rules again */
1196       solver_reset(solv);
1197       return 1;
1198     }
1199   POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "UNSOLVABLE\n");
1200   return 0;
1201 }
1202
1203
1204 /********************************************************************/
1205 /* Decision revert */
1206
1207 /*-------------------------------------------------------------------
1208  * 
1209  * revert
1210  * revert decisionq to a level
1211  */
1212
1213 static void
1214 revert(Solver *solv, int level)
1215 {
1216   Pool *pool = solv->pool;
1217   Id v, vv;
1218   while (solv->decisionq.count)
1219     {
1220       v = solv->decisionq.elements[solv->decisionq.count - 1];
1221       vv = v > 0 ? v : -v;
1222       if (solv->decisionmap[vv] <= level && solv->decisionmap[vv] >= -level)
1223         break;
1224       POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "reverting decision %d at %d\n", v, solv->decisionmap[vv]);
1225       solv->decisionmap[vv] = 0;
1226       solv->decisionq.count--;
1227       solv->decisionq_why.count--;
1228       solv->propagate_index = solv->decisionq.count;
1229     }
1230   while (solv->branches.count && solv->branches.elements[solv->branches.count - 1] <= -level)
1231     {
1232       solv->branches.count--;
1233       while (solv->branches.count && solv->branches.elements[solv->branches.count - 1] >= 0)
1234         solv->branches.count--;
1235     }
1236   solv->recommends_index = -1;
1237 }
1238
1239
1240 /*-------------------------------------------------------------------
1241  * 
1242  * watch2onhighest - put watch2 on literal with highest level
1243  */
1244
1245 static inline void
1246 watch2onhighest(Solver *solv, Rule *r)
1247 {
1248   int l, wl = 0;
1249   Id d, v, *dp;
1250
1251   d = r->d < 0 ? -r->d - 1 : r->d;
1252   if (!d)
1253     return;     /* binary rule, both watches are set */
1254   dp = solv->pool->whatprovidesdata + d;
1255   while ((v = *dp++) != 0)
1256     {
1257       l = solv->decisionmap[v < 0 ? -v : v];
1258       if (l < 0)
1259         l = -l;
1260       if (l > wl)
1261         {
1262           r->w2 = dp[-1];
1263           wl = l;
1264         }
1265     }
1266 }
1267
1268
1269 /*-------------------------------------------------------------------
1270  * 
1271  * setpropagatelearn
1272  *
1273  * add free decision (solvable to install) to decisionq
1274  * increase level and propagate decision
1275  * return if no conflict.
1276  *
1277  * in conflict case, analyze conflict rule, add resulting
1278  * rule to learnt rule set, make decision from learnt
1279  * rule (always unit) and re-propagate.
1280  *
1281  * returns the new solver level or 0 if unsolvable
1282  *
1283  */
1284
1285 static int
1286 setpropagatelearn(Solver *solv, int level, Id decision, int disablerules, Id ruleid)
1287 {
1288   Pool *pool = solv->pool;
1289   Rule *r;
1290   Id p = 0, d = 0;
1291   int l, why;
1292
1293   assert(ruleid >= 0);
1294   if (decision)
1295     {
1296       level++;
1297       if (decision > 0)
1298         solv->decisionmap[decision] = level;
1299       else
1300         solv->decisionmap[-decision] = -level;
1301       queue_push(&solv->decisionq, decision);
1302       queue_push(&solv->decisionq_why, -ruleid);        /* <= 0 -> free decision */
1303     }
1304   for (;;)
1305     {
1306       r = propagate(solv, level);
1307       if (!r)
1308         break;
1309       if (level == 1)
1310         return analyze_unsolvable(solv, r, disablerules);
1311       POOL_DEBUG(SOLV_DEBUG_ANALYZE, "conflict with rule #%d\n", (int)(r - solv->rules));
1312       l = analyze(solv, level, r, &p, &d, &why);        /* learnt rule in p and d */
1313       assert(l > 0 && l < level);
1314       POOL_DEBUG(SOLV_DEBUG_ANALYZE, "reverting decisions (level %d -> %d)\n", level, l);
1315       level = l;
1316       revert(solv, level);
1317       r = solver_addrule(solv, p, d);
1318       assert(r);
1319       assert(solv->learnt_why.count == (r - solv->rules) - solv->learntrules);
1320       queue_push(&solv->learnt_why, why);
1321       if (d)
1322         {
1323           /* at least 2 literals, needs watches */
1324           watch2onhighest(solv, r);
1325           addwatches_rule(solv, r);
1326         }
1327       else
1328         {
1329           /* learnt rule is an assertion */
1330           queue_push(&solv->ruleassertions, r - solv->rules);
1331         }
1332       /* the new rule is unit by design */
1333       solv->decisionmap[p > 0 ? p : -p] = p > 0 ? level : -level;
1334       queue_push(&solv->decisionq, p);
1335       queue_push(&solv->decisionq_why, r - solv->rules);
1336       IF_POOLDEBUG (SOLV_DEBUG_ANALYZE)
1337         {
1338           POOL_DEBUG(SOLV_DEBUG_ANALYZE, "decision: ");
1339           solver_printruleelement(solv, SOLV_DEBUG_ANALYZE, 0, p);
1340           POOL_DEBUG(SOLV_DEBUG_ANALYZE, "new rule: ");
1341           solver_printrule(solv, SOLV_DEBUG_ANALYZE, r);
1342         }
1343     }
1344   return level;
1345 }
1346
1347
1348 /*-------------------------------------------------------------------
1349  * 
1350  * select and install
1351  * 
1352  * install best package from the queue. We add an extra package, inst, if
1353  * provided. See comment in weak install section.
1354  *
1355  * returns the new solver level or 0 if unsolvable
1356  *
1357  */
1358
1359 static int
1360 selectandinstall(Solver *solv, int level, Queue *dq, int disablerules, Id ruleid)
1361 {
1362   Pool *pool = solv->pool;
1363   Id p;
1364   int i;
1365
1366   if (dq->count > 1)
1367     policy_filter_unwanted(solv, dq, POLICY_MODE_CHOOSE);
1368   if (dq->count > 1)
1369     {
1370       /* XXX: didn't we already do that? */
1371       /* XXX: shouldn't we prefer installed packages? */
1372       /* XXX: move to policy.c? */
1373       /* choose the supplemented one */
1374       for (i = 0; i < dq->count; i++)
1375         if (solver_is_supplementing(solv, pool->solvables + dq->elements[i]))
1376           {
1377             dq->elements[0] = dq->elements[i];
1378             dq->count = 1;
1379             break;
1380           }
1381     }
1382   if (dq->count > 1)
1383     {
1384       /* multiple candidates, open a branch */
1385       for (i = 1; i < dq->count; i++)
1386         queue_push(&solv->branches, dq->elements[i]);
1387       queue_push(&solv->branches, -level);
1388     }
1389   p = dq->elements[0];
1390
1391   POOL_DEBUG(SOLV_DEBUG_POLICY, "installing %s\n", pool_solvid2str(pool, p));
1392
1393   return setpropagatelearn(solv, level, p, disablerules, ruleid);
1394 }
1395
1396
1397 /********************************************************************/
1398 /* Main solver interface */
1399
1400
1401 /*-------------------------------------------------------------------
1402  * 
1403  * solver_create
1404  * create solver structure
1405  *
1406  * pool: all available solvables
1407  * installed: installed Solvables
1408  *
1409  *
1410  * Upon solving, rules are created to flag the Solvables
1411  * of the 'installed' Repo as installed.
1412  */
1413
1414 Solver *
1415 solver_create(Pool *pool)
1416 {
1417   Solver *solv;
1418   solv = (Solver *)solv_calloc(1, sizeof(Solver));
1419   solv->pool = pool;
1420   solv->installed = pool->installed;
1421
1422   solv->allownamechange = 1;
1423
1424   solv->dup_allowdowngrade = 1;
1425   solv->dup_allownamechange = 1;
1426   solv->dup_allowarchchange = 1;
1427   solv->dup_allowvendorchange = 1;
1428
1429   queue_init(&solv->ruletojob);
1430   queue_init(&solv->decisionq);
1431   queue_init(&solv->decisionq_why);
1432   queue_init(&solv->problems);
1433   queue_init(&solv->orphaned);
1434   queue_init(&solv->learnt_why);
1435   queue_init(&solv->learnt_pool);
1436   queue_init(&solv->branches);
1437   queue_init(&solv->weakruleq);
1438   queue_init(&solv->ruleassertions);
1439
1440   queue_push(&solv->learnt_pool, 0);    /* so that 0 does not describe a proof */
1441
1442   map_init(&solv->recommendsmap, pool->nsolvables);
1443   map_init(&solv->suggestsmap, pool->nsolvables);
1444   map_init(&solv->noupdate, solv->installed ? solv->installed->end - solv->installed->start : 0);
1445   solv->recommends_index = 0;
1446
1447   solv->decisionmap = (Id *)solv_calloc(pool->nsolvables, sizeof(Id));
1448   solv->nrules = 1;
1449   solv->rules = solv_extend_resize(solv->rules, solv->nrules, sizeof(Rule), RULES_BLOCK);
1450   memset(solv->rules, 0, sizeof(Rule));
1451
1452   return solv;
1453 }
1454
1455
1456 /*-------------------------------------------------------------------
1457  * 
1458  * solver_free
1459  */
1460
1461 void
1462 solver_free(Solver *solv)
1463 {
1464   queue_free(&solv->job);
1465   queue_free(&solv->ruletojob);
1466   queue_free(&solv->decisionq);
1467   queue_free(&solv->decisionq_why);
1468   queue_free(&solv->learnt_why);
1469   queue_free(&solv->learnt_pool);
1470   queue_free(&solv->problems);
1471   queue_free(&solv->solutions);
1472   queue_free(&solv->orphaned);
1473   queue_free(&solv->branches);
1474   queue_free(&solv->weakruleq);
1475   queue_free(&solv->ruleassertions);
1476   if (solv->cleandeps_updatepkgs)
1477     {
1478       queue_free(solv->cleandeps_updatepkgs);
1479       solv->cleandeps_updatepkgs = solv_free(solv->cleandeps_updatepkgs);
1480     }
1481   if (solv->cleandeps_mistakes)
1482     {
1483       queue_free(solv->cleandeps_mistakes);
1484       solv->cleandeps_mistakes = solv_free(solv->cleandeps_mistakes);
1485     }
1486   if (solv->update_targets)
1487     {
1488       queue_free(solv->update_targets);
1489       solv->update_targets = solv_free(solv->update_targets);
1490     }
1491   if (solv->installsuppdepq)
1492     {
1493       queue_free(solv->installsuppdepq);
1494       solv->installsuppdepq = solv_free(solv->installsuppdepq);
1495     }
1496
1497   map_free(&solv->recommendsmap);
1498   map_free(&solv->suggestsmap);
1499   map_free(&solv->noupdate);
1500   map_free(&solv->weakrulemap);
1501   map_free(&solv->noobsoletes);
1502
1503   map_free(&solv->updatemap);
1504   map_free(&solv->bestupdatemap);
1505   map_free(&solv->fixmap);
1506   map_free(&solv->dupmap);
1507   map_free(&solv->dupinvolvedmap);
1508   map_free(&solv->droporphanedmap);
1509   map_free(&solv->cleandepsmap);
1510
1511   solv_free(solv->decisionmap);
1512   solv_free(solv->rules);
1513   solv_free(solv->watches);
1514   solv_free(solv->obsoletes);
1515   solv_free(solv->obsoletes_data);
1516   solv_free(solv->multiversionupdaters);
1517   solv_free(solv->choicerules_ref);
1518   solv_free(solv->bestrules_pkg);
1519   solv_free(solv);
1520 }
1521
1522 int
1523 solver_get_flag(Solver *solv, int flag)
1524 {
1525   switch (flag)
1526   {
1527   case SOLVER_FLAG_ALLOW_DOWNGRADE:
1528     return solv->allowdowngrade;
1529   case SOLVER_FLAG_ALLOW_NAMECHANGE:
1530     return solv->allownamechange;
1531   case SOLVER_FLAG_ALLOW_ARCHCHANGE:
1532     return solv->allowarchchange;
1533   case SOLVER_FLAG_ALLOW_VENDORCHANGE:
1534     return solv->allowvendorchange;
1535   case SOLVER_FLAG_ALLOW_UNINSTALL:
1536     return solv->allowuninstall;
1537   case SOLVER_FLAG_NO_UPDATEPROVIDE:
1538     return solv->noupdateprovide;
1539   case SOLVER_FLAG_SPLITPROVIDES:
1540     return solv->dosplitprovides;
1541   case SOLVER_FLAG_IGNORE_RECOMMENDED:
1542     return solv->dontinstallrecommended;
1543   case SOLVER_FLAG_ADD_ALREADY_RECOMMENDED:
1544     return solv->addalreadyrecommended;
1545   case SOLVER_FLAG_NO_INFARCHCHECK:
1546     return solv->noinfarchcheck;
1547   case SOLVER_FLAG_KEEP_EXPLICIT_OBSOLETES:
1548     return solv->keepexplicitobsoletes;
1549   case SOLVER_FLAG_BEST_OBEY_POLICY:
1550     return solv->bestobeypolicy;
1551   case SOLVER_FLAG_NO_AUTOTARGET:
1552     return solv->noautotarget;
1553   default:
1554     break;
1555   }
1556   return -1;
1557 }
1558
1559 int
1560 solver_set_flag(Solver *solv, int flag, int value)
1561 {
1562   int old = solver_get_flag(solv, flag);
1563   switch (flag)
1564   {
1565   case SOLVER_FLAG_ALLOW_DOWNGRADE:
1566     solv->allowdowngrade = value;
1567     break;
1568   case SOLVER_FLAG_ALLOW_NAMECHANGE:
1569     solv->allownamechange = value;
1570     break;
1571   case SOLVER_FLAG_ALLOW_ARCHCHANGE:
1572     solv->allowarchchange = value;
1573     break;
1574   case SOLVER_FLAG_ALLOW_VENDORCHANGE:
1575     solv->allowvendorchange = value;
1576     break;
1577   case SOLVER_FLAG_ALLOW_UNINSTALL:
1578     solv->allowuninstall = value;
1579     break;
1580   case SOLVER_FLAG_NO_UPDATEPROVIDE:
1581     solv->noupdateprovide = value;
1582     break;
1583   case SOLVER_FLAG_SPLITPROVIDES:
1584     solv->dosplitprovides = value;
1585     break;
1586   case SOLVER_FLAG_IGNORE_RECOMMENDED:
1587     solv->dontinstallrecommended = value;
1588     break;
1589   case SOLVER_FLAG_ADD_ALREADY_RECOMMENDED:
1590     solv->addalreadyrecommended = value;
1591     break;
1592   case SOLVER_FLAG_NO_INFARCHCHECK:
1593     solv->noinfarchcheck = value;
1594     break;
1595   case SOLVER_FLAG_KEEP_EXPLICIT_OBSOLETES:
1596     solv->keepexplicitobsoletes = value;
1597     break;
1598   case SOLVER_FLAG_BEST_OBEY_POLICY:
1599     solv->bestobeypolicy = value;
1600     break;
1601   case SOLVER_FLAG_NO_AUTOTARGET:
1602     solv->noautotarget = value;
1603     break;
1604   default:
1605     break;
1606   }
1607   return old;
1608 }
1609
1610 int
1611 cleandeps_check_mistakes(Solver *solv, int level)
1612 {
1613   Pool *pool = solv->pool;
1614   Rule *r;
1615   Id p, pp;
1616   int i;
1617   int mademistake = 0;
1618
1619   if (!solv->cleandepsmap.size)
1620     return 0;
1621   /* check for mistakes */
1622   for (i = solv->installed->start; i < solv->installed->end; i++)
1623     {
1624       if (!MAPTST(&solv->cleandepsmap, i - solv->installed->start))
1625         continue;
1626       r = solv->rules + solv->featurerules + (i - solv->installed->start);
1627       /* a mistake is when the featurerule is true but the updaterule is false */
1628       if (!r->p)
1629         continue;
1630       FOR_RULELITERALS(p, pp, r)
1631         if (p > 0 && solv->decisionmap[p] > 0)
1632           break;
1633       if (!p)
1634         continue;       /* feature rule is not true */
1635       r = solv->rules + solv->updaterules + (i - solv->installed->start);
1636       if (!r->p)
1637         continue;
1638       FOR_RULELITERALS(p, pp, r)
1639         if (p > 0 && solv->decisionmap[p] > 0)
1640           break;
1641       if (p)
1642         continue;       /* update rule is true */
1643       POOL_DEBUG(SOLV_DEBUG_SOLVER, "cleandeps mistake: ");
1644       solver_printruleclass(solv, SOLV_DEBUG_SOLVER, r);
1645       POOL_DEBUG(SOLV_DEBUG_SOLVER, "feature rule: ");
1646       solver_printruleclass(solv, SOLV_DEBUG_SOLVER, solv->rules + solv->featurerules + (i - solv->installed->start));
1647       if (!solv->cleandeps_mistakes)
1648         {
1649           solv->cleandeps_mistakes = solv_calloc(1, sizeof(Queue));
1650           queue_init(solv->cleandeps_mistakes);
1651         }
1652       queue_push(solv->cleandeps_mistakes, i);
1653       MAPCLR(&solv->cleandepsmap, i - solv->installed->start);
1654       solver_reenablepolicyrules_cleandeps(solv, i);
1655       mademistake = 1;
1656     }
1657   if (mademistake)
1658     solver_reset(solv);
1659   return mademistake;
1660 }
1661
1662 static void
1663 prune_to_update_targets(Solver *solv, Id *cp, Queue *q)
1664 {
1665   int i, j;
1666   Id p, *cp2;
1667   for (i = j = 0; i < q->count; i++)
1668     {
1669       p = q->elements[i];
1670       for (cp2 = cp; *cp2; cp2++)
1671         if (*cp2 == p)
1672           {
1673             q->elements[j++] = p;
1674             break;
1675           }
1676     }
1677   queue_truncate(q, j);
1678 }
1679
1680 /*-------------------------------------------------------------------
1681  * 
1682  * solver_run_sat
1683  *
1684  * all rules have been set up, now actually run the solver
1685  *
1686  */
1687
1688 void
1689 solver_run_sat(Solver *solv, int disablerules, int doweak)
1690 {
1691   Queue dq;             /* local decisionqueue */
1692   Queue dqs;            /* local decisionqueue for supplements */
1693   int systemlevel;
1694   int level, olevel;
1695   Rule *r;
1696   int i, j, n;
1697   Solvable *s;
1698   Pool *pool = solv->pool;
1699   Id p, pp, *dp;
1700   int minimizationsteps;
1701   int installedpos = solv->installed ? solv->installed->start : 0;
1702
1703   IF_POOLDEBUG (SOLV_DEBUG_RULE_CREATION)
1704     {
1705       POOL_DEBUG (SOLV_DEBUG_RULE_CREATION, "number of rules: %d\n", solv->nrules);
1706       for (i = 1; i < solv->nrules; i++)
1707         solver_printruleclass(solv, SOLV_DEBUG_RULE_CREATION, solv->rules + i);
1708     }
1709
1710   POOL_DEBUG(SOLV_DEBUG_SOLVER, "initial decisions: %d\n", solv->decisionq.count);
1711
1712   /* start SAT algorithm */
1713   level = 1;
1714   systemlevel = level + 1;
1715   POOL_DEBUG(SOLV_DEBUG_SOLVER, "solving...\n");
1716
1717   queue_init(&dq);
1718   queue_init(&dqs);
1719
1720   /*
1721    * here's the main loop:
1722    * 1) propagate new decisions (only needed once)
1723    * 2) fulfill jobs
1724    * 3) try to keep installed packages
1725    * 4) fulfill all unresolved rules
1726    * 5) install recommended packages
1727    * 6) minimalize solution if we had choices
1728    * if we encounter a problem, we rewind to a safe level and restart
1729    * with step 1
1730    */
1731    
1732   minimizationsteps = 0;
1733   for (;;)
1734     {
1735       /*
1736        * initial propagation of the assertions
1737        */
1738       if (level == 1)
1739         {
1740           POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "propagating (propagate_index: %d;  size decisionq: %d)...\n", solv->propagate_index, solv->decisionq.count);
1741           if ((r = propagate(solv, level)) != 0)
1742             {
1743               if (analyze_unsolvable(solv, r, disablerules))
1744                 continue;
1745               level = 0;
1746               break;    /* unsolvable */
1747             }
1748         }
1749
1750       /*
1751        * resolve jobs first
1752        */
1753      if (level < systemlevel)
1754         {
1755           POOL_DEBUG(SOLV_DEBUG_SOLVER, "resolving job rules\n");
1756           for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++)
1757             {
1758               Id l;
1759               if (r->d < 0)             /* ignore disabled rules */
1760                 continue;
1761               queue_empty(&dq);
1762               FOR_RULELITERALS(l, pp, r)
1763                 {
1764                   if (l < 0)
1765                     {
1766                       if (solv->decisionmap[-l] <= 0)
1767                         break;
1768                     }
1769                   else
1770                     {
1771                       if (solv->decisionmap[l] > 0)
1772                         break;
1773                       if (solv->decisionmap[l] == 0)
1774                         queue_push(&dq, l);
1775                     }
1776                 }
1777               if (l || !dq.count)
1778                 continue;
1779               /* prune to installed if not updating */
1780               if (dq.count > 1 && solv->installed && !solv->updatemap_all &&
1781                   !(solv->job.elements[solv->ruletojob.elements[i - solv->jobrules]] & SOLVER_ORUPDATE))
1782                 {
1783                   int j, k;
1784                   for (j = k = 0; j < dq.count; j++)
1785                     {
1786                       Solvable *s = pool->solvables + dq.elements[j];
1787                       if (s->repo == solv->installed)
1788                         {
1789                           dq.elements[k++] = dq.elements[j];
1790                           if (solv->updatemap.size && MAPTST(&solv->updatemap, dq.elements[j] - solv->installed->start))
1791                             {
1792                               k = 0;    /* package wants to be updated, do not prune */
1793                               break;
1794                             }
1795                         }
1796                     }
1797                   if (k)
1798                     dq.count = k;
1799                 }
1800               olevel = level;
1801               level = selectandinstall(solv, level, &dq, disablerules, i);
1802               if (level == 0)
1803                 break;
1804               if (level <= olevel)
1805                 break;
1806             }
1807           if (level == 0)
1808             break;      /* unsolvable */
1809           systemlevel = level + 1;
1810           if (i < solv->jobrules_end)
1811             continue;
1812           solv->decisioncnt_update = solv->decisionq.count;
1813           solv->decisioncnt_keep = solv->decisionq.count;
1814         }
1815
1816       /*
1817        * installed packages
1818        */
1819       if (level < systemlevel && solv->installed && solv->installed->nsolvables && !solv->installed->disabled)
1820         {
1821           Repo *installed = solv->installed;
1822           int pass;
1823
1824           POOL_DEBUG(SOLV_DEBUG_SOLVER, "resolving installed packages\n");
1825           /* we use two passes if we need to update packages 
1826            * to create a better user experience */
1827           for (pass = solv->updatemap.size ? 0 : 1; pass < 2; pass++)
1828             {
1829               int passlevel = level;
1830               if (pass == 1)
1831                 solv->decisioncnt_keep = solv->decisionq.count;
1832               /* start with installedpos, the position that gave us problems last time */
1833               for (i = installedpos, n = installed->start; n < installed->end; i++, n++)
1834                 {
1835                   Rule *rr;
1836                   Id d;
1837
1838                   if (i == installed->end)
1839                     i = installed->start;
1840                   s = pool->solvables + i;
1841                   if (s->repo != installed)
1842                     continue;
1843
1844                   if (solv->decisionmap[i] > 0)
1845                     continue;
1846                   if (!pass && solv->updatemap.size && !MAPTST(&solv->updatemap, i - installed->start))
1847                     continue;           /* updates first */
1848                   r = solv->rules + solv->updaterules + (i - installed->start);
1849                   rr = r;
1850                   if (!rr->p || rr->d < 0)      /* disabled -> look at feature rule */
1851                     rr -= solv->installed->end - solv->installed->start;
1852                   if (!rr->p)           /* identical to update rule? */
1853                     rr = r;
1854                   if (!rr->p)
1855                     continue;           /* orpaned package */
1856
1857                   /* XXX: noupdate check is probably no longer needed, as all jobs should
1858                    * already be satisfied */
1859                   /* Actually we currently still need it because of erase jobs */
1860                   /* if noupdate is set we do not look at update candidates */
1861                   queue_empty(&dq);
1862                   if (!MAPTST(&solv->noupdate, i - installed->start) && (solv->decisionmap[i] < 0 || solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, i - installed->start)) || rr->p != i))
1863                     {
1864                       if (solv->noobsoletes.size && solv->multiversionupdaters
1865                              && (d = solv->multiversionupdaters[i - installed->start]) != 0)
1866                         {
1867                           /* special multiversion handling, make sure best version is chosen */
1868                           queue_push(&dq, i);
1869                           while ((p = pool->whatprovidesdata[d++]) != 0)
1870                             if (solv->decisionmap[p] >= 0)
1871                               queue_push(&dq, p);
1872                           if (dq.count && solv->update_targets && solv->update_targets->elements[i - installed->start])
1873                             prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[i - installed->start], &dq);
1874                           if (dq.count)
1875                             {
1876                               policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE);
1877                               p = dq.elements[0];
1878                               if (p != i && solv->decisionmap[p] == 0)
1879                                 {
1880                                   rr = solv->rules + solv->featurerules + (i - solv->installed->start);
1881                                   if (!rr->p)           /* update rule == feature rule? */
1882                                     rr = rr - solv->featurerules + solv->updaterules;
1883                                   dq.count = 1;
1884                                 }
1885                               else
1886                                 dq.count = 0;
1887                             }
1888                         }
1889                       else
1890                         {
1891                           /* update to best package */
1892                           FOR_RULELITERALS(p, pp, rr)
1893                             {
1894                               if (solv->decisionmap[p] > 0)
1895                                 {
1896                                   dq.count = 0;         /* already fulfilled */
1897                                   break;
1898                                 }
1899                               if (!solv->decisionmap[p])
1900                                 queue_push(&dq, p);
1901                             }
1902                         }
1903                     }
1904                   if (dq.count && solv->update_targets && solv->update_targets->elements[i - installed->start])
1905                     prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[i - installed->start], &dq);
1906                   /* install best version */
1907                   if (dq.count)
1908                     {
1909                       olevel = level;
1910                       level = selectandinstall(solv, level, &dq, disablerules, rr - solv->rules);
1911                       if (level == 0)
1912                         {
1913                           queue_free(&dq);
1914                           queue_free(&dqs);
1915                           return;
1916                         }
1917                       if (level <= olevel)
1918                         {
1919                           if (level == 1 || level < passlevel)
1920                             break;      /* trouble */
1921                           if (level < olevel)
1922                             n = installed->start;       /* redo all */
1923                           i--;
1924                           n--;
1925                           continue;
1926                         }
1927                     }
1928                   /* if still undecided keep package */
1929                   if (solv->decisionmap[i] == 0)
1930                     {
1931                       olevel = level;
1932                       if (solv->cleandepsmap.size && MAPTST(&solv->cleandepsmap, i - installed->start))
1933                         {
1934 #if 0
1935                           POOL_DEBUG(SOLV_DEBUG_POLICY, "cleandeps erasing %s\n", pool_solvid2str(pool, i));
1936                           level = setpropagatelearn(solv, level, -i, disablerules, 0);
1937 #else
1938                           continue;
1939 #endif
1940                         }
1941                       else
1942                         {
1943                           POOL_DEBUG(SOLV_DEBUG_POLICY, "keeping %s\n", pool_solvid2str(pool, i));
1944                           level = setpropagatelearn(solv, level, i, disablerules, r - solv->rules);
1945                         }
1946                       if (level == 0)
1947                         break;
1948                       if (level <= olevel)
1949                         {
1950                           if (level == 1 || level < passlevel)
1951                             break;      /* trouble */
1952                           if (level < olevel)
1953                             n = installed->start;       /* redo all */
1954                           i--;
1955                           n--;
1956                           continue;     /* retry with learnt rule */
1957                         }
1958                     }
1959                 }
1960               if (n < installed->end)
1961                 {
1962                   installedpos = i;     /* retry problem solvable next time */
1963                   break;                /* ran into trouble */
1964                 }
1965               installedpos = installed->start;  /* reset installedpos */
1966             }
1967           if (level == 0)
1968             break;              /* unsolvable */
1969           systemlevel = level + 1;
1970           if (pass < 2)
1971             continue;           /* had trouble, retry */
1972         }
1973
1974       if (level < systemlevel)
1975         systemlevel = level;
1976
1977       /*
1978        * decide
1979        */
1980       solv->decisioncnt_resolve = solv->decisionq.count;
1981       POOL_DEBUG(SOLV_DEBUG_POLICY, "deciding unresolved rules\n");
1982       for (i = 1, n = 1; n < solv->nrules; i++, n++)
1983         {
1984           if (i == solv->nrules)
1985             i = 1;
1986           r = solv->rules + i;
1987           if (r->d < 0)         /* ignore disabled rules */
1988             continue;
1989           queue_empty(&dq);
1990           if (r->d == 0)
1991             {
1992               /* binary or unary rule */
1993               /* need two positive undecided literals */
1994               if (r->p < 0 || r->w2 <= 0)
1995                 continue;
1996               if (solv->decisionmap[r->p] || solv->decisionmap[r->w2])
1997                 continue;
1998               queue_push(&dq, r->p);
1999               queue_push(&dq, r->w2);
2000             }
2001           else
2002             {
2003               /* make sure that
2004                * all negative literals are installed
2005                * no positive literal is installed
2006                * i.e. the rule is not fulfilled and we
2007                * just need to decide on the positive literals
2008                */
2009               if (r->p < 0)
2010                 {
2011                   if (solv->decisionmap[-r->p] <= 0)
2012                     continue;
2013                 }
2014               else
2015                 {
2016                   if (solv->decisionmap[r->p] > 0)
2017                     continue;
2018                   if (solv->decisionmap[r->p] == 0)
2019                     queue_push(&dq, r->p);
2020                 }
2021               dp = pool->whatprovidesdata + r->d;
2022               while ((p = *dp++) != 0)
2023                 {
2024                   if (p < 0)
2025                     {
2026                       if (solv->decisionmap[-p] <= 0)
2027                         break;
2028                     }
2029                   else
2030                     {
2031                       if (solv->decisionmap[p] > 0)
2032                         break;
2033                       if (solv->decisionmap[p] == 0)
2034                         queue_push(&dq, p);
2035                     }
2036                 }
2037               if (p)
2038                 continue;
2039             }
2040           IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
2041             {
2042               POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "unfulfilled ");
2043               solver_printruleclass(solv, SOLV_DEBUG_PROPAGATE, r);
2044             }
2045           /* dq.count < 2 cannot happen as this means that
2046            * the rule is unit */
2047           assert(dq.count > 1);
2048
2049           /* prune to cleandeps packages */
2050           if (solv->cleandepsmap.size && solv->installed)
2051             {
2052               Repo *installed = solv->installed;
2053               for (j = 0; j < dq.count; j++)
2054                 if (pool->solvables[dq.elements[j]].repo == installed && MAPTST(&solv->cleandepsmap, dq.elements[j] - installed->start))
2055                   break;
2056               if (j < dq.count)
2057                 {
2058                   dq.elements[0] = dq.elements[j];
2059                   queue_truncate(&dq, 1);
2060                 }
2061             }
2062
2063           olevel = level;
2064           level = selectandinstall(solv, level, &dq, disablerules, r - solv->rules);
2065           if (level == 0)
2066             break;              /* unsolvable */
2067           if (level < systemlevel || level == 1)
2068             break;              /* trouble */
2069           /* something changed, so look at all rules again */
2070           n = 0;
2071         }
2072
2073       if (n != solv->nrules)    /* ran into trouble? */
2074         {
2075           if (level == 0)
2076             break;              /* unsolvable */
2077           continue;             /* start over */
2078         }
2079
2080       /* at this point we have a consistent system. now do the extras... */
2081
2082       /* first decide leftover cleandeps packages */
2083       if (solv->cleandepsmap.size && solv->installed)
2084         {
2085           for (p = solv->installed->start; p < solv->installed->end; p++)
2086             {
2087               s = pool->solvables + p;
2088               if (s->repo != solv->installed)
2089                 continue;
2090               if (solv->decisionmap[p] == 0 && MAPTST(&solv->cleandepsmap, p - solv->installed->start))
2091                 {
2092                   POOL_DEBUG(SOLV_DEBUG_POLICY, "cleandeps erasing %s\n", pool_solvid2str(pool, p));
2093                   olevel = level;
2094                   level = setpropagatelearn(solv, level, -p, 0, 0);
2095                   if (level < olevel)
2096                     break;
2097                 }
2098             }
2099           if (p < solv->installed->end)
2100             continue;
2101         }
2102
2103       solv->decisioncnt_weak = solv->decisionq.count;
2104       if (doweak)
2105         {
2106           int qcount;
2107
2108           POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended packages\n");
2109           queue_empty(&dq);     /* recommended packages */
2110           queue_empty(&dqs);    /* supplemented packages */
2111           for (i = 1; i < pool->nsolvables; i++)
2112             {
2113               if (solv->decisionmap[i] < 0)
2114                 continue;
2115               if (solv->decisionmap[i] > 0)
2116                 {
2117                   /* installed, check for recommends */
2118                   Id *recp, rec, pp, p;
2119                   s = pool->solvables + i;
2120                   if (!solv->addalreadyrecommended && s->repo == solv->installed)
2121                     continue;
2122                   /* XXX need to special case AND ? */
2123                   if (s->recommends)
2124                     {
2125                       recp = s->repo->idarraydata + s->recommends;
2126                       while ((rec = *recp++) != 0)
2127                         {
2128                           qcount = dq.count;
2129                           FOR_PROVIDES(p, pp, rec)
2130                             {
2131                               if (solv->decisionmap[p] > 0)
2132                                 {
2133                                   dq.count = qcount;
2134                                   break;
2135                                 }
2136                               else if (solv->decisionmap[p] == 0)
2137                                 {
2138                                   if (solv->dupmap_all && solv->installed && pool->solvables[p].repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start))))
2139                                     continue;
2140                                   queue_pushunique(&dq, p);
2141                                 }
2142                             }
2143                         }
2144                     }
2145                 }
2146               else
2147                 {
2148                   s = pool->solvables + i;
2149                   if (!s->supplements)
2150                     continue;
2151                   if (!pool_installable(pool, s))
2152                     continue;
2153                   if (!solver_is_supplementing(solv, s))
2154                     continue;
2155                   if (solv->dupmap_all && solv->installed && s->repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, i - solv->installed->start))))
2156                     continue;
2157                   queue_push(&dqs, i);
2158                 }
2159             }
2160
2161           /* filter out all packages obsoleted by installed packages */
2162           /* this is no longer needed if we have reverse obsoletes */
2163           if ((dqs.count || dq.count) && solv->installed)
2164             {
2165               Map obsmap;
2166               Id obs, *obsp, po, ppo;
2167
2168               map_init(&obsmap, pool->nsolvables);
2169               for (p = solv->installed->start; p < solv->installed->end; p++)
2170                 {
2171                   s = pool->solvables + p;
2172                   if (s->repo != solv->installed || !s->obsoletes)
2173                     continue;
2174                   if (solv->decisionmap[p] <= 0)
2175                     continue;
2176                   if (solv->noobsoletes.size && MAPTST(&solv->noobsoletes, p))
2177                     continue;
2178                   obsp = s->repo->idarraydata + s->obsoletes;
2179                   /* foreach obsoletes */
2180                   while ((obs = *obsp++) != 0)
2181                     FOR_PROVIDES(po, ppo, obs)
2182                       MAPSET(&obsmap, po);
2183                 }
2184               for (i = j = 0; i < dqs.count; i++)
2185                 if (!MAPTST(&obsmap, dqs.elements[i]))
2186                   dqs.elements[j++] = dqs.elements[i];
2187               dqs.count = j;
2188               for (i = j = 0; i < dq.count; i++)
2189                 if (!MAPTST(&obsmap, dq.elements[i]))
2190                   dq.elements[j++] = dq.elements[i];
2191               dq.count = j;
2192               map_free(&obsmap);
2193             }
2194
2195           /* filter out all already supplemented packages if requested */
2196           if (!solv->addalreadyrecommended && dqs.count)
2197             {
2198               /* turn off all new packages */
2199               for (i = 0; i < solv->decisionq.count; i++)
2200                 {
2201                   p = solv->decisionq.elements[i];
2202                   if (p < 0)
2203                     continue;
2204                   s = pool->solvables + p;
2205                   if (s->repo && s->repo != solv->installed)
2206                     solv->decisionmap[p] = -solv->decisionmap[p];
2207                 }
2208               /* filter out old supplements */
2209               for (i = j = 0; i < dqs.count; i++)
2210                 {
2211                   p = dqs.elements[i];
2212                   s = pool->solvables + p;
2213                   if (!s->supplements)
2214                     continue;
2215                   if (!solver_is_supplementing(solv, s))
2216                     dqs.elements[j++] = p;
2217                   else if (s->supplements && solv->installsuppdepq && solver_check_installsuppdepq(solv, s))
2218                     dqs.elements[j++] = p;
2219                 }
2220               dqs.count = j;
2221               /* undo turning off */
2222               for (i = 0; i < solv->decisionq.count; i++)
2223                 {
2224                   p = solv->decisionq.elements[i];
2225                   if (p < 0)
2226                     continue;
2227                   s = pool->solvables + p;
2228                   if (s->repo && s->repo != solv->installed)
2229                     solv->decisionmap[p] = -solv->decisionmap[p];
2230                 }
2231             }
2232
2233           /* multiversion doesn't mix well with supplements.
2234            * filter supplemented packages where we already decided
2235            * to install a different version (see bnc#501088) */
2236           if (dqs.count && solv->noobsoletes.size)
2237             {
2238               for (i = j = 0; i < dqs.count; i++)
2239                 {
2240                   p = dqs.elements[i];
2241                   if (MAPTST(&solv->noobsoletes, p))
2242                     {
2243                       Id p2, pp2;
2244                       s = pool->solvables + p;
2245                       FOR_PROVIDES(p2, pp2, s->name)
2246                         if (solv->decisionmap[p2] > 0 && pool->solvables[p2].name == s->name)
2247                           break;
2248                       if (p2)
2249                         continue;       /* ignore this package */
2250                     }
2251                   dqs.elements[j++] = p;
2252                 }
2253               dqs.count = j;
2254             }
2255
2256           /* make dq contain both recommended and supplemented pkgs */
2257           if (dqs.count)
2258             {
2259               for (i = 0; i < dqs.count; i++)
2260                 queue_pushunique(&dq, dqs.elements[i]);
2261             }
2262
2263           if (dq.count)
2264             {
2265               Map dqmap;
2266               int decisioncount = solv->decisionq.count;
2267
2268               if (dq.count == 1)
2269                 {
2270                   /* simple case, just one package. no need to choose to best version */
2271                   p = dq.elements[0];
2272                   if (dqs.count)
2273                     POOL_DEBUG(SOLV_DEBUG_POLICY, "installing supplemented %s\n", pool_solvid2str(pool, p));
2274                   else
2275                     POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended %s\n", pool_solvid2str(pool, p));
2276                   level = setpropagatelearn(solv, level, p, 0, 0);
2277                   if (level == 0)
2278                     break;
2279                   continue;     /* back to main loop */
2280                 }
2281
2282               /* filter packages, this gives us the best versions */
2283               policy_filter_unwanted(solv, &dq, POLICY_MODE_RECOMMEND);
2284
2285               /* create map of result */
2286               map_init(&dqmap, pool->nsolvables);
2287               for (i = 0; i < dq.count; i++)
2288                 MAPSET(&dqmap, dq.elements[i]);
2289
2290               /* install all supplemented packages */
2291               for (i = 0; i < dqs.count; i++)
2292                 {
2293                   p = dqs.elements[i];
2294                   if (solv->decisionmap[p] || !MAPTST(&dqmap, p))
2295                     continue;
2296                   POOL_DEBUG(SOLV_DEBUG_POLICY, "installing supplemented %s\n", pool_solvid2str(pool, p));
2297                   olevel = level;
2298                   level = setpropagatelearn(solv, level, p, 0, 0);
2299                   if (level <= olevel)
2300                     break;
2301                 }
2302               if (i < dqs.count || solv->decisionq.count < decisioncount)
2303                 {
2304                   map_free(&dqmap);
2305                   if (level == 0)
2306                     break;
2307                   continue;
2308                 }
2309
2310               /* install all recommended packages */
2311               /* more work as we want to created branches if multiple
2312                * choices are valid */
2313               for (i = 0; i < decisioncount; i++)
2314                 {
2315                   Id rec, *recp, pp;
2316                   p = solv->decisionq.elements[i];
2317                   if (p < 0)
2318                     continue;
2319                   s = pool->solvables + p;
2320                   if (!s->repo || (!solv->addalreadyrecommended && s->repo == solv->installed))
2321                     continue;
2322                   if (!s->recommends)
2323                     continue;
2324                   recp = s->repo->idarraydata + s->recommends;
2325                   while ((rec = *recp++) != 0)
2326                     {
2327                       queue_empty(&dq);
2328                       FOR_PROVIDES(p, pp, rec)
2329                         {
2330                           if (solv->decisionmap[p] > 0)
2331                             {
2332                               dq.count = 0;
2333                               break;
2334                             }
2335                           else if (solv->decisionmap[p] == 0 && MAPTST(&dqmap, p))
2336                             queue_pushunique(&dq, p);
2337                         }
2338                       if (!dq.count)
2339                         continue;
2340                       if (dq.count > 1)
2341                         {
2342                           /* multiple candidates, open a branch */
2343                           for (i = 1; i < dq.count; i++)
2344                             queue_push(&solv->branches, dq.elements[i]);
2345                           queue_push(&solv->branches, -level);
2346                         }
2347                       p = dq.elements[0];
2348                       POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended %s\n", pool_solvid2str(pool, p));
2349                       olevel = level;
2350                       level = setpropagatelearn(solv, level, p, 0, 0);
2351                       if (level <= olevel || solv->decisionq.count < decisioncount)
2352                         break;  /* we had to revert some decisions */
2353                     }
2354                   if (rec)
2355                     break;      /* had a problem above, quit loop */
2356                 }
2357               map_free(&dqmap);
2358               if (level == 0)
2359                 break;
2360               continue;         /* back to main loop so that all deps are checked */
2361             }
2362         }
2363
2364       solv->decisioncnt_orphan = solv->decisionq.count;
2365       if (solv->dupmap_all && solv->installed)
2366         {
2367           int installedone = 0;
2368
2369           /* let's see if we can install some unsupported package */
2370           POOL_DEBUG(SOLV_DEBUG_SOLVER, "deciding orphaned packages\n");
2371           for (i = 0; i < solv->orphaned.count; i++)
2372             {
2373               p = solv->orphaned.elements[i];
2374               if (solv->decisionmap[p])
2375                 continue;       /* already decided */
2376               if (solv->droporphanedmap_all)
2377                 continue;
2378               if (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start))
2379                 continue;
2380               POOL_DEBUG(SOLV_DEBUG_SOLVER, "keeping orphaned %s\n", pool_solvid2str(pool, p));
2381               olevel = level;
2382               level = setpropagatelearn(solv, level, p, 0, 0);
2383               installedone = 1;
2384               if (level < olevel)
2385                 break;
2386             }
2387           if (installedone || i < solv->orphaned.count)
2388             {
2389               if (level == 0)
2390                 break;
2391               continue;         /* back to main loop */
2392             }
2393           for (i = 0; i < solv->orphaned.count; i++)
2394             {
2395               p = solv->orphaned.elements[i];
2396               if (solv->decisionmap[p])
2397                 continue;       /* already decided */
2398               POOL_DEBUG(SOLV_DEBUG_SOLVER, "removing orphaned %s\n", pool_solvid2str(pool, p));
2399               olevel = level;
2400               level = setpropagatelearn(solv, level, -p, 0, 0);
2401               if (level < olevel)
2402                 break;
2403             }
2404           if (i < solv->orphaned.count)
2405             {
2406               if (level == 0)
2407                 break;
2408               continue;         /* back to main loop */
2409             }
2410         }
2411
2412      if (solv->installed && solv->cleandepsmap.size)
2413         {
2414           if (cleandeps_check_mistakes(solv, level))
2415             {
2416               level = 1;        /* restart from scratch */
2417               systemlevel = level + 1;
2418               continue;
2419             }
2420         }
2421
2422      if (solv->solution_callback)
2423         {
2424           solv->solution_callback(solv, solv->solution_callback_data);
2425           if (solv->branches.count)
2426             {
2427               int i = solv->branches.count - 1;
2428               int l = -solv->branches.elements[i];
2429               Id why;
2430
2431               for (; i > 0; i--)
2432                 if (solv->branches.elements[i - 1] < 0)
2433                   break;
2434               p = solv->branches.elements[i];
2435               POOL_DEBUG(SOLV_DEBUG_SOLVER, "branching with %s\n", pool_solvid2str(pool, p));
2436               queue_empty(&dq);
2437               for (j = i + 1; j < solv->branches.count; j++)
2438                 queue_push(&dq, solv->branches.elements[j]);
2439               solv->branches.count = i;
2440               level = l;
2441               revert(solv, level);
2442               if (dq.count > 1)
2443                 for (j = 0; j < dq.count; j++)
2444                   queue_push(&solv->branches, dq.elements[j]);
2445               olevel = level;
2446               why = -solv->decisionq_why.elements[solv->decisionq_why.count];
2447               assert(why >= 0);
2448               level = setpropagatelearn(solv, level, p, disablerules, why);
2449               if (level == 0)
2450                 break;
2451               continue;
2452             }
2453           /* all branches done, we're finally finished */
2454           break;
2455         }
2456
2457       /* auto-minimization step */
2458      if (solv->branches.count)
2459         {
2460           int l = 0, lasti = -1, lastl = -1;
2461           Id why;
2462
2463           p = 0;
2464           for (i = solv->branches.count - 1; i >= 0; i--)
2465             {
2466               p = solv->branches.elements[i];
2467               if (p < 0)
2468                 l = -p;
2469               else if (p > 0 && solv->decisionmap[p] > l + 1)
2470                 {
2471                   lasti = i;
2472                   lastl = l;
2473                 }
2474             }
2475           if (lasti >= 0)
2476             {
2477               /* kill old solvable so that we do not loop */
2478               p = solv->branches.elements[lasti];
2479               solv->branches.elements[lasti] = 0;
2480               POOL_DEBUG(SOLV_DEBUG_SOLVER, "minimizing %d -> %d with %s\n", solv->decisionmap[p], lastl, pool_solvid2str(pool, p));
2481               minimizationsteps++;
2482
2483               level = lastl;
2484               revert(solv, level);
2485               why = -solv->decisionq_why.elements[solv->decisionq_why.count];
2486               assert(why >= 0);
2487               olevel = level;
2488               level = setpropagatelearn(solv, level, p, disablerules, why);
2489               if (level == 0)
2490                 break;
2491               continue;         /* back to main loop */
2492             }
2493         }
2494       /* no minimization found, we're finally finished! */
2495       break;
2496     }
2497
2498   POOL_DEBUG(SOLV_DEBUG_STATS, "solver statistics: %d learned rules, %d unsolvable, %d minimization steps\n", solv->stats_learned, solv->stats_unsolvable, minimizationsteps);
2499
2500   POOL_DEBUG(SOLV_DEBUG_STATS, "done solving.\n\n");
2501   queue_free(&dq);
2502   queue_free(&dqs);
2503   if (level == 0)
2504     {
2505       /* unsolvable */
2506       solv->decisioncnt_update = solv->decisionq.count;
2507       solv->decisioncnt_keep = solv->decisionq.count;
2508       solv->decisioncnt_resolve = solv->decisionq.count;
2509       solv->decisioncnt_weak = solv->decisionq.count;
2510       solv->decisioncnt_orphan = solv->decisionq.count;
2511     }
2512 #if 0
2513   solver_printdecisionq(solv, SOLV_DEBUG_RESULT);
2514 #endif
2515 }
2516
2517
2518 /*-------------------------------------------------------------------
2519  * 
2520  * remove disabled conflicts
2521  *
2522  * purpose: update the decisionmap after some rules were disabled.
2523  * this is used to calculate the suggested/recommended package list.
2524  * Also returns a "removed" list to undo the discisionmap changes.
2525  */
2526
2527 static void
2528 removedisabledconflicts(Solver *solv, Queue *removed)
2529 {
2530   Pool *pool = solv->pool;
2531   int i, n;
2532   Id p, why, *dp;
2533   Id new;
2534   Rule *r;
2535   Id *decisionmap = solv->decisionmap;
2536
2537   queue_empty(removed);
2538   for (i = 0; i < solv->decisionq.count; i++)
2539     {
2540       p = solv->decisionq.elements[i];
2541       if (p > 0)
2542         continue;       /* conflicts only, please */
2543       why = solv->decisionq_why.elements[i];
2544       if (why == 0)
2545         {
2546           /* no rule involved, must be a orphan package drop */
2547           continue;
2548         }
2549       /* we never do conflicts on free decisions, so there
2550        * must have been an unit rule */
2551       assert(why > 0);
2552       r = solv->rules + why;
2553       if (r->d < 0 && decisionmap[-p])
2554         {
2555           /* rule is now disabled, remove from decisionmap */
2556           POOL_DEBUG(SOLV_DEBUG_SOLVER, "removing conflict for package %s[%d]\n", pool_solvid2str(pool, -p), -p);
2557           queue_push(removed, -p);
2558           queue_push(removed, decisionmap[-p]);
2559           decisionmap[-p] = 0;
2560         }
2561     }
2562   if (!removed->count)
2563     return;
2564   /* we removed some confliced packages. some of them might still
2565    * be in conflict, so search for unit rules and re-conflict */
2566   new = 0;
2567   for (i = n = 1, r = solv->rules + i; n < solv->nrules; i++, r++, n++)
2568     {
2569       if (i == solv->nrules)
2570         {
2571           i = 1;
2572           r = solv->rules + i;
2573         }
2574       if (r->d < 0)
2575         continue;
2576       if (!r->w2)
2577         {
2578           if (r->p < 0 && !decisionmap[-r->p])
2579             new = r->p;
2580         }
2581       else if (!r->d)
2582         {
2583           /* binary rule */
2584           if (r->p < 0 && decisionmap[-r->p] == 0 && DECISIONMAP_FALSE(r->w2))
2585             new = r->p;
2586           else if (r->w2 < 0 && decisionmap[-r->w2] == 0 && DECISIONMAP_FALSE(r->p))
2587             new = r->w2;
2588         }
2589       else
2590         {
2591           if (r->p < 0 && decisionmap[-r->p] == 0)
2592             new = r->p;
2593           if (new || DECISIONMAP_FALSE(r->p))
2594             {
2595               dp = pool->whatprovidesdata + r->d;
2596               while ((p = *dp++) != 0)
2597                 {
2598                   if (new && p == new)
2599                     continue;
2600                   if (p < 0 && decisionmap[-p] == 0)
2601                     {
2602                       if (new)
2603                         {
2604                           new = 0;
2605                           break;
2606                         }
2607                       new = p;
2608                     }
2609                   else if (!DECISIONMAP_FALSE(p))
2610                     {
2611                       new = 0;
2612                       break;
2613                     }
2614                 }
2615             }
2616         }
2617       if (new)
2618         {
2619           POOL_DEBUG(SOLV_DEBUG_SOLVER, "re-conflicting package %s[%d]\n", pool_solvid2str(pool, -new), -new);
2620           decisionmap[-new] = -1;
2621           new = 0;
2622           n = 0;        /* redo all rules */
2623         }
2624     }
2625 }
2626
2627 static inline void
2628 undo_removedisabledconflicts(Solver *solv, Queue *removed)
2629 {
2630   int i;
2631   for (i = 0; i < removed->count; i += 2)
2632     solv->decisionmap[removed->elements[i]] = removed->elements[i + 1];
2633 }
2634
2635
2636 /*-------------------------------------------------------------------
2637  *
2638  * weaken solvable dependencies
2639  */
2640
2641 static void
2642 weaken_solvable_deps(Solver *solv, Id p)
2643 {
2644   int i;
2645   Rule *r;
2646
2647   for (i = 1, r = solv->rules + i; i < solv->rpmrules_end; i++, r++)
2648     {
2649       if (r->p != -p)
2650         continue;
2651       if ((r->d == 0 || r->d == -1) && r->w2 < 0)
2652         continue;       /* conflict */
2653       queue_push(&solv->weakruleq, i);
2654     }
2655 }
2656
2657
2658 /********************************************************************/
2659 /* main() */
2660
2661
2662 void
2663 solver_calculate_noobsmap(Pool *pool, Queue *job, Map *noobsmap)
2664 {
2665   int i;
2666   Id how, what, select;
2667   Id p, pp;
2668   for (i = 0; i < job->count; i += 2)
2669     {
2670       how = job->elements[i];
2671       if ((how & SOLVER_JOBMASK) != SOLVER_NOOBSOLETES)
2672         continue;
2673       what = job->elements[i + 1];
2674       select = how & SOLVER_SELECTMASK;
2675       if (!noobsmap->size)
2676         map_grow(noobsmap, pool->nsolvables);
2677       if (select == SOLVER_SOLVABLE_ALL)
2678         {
2679           FOR_POOL_SOLVABLES(p)
2680             MAPSET(noobsmap, p);
2681         }
2682       else if (select == SOLVER_SOLVABLE_REPO)
2683         {
2684           Solvable *s;
2685           Repo *repo = pool_id2repo(pool, what);
2686           if (repo)
2687             FOR_REPO_SOLVABLES(repo, p, s)
2688               MAPSET(noobsmap, p);
2689         }
2690       FOR_JOB_SELECT(p, pp, select, what)
2691         MAPSET(noobsmap, p);
2692     }
2693 }
2694
2695 /*
2696  * add a rule created by a job, record job number and weak flag
2697  */
2698 static inline void
2699 solver_addjobrule(Solver *solv, Id p, Id d, Id job, int weak)
2700 {
2701   solver_addrule(solv, p, d);
2702   queue_push(&solv->ruletojob, job);
2703   if (weak)
2704     queue_push(&solv->weakruleq, solv->nrules - 1);
2705 }
2706
2707 static inline void
2708 add_cleandeps_package(Solver *solv, Id p)
2709 {
2710   if (!solv->cleandeps_updatepkgs)
2711     {
2712       solv->cleandeps_updatepkgs = solv_calloc(1, sizeof(Queue));
2713       queue_init(solv->cleandeps_updatepkgs);
2714     }
2715   queue_pushunique(solv->cleandeps_updatepkgs, p);
2716 }
2717
2718 static void
2719 add_update_target(Solver *solv, Id p, Id how)
2720 {
2721   Pool *pool = solv->pool;
2722   Solvable *s = pool->solvables + p;
2723   Repo *installed = solv->installed;
2724   Id pi, pip;
2725   if (!solv->update_targets)
2726     {
2727       solv->update_targets = solv_calloc(1, sizeof(Queue));
2728       queue_init(solv->update_targets);
2729     }
2730   if (s->repo == installed)
2731     {
2732       queue_push2(solv->update_targets, p, p);
2733       return;
2734     }
2735   FOR_PROVIDES(pi, pip, s->name)
2736     {
2737       Solvable *si = pool->solvables + pi;
2738       if (si->repo != installed || si->name != s->name)
2739         continue;
2740       if (how & SOLVER_FORCEBEST)
2741         {
2742           if (!solv->bestupdatemap.size)
2743             map_grow(&solv->bestupdatemap, installed->end - installed->start);
2744           MAPSET(&solv->bestupdatemap, pi - installed->start);
2745         }
2746       if (how & SOLVER_CLEANDEPS)
2747         add_cleandeps_package(solv, pi);
2748       queue_push2(solv->update_targets, pi, p);
2749       /* check if it's ok to keep the installed package */
2750       if (s->evr == si->evr && solvable_identical(s, si))
2751         queue_push2(solv->update_targets, pi, pi);
2752     }
2753   if (s->obsoletes)
2754     {
2755       Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
2756       while ((obs = *obsp++) != 0)
2757         {
2758           FOR_PROVIDES(pi, pip, obs) 
2759             {
2760               Solvable *si = pool->solvables + pi;
2761               if (si->repo != installed)
2762                 continue;
2763               if (si->name == s->name)
2764                 continue;       /* already handled above */
2765               if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, si, obs))
2766                 continue;
2767               if (pool->obsoleteusescolors && !pool_colormatch(pool, s, si))
2768                 continue;
2769               if (how & SOLVER_FORCEBEST)
2770                 {
2771                   if (!solv->bestupdatemap.size)
2772                     map_grow(&solv->bestupdatemap, installed->end - installed->start);
2773                   MAPSET(&solv->bestupdatemap, pi - installed->start);
2774                 }
2775               if (how & SOLVER_CLEANDEPS)
2776                 add_cleandeps_package(solv, pi);
2777               queue_push2(solv->update_targets, pi, p);
2778             }
2779         }
2780     }
2781 }
2782
2783 static int
2784 transform_update_targets_sortfn(const void *ap, const void *bp, void *dp)
2785 {
2786   const Id *a = ap;
2787   const Id *b = bp;
2788   if (a[0] - b[0])
2789     return a[0] - b[0];
2790   return a[1] - b[1];
2791 }
2792
2793 static void
2794 transform_update_targets(Solver *solv)
2795 {
2796   Repo *installed = solv->installed;
2797   Queue *update_targets = solv->update_targets;
2798   int i, j;
2799   Id p, q, lastp, lastq;
2800
2801   if (!update_targets->count)
2802     {
2803       queue_free(update_targets);
2804       solv->update_targets = solv_free(update_targets);
2805       return;
2806     }
2807   if (update_targets->count > 2)
2808     solv_sort(update_targets->elements, update_targets->count >> 1, 2 * sizeof(Id), transform_update_targets_sortfn, solv);
2809   queue_insertn(update_targets, 0, installed->end - installed->start);
2810   lastp = lastq = 0;
2811   for (i = j = installed->end - installed->start; i < update_targets->count; i += 2)
2812     {
2813       if ((p = update_targets->elements[i]) != lastp)
2814         {
2815           if (!solv->updatemap.size)
2816             map_grow(&solv->updatemap, installed->end - installed->start);
2817           MAPSET(&solv->updatemap, p - installed->start);
2818           update_targets->elements[j++] = 0;                    /* finish old set */
2819           update_targets->elements[p - installed->start] = j;   /* start new set */
2820           lastp = p;
2821           lastq = 0;
2822         }
2823       if ((q = update_targets->elements[i + 1]) != lastq)
2824         {
2825           update_targets->elements[j++] = q;
2826           lastq = q;
2827         }
2828     }
2829   queue_truncate(update_targets, j);
2830   queue_push(update_targets, 0);        /* finish last set */
2831 }
2832
2833
2834 /*
2835  *
2836  * solve job queue
2837  *
2838  */
2839
2840 int
2841 solver_solve(Solver *solv, Queue *job)
2842 {
2843   Pool *pool = solv->pool;
2844   Repo *installed = solv->installed;
2845   int i;
2846   int oldnrules;
2847   Map addedmap;                /* '1' == have rpm-rules for solvable */
2848   Map installcandidatemap;
2849   Id how, what, select, name, weak, p, pp, d;
2850   Queue q;
2851   Solvable *s;
2852   Rule *r;
2853   int now, solve_start;
2854   int hasdupjob = 0;
2855   int hasbestinstalljob = 0;
2856
2857   solve_start = solv_timems(0);
2858
2859   /* log solver options */
2860   POOL_DEBUG(SOLV_DEBUG_STATS, "solver started\n");
2861   POOL_DEBUG(SOLV_DEBUG_STATS, "dosplitprovides=%d, noupdateprovide=%d, noinfarchcheck=%d\n", solv->dosplitprovides, solv->noupdateprovide, solv->noinfarchcheck);
2862   POOL_DEBUG(SOLV_DEBUG_STATS, "allowuninstall=%d, allowdowngrade=%d, allownamechange=%d, allowarchchange=%d, allowvendorchange=%d\n", solv->allowuninstall, solv->allowdowngrade, solv->allownamechange, solv->allowarchchange, solv->allowvendorchange);
2863   POOL_DEBUG(SOLV_DEBUG_STATS, "promoteepoch=%d, forbidselfconflicts=%d\n", pool->promoteepoch, pool->forbidselfconflicts);
2864   POOL_DEBUG(SOLV_DEBUG_STATS, "obsoleteusesprovides=%d, implicitobsoleteusesprovides=%d, obsoleteusescolors=%d\n", pool->obsoleteusesprovides, pool->implicitobsoleteusesprovides, pool->obsoleteusescolors);
2865   POOL_DEBUG(SOLV_DEBUG_STATS, "dontinstallrecommended=%d, addalreadyrecommended=%d\n", solv->dontinstallrecommended, solv->addalreadyrecommended);
2866
2867   /* create whatprovides if not already there */
2868   if (!pool->whatprovides)
2869     pool_createwhatprovides(pool);
2870
2871   /* create obsolete index */
2872   policy_create_obsolete_index(solv);
2873
2874   /* remember job */
2875   queue_free(&solv->job);
2876   queue_init_clone(&solv->job, job);
2877   solv->pooljobcnt = pool->pooljobs.count;
2878   if (pool->pooljobs.count)
2879     {
2880       queue_insertn(&solv->job, 0, pool->pooljobs.count);
2881       memcpy(solv->job.elements, pool->pooljobs.elements, pool->pooljobs.count * sizeof(Id));
2882     }
2883   job = &solv->job;
2884
2885   /* free old stuff */
2886   if (solv->update_targets)
2887     {
2888       queue_free(solv->update_targets);
2889       solv->update_targets = solv_free(solv->update_targets);
2890     }
2891   if (solv->cleandeps_updatepkgs)
2892     {
2893       queue_free(solv->cleandeps_updatepkgs);
2894       solv->cleandeps_updatepkgs = solv_free(solv->cleandeps_updatepkgs);
2895     }
2896
2897   /*
2898    * create basic rule set of all involved packages
2899    * use addedmap bitmap to make sure we don't create rules twice
2900    */
2901
2902   /* create noobsolete map if needed */
2903   solver_calculate_noobsmap(pool, job, &solv->noobsoletes);
2904
2905   map_init(&addedmap, pool->nsolvables);
2906   MAPSET(&addedmap, SYSTEMSOLVABLE);
2907
2908   map_init(&installcandidatemap, pool->nsolvables);
2909   queue_init(&q);
2910
2911   now = solv_timems(0);
2912   /*
2913    * create rules for all package that could be involved with the solving
2914    * so called: rpm rules
2915    *
2916    */
2917   if (installed)
2918     {
2919       /* check for update/verify jobs as they need to be known early */
2920       for (i = 0; i < job->count; i += 2)
2921         {
2922           how = job->elements[i];
2923           what = job->elements[i + 1];
2924           select = how & SOLVER_SELECTMASK;
2925           switch (how & SOLVER_JOBMASK)
2926             {
2927             case SOLVER_VERIFY:
2928               if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && installed && what == installed->repoid))
2929                 solv->fixmap_all = 1;
2930               FOR_JOB_SELECT(p, pp, select, what)
2931                 {
2932                   s = pool->solvables + p;
2933                   if (s->repo != installed)
2934                     continue;
2935                   if (!solv->fixmap.size)
2936                     map_grow(&solv->fixmap, installed->end - installed->start);
2937                   MAPSET(&solv->fixmap, p - installed->start);
2938                 }
2939               break;
2940             case SOLVER_UPDATE:
2941               if (select == SOLVER_SOLVABLE_ALL)
2942                 {
2943                   solv->updatemap_all = 1;
2944                   if (how & SOLVER_FORCEBEST)
2945                     solv->bestupdatemap_all = 1;
2946                   if (how & SOLVER_CLEANDEPS)
2947                     {
2948                       FOR_REPO_SOLVABLES(installed, p, s)
2949                         add_cleandeps_package(solv, p);
2950                     }
2951                 }
2952               else if (select == SOLVER_SOLVABLE_REPO)
2953                 {
2954                   Repo *repo = pool_id2repo(pool, what);
2955                   if (!repo)
2956                     break;
2957                   if (repo == installed && !(how & SOLVER_TARGETED))
2958                     {
2959                       solv->updatemap_all = 1;
2960                       if (how & SOLVER_FORCEBEST)
2961                         solv->bestupdatemap_all = 1;
2962                       if (how & SOLVER_CLEANDEPS)
2963                         {
2964                           FOR_REPO_SOLVABLES(installed, p, s)
2965                             add_cleandeps_package(solv, p);
2966                         }
2967                       break;
2968                     }
2969                   if (solv->noautotarget && !(how & SOLVER_TARGETED))
2970                     break;
2971                   /* targeted update */
2972                   FOR_REPO_SOLVABLES(repo, p, s)
2973                     add_update_target(solv, p, how);
2974                 }
2975               else
2976                 {
2977                   if (!(how & SOLVER_TARGETED))
2978                     {
2979                       int targeted = 1;
2980                       FOR_JOB_SELECT(p, pp, select, what)
2981                         {
2982                           s = pool->solvables + p;
2983                           if (s->repo != installed)
2984                             continue;
2985                           if (!solv->updatemap.size)
2986                             map_grow(&solv->updatemap, installed->end - installed->start);
2987                           MAPSET(&solv->updatemap, p - installed->start);
2988                           if (how & SOLVER_FORCEBEST)
2989                             {
2990                               if (!solv->bestupdatemap.size)
2991                                 map_grow(&solv->bestupdatemap, installed->end - installed->start);
2992                               MAPSET(&solv->bestupdatemap, p - installed->start);
2993                             }
2994                           if (how & SOLVER_CLEANDEPS)
2995                             add_cleandeps_package(solv, p);
2996                           targeted = 0;
2997                         }
2998                       if (!targeted || solv->noautotarget)
2999                         break;
3000                     }
3001                   FOR_JOB_SELECT(p, pp, select, what)
3002                     add_update_target(solv, p, how);
3003                 }
3004               break;
3005             default:
3006               break;
3007             }
3008         }
3009
3010       if (solv->update_targets)
3011         transform_update_targets(solv);
3012
3013       oldnrules = solv->nrules;
3014       FOR_REPO_SOLVABLES(installed, p, s)
3015         solver_addrpmrulesforsolvable(solv, s, &addedmap);
3016       POOL_DEBUG(SOLV_DEBUG_STATS, "added %d rpm rules for installed solvables\n", solv->nrules - oldnrules);
3017       oldnrules = solv->nrules;
3018       FOR_REPO_SOLVABLES(installed, p, s)
3019         solver_addrpmrulesforupdaters(solv, s, &addedmap, 1);
3020       POOL_DEBUG(SOLV_DEBUG_STATS, "added %d rpm rules for updaters of installed solvables\n", solv->nrules - oldnrules);
3021     }
3022
3023   /*
3024    * create rules for all packages involved in the job
3025    * (to be installed or removed)
3026    */
3027     
3028   oldnrules = solv->nrules;
3029   for (i = 0; i < job->count; i += 2)
3030     {
3031       how = job->elements[i];
3032       what = job->elements[i + 1];
3033       select = how & SOLVER_SELECTMASK;
3034
3035       switch (how & SOLVER_JOBMASK)
3036         {
3037         case SOLVER_INSTALL:
3038           FOR_JOB_SELECT(p, pp, select, what)
3039             {
3040               MAPSET(&installcandidatemap, p);
3041               solver_addrpmrulesforsolvable(solv, pool->solvables + p, &addedmap);
3042             }
3043           break;
3044         case SOLVER_DISTUPGRADE:
3045           if (select == SOLVER_SOLVABLE_ALL)
3046             {
3047               solv->dupmap_all = 1;
3048               solv->updatemap_all = 1;
3049               if (how & SOLVER_FORCEBEST)
3050                 solv->bestupdatemap_all = 1;
3051             }
3052           if (!solv->dupmap_all)
3053             hasdupjob = 1;
3054           break;
3055         default:
3056           break;
3057         }
3058     }
3059   POOL_DEBUG(SOLV_DEBUG_STATS, "added %d rpm rules for packages involved in a job\n", solv->nrules - oldnrules);
3060
3061     
3062   /*
3063    * add rules for suggests, enhances
3064    */
3065   oldnrules = solv->nrules;
3066   solver_addrpmrulesforweak(solv, &addedmap);
3067   POOL_DEBUG(SOLV_DEBUG_STATS, "added %d rpm rules because of weak dependencies\n", solv->nrules - oldnrules);
3068
3069   /*
3070    * first pass done, we now have all the rpm rules we need.
3071    * unify existing rules before going over all job rules and
3072    * policy rules.
3073    * at this point the system is always solvable,
3074    * as an empty system (remove all packages) is a valid solution
3075    */
3076
3077   IF_POOLDEBUG (SOLV_DEBUG_STATS)
3078     {
3079       int possible = 0, installable = 0;
3080       for (i = 1; i < pool->nsolvables; i++)
3081         {
3082           if (pool_installable(pool, pool->solvables + i))
3083             installable++;
3084           if (MAPTST(&addedmap, i))
3085             possible++;
3086         }
3087       POOL_DEBUG(SOLV_DEBUG_STATS, "%d of %d installable solvables considered for solving\n", possible, installable);
3088     }
3089
3090   solver_unifyrules(solv);                          /* remove duplicate rpm rules */
3091   solv->rpmrules_end = solv->nrules;              /* mark end of rpm rules */
3092
3093   POOL_DEBUG(SOLV_DEBUG_STATS, "rpm rule memory used: %d K\n", solv->nrules * (int)sizeof(Rule) / 1024);
3094   POOL_DEBUG(SOLV_DEBUG_STATS, "rpm rule creation took %d ms\n", solv_timems(now));
3095
3096   /* create dup maps if needed. We need the maps early to create our
3097    * update rules */
3098   if (hasdupjob)
3099     solver_createdupmaps(solv);
3100
3101   /*
3102    * create feature rules
3103    * 
3104    * foreach installed:
3105    *   create assertion (keep installed, if no update available)
3106    *   or
3107    *   create update rule (A|update1(A)|update2(A)|...)
3108    * 
3109    * those are used later on to keep a version of the installed packages in
3110    * best effort mode
3111    */
3112     
3113   solv->featurerules = solv->nrules;              /* mark start of feature rules */
3114   if (installed)
3115     {
3116       /* foreach possibly installed solvable */
3117       for (i = installed->start, s = pool->solvables + i; i < installed->end; i++, s++)
3118         {
3119           if (s->repo != installed)
3120             {
3121               solver_addrule(solv, 0, 0);       /* create dummy rule */
3122               continue;
3123             }
3124           solver_addupdaterule(solv, s, 1);    /* allow s to be updated */
3125         }
3126       /* make sure we accounted for all rules */
3127       assert(solv->nrules - solv->featurerules == installed->end - installed->start);
3128     }
3129   solv->featurerules_end = solv->nrules;
3130
3131     /*
3132      * Add update rules for installed solvables
3133      * 
3134      * almost identical to feature rules
3135      * except that downgrades/archchanges/vendorchanges are not allowed
3136      */
3137     
3138   solv->updaterules = solv->nrules;
3139
3140   if (installed)
3141     { /* foreach installed solvables */
3142       /* we create all update rules, but disable some later on depending on the job */
3143       for (i = installed->start, s = pool->solvables + i; i < installed->end; i++, s++)
3144         {
3145           Rule *sr;
3146
3147           if (s->repo != installed)
3148             {
3149               solver_addrule(solv, 0, 0);       /* create dummy rule */
3150               continue;
3151             }
3152           solver_addupdaterule(solv, s, 0);     /* allowall = 0: downgrades not allowed */
3153           /*
3154            * check for and remove duplicate
3155            */
3156           r = solv->rules + solv->nrules - 1;           /* r: update rule */
3157           sr = r - (installed->end - installed->start); /* sr: feature rule */
3158           /* it's orphaned if there is no feature rule or the feature rule
3159            * consists just of the installed package */
3160           if (!sr->p || (sr->p == i && !sr->d && !sr->w2))
3161             queue_push(&solv->orphaned, i);
3162           if (!r->p)
3163             {
3164               assert(solv->dupmap_all && !sr->p);
3165               continue;
3166             }
3167           if (!solver_rulecmp(solv, r, sr))
3168             memset(sr, 0, sizeof(*sr));         /* delete unneeded feature rule */
3169           else
3170             solver_disablerule(solv, sr);       /* disable feature rule */
3171         }
3172       /* consistency check: we added a rule for _every_ installed solvable */
3173       assert(solv->nrules - solv->updaterules == installed->end - installed->start);
3174     }
3175   solv->updaterules_end = solv->nrules;
3176
3177
3178   /*
3179    * now add all job rules
3180    */
3181
3182   solv->jobrules = solv->nrules;
3183   for (i = 0; i < job->count; i += 2)
3184     {
3185       oldnrules = solv->nrules;
3186
3187       if (i && i == solv->pooljobcnt)
3188         POOL_DEBUG(SOLV_DEBUG_JOB, "end of pool jobs\n");
3189       how = job->elements[i];
3190       what = job->elements[i + 1];
3191       weak = how & SOLVER_WEAK;
3192       select = how & SOLVER_SELECTMASK;
3193       switch (how & SOLVER_JOBMASK)
3194         {
3195         case SOLVER_INSTALL:
3196           POOL_DEBUG(SOLV_DEBUG_JOB, "job: %sinstall %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
3197           if ((how & SOLVER_CLEANDEPS) != 0 && !solv->cleandepsmap.size && installed)
3198             map_grow(&solv->cleandepsmap, installed->end - installed->start);
3199           if (select == SOLVER_SOLVABLE)
3200             {
3201               p = what;
3202               d = 0;
3203             }
3204           else
3205             {
3206               queue_empty(&q);
3207               FOR_JOB_SELECT(p, pp, select, what)
3208                 queue_push(&q, p);
3209               if (!q.count)
3210                 {
3211                   /* no candidate found, make this an impossible rule */
3212                   queue_push(&q, -SYSTEMSOLVABLE);
3213                 }
3214               p = queue_shift(&q);      /* get first candidate */
3215               d = !q.count ? 0 : pool_queuetowhatprovides(pool, &q);    /* internalize */
3216             }
3217           /* force install of namespace supplements hack */
3218           if (select == SOLVER_SOLVABLE_PROVIDES && !d && (p == SYSTEMSOLVABLE || p == -SYSTEMSOLVABLE) && ISRELDEP(what))
3219             {
3220               Reldep *rd = GETRELDEP(pool, what);
3221               if (rd->flags == REL_NAMESPACE)
3222                 {
3223                   p = SYSTEMSOLVABLE;
3224                   if (!solv->installsuppdepq)
3225                     {
3226                       solv->installsuppdepq = solv_calloc(1, sizeof(Queue));
3227                       queue_init(solv->installsuppdepq);
3228                     }
3229                   queue_pushunique(solv->installsuppdepq, rd->evr == 0 ? rd->name : what);
3230                 }
3231             }
3232           solver_addjobrule(solv, p, d, i, weak);
3233           if (how & SOLVER_FORCEBEST)
3234             hasbestinstalljob = 1;
3235           break;
3236         case SOLVER_ERASE:
3237           POOL_DEBUG(SOLV_DEBUG_JOB, "job: %s%serase %s\n", weak ? "weak " : "", how & SOLVER_CLEANDEPS ? "clean deps " : "", solver_select2str(pool, select, what));
3238           if ((how & SOLVER_CLEANDEPS) != 0 && !solv->cleandepsmap.size && installed)
3239             map_grow(&solv->cleandepsmap, installed->end - installed->start);
3240           /* specific solvable: by id or by nevra */
3241           name = (select == SOLVER_SOLVABLE || (select == SOLVER_SOLVABLE_NAME && ISRELDEP(what))) ? 0 : -1;
3242           if (select == SOLVER_SOLVABLE_ALL)    /* hmmm ;) */
3243             {
3244               FOR_POOL_SOLVABLES(p)
3245                 solver_addjobrule(solv, -p, 0, i, weak);
3246             }
3247           else if (select == SOLVER_SOLVABLE_REPO)
3248             {
3249               Repo *repo = pool_id2repo(pool, what);
3250               if (repo)
3251                 FOR_REPO_SOLVABLES(repo, p, s)
3252                   solver_addjobrule(solv, -p, 0, i, weak);
3253             }
3254           FOR_JOB_SELECT(p, pp, select, what)
3255             {
3256               s = pool->solvables + p;
3257               if (installed && s->repo == installed)
3258                 name = !name ? s->name : -1;
3259               solver_addjobrule(solv, -p, 0, i, weak);
3260             }
3261           /* special case for "erase a specific solvable": we also
3262            * erase all other solvables with that name, so that they
3263            * don't get picked up as replacement.
3264            * name is > 0 if exactly one installed solvable matched.
3265            */
3266           /* XXX: look also at packages that obsolete this package? */
3267           if (name > 0)
3268             {
3269               int j, k;
3270               k = solv->nrules;
3271               FOR_PROVIDES(p, pp, name)
3272                 {
3273                   s = pool->solvables + p;
3274                   if (s->name != name)
3275                     continue;
3276                   /* keep other versions installed */
3277                   if (s->repo == installed)
3278                     continue;
3279                   /* keep installcandidates of other jobs */
3280                   if (MAPTST(&installcandidatemap, p))
3281                     continue;
3282                   /* don't add the same rule twice */
3283                   for (j = oldnrules; j < k; j++)
3284                     if (solv->rules[j].p == -p)
3285                       break;
3286                   if (j == k)
3287                     solver_addjobrule(solv, -p, 0, i, weak);    /* remove by id */
3288                 }
3289             }
3290           break;
3291
3292         case SOLVER_UPDATE:
3293           POOL_DEBUG(SOLV_DEBUG_JOB, "job: %supdate %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
3294           break;
3295         case SOLVER_VERIFY:
3296           POOL_DEBUG(SOLV_DEBUG_JOB, "job: %sverify %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
3297           break;
3298         case SOLVER_WEAKENDEPS:
3299           POOL_DEBUG(SOLV_DEBUG_JOB, "job: %sweaken deps %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
3300           if (select != SOLVER_SOLVABLE)
3301             break;
3302           s = pool->solvables + what;
3303           weaken_solvable_deps(solv, what);
3304           break;
3305         case SOLVER_NOOBSOLETES:
3306           POOL_DEBUG(SOLV_DEBUG_JOB, "job: %sno obsolete %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
3307           break;
3308         case SOLVER_LOCK:
3309           POOL_DEBUG(SOLV_DEBUG_JOB, "job: %slock %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
3310           if (select == SOLVER_SOLVABLE_ALL)
3311             {
3312               FOR_POOL_SOLVABLES(p)
3313                 solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, i, weak);
3314             }
3315           else if (select == SOLVER_SOLVABLE_REPO)
3316             {
3317               Repo *repo = pool_id2repo(pool, what);
3318               if (repo)
3319                 FOR_REPO_SOLVABLES(repo, p, s)
3320                   solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, i, weak);
3321             }
3322           FOR_JOB_SELECT(p, pp, select, what)
3323             solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, i, weak);
3324           break;
3325         case SOLVER_DISTUPGRADE:
3326           POOL_DEBUG(SOLV_DEBUG_JOB, "job: distupgrade %s\n", solver_select2str(pool, select, what));
3327           break;
3328         case SOLVER_DROP_ORPHANED:
3329           POOL_DEBUG(SOLV_DEBUG_JOB, "job: drop orphaned %s\n", solver_select2str(pool, select, what));
3330           if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && installed && what == installed->repoid))
3331             solv->droporphanedmap_all = 1;
3332           FOR_JOB_SELECT(p, pp, select, what)
3333             {
3334               s = pool->solvables + p;
3335               if (!installed || s->repo != installed)
3336                 continue;
3337               if (!solv->droporphanedmap.size)
3338                 map_grow(&solv->droporphanedmap, installed->end - installed->start);
3339               MAPSET(&solv->droporphanedmap, p - installed->start);
3340             }
3341           break;
3342         case SOLVER_USERINSTALLED:
3343           POOL_DEBUG(SOLV_DEBUG_JOB, "job: user installed %s\n", solver_select2str(pool, select, what));
3344           break;
3345         default:
3346           POOL_DEBUG(SOLV_DEBUG_JOB, "job: unknown job\n");
3347           break;
3348         }
3349         
3350         /*
3351          * debug
3352          */
3353         
3354       IF_POOLDEBUG (SOLV_DEBUG_JOB)
3355         {
3356           int j;
3357           if (solv->nrules == oldnrules)
3358             POOL_DEBUG(SOLV_DEBUG_JOB, "  - no rule created\n");
3359           for (j = oldnrules; j < solv->nrules; j++)
3360             {
3361               POOL_DEBUG(SOLV_DEBUG_JOB, "  - job ");
3362               solver_printrule(solv, SOLV_DEBUG_JOB, solv->rules + j);
3363             }
3364         }
3365     }
3366   assert(solv->ruletojob.count == solv->nrules - solv->jobrules);
3367   solv->jobrules_end = solv->nrules;
3368
3369   /* now create infarch and dup rules */
3370   if (!solv->noinfarchcheck)
3371     {
3372       solver_addinfarchrules(solv, &addedmap);
3373       if (pool->obsoleteusescolors)
3374         {
3375           /* currently doesn't work well with infarch rules, so make
3376            * them weak */
3377           for (i = solv->infarchrules; i < solv->infarchrules_end; i++)
3378             queue_push(&solv->weakruleq, i);
3379         }
3380     }
3381   else
3382     solv->infarchrules = solv->infarchrules_end = solv->nrules;
3383
3384   if (hasdupjob)
3385     solver_addduprules(solv, &addedmap);
3386   else
3387     solv->duprules = solv->duprules_end = solv->nrules;
3388
3389   if (solv->bestupdatemap_all || solv->bestupdatemap.size || hasbestinstalljob)
3390     solver_addbestrules(solv, hasbestinstalljob);
3391   else
3392     solv->bestrules = solv->bestrules_end = solv->nrules;
3393
3394   if (hasdupjob)
3395     solver_freedupmaps(solv);   /* no longer needed */
3396
3397   if (1)
3398     solver_addchoicerules(solv);
3399   else
3400     solv->choicerules = solv->choicerules_end = solv->nrules;
3401
3402   if (0)
3403     {
3404       for (i = solv->featurerules; i < solv->nrules; i++)
3405         solver_printruleclass(solv, SOLV_DEBUG_RESULT, solv->rules + i);
3406     }
3407   /* all rules created
3408    * --------------------------------------------------------------
3409    * prepare for solving
3410    */
3411     
3412   /* free unneeded memory */
3413   map_free(&addedmap);
3414   map_free(&installcandidatemap);
3415   queue_free(&q);
3416
3417   POOL_DEBUG(SOLV_DEBUG_STATS, "%d rpm rules, 2 * %d update rules, %d job rules, %d infarch rules, %d dup rules, %d choice rules, %d best rules\n", solv->rpmrules_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);
3418   POOL_DEBUG(SOLV_DEBUG_STATS, "overall rule memory used: %d K\n", solv->nrules * (int)sizeof(Rule) / 1024);
3419
3420   /* create weak map */
3421   map_init(&solv->weakrulemap, solv->nrules);
3422   for (i = 0; i < solv->weakruleq.count; i++)
3423     {
3424       p = solv->weakruleq.elements[i];
3425       MAPSET(&solv->weakrulemap, p);
3426     }
3427
3428   /* enable cleandepsmap creation if we have updatepkgs */
3429   if (solv->cleandeps_updatepkgs && !solv->cleandepsmap.size)
3430     map_grow(&solv->cleandepsmap, installed->end - installed->start);
3431   /* no mistakes */
3432   if (solv->cleandeps_mistakes)
3433     {    
3434       queue_free(solv->cleandeps_mistakes);
3435       solv->cleandeps_mistakes = solv_free(solv->cleandeps_mistakes);
3436     }    
3437
3438   /* all new rules are learnt after this point */
3439   solv->learntrules = solv->nrules;
3440
3441   /* create watches chains */
3442   makewatches(solv);
3443
3444   /* create assertion index. it is only used to speed up
3445    * makeruledecsions() a bit */
3446   for (i = 1, r = solv->rules + i; i < solv->nrules; i++, r++)
3447     if (r->p && !r->w2 && (r->d == 0 || r->d == -1))
3448       queue_push(&solv->ruleassertions, i);
3449
3450   /* disable update rules that conflict with our job */
3451   solver_disablepolicyrules(solv);
3452
3453   /* make initial decisions based on assertion rules */
3454   makeruledecisions(solv);
3455   POOL_DEBUG(SOLV_DEBUG_SOLVER, "problems so far: %d\n", solv->problems.count);
3456
3457   /*
3458    * ********************************************
3459    * solve!
3460    * ********************************************
3461    */
3462     
3463   now = solv_timems(0);
3464   solver_run_sat(solv, 1, solv->dontinstallrecommended ? 0 : 1);
3465   POOL_DEBUG(SOLV_DEBUG_STATS, "solver took %d ms\n", solv_timems(now));
3466
3467   /*
3468    * prepare solution queue if there were problems
3469    */
3470   solver_prepare_solutions(solv);
3471
3472   POOL_DEBUG(SOLV_DEBUG_STATS, "final solver statistics: %d problems, %d learned rules, %d unsolvable\n", solv->problems.count / 2, solv->stats_learned, solv->stats_unsolvable);
3473   POOL_DEBUG(SOLV_DEBUG_STATS, "solver_solve took %d ms\n", solv_timems(solve_start));
3474
3475   /* return number of problems */
3476   return solv->problems.count ? solv->problems.count / 2 : 0;
3477 }
3478
3479 Transaction *
3480 solver_create_transaction(Solver *solv)
3481 {
3482   return transaction_create_decisionq(solv->pool, &solv->decisionq, &solv->noobsoletes);
3483 }
3484
3485 void solver_get_orphaned(Solver *solv, Queue *orphanedq)
3486 {
3487   queue_free(orphanedq);
3488   queue_init_clone(orphanedq, &solv->orphaned);
3489 }
3490
3491 void solver_get_recommendations(Solver *solv, Queue *recommendationsq, Queue *suggestionsq, int noselected)
3492 {
3493   Pool *pool = solv->pool;
3494   Queue redoq, disabledq;
3495   int goterase, i;
3496   Solvable *s;
3497   Rule *r;
3498   Map obsmap;
3499
3500   if (!recommendationsq && !suggestionsq)
3501     return;
3502
3503   map_init(&obsmap, pool->nsolvables);
3504   if (solv->installed)
3505     {
3506       Id obs, *obsp, p, po, ppo;
3507       for (p = solv->installed->start; p < solv->installed->end; p++)
3508         {
3509           s = pool->solvables + p;
3510           if (s->repo != solv->installed || !s->obsoletes)
3511             continue;
3512           if (solv->decisionmap[p] <= 0)
3513             continue;
3514           if (solv->noobsoletes.size && MAPTST(&solv->noobsoletes, p))
3515             continue;
3516           obsp = s->repo->idarraydata + s->obsoletes;
3517           /* foreach obsoletes */
3518           while ((obs = *obsp++) != 0)
3519             FOR_PROVIDES(po, ppo, obs)
3520               MAPSET(&obsmap, po);
3521         }
3522     }
3523
3524   queue_init(&redoq);
3525   queue_init(&disabledq);
3526   goterase = 0;
3527   /* disable all erase jobs (including weak "keep uninstalled" rules) */
3528   for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++)
3529     {
3530       if (r->d < 0)     /* disabled ? */
3531         continue;
3532       if (r->p >= 0)    /* install job? */
3533         continue;
3534       queue_push(&disabledq, i);
3535       solver_disablerule(solv, r);
3536       goterase++;
3537     }
3538   
3539   if (goterase)
3540     {
3541       enabledisablelearntrules(solv);
3542       removedisabledconflicts(solv, &redoq);
3543     }
3544
3545   /*
3546    * find recommended packages
3547    */
3548   if (recommendationsq)
3549     {
3550       Id rec, *recp, p, pp;
3551
3552       queue_empty(recommendationsq);
3553       /* create map of all recommened packages */
3554       solv->recommends_index = -1;
3555       MAPZERO(&solv->recommendsmap);
3556
3557       /* put all packages the solver already chose in the map */
3558       if (solv->decisioncnt_weak)
3559         {
3560           for (i = solv->decisioncnt_weak; i < solv->decisioncnt_orphan; i++)
3561             {
3562               Id why;
3563               why = solv->decisionq_why.elements[i];
3564               if (why)
3565                 continue;       /* forced by unit rule */
3566               p = solv->decisionq.elements[i];
3567               if (p < 0)
3568                 continue;
3569               MAPSET(&solv->recommendsmap, p);
3570             }
3571         }
3572
3573       for (i = 0; i < solv->decisionq.count; i++)
3574         {
3575           p = solv->decisionq.elements[i];
3576           if (p < 0)
3577             continue;
3578           s = pool->solvables + p;
3579           if (s->recommends)
3580             {
3581               recp = s->repo->idarraydata + s->recommends;
3582               while ((rec = *recp++) != 0)
3583                 {
3584                   FOR_PROVIDES(p, pp, rec)
3585                     if (solv->decisionmap[p] > 0)
3586                       break;
3587                   if (p)
3588                     {
3589                       if (!noselected)
3590                         {
3591                           FOR_PROVIDES(p, pp, rec)
3592                             if (solv->decisionmap[p] > 0)
3593                               MAPSET(&solv->recommendsmap, p);
3594                         }
3595                       continue; /* p != 0: already fulfilled */
3596                     }
3597                   FOR_PROVIDES(p, pp, rec)
3598                     MAPSET(&solv->recommendsmap, p);
3599                 }
3600             }
3601         }
3602       for (i = 1; i < pool->nsolvables; i++)
3603         {
3604           if (solv->decisionmap[i] < 0)
3605             continue;
3606           if (solv->decisionmap[i] > 0 && noselected)
3607             continue;
3608           if (MAPTST(&obsmap, i))
3609             continue;
3610           s = pool->solvables + i;
3611           if (!MAPTST(&solv->recommendsmap, i))
3612             {
3613               if (!s->supplements)
3614                 continue;
3615               if (!pool_installable(pool, s))
3616                 continue;
3617               if (!solver_is_supplementing(solv, s))
3618                 continue;
3619             }
3620           queue_push(recommendationsq, i);
3621         }
3622       /* we use MODE_SUGGEST here so that repo prio is ignored */
3623       policy_filter_unwanted(solv, recommendationsq, POLICY_MODE_SUGGEST);
3624     }
3625
3626   /*
3627    * find suggested packages
3628    */
3629     
3630   if (suggestionsq)
3631     {
3632       Id sug, *sugp, p, pp;
3633
3634       queue_empty(suggestionsq);
3635       /* create map of all suggests that are still open */
3636       solv->recommends_index = -1;
3637       MAPZERO(&solv->suggestsmap);
3638       for (i = 0; i < solv->decisionq.count; i++)
3639         {
3640           p = solv->decisionq.elements[i];
3641           if (p < 0)
3642             continue;
3643           s = pool->solvables + p;
3644           if (s->suggests)
3645             {
3646               sugp = s->repo->idarraydata + s->suggests;
3647               while ((sug = *sugp++) != 0)
3648                 {
3649                   FOR_PROVIDES(p, pp, sug)
3650                     if (solv->decisionmap[p] > 0)
3651                       break;
3652                   if (p)
3653                     {
3654                       if (!noselected)
3655                         {
3656                           FOR_PROVIDES(p, pp, sug)
3657                             if (solv->decisionmap[p] > 0)
3658                               MAPSET(&solv->suggestsmap, p);
3659                         }
3660                       continue; /* already fulfilled */
3661                     }
3662                   FOR_PROVIDES(p, pp, sug)
3663                     MAPSET(&solv->suggestsmap, p);
3664                 }
3665             }
3666         }
3667       for (i = 1; i < pool->nsolvables; i++)
3668         {
3669           if (solv->decisionmap[i] < 0)
3670             continue;
3671           if (solv->decisionmap[i] > 0 && noselected)
3672             continue;
3673           if (MAPTST(&obsmap, i))
3674             continue;
3675           s = pool->solvables + i;
3676           if (!MAPTST(&solv->suggestsmap, i))
3677             {
3678               if (!s->enhances)
3679                 continue;
3680               if (!pool_installable(pool, s))
3681                 continue;
3682               if (!solver_is_enhancing(solv, s))
3683                 continue;
3684             }
3685           queue_push(suggestionsq, i);
3686         }
3687       policy_filter_unwanted(solv, suggestionsq, POLICY_MODE_SUGGEST);
3688     }
3689
3690   /* undo removedisabledconflicts */
3691   if (redoq.count)
3692     undo_removedisabledconflicts(solv, &redoq);
3693   queue_free(&redoq);
3694   
3695   /* undo job rule disabling */
3696   for (i = 0; i < disabledq.count; i++)
3697     solver_enablerule(solv, solv->rules + disabledq.elements[i]);
3698   queue_free(&disabledq);
3699   map_free(&obsmap);
3700 }
3701
3702
3703 /***********************************************************************/
3704 /* disk usage computations */
3705
3706 /*-------------------------------------------------------------------
3707  * 
3708  * calculate DU changes
3709  */
3710
3711 void
3712 solver_calc_duchanges(Solver *solv, DUChanges *mps, int nmps)
3713 {
3714   Map installedmap;
3715
3716   solver_create_state_maps(solv, &installedmap, 0);
3717   pool_calc_duchanges(solv->pool, &installedmap, mps, nmps);
3718   map_free(&installedmap);
3719 }
3720
3721
3722 /*-------------------------------------------------------------------
3723  * 
3724  * calculate changes in install size
3725  */
3726
3727 int
3728 solver_calc_installsizechange(Solver *solv)
3729 {
3730   Map installedmap;
3731   int change;
3732
3733   solver_create_state_maps(solv, &installedmap, 0);
3734   change = pool_calc_installsizechange(solv->pool, &installedmap);
3735   map_free(&installedmap);
3736   return change;
3737 }
3738
3739 void
3740 solver_create_state_maps(Solver *solv, Map *installedmap, Map *conflictsmap)
3741 {
3742   pool_create_state_maps(solv->pool, &solv->decisionq, installedmap, conflictsmap);
3743 }
3744
3745 void
3746 solver_trivial_installable(Solver *solv, Queue *pkgs, Queue *res)
3747 {
3748   Pool *pool = solv->pool;
3749   Map installedmap;
3750   int i;
3751   pool_create_state_maps(pool,  &solv->decisionq, &installedmap, 0);
3752   pool_trivial_installable_noobsoletesmap(pool, &installedmap, pkgs, res, solv->noobsoletes.size ? &solv->noobsoletes : 0);
3753   for (i = 0; i < res->count; i++)
3754     if (res->elements[i] != -1)
3755       {
3756         Solvable *s = pool->solvables + pkgs->elements[i];
3757         if (!strncmp("patch:", pool_id2str(pool, s->name), 6) && solvable_is_irrelevant_patch(s, &installedmap, solv))
3758           res->elements[i] = -1;
3759       }
3760   map_free(&installedmap);
3761 }
3762
3763 /*-------------------------------------------------------------------
3764  * 
3765  * decision introspection
3766  */
3767
3768 int
3769 solver_get_decisionlevel(Solver *solv, Id p)
3770 {
3771   return solv->decisionmap[p];
3772 }
3773
3774 void
3775 solver_get_decisionqueue(Solver *solv, Queue *decisionq)
3776 {
3777   queue_free(decisionq);
3778   queue_init_clone(decisionq, &solv->decisionq);
3779 }
3780
3781 int
3782 solver_get_lastdecisionblocklevel(Solver *solv)
3783 {
3784   Id p;
3785   if (solv->decisionq.count == 0)
3786     return 0;
3787   p = solv->decisionq.elements[solv->decisionq.count - 1];
3788   if (p < 0)
3789     p = -p;
3790   return solv->decisionmap[p] < 0 ? -solv->decisionmap[p] : solv->decisionmap[p];
3791 }
3792
3793 void
3794 solver_get_decisionblock(Solver *solv, int level, Queue *decisionq)
3795 {
3796   Id p;
3797   int i;
3798
3799   queue_empty(decisionq);
3800   for (i = 0; i < solv->decisionq.count; i++)
3801     {
3802       p = solv->decisionq.elements[i];
3803       if (p < 0)
3804         p = -p;
3805       if (solv->decisionmap[p] == level || solv->decisionmap[p] == -level)
3806         break;
3807     }
3808   if (i == solv->decisionq.count)
3809     return;
3810   for (i = 0; i < solv->decisionq.count; i++)
3811     {
3812       p = solv->decisionq.elements[i];
3813       if (p < 0)
3814         p = -p;
3815       if (solv->decisionmap[p] == level || solv->decisionmap[p] == -level)
3816         queue_push(decisionq, p);
3817       else
3818         break;
3819     }
3820 }
3821
3822 int
3823 solver_describe_decision(Solver *solv, Id p, Id *infop)
3824 {
3825   int i;
3826   Id pp, why;
3827   
3828   if (infop)
3829     *infop = 0;
3830   if (!solv->decisionmap[p])
3831     return SOLVER_REASON_UNRELATED;
3832   pp = solv->decisionmap[p] < 0 ? -p : p;
3833   for (i = 0; i < solv->decisionq.count; i++)
3834     if (solv->decisionq.elements[i] == pp)
3835       break;
3836   if (i == solv->decisionq.count)       /* just in case... */
3837     return SOLVER_REASON_UNRELATED;
3838   why = solv->decisionq_why.elements[i];
3839   if (why > 0)
3840     {
3841       if (infop)
3842         *infop = why;
3843       return SOLVER_REASON_UNIT_RULE;
3844     }
3845   why = -why;
3846   if (i < solv->decisioncnt_update)
3847     {
3848       if (i == 0)
3849         {
3850           if (infop)
3851             *infop = SYSTEMSOLVABLE;
3852           return SOLVER_REASON_KEEP_INSTALLED;
3853         }
3854       if (infop)
3855         *infop = why;
3856       return SOLVER_REASON_RESOLVE_JOB;
3857     }
3858   if (i < solv->decisioncnt_keep)
3859     {
3860       if (why == 0 && pp < 0)
3861         return SOLVER_REASON_CLEANDEPS_ERASE;
3862       if (infop)
3863         {
3864           if (why >= solv->updaterules && why < solv->updaterules_end)
3865             *infop = why - solv->updaterules;
3866           else if (why >= solv->featurerules && why < solv->featurerules_end)
3867             *infop = why - solv->featurerules;
3868         }
3869       return SOLVER_REASON_UPDATE_INSTALLED;
3870     }
3871   if (i < solv->decisioncnt_resolve)
3872     {
3873       if (why == 0 && pp < 0)
3874         return SOLVER_REASON_CLEANDEPS_ERASE;
3875       if (infop)
3876         {
3877           if (why >= solv->updaterules && why < solv->updaterules_end)
3878             *infop = why - solv->updaterules;
3879           else if (why >= solv->featurerules && why < solv->featurerules_end)
3880             *infop = why - solv->featurerules;
3881         }
3882       return SOLVER_REASON_KEEP_INSTALLED;
3883     }
3884   if (i < solv->decisioncnt_weak)
3885     {
3886       if (infop)
3887         *infop = why;
3888       return SOLVER_REASON_RESOLVE;
3889     }
3890   if (solv->decisionq.count < solv->decisioncnt_orphan)
3891     return SOLVER_REASON_WEAKDEP;
3892   return SOLVER_REASON_RESOLVE_ORPHAN;
3893 }
3894
3895
3896 void
3897 solver_describe_weakdep_decision(Solver *solv, Id p, Queue *whyq)
3898 {
3899   Pool *pool = solv->pool;
3900   int i;
3901   int level = solv->decisionmap[p];
3902   int decisionno;
3903   Solvable *s;
3904
3905   queue_empty(whyq);
3906   if (level < 0)
3907     return;     /* huh? */
3908   for (decisionno = 0; decisionno < solv->decisionq.count; decisionno++)
3909     if (solv->decisionq.elements[decisionno] == p)
3910       break;
3911   if (decisionno == solv->decisionq.count)
3912     return;     /* huh? */
3913   if (decisionno < solv->decisioncnt_weak || decisionno >= solv->decisioncnt_orphan)
3914     return;     /* huh? */
3915
3916   /* 1) list all packages that recommend us */
3917   for (i = 1; i < pool->nsolvables; i++)
3918     {
3919       Id *recp, rec, pp2, p2;
3920       if (solv->decisionmap[i] < 0 || solv->decisionmap[i] >= level)
3921         continue;
3922       s = pool->solvables + i;
3923       if (!s->recommends)
3924         continue;
3925       if (!solv->addalreadyrecommended && s->repo == solv->installed)
3926         continue;
3927       recp = s->repo->idarraydata + s->recommends;
3928       while ((rec = *recp++) != 0)
3929         {
3930           int found = 0;
3931           FOR_PROVIDES(p2, pp2, rec)
3932             {
3933               if (p2 == p)
3934                 found = 1;
3935               else
3936                 {
3937                   /* if p2 is already installed, this recommends is ignored */
3938                   if (solv->decisionmap[p2] > 0 && solv->decisionmap[p2] < level)
3939                     break;
3940                 }
3941             }
3942           if (!p2 && found)
3943             {
3944               queue_push(whyq, SOLVER_REASON_RECOMMENDED);
3945               queue_push2(whyq, p2, rec);
3946             }
3947         }
3948     }
3949   /* 2) list all supplements */
3950   s = pool->solvables + p;
3951   if (s->supplements && level > 0)
3952     {
3953       Id *supp, sup, pp2, p2;
3954       /* this is a hack. to use solver_dep_fulfilled we temporarily clear
3955        * everything above our level in the decisionmap */
3956       for (i = decisionno; i < solv->decisionq.count; i++ )
3957         {
3958           p2 = solv->decisionq.elements[i];
3959           if (p2 > 0)
3960             solv->decisionmap[p2] = -solv->decisionmap[p2];
3961         }
3962       supp = s->repo->idarraydata + s->supplements;
3963       while ((sup = *supp++) != 0)
3964         if (solver_dep_fulfilled(solv, sup))
3965           {
3966             int found = 0;
3967             /* let's see if this is an easy supp */
3968             FOR_PROVIDES(p2, pp2, sup)
3969               {
3970                 if (!solv->addalreadyrecommended && solv->installed)
3971                   {
3972                     if (pool->solvables[p2].repo == solv->installed)
3973                       continue;
3974                   }
3975                 if (solv->decisionmap[p2] > 0 && solv->decisionmap[p2] < level)
3976                   {
3977                     queue_push(whyq, SOLVER_REASON_SUPPLEMENTED);
3978                     queue_push2(whyq, p2, sup);
3979                     found = 1;
3980                   }
3981               }
3982             if (!found)
3983               {
3984                 /* hard case, just note dependency with no package */
3985                 queue_push(whyq, SOLVER_REASON_SUPPLEMENTED);
3986                 queue_push2(whyq, 0, sup);
3987               }
3988           }
3989       for (i = decisionno; i < solv->decisionq.count; i++)
3990         {
3991           p2 = solv->decisionq.elements[i];
3992           if (p2 > 0)
3993             solv->decisionmap[p2] = -solv->decisionmap[p2];
3994         }
3995     }
3996 }
3997
3998 void
3999 pool_job2solvables(Pool *pool, Queue *pkgs, Id how, Id what)
4000 {
4001   Id p, pp;
4002   how &= SOLVER_SELECTMASK;
4003   queue_empty(pkgs);
4004   if (how == SOLVER_SOLVABLE_ALL)
4005     {
4006       FOR_POOL_SOLVABLES(p)
4007         queue_push(pkgs, p);
4008     }
4009   else if (how == SOLVER_SOLVABLE_REPO)
4010     {
4011       Repo *repo = pool_id2repo(pool, what);
4012       Solvable *s;
4013       if (repo)
4014         FOR_REPO_SOLVABLES(repo, p, s)
4015           queue_push(pkgs, p);
4016     }
4017   else
4018     {
4019       FOR_JOB_SELECT(p, pp, how, what)
4020         queue_push(pkgs, p);
4021     }
4022 }
4023
4024 int
4025 pool_isemptyupdatejob(Pool *pool, Id how, Id what)
4026 {
4027   Id p, pp, pi, pip;
4028   Id select = how & SOLVER_SELECTMASK;
4029   if ((how & SOLVER_JOBMASK) != SOLVER_UPDATE)
4030     return 0;
4031   if (select == SOLVER_SOLVABLE_ALL || select == SOLVER_SOLVABLE_REPO)
4032     return 0;
4033   if (!pool->installed)
4034     return 1;
4035   FOR_JOB_SELECT(p, pp, select, what)
4036     if (pool->solvables[p].repo == pool->installed)
4037       return 0;
4038   /* hard work */
4039   FOR_JOB_SELECT(p, pp, select, what)
4040     {
4041       Solvable *s = pool->solvables + p;
4042       FOR_PROVIDES(pi, pip, s->name)
4043         {
4044           Solvable *si = pool->solvables + pi;
4045           if (si->repo != pool->installed || si->name != s->name)
4046             continue;
4047           return 0;
4048         }
4049       if (s->obsoletes)
4050         {
4051           Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
4052           while ((obs = *obsp++) != 0)
4053             {
4054               FOR_PROVIDES(pi, pip, obs) 
4055                 {
4056                   Solvable *si = pool->solvables + pi;
4057                   if (si->repo != pool->installed)
4058                     continue;
4059                   if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, si, obs))
4060                     continue;
4061                   if (pool->obsoleteusescolors && !pool_colormatch(pool, s, si))
4062                     continue;
4063                   return 0;
4064                 }
4065             }
4066         }
4067     }
4068   return 1;
4069 }