+static void
+prune_to_update_targets(Solver *solv, Id *cp, Queue *q)
+{
+ int i, j;
+ Id p, *cp2;
+ for (i = j = 0; i < q->count; i++)
+ {
+ p = q->elements[i];
+ for (cp2 = cp; *cp2; cp2++)
+ if (*cp2 == p)
+ {
+ q->elements[j++] = p;
+ break;
+ }
+ }
+ queue_truncate(q, j);
+}
+
+static void
+prune_to_dup_packages(Solver *solv, Id p, Queue *q)
+{
+ int i, j;
+ for (i = j = 0; i < q->count; i++)
+ {
+ Id p = q->elements[i];
+ if (MAPTST(&solv->dupmap, p))
+ q->elements[j++] = p;
+ }
+ queue_truncate(q, j);
+}
+
+void
+solver_addbestrules(Solver *solv, int havebestinstalljobs)
+{
+ Pool *pool = solv->pool;
+ Id p;
+ Solvable *s;
+ Repo *installed = solv->installed;
+ Queue q, q2;
+ Rule *r;
+ Queue r2pkg;
+ int i, oldcnt;
+
+ solv->bestrules = solv->nrules;
+ if (!installed)
+ {
+ solv->bestrules_end = solv->nrules;
+ return;
+ }
+ queue_init(&q);
+ queue_init(&q2);
+ queue_init(&r2pkg);
+
+ if (havebestinstalljobs)
+ {
+ for (i = 0; i < solv->job.count; i += 2)
+ {
+ if ((solv->job.elements[i] & (SOLVER_JOBMASK | SOLVER_FORCEBEST)) == (SOLVER_INSTALL | SOLVER_FORCEBEST))
+ {
+ int j;
+ Id p2, pp2;
+ for (j = 0; j < solv->ruletojob.count; j++)
+ if (solv->ruletojob.elements[j] == i)
+ break;
+ if (j == solv->ruletojob.count)
+ continue;
+ r = solv->rules + solv->jobrules + j;
+ queue_empty(&q);
+ FOR_RULELITERALS(p2, pp2, r)
+ if (p2 > 0)
+ queue_push(&q, p2);
+ if (!q.count)
+ continue; /* orphaned */
+ /* select best packages, just look at prio and version */
+ oldcnt = q.count;
+ policy_filter_unwanted(solv, &q, POLICY_MODE_RECOMMEND);
+ if (q.count == oldcnt)
+ continue; /* nothing filtered */
+ p2 = queue_shift(&q);
+ solver_addrule(solv, p2, q.count ? pool_queuetowhatprovides(pool, &q) : 0);
+ queue_push(&r2pkg, -(solv->jobrules + j));
+ }
+ }
+ }
+
+ if (solv->bestupdatemap_all || solv->bestupdatemap.size)
+ {
+ FOR_REPO_SOLVABLES(installed, p, s)
+ {
+ Id d, p2, pp2;
+ if (!solv->updatemap_all && (!solv->updatemap.size || !MAPTST(&solv->updatemap, p - installed->start)))
+ continue;
+ if (!solv->bestupdatemap_all && (!solv->bestupdatemap.size || !MAPTST(&solv->bestupdatemap, p - installed->start)))
+ continue;
+ queue_empty(&q);
+ if (solv->bestobeypolicy)
+ r = solv->rules + solv->updaterules + (p - installed->start);
+ else
+ {
+ r = solv->rules + solv->featurerules + (p - installed->start);
+ if (!r->p) /* identical to update rule? */
+ r = solv->rules + solv->updaterules + (p - installed->start);
+ }
+ if (solv->multiversionupdaters && (d = solv->multiversionupdaters[p - installed->start]) != 0 && r == solv->rules + solv->updaterules + (p - installed->start))
+ {
+ /* need to check multiversionupdaters */
+ if (r->p == p) /* be careful with the dup case */
+ queue_push(&q, p);
+ while ((p2 = pool->whatprovidesdata[d++]) != 0)
+ queue_push(&q, p2);
+ }
+ else
+ {
+ FOR_RULELITERALS(p2, pp2, r)
+ if (p2 > 0)
+ queue_push(&q, p2);
+ }
+ if (solv->update_targets && solv->update_targets->elements[p - installed->start])
+ prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[p - installed->start], &q);
+ if (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))
+ prune_to_dup_packages(solv, p, &q);
+ /* select best packages, just look at prio and version */
+ policy_filter_unwanted(solv, &q, POLICY_MODE_RECOMMEND);
+ if (!q.count)
+ continue; /* orphaned */
+ if (solv->bestobeypolicy)
+ {
+ /* also filter the best of the feature rule packages and add them */
+ r = solv->rules + solv->featurerules + (p - installed->start);
+ if (r->p)
+ {
+ int j;
+ queue_empty(&q2);
+ FOR_RULELITERALS(p2, pp2, r)
+ if (p2 > 0)
+ queue_push(&q2, p2);
+ if (solv->update_targets && solv->update_targets->elements[p - installed->start])
+ prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[p - installed->start], &q2);
+ if (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))
+ prune_to_dup_packages(solv, p, &q);
+ policy_filter_unwanted(solv, &q2, POLICY_MODE_RECOMMEND);
+ for (j = 0; j < q2.count; j++)
+ queue_pushunique(&q, q2.elements[j]);
+ }
+ }
+ p2 = queue_shift(&q);
+ solver_addrule(solv, p2, q.count ? pool_queuetowhatprovides(pool, &q) : 0);
+ queue_push(&r2pkg, p);
+ }
+ }
+ if (r2pkg.count)
+ {
+ solv->bestrules_pkg = solv_calloc(r2pkg.count, sizeof(Id));
+ memcpy(solv->bestrules_pkg, r2pkg.elements, r2pkg.count * sizeof(Id));
+ }
+ solv->bestrules_end = solv->nrules;
+ queue_free(&q);
+ queue_free(&q2);
+ queue_free(&r2pkg);
+}
+