implement special install/erase namespace provides hack
[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
2878   /* free old stuff */
2879   if (solv->update_targets)
2880     {
2881       queue_free(solv->update_targets);
2882       solv->update_targets = solv_free(solv->update_targets);
2883     }
2884   if (solv->cleandeps_updatepkgs)
2885     {
2886       queue_free(solv->cleandeps_updatepkgs);
2887       solv->cleandeps_updatepkgs = solv_free(solv->cleandeps_updatepkgs);
2888     }
2889
2890   /*
2891    * create basic rule set of all involved packages
2892    * use addedmap bitmap to make sure we don't create rules twice
2893    */
2894
2895   /* create noobsolete map if needed */
2896   solver_calculate_noobsmap(pool, job, &solv->noobsoletes);
2897
2898   map_init(&addedmap, pool->nsolvables);
2899   MAPSET(&addedmap, SYSTEMSOLVABLE);
2900
2901   map_init(&installcandidatemap, pool->nsolvables);
2902   queue_init(&q);
2903
2904   now = solv_timems(0);
2905   /*
2906    * create rules for all package that could be involved with the solving
2907    * so called: rpm rules
2908    *
2909    */
2910   if (installed)
2911     {
2912       /* check for update/verify jobs as they need to be known early */
2913       for (i = 0; i < job->count; i += 2)
2914         {
2915           how = job->elements[i];
2916           what = job->elements[i + 1];
2917           select = how & SOLVER_SELECTMASK;
2918           switch (how & SOLVER_JOBMASK)
2919             {
2920             case SOLVER_VERIFY:
2921               if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && installed && what == installed->repoid))
2922                 solv->fixmap_all = 1;
2923               FOR_JOB_SELECT(p, pp, select, what)
2924                 {
2925                   s = pool->solvables + p;
2926                   if (s->repo != installed)
2927                     continue;
2928                   if (!solv->fixmap.size)
2929                     map_grow(&solv->fixmap, installed->end - installed->start);
2930                   MAPSET(&solv->fixmap, p - installed->start);
2931                 }
2932               break;
2933             case SOLVER_UPDATE:
2934               if (select == SOLVER_SOLVABLE_ALL)
2935                 {
2936                   solv->updatemap_all = 1;
2937                   if (how & SOLVER_FORCEBEST)
2938                     solv->bestupdatemap_all = 1;
2939                   if (how & SOLVER_CLEANDEPS)
2940                     {
2941                       FOR_REPO_SOLVABLES(installed, p, s)
2942                         add_cleandeps_package(solv, p);
2943                     }
2944                 }
2945               else if (select == SOLVER_SOLVABLE_REPO)
2946                 {
2947                   Repo *repo = pool_id2repo(pool, what);
2948                   if (!repo)
2949                     break;
2950                   if (repo == installed && !(how & SOLVER_TARGETED))
2951                     {
2952                       solv->updatemap_all = 1;
2953                       if (how & SOLVER_FORCEBEST)
2954                         solv->bestupdatemap_all = 1;
2955                       if (how & SOLVER_CLEANDEPS)
2956                         {
2957                           FOR_REPO_SOLVABLES(installed, p, s)
2958                             add_cleandeps_package(solv, p);
2959                         }
2960                       break;
2961                     }
2962                   if (solv->noautotarget && !(how & SOLVER_TARGETED))
2963                     break;
2964                   /* targeted update */
2965                   FOR_REPO_SOLVABLES(repo, p, s)
2966                     add_update_target(solv, p, how);
2967                 }
2968               else
2969                 {
2970                   if (!(how & SOLVER_TARGETED))
2971                     {
2972                       int targeted = 1;
2973                       FOR_JOB_SELECT(p, pp, select, what)
2974                         {
2975                           s = pool->solvables + p;
2976                           if (s->repo != installed)
2977                             continue;
2978                           if (!solv->updatemap.size)
2979                             map_grow(&solv->updatemap, installed->end - installed->start);
2980                           MAPSET(&solv->updatemap, p - installed->start);
2981                           if (how & SOLVER_FORCEBEST)
2982                             {
2983                               if (!solv->bestupdatemap.size)
2984                                 map_grow(&solv->bestupdatemap, installed->end - installed->start);
2985                               MAPSET(&solv->bestupdatemap, p - installed->start);
2986                             }
2987                           if (how & SOLVER_CLEANDEPS)
2988                             add_cleandeps_package(solv, p);
2989                           targeted = 0;
2990                         }
2991                       if (!targeted || solv->noautotarget)
2992                         break;
2993                     }
2994                   FOR_JOB_SELECT(p, pp, select, what)
2995                     add_update_target(solv, p, how);
2996                 }
2997               break;
2998             default:
2999               break;
3000             }
3001         }
3002
3003       if (solv->update_targets)
3004         transform_update_targets(solv);
3005
3006       oldnrules = solv->nrules;
3007       FOR_REPO_SOLVABLES(installed, p, s)
3008         solver_addrpmrulesforsolvable(solv, s, &addedmap);
3009       POOL_DEBUG(SOLV_DEBUG_STATS, "added %d rpm rules for installed solvables\n", solv->nrules - oldnrules);
3010       oldnrules = solv->nrules;
3011       FOR_REPO_SOLVABLES(installed, p, s)
3012         solver_addrpmrulesforupdaters(solv, s, &addedmap, 1);
3013       POOL_DEBUG(SOLV_DEBUG_STATS, "added %d rpm rules for updaters of installed solvables\n", solv->nrules - oldnrules);
3014     }
3015
3016   /*
3017    * create rules for all packages involved in the job
3018    * (to be installed or removed)
3019    */
3020     
3021   oldnrules = solv->nrules;
3022   for (i = 0; i < job->count; i += 2)
3023     {
3024       how = job->elements[i];
3025       what = job->elements[i + 1];
3026       select = how & SOLVER_SELECTMASK;
3027
3028       switch (how & SOLVER_JOBMASK)
3029         {
3030         case SOLVER_INSTALL:
3031           FOR_JOB_SELECT(p, pp, select, what)
3032             {
3033               MAPSET(&installcandidatemap, p);
3034               solver_addrpmrulesforsolvable(solv, pool->solvables + p, &addedmap);
3035             }
3036           break;
3037         case SOLVER_DISTUPGRADE:
3038           if (select == SOLVER_SOLVABLE_ALL)
3039             {
3040               solv->dupmap_all = 1;
3041               solv->updatemap_all = 1;
3042               if (how & SOLVER_FORCEBEST)
3043                 solv->bestupdatemap_all = 1;
3044             }
3045           if (!solv->dupmap_all)
3046             hasdupjob = 1;
3047           break;
3048         default:
3049           break;
3050         }
3051     }
3052   POOL_DEBUG(SOLV_DEBUG_STATS, "added %d rpm rules for packages involved in a job\n", solv->nrules - oldnrules);
3053
3054     
3055   /*
3056    * add rules for suggests, enhances
3057    */
3058   oldnrules = solv->nrules;
3059   solver_addrpmrulesforweak(solv, &addedmap);
3060   POOL_DEBUG(SOLV_DEBUG_STATS, "added %d rpm rules because of weak dependencies\n", solv->nrules - oldnrules);
3061
3062   /*
3063    * first pass done, we now have all the rpm rules we need.
3064    * unify existing rules before going over all job rules and
3065    * policy rules.
3066    * at this point the system is always solvable,
3067    * as an empty system (remove all packages) is a valid solution
3068    */
3069
3070   IF_POOLDEBUG (SOLV_DEBUG_STATS)
3071     {
3072       int possible = 0, installable = 0;
3073       for (i = 1; i < pool->nsolvables; i++)
3074         {
3075           if (pool_installable(pool, pool->solvables + i))
3076             installable++;
3077           if (MAPTST(&addedmap, i))
3078             possible++;
3079         }
3080       POOL_DEBUG(SOLV_DEBUG_STATS, "%d of %d installable solvables considered for solving\n", possible, installable);
3081     }
3082
3083   solver_unifyrules(solv);                          /* remove duplicate rpm rules */
3084   solv->rpmrules_end = solv->nrules;              /* mark end of rpm rules */
3085
3086   POOL_DEBUG(SOLV_DEBUG_STATS, "rpm rule memory used: %d K\n", solv->nrules * (int)sizeof(Rule) / 1024);
3087   POOL_DEBUG(SOLV_DEBUG_STATS, "rpm rule creation took %d ms\n", solv_timems(now));
3088
3089   /* create dup maps if needed. We need the maps early to create our
3090    * update rules */
3091   if (hasdupjob)
3092     solver_createdupmaps(solv);
3093
3094   /*
3095    * create feature rules
3096    * 
3097    * foreach installed:
3098    *   create assertion (keep installed, if no update available)
3099    *   or
3100    *   create update rule (A|update1(A)|update2(A)|...)
3101    * 
3102    * those are used later on to keep a version of the installed packages in
3103    * best effort mode
3104    */
3105     
3106   solv->featurerules = solv->nrules;              /* mark start of feature rules */
3107   if (installed)
3108     {
3109       /* foreach possibly installed solvable */
3110       for (i = installed->start, s = pool->solvables + i; i < installed->end; i++, s++)
3111         {
3112           if (s->repo != installed)
3113             {
3114               solver_addrule(solv, 0, 0);       /* create dummy rule */
3115               continue;
3116             }
3117           solver_addupdaterule(solv, s, 1);    /* allow s to be updated */
3118         }
3119       /* make sure we accounted for all rules */
3120       assert(solv->nrules - solv->featurerules == installed->end - installed->start);
3121     }
3122   solv->featurerules_end = solv->nrules;
3123
3124     /*
3125      * Add update rules for installed solvables
3126      * 
3127      * almost identical to feature rules
3128      * except that downgrades/archchanges/vendorchanges are not allowed
3129      */
3130     
3131   solv->updaterules = solv->nrules;
3132
3133   if (installed)
3134     { /* foreach installed solvables */
3135       /* we create all update rules, but disable some later on depending on the job */
3136       for (i = installed->start, s = pool->solvables + i; i < installed->end; i++, s++)
3137         {
3138           Rule *sr;
3139
3140           if (s->repo != installed)
3141             {
3142               solver_addrule(solv, 0, 0);       /* create dummy rule */
3143               continue;
3144             }
3145           solver_addupdaterule(solv, s, 0);     /* allowall = 0: downgrades not allowed */
3146           /*
3147            * check for and remove duplicate
3148            */
3149           r = solv->rules + solv->nrules - 1;           /* r: update rule */
3150           sr = r - (installed->end - installed->start); /* sr: feature rule */
3151           /* it's orphaned if there is no feature rule or the feature rule
3152            * consists just of the installed package */
3153           if (!sr->p || (sr->p == i && !sr->d && !sr->w2))
3154             queue_push(&solv->orphaned, i);
3155           if (!r->p)
3156             {
3157               assert(solv->dupmap_all && !sr->p);
3158               continue;
3159             }
3160           if (!solver_rulecmp(solv, r, sr))
3161             memset(sr, 0, sizeof(*sr));         /* delete unneeded feature rule */
3162           else
3163             solver_disablerule(solv, sr);       /* disable feature rule */
3164         }
3165       /* consistency check: we added a rule for _every_ installed solvable */
3166       assert(solv->nrules - solv->updaterules == installed->end - installed->start);
3167     }
3168   solv->updaterules_end = solv->nrules;
3169
3170
3171   /*
3172    * now add all job rules
3173    */
3174
3175   solv->jobrules = solv->nrules;
3176   for (i = 0; i < job->count; i += 2)
3177     {
3178       oldnrules = solv->nrules;
3179
3180       how = job->elements[i];
3181       what = job->elements[i + 1];
3182       weak = how & SOLVER_WEAK;
3183       select = how & SOLVER_SELECTMASK;
3184       switch (how & SOLVER_JOBMASK)
3185         {
3186         case SOLVER_INSTALL:
3187           POOL_DEBUG(SOLV_DEBUG_JOB, "job: %sinstall %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
3188           if ((how & SOLVER_CLEANDEPS) != 0 && !solv->cleandepsmap.size && installed)
3189             map_grow(&solv->cleandepsmap, installed->end - installed->start);
3190           if (select == SOLVER_SOLVABLE)
3191             {
3192               p = what;
3193               d = 0;
3194             }
3195           else
3196             {
3197               queue_empty(&q);
3198               FOR_JOB_SELECT(p, pp, select, what)
3199                 queue_push(&q, p);
3200               if (!q.count)
3201                 {
3202                   /* no candidate found, make this an impossible rule */
3203                   queue_push(&q, -SYSTEMSOLVABLE);
3204                 }
3205               p = queue_shift(&q);      /* get first candidate */
3206               d = !q.count ? 0 : pool_queuetowhatprovides(pool, &q);    /* internalize */
3207             }
3208           /* force install of namespace supplements hack */
3209           if (select == SOLVER_SOLVABLE_PROVIDES && !d && (p == SYSTEMSOLVABLE || p == -SYSTEMSOLVABLE) && ISRELDEP(what))
3210             {
3211               Reldep *rd = GETRELDEP(pool, what);
3212               if (rd->flags == REL_NAMESPACE)
3213                 {
3214                   p = SYSTEMSOLVABLE;
3215                   if (!solv->installsuppdepq)
3216                     {
3217                       solv->installsuppdepq = solv_calloc(1, sizeof(Queue));
3218                       queue_init(solv->installsuppdepq);
3219                     }
3220                   queue_pushunique(solv->installsuppdepq, rd->evr == 0 ? rd->name : what);
3221                 }
3222             }
3223           solver_addjobrule(solv, p, d, i, weak);
3224           if (how & SOLVER_FORCEBEST)
3225             hasbestinstalljob = 1;
3226           break;
3227         case SOLVER_ERASE:
3228           POOL_DEBUG(SOLV_DEBUG_JOB, "job: %s%serase %s\n", weak ? "weak " : "", how & SOLVER_CLEANDEPS ? "clean deps " : "", solver_select2str(pool, select, what));
3229           if ((how & SOLVER_CLEANDEPS) != 0 && !solv->cleandepsmap.size && installed)
3230             map_grow(&solv->cleandepsmap, installed->end - installed->start);
3231           /* specific solvable: by id or by nevra */
3232           name = (select == SOLVER_SOLVABLE || (select == SOLVER_SOLVABLE_NAME && ISRELDEP(what))) ? 0 : -1;
3233           if (select == SOLVER_SOLVABLE_ALL)    /* hmmm ;) */
3234             {
3235               FOR_POOL_SOLVABLES(p)
3236                 solver_addjobrule(solv, -p, 0, i, weak);
3237             }
3238           else if (select == SOLVER_SOLVABLE_REPO)
3239             {
3240               Repo *repo = pool_id2repo(pool, what);
3241               if (repo)
3242                 FOR_REPO_SOLVABLES(repo, p, s)
3243                   solver_addjobrule(solv, -p, 0, i, weak);
3244             }
3245           FOR_JOB_SELECT(p, pp, select, what)
3246             {
3247               s = pool->solvables + p;
3248               if (installed && s->repo == installed)
3249                 name = !name ? s->name : -1;
3250               solver_addjobrule(solv, -p, 0, i, weak);
3251             }
3252           /* special case for "erase a specific solvable": we also
3253            * erase all other solvables with that name, so that they
3254            * don't get picked up as replacement.
3255            * name is > 0 if exactly one installed solvable matched.
3256            */
3257           /* XXX: look also at packages that obsolete this package? */
3258           if (name > 0)
3259             {
3260               int j, k;
3261               k = solv->nrules;
3262               FOR_PROVIDES(p, pp, name)
3263                 {
3264                   s = pool->solvables + p;
3265                   if (s->name != name)
3266                     continue;
3267                   /* keep other versions installed */
3268                   if (s->repo == installed)
3269                     continue;
3270                   /* keep installcandidates of other jobs */
3271                   if (MAPTST(&installcandidatemap, p))
3272                     continue;
3273                   /* don't add the same rule twice */
3274                   for (j = oldnrules; j < k; j++)
3275                     if (solv->rules[j].p == -p)
3276                       break;
3277                   if (j == k)
3278                     solver_addjobrule(solv, -p, 0, i, weak);    /* remove by id */
3279                 }
3280             }
3281           break;
3282
3283         case SOLVER_UPDATE:
3284           POOL_DEBUG(SOLV_DEBUG_JOB, "job: %supdate %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
3285           break;
3286         case SOLVER_VERIFY:
3287           POOL_DEBUG(SOLV_DEBUG_JOB, "job: %sverify %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
3288           break;
3289         case SOLVER_WEAKENDEPS:
3290           POOL_DEBUG(SOLV_DEBUG_JOB, "job: %sweaken deps %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
3291           if (select != SOLVER_SOLVABLE)
3292             break;
3293           s = pool->solvables + what;
3294           weaken_solvable_deps(solv, what);
3295           break;
3296         case SOLVER_NOOBSOLETES:
3297           POOL_DEBUG(SOLV_DEBUG_JOB, "job: %sno obsolete %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
3298           break;
3299         case SOLVER_LOCK:
3300           POOL_DEBUG(SOLV_DEBUG_JOB, "job: %slock %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
3301           if (select == SOLVER_SOLVABLE_ALL)
3302             {
3303               FOR_POOL_SOLVABLES(p)
3304                 solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, i, weak);
3305             }
3306           else if (select == SOLVER_SOLVABLE_REPO)
3307             {
3308               Repo *repo = pool_id2repo(pool, what);
3309               if (repo)
3310                 FOR_REPO_SOLVABLES(repo, p, s)
3311                   solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, i, weak);
3312             }
3313           FOR_JOB_SELECT(p, pp, select, what)
3314             solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, i, weak);
3315           break;
3316         case SOLVER_DISTUPGRADE:
3317           POOL_DEBUG(SOLV_DEBUG_JOB, "job: distupgrade %s\n", solver_select2str(pool, select, what));
3318           break;
3319         case SOLVER_DROP_ORPHANED:
3320           POOL_DEBUG(SOLV_DEBUG_JOB, "job: drop orphaned %s\n", solver_select2str(pool, select, what));
3321           if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && installed && what == installed->repoid))
3322             solv->droporphanedmap_all = 1;
3323           FOR_JOB_SELECT(p, pp, select, what)
3324             {
3325               s = pool->solvables + p;
3326               if (!installed || s->repo != installed)
3327                 continue;
3328               if (!solv->droporphanedmap.size)
3329                 map_grow(&solv->droporphanedmap, installed->end - installed->start);
3330               MAPSET(&solv->droporphanedmap, p - installed->start);
3331             }
3332           break;
3333         case SOLVER_USERINSTALLED:
3334           POOL_DEBUG(SOLV_DEBUG_JOB, "job: user installed %s\n", solver_select2str(pool, select, what));
3335           break;
3336         default:
3337           POOL_DEBUG(SOLV_DEBUG_JOB, "job: unknown job\n");
3338           break;
3339         }
3340         
3341         /*
3342          * debug
3343          */
3344         
3345       IF_POOLDEBUG (SOLV_DEBUG_JOB)
3346         {
3347           int j;
3348           if (solv->nrules == oldnrules)
3349             POOL_DEBUG(SOLV_DEBUG_JOB, " - no rule created\n");
3350           for (j = oldnrules; j < solv->nrules; j++)
3351             {
3352               POOL_DEBUG(SOLV_DEBUG_JOB, " - job ");
3353               solver_printrule(solv, SOLV_DEBUG_JOB, solv->rules + j);
3354             }
3355         }
3356     }
3357   assert(solv->ruletojob.count == solv->nrules - solv->jobrules);
3358   solv->jobrules_end = solv->nrules;
3359
3360   /* now create infarch and dup rules */
3361   if (!solv->noinfarchcheck)
3362     {
3363       solver_addinfarchrules(solv, &addedmap);
3364       if (pool->obsoleteusescolors)
3365         {
3366           /* currently doesn't work well with infarch rules, so make
3367            * them weak */
3368           for (i = solv->infarchrules; i < solv->infarchrules_end; i++)
3369             queue_push(&solv->weakruleq, i);
3370         }
3371     }
3372   else
3373     solv->infarchrules = solv->infarchrules_end = solv->nrules;
3374
3375   if (hasdupjob)
3376     solver_addduprules(solv, &addedmap);
3377   else
3378     solv->duprules = solv->duprules_end = solv->nrules;
3379
3380   if (solv->bestupdatemap_all || solv->bestupdatemap.size || hasbestinstalljob)
3381     solver_addbestrules(solv, hasbestinstalljob);
3382   else
3383     solv->bestrules = solv->bestrules_end = solv->nrules;
3384
3385   if (hasdupjob)
3386     solver_freedupmaps(solv);   /* no longer needed */
3387
3388   if (1)
3389     solver_addchoicerules(solv);
3390   else
3391     solv->choicerules = solv->choicerules_end = solv->nrules;
3392
3393   if (0)
3394     {
3395       for (i = solv->featurerules; i < solv->nrules; i++)
3396         solver_printruleclass(solv, SOLV_DEBUG_RESULT, solv->rules + i);
3397     }
3398   /* all rules created
3399    * --------------------------------------------------------------
3400    * prepare for solving
3401    */
3402     
3403   /* free unneeded memory */
3404   map_free(&addedmap);
3405   map_free(&installcandidatemap);
3406   queue_free(&q);
3407
3408   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);
3409   POOL_DEBUG(SOLV_DEBUG_STATS, "overall rule memory used: %d K\n", solv->nrules * (int)sizeof(Rule) / 1024);
3410
3411   /* create weak map */
3412   map_init(&solv->weakrulemap, solv->nrules);
3413   for (i = 0; i < solv->weakruleq.count; i++)
3414     {
3415       p = solv->weakruleq.elements[i];
3416       MAPSET(&solv->weakrulemap, p);
3417     }
3418
3419   /* enable cleandepsmap creation if we have updatepkgs */
3420   if (solv->cleandeps_updatepkgs && !solv->cleandepsmap.size)
3421     map_grow(&solv->cleandepsmap, installed->end - installed->start);
3422   /* no mistakes */
3423   if (solv->cleandeps_mistakes)
3424     {    
3425       queue_free(solv->cleandeps_mistakes);
3426       solv->cleandeps_mistakes = solv_free(solv->cleandeps_mistakes);
3427     }    
3428
3429   /* all new rules are learnt after this point */
3430   solv->learntrules = solv->nrules;
3431
3432   /* create watches chains */
3433   makewatches(solv);
3434
3435   /* create assertion index. it is only used to speed up
3436    * makeruledecsions() a bit */
3437   for (i = 1, r = solv->rules + i; i < solv->nrules; i++, r++)
3438     if (r->p && !r->w2 && (r->d == 0 || r->d == -1))
3439       queue_push(&solv->ruleassertions, i);
3440
3441   /* disable update rules that conflict with our job */
3442   solver_disablepolicyrules(solv);
3443
3444   /* make initial decisions based on assertion rules */
3445   makeruledecisions(solv);
3446   POOL_DEBUG(SOLV_DEBUG_SOLVER, "problems so far: %d\n", solv->problems.count);
3447
3448   /*
3449    * ********************************************
3450    * solve!
3451    * ********************************************
3452    */
3453     
3454   now = solv_timems(0);
3455   solver_run_sat(solv, 1, solv->dontinstallrecommended ? 0 : 1);
3456   POOL_DEBUG(SOLV_DEBUG_STATS, "solver took %d ms\n", solv_timems(now));
3457
3458   /*
3459    * prepare solution queue if there were problems
3460    */
3461   solver_prepare_solutions(solv);
3462
3463   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);
3464   POOL_DEBUG(SOLV_DEBUG_STATS, "solver_solve took %d ms\n", solv_timems(solve_start));
3465
3466   /* return number of problems */
3467   return solv->problems.count ? solv->problems.count / 2 : 0;
3468 }
3469
3470 Transaction *
3471 solver_create_transaction(Solver *solv)
3472 {
3473   return transaction_create_decisionq(solv->pool, &solv->decisionq, &solv->noobsoletes);
3474 }
3475
3476 void solver_get_orphaned(Solver *solv, Queue *orphanedq)
3477 {
3478   queue_free(orphanedq);
3479   queue_init_clone(orphanedq, &solv->orphaned);
3480 }
3481
3482 void solver_get_recommendations(Solver *solv, Queue *recommendationsq, Queue *suggestionsq, int noselected)
3483 {
3484   Pool *pool = solv->pool;
3485   Queue redoq, disabledq;
3486   int goterase, i;
3487   Solvable *s;
3488   Rule *r;
3489   Map obsmap;
3490
3491   if (!recommendationsq && !suggestionsq)
3492     return;
3493
3494   map_init(&obsmap, pool->nsolvables);
3495   if (solv->installed)
3496     {
3497       Id obs, *obsp, p, po, ppo;
3498       for (p = solv->installed->start; p < solv->installed->end; p++)
3499         {
3500           s = pool->solvables + p;
3501           if (s->repo != solv->installed || !s->obsoletes)
3502             continue;
3503           if (solv->decisionmap[p] <= 0)
3504             continue;
3505           if (solv->noobsoletes.size && MAPTST(&solv->noobsoletes, p))
3506             continue;
3507           obsp = s->repo->idarraydata + s->obsoletes;
3508           /* foreach obsoletes */
3509           while ((obs = *obsp++) != 0)
3510             FOR_PROVIDES(po, ppo, obs)
3511               MAPSET(&obsmap, po);
3512         }
3513     }
3514
3515   queue_init(&redoq);
3516   queue_init(&disabledq);
3517   goterase = 0;
3518   /* disable all erase jobs (including weak "keep uninstalled" rules) */
3519   for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++)
3520     {
3521       if (r->d < 0)     /* disabled ? */
3522         continue;
3523       if (r->p >= 0)    /* install job? */
3524         continue;
3525       queue_push(&disabledq, i);
3526       solver_disablerule(solv, r);
3527       goterase++;
3528     }
3529   
3530   if (goterase)
3531     {
3532       enabledisablelearntrules(solv);
3533       removedisabledconflicts(solv, &redoq);
3534     }
3535
3536   /*
3537    * find recommended packages
3538    */
3539   if (recommendationsq)
3540     {
3541       Id rec, *recp, p, pp;
3542
3543       queue_empty(recommendationsq);
3544       /* create map of all recommened packages */
3545       solv->recommends_index = -1;
3546       MAPZERO(&solv->recommendsmap);
3547
3548       /* put all packages the solver already chose in the map */
3549       if (solv->decisioncnt_weak)
3550         {
3551           for (i = solv->decisioncnt_weak; i < solv->decisioncnt_orphan; i++)
3552             {
3553               Id why;
3554               why = solv->decisionq_why.elements[i];
3555               if (why)
3556                 continue;       /* forced by unit rule */
3557               p = solv->decisionq.elements[i];
3558               if (p < 0)
3559                 continue;
3560               MAPSET(&solv->recommendsmap, p);
3561             }
3562         }
3563
3564       for (i = 0; i < solv->decisionq.count; i++)
3565         {
3566           p = solv->decisionq.elements[i];
3567           if (p < 0)
3568             continue;
3569           s = pool->solvables + p;
3570           if (s->recommends)
3571             {
3572               recp = s->repo->idarraydata + s->recommends;
3573               while ((rec = *recp++) != 0)
3574                 {
3575                   FOR_PROVIDES(p, pp, rec)
3576                     if (solv->decisionmap[p] > 0)
3577                       break;
3578                   if (p)
3579                     {
3580                       if (!noselected)
3581                         {
3582                           FOR_PROVIDES(p, pp, rec)
3583                             if (solv->decisionmap[p] > 0)
3584                               MAPSET(&solv->recommendsmap, p);
3585                         }
3586                       continue; /* p != 0: already fulfilled */
3587                     }
3588                   FOR_PROVIDES(p, pp, rec)
3589                     MAPSET(&solv->recommendsmap, p);
3590                 }
3591             }
3592         }
3593       for (i = 1; i < pool->nsolvables; i++)
3594         {
3595           if (solv->decisionmap[i] < 0)
3596             continue;
3597           if (solv->decisionmap[i] > 0 && noselected)
3598             continue;
3599           if (MAPTST(&obsmap, i))
3600             continue;
3601           s = pool->solvables + i;
3602           if (!MAPTST(&solv->recommendsmap, i))
3603             {
3604               if (!s->supplements)
3605                 continue;
3606               if (!pool_installable(pool, s))
3607                 continue;
3608               if (!solver_is_supplementing(solv, s))
3609                 continue;
3610             }
3611           queue_push(recommendationsq, i);
3612         }
3613       /* we use MODE_SUGGEST here so that repo prio is ignored */
3614       policy_filter_unwanted(solv, recommendationsq, POLICY_MODE_SUGGEST);
3615     }
3616
3617   /*
3618    * find suggested packages
3619    */
3620     
3621   if (suggestionsq)
3622     {
3623       Id sug, *sugp, p, pp;
3624
3625       queue_empty(suggestionsq);
3626       /* create map of all suggests that are still open */
3627       solv->recommends_index = -1;
3628       MAPZERO(&solv->suggestsmap);
3629       for (i = 0; i < solv->decisionq.count; i++)
3630         {
3631           p = solv->decisionq.elements[i];
3632           if (p < 0)
3633             continue;
3634           s = pool->solvables + p;
3635           if (s->suggests)
3636             {
3637               sugp = s->repo->idarraydata + s->suggests;
3638               while ((sug = *sugp++) != 0)
3639                 {
3640                   FOR_PROVIDES(p, pp, sug)
3641                     if (solv->decisionmap[p] > 0)
3642                       break;
3643                   if (p)
3644                     {
3645                       if (!noselected)
3646                         {
3647                           FOR_PROVIDES(p, pp, sug)
3648                             if (solv->decisionmap[p] > 0)
3649                               MAPSET(&solv->suggestsmap, p);
3650                         }
3651                       continue; /* already fulfilled */
3652                     }
3653                   FOR_PROVIDES(p, pp, sug)
3654                     MAPSET(&solv->suggestsmap, p);
3655                 }
3656             }
3657         }
3658       for (i = 1; i < pool->nsolvables; i++)
3659         {
3660           if (solv->decisionmap[i] < 0)
3661             continue;
3662           if (solv->decisionmap[i] > 0 && noselected)
3663             continue;
3664           if (MAPTST(&obsmap, i))
3665             continue;
3666           s = pool->solvables + i;
3667           if (!MAPTST(&solv->suggestsmap, i))
3668             {
3669               if (!s->enhances)
3670                 continue;
3671               if (!pool_installable(pool, s))
3672                 continue;
3673               if (!solver_is_enhancing(solv, s))
3674                 continue;
3675             }
3676           queue_push(suggestionsq, i);
3677         }
3678       policy_filter_unwanted(solv, suggestionsq, POLICY_MODE_SUGGEST);
3679     }
3680
3681   /* undo removedisabledconflicts */
3682   if (redoq.count)
3683     undo_removedisabledconflicts(solv, &redoq);
3684   queue_free(&redoq);
3685   
3686   /* undo job rule disabling */
3687   for (i = 0; i < disabledq.count; i++)
3688     solver_enablerule(solv, solv->rules + disabledq.elements[i]);
3689   queue_free(&disabledq);
3690   map_free(&obsmap);
3691 }
3692
3693
3694 /***********************************************************************/
3695 /* disk usage computations */
3696
3697 /*-------------------------------------------------------------------
3698  * 
3699  * calculate DU changes
3700  */
3701
3702 void
3703 solver_calc_duchanges(Solver *solv, DUChanges *mps, int nmps)
3704 {
3705   Map installedmap;
3706
3707   solver_create_state_maps(solv, &installedmap, 0);
3708   pool_calc_duchanges(solv->pool, &installedmap, mps, nmps);
3709   map_free(&installedmap);
3710 }
3711
3712
3713 /*-------------------------------------------------------------------
3714  * 
3715  * calculate changes in install size
3716  */
3717
3718 int
3719 solver_calc_installsizechange(Solver *solv)
3720 {
3721   Map installedmap;
3722   int change;
3723
3724   solver_create_state_maps(solv, &installedmap, 0);
3725   change = pool_calc_installsizechange(solv->pool, &installedmap);
3726   map_free(&installedmap);
3727   return change;
3728 }
3729
3730 void
3731 solver_create_state_maps(Solver *solv, Map *installedmap, Map *conflictsmap)
3732 {
3733   pool_create_state_maps(solv->pool, &solv->decisionq, installedmap, conflictsmap);
3734 }
3735
3736 void
3737 solver_trivial_installable(Solver *solv, Queue *pkgs, Queue *res)
3738 {
3739   Map installedmap;
3740   pool_create_state_maps(solv->pool,  &solv->decisionq, &installedmap, 0);
3741   pool_trivial_installable_noobsoletesmap(solv->pool, &installedmap, pkgs, res, solv->noobsoletes.size ? &solv->noobsoletes : 0);
3742   map_free(&installedmap);
3743 }
3744
3745 /*-------------------------------------------------------------------
3746  * 
3747  * decision introspection
3748  */
3749
3750 int
3751 solver_get_decisionlevel(Solver *solv, Id p)
3752 {
3753   return solv->decisionmap[p];
3754 }
3755
3756 void
3757 solver_get_decisionqueue(Solver *solv, Queue *decisionq)
3758 {
3759   queue_free(decisionq);
3760   queue_init_clone(decisionq, &solv->decisionq);
3761 }
3762
3763 int
3764 solver_get_lastdecisionblocklevel(Solver *solv)
3765 {
3766   Id p;
3767   if (solv->decisionq.count == 0)
3768     return 0;
3769   p = solv->decisionq.elements[solv->decisionq.count - 1];
3770   if (p < 0)
3771     p = -p;
3772   return solv->decisionmap[p] < 0 ? -solv->decisionmap[p] : solv->decisionmap[p];
3773 }
3774
3775 void
3776 solver_get_decisionblock(Solver *solv, int level, Queue *decisionq)
3777 {
3778   Id p;
3779   int i;
3780
3781   queue_empty(decisionq);
3782   for (i = 0; i < solv->decisionq.count; i++)
3783     {
3784       p = solv->decisionq.elements[i];
3785       if (p < 0)
3786         p = -p;
3787       if (solv->decisionmap[p] == level || solv->decisionmap[p] == -level)
3788         break;
3789     }
3790   if (i == solv->decisionq.count)
3791     return;
3792   for (i = 0; i < solv->decisionq.count; i++)
3793     {
3794       p = solv->decisionq.elements[i];
3795       if (p < 0)
3796         p = -p;
3797       if (solv->decisionmap[p] == level || solv->decisionmap[p] == -level)
3798         queue_push(decisionq, p);
3799       else
3800         break;
3801     }
3802 }
3803
3804 int
3805 solver_describe_decision(Solver *solv, Id p, Id *infop)
3806 {
3807   int i;
3808   Id pp, why;
3809   
3810   if (infop)
3811     *infop = 0;
3812   if (!solv->decisionmap[p])
3813     return SOLVER_REASON_UNRELATED;
3814   pp = solv->decisionmap[p] < 0 ? -p : p;
3815   for (i = 0; i < solv->decisionq.count; i++)
3816     if (solv->decisionq.elements[i] == pp)
3817       break;
3818   if (i == solv->decisionq.count)       /* just in case... */
3819     return SOLVER_REASON_UNRELATED;
3820   why = solv->decisionq_why.elements[i];
3821   if (why > 0)
3822     {
3823       if (infop)
3824         *infop = why;
3825       return SOLVER_REASON_UNIT_RULE;
3826     }
3827   why = -why;
3828   if (i < solv->decisioncnt_update)
3829     {
3830       if (i == 0)
3831         {
3832           if (infop)
3833             *infop = SYSTEMSOLVABLE;
3834           return SOLVER_REASON_KEEP_INSTALLED;
3835         }
3836       if (infop)
3837         *infop = why;
3838       return SOLVER_REASON_RESOLVE_JOB;
3839     }
3840   if (i < solv->decisioncnt_keep)
3841     {
3842       if (why == 0 && pp < 0)
3843         return SOLVER_REASON_CLEANDEPS_ERASE;
3844       if (infop)
3845         {
3846           if (why >= solv->updaterules && why < solv->updaterules_end)
3847             *infop = why - solv->updaterules;
3848           else if (why >= solv->featurerules && why < solv->featurerules_end)
3849             *infop = why - solv->featurerules;
3850         }
3851       return SOLVER_REASON_UPDATE_INSTALLED;
3852     }
3853   if (i < solv->decisioncnt_resolve)
3854     {
3855       if (why == 0 && pp < 0)
3856         return SOLVER_REASON_CLEANDEPS_ERASE;
3857       if (infop)
3858         {
3859           if (why >= solv->updaterules && why < solv->updaterules_end)
3860             *infop = why - solv->updaterules;
3861           else if (why >= solv->featurerules && why < solv->featurerules_end)
3862             *infop = why - solv->featurerules;
3863         }
3864       return SOLVER_REASON_KEEP_INSTALLED;
3865     }
3866   if (i < solv->decisioncnt_weak)
3867     {
3868       if (infop)
3869         *infop = why;
3870       return SOLVER_REASON_RESOLVE;
3871     }
3872   if (solv->decisionq.count < solv->decisioncnt_orphan)
3873     return SOLVER_REASON_WEAKDEP;
3874   return SOLVER_REASON_RESOLVE_ORPHAN;
3875 }
3876
3877
3878 void
3879 solver_describe_weakdep_decision(Solver *solv, Id p, Queue *whyq)
3880 {
3881   Pool *pool = solv->pool;
3882   int i;
3883   int level = solv->decisionmap[p];
3884   int decisionno;
3885   Solvable *s;
3886
3887   queue_empty(whyq);
3888   if (level < 0)
3889     return;     /* huh? */
3890   for (decisionno = 0; decisionno < solv->decisionq.count; decisionno++)
3891     if (solv->decisionq.elements[decisionno] == p)
3892       break;
3893   if (decisionno == solv->decisionq.count)
3894     return;     /* huh? */
3895   if (decisionno < solv->decisioncnt_weak || decisionno >= solv->decisioncnt_orphan)
3896     return;     /* huh? */
3897
3898   /* 1) list all packages that recommend us */
3899   for (i = 1; i < pool->nsolvables; i++)
3900     {
3901       Id *recp, rec, pp2, p2;
3902       if (solv->decisionmap[i] < 0 || solv->decisionmap[i] >= level)
3903         continue;
3904       s = pool->solvables + i;
3905       if (!s->recommends)
3906         continue;
3907       if (!solv->addalreadyrecommended && s->repo == solv->installed)
3908         continue;
3909       recp = s->repo->idarraydata + s->recommends;
3910       while ((rec = *recp++) != 0)
3911         {
3912           int found = 0;
3913           FOR_PROVIDES(p2, pp2, rec)
3914             {
3915               if (p2 == p)
3916                 found = 1;
3917               else
3918                 {
3919                   /* if p2 is already installed, this recommends is ignored */
3920                   if (solv->decisionmap[p2] > 0 && solv->decisionmap[p2] < level)
3921                     break;
3922                 }
3923             }
3924           if (!p2 && found)
3925             {
3926               queue_push(whyq, SOLVER_REASON_RECOMMENDED);
3927               queue_push2(whyq, p2, rec);
3928             }
3929         }
3930     }
3931   /* 2) list all supplements */
3932   s = pool->solvables + p;
3933   if (s->supplements && level > 0)
3934     {
3935       Id *supp, sup, pp2, p2;
3936       /* this is a hack. to use solver_dep_fulfilled we temporarily clear
3937        * everything above our level in the decisionmap */
3938       for (i = decisionno; i < solv->decisionq.count; i++ )
3939         {
3940           p2 = solv->decisionq.elements[i];
3941           if (p2 > 0)
3942             solv->decisionmap[p2] = -solv->decisionmap[p2];
3943         }
3944       supp = s->repo->idarraydata + s->supplements;
3945       while ((sup = *supp++) != 0)
3946         if (solver_dep_fulfilled(solv, sup))
3947           {
3948             int found = 0;
3949             /* let's see if this is an easy supp */
3950             FOR_PROVIDES(p2, pp2, sup)
3951               {
3952                 if (!solv->addalreadyrecommended && solv->installed)
3953                   {
3954                     if (pool->solvables[p2].repo == solv->installed)
3955                       continue;
3956                   }
3957                 if (solv->decisionmap[p2] > 0 && solv->decisionmap[p2] < level)
3958                   {
3959                     queue_push(whyq, SOLVER_REASON_SUPPLEMENTED);
3960                     queue_push2(whyq, p2, sup);
3961                     found = 1;
3962                   }
3963               }
3964             if (!found)
3965               {
3966                 /* hard case, just note dependency with no package */
3967                 queue_push(whyq, SOLVER_REASON_SUPPLEMENTED);
3968                 queue_push2(whyq, 0, sup);
3969               }
3970           }
3971       for (i = decisionno; i < solv->decisionq.count; i++)
3972         {
3973           p2 = solv->decisionq.elements[i];
3974           if (p2 > 0)
3975             solv->decisionmap[p2] = -solv->decisionmap[p2];
3976         }
3977     }
3978 }
3979
3980 void
3981 pool_job2solvables(Pool *pool, Queue *pkgs, Id how, Id what)
3982 {
3983   Id p, pp;
3984   how &= SOLVER_SELECTMASK;
3985   queue_empty(pkgs);
3986   if (how == SOLVER_SOLVABLE_ALL)
3987     {
3988       FOR_POOL_SOLVABLES(p)
3989         queue_push(pkgs, p);
3990     }
3991   else if (how == SOLVER_SOLVABLE_REPO)
3992     {
3993       Repo *repo = pool_id2repo(pool, what);
3994       Solvable *s;
3995       if (repo)
3996         FOR_REPO_SOLVABLES(repo, p, s)
3997           queue_push(pkgs, p);
3998     }
3999   else
4000     {
4001       FOR_JOB_SELECT(p, pp, how, what)
4002         queue_push(pkgs, p);
4003     }
4004 }
4005
4006 int
4007 pool_isemptyupdatejob(Pool *pool, Id how, Id what)
4008 {
4009   Id p, pp, pi, pip;
4010   Id select = how & SOLVER_SELECTMASK;
4011   if ((how & SOLVER_JOBMASK) != SOLVER_UPDATE)
4012     return 0;
4013   if (select == SOLVER_SOLVABLE_ALL || select == SOLVER_SOLVABLE_REPO)
4014     return 0;
4015   if (!pool->installed)
4016     return 1;
4017   FOR_JOB_SELECT(p, pp, select, what)
4018     if (pool->solvables[p].repo == pool->installed)
4019       return 0;
4020   /* hard work */
4021   FOR_JOB_SELECT(p, pp, select, what)
4022     {
4023       Solvable *s = pool->solvables + p;
4024       FOR_PROVIDES(pi, pip, s->name)
4025         {
4026           Solvable *si = pool->solvables + pi;
4027           if (si->repo != pool->installed || si->name != s->name)
4028             continue;
4029           return 0;
4030         }
4031       if (s->obsoletes)
4032         {
4033           Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
4034           while ((obs = *obsp++) != 0)
4035             {
4036               FOR_PROVIDES(pi, pip, obs) 
4037                 {
4038                   Solvable *si = pool->solvables + pi;
4039                   if (si->repo != pool->installed)
4040                     continue;
4041                   if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, si, obs))
4042                     continue;
4043                   if (pool->obsoleteusescolors && !pool_colormatch(pool, s, si))
4044                     continue;
4045                   return 0;
4046                 }
4047             }
4048         }
4049     }
4050   return 1;
4051 }