- if (rd->flags == REL_AND)
- {
- dep_pkgcheck(solv, rd->name, m, q);
- dep_pkgcheck(solv, rd->evr, m, q);
- return;
- }
- if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES)
- return;
- }
- }
- FOR_PROVIDES(p, pp, dep)
- if (!m || MAPTST(m, p))
- queue_push(q, p);
-}
-
-static int
-check_xsupp(Solver *solv, Queue *depq, Id dep)
-{
- Pool *pool = solv->pool;
- Id p, pp;
-
- if (ISRELDEP(dep))
- {
- Reldep *rd = GETRELDEP(pool, dep);
- if (rd->flags >= 8)
- {
- if (rd->flags == REL_AND)
- {
- if (!check_xsupp(solv, depq, rd->name))
- return 0;
- return check_xsupp(solv, depq, rd->evr);
- }
- if (rd->flags == REL_OR)
- {
- if (check_xsupp(solv, depq, rd->name))
- return 1;
- return check_xsupp(solv, depq, rd->evr);
- }
- if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES)
-#if 0
- return solver_splitprovides(solv, rd->evr);
-#else
- return 0;
-#endif
- }
- if (depq && rd->flags == REL_NAMESPACE)
- {
- int i;
- for (i = 0; i < depq->count; i++)
- if (depq->elements[i] == dep || depq->elements[i] == rd->name)
- return 1;
- }
- }
- FOR_PROVIDES(p, pp, dep)
- if (p == SYSTEMSOLVABLE || pool->solvables[p].repo == solv->installed)
- return 1;
- return 0;
-}
-
-static inline int
-queue_contains(Queue *q, Id id)
-{
- int i;
- for (i = 0; i < q->count; i++)
- if (q->elements[i] == id)
- return 1;
- return 0;
-}
-
-#ifdef ENABLE_COMPLEX_DEPS
-static void
-complex_cleandeps_remove(Pool *pool, Id ip, Id req, Map *im, Map *installedm, Queue *iq)
-{
- int i;
- Queue dq;
- Id p;
-
- queue_init(&dq);
- i = pool_normalize_complex_dep(pool, req, &dq, CPLXDEPS_EXPAND);
- if (i == 0 || i == 1)
- {
- queue_free(&dq);
- return;
- }
- for (i = 0; i < dq.count; i++)
- {
- for (; (p = dq.elements[i]) != 0; i++)
- {
- if (p < 0)
- {
- if (!MAPTST(installedm, -p))
- break;
- continue;
- }
- if (p != SYSTEMSOLVABLE && MAPTST(im, p))
- {
-#ifdef CLEANDEPSDEBUG
- printf("%s requires/recommends %s\n", pool_solvid2str(pool, ip), pool_solvid2str(pool, p));
-#endif
- queue_push(iq, p);
- }
- }
- while (dq.elements[i])
- i++;
- }
- queue_free(&dq);
-}
-
-static void
-complex_cleandeps_addback(Pool *pool, Id ip, Id req, Map *im, Map *installedm, Queue *iq, Map *userinstalled)
-{
- int i, blk;
- Queue dq;
- Id p;
-
- queue_init(&dq);
- i = pool_normalize_complex_dep(pool, req, &dq, CPLXDEPS_EXPAND);
- if (i == 0 || i == 1)
- {
- queue_free(&dq);
- return;
- }
- for (i = 0; i < dq.count; i++)
- {
- blk = i;
- for (; (p = dq.elements[i]) != 0; i++)
- {
- if (p < 0)
- {
- if (!MAPTST(installedm, -p))
- break;
- continue;
- }
- if (MAPTST(im, p))
- break;
- }
- if (!p)
- {
- for (i = blk; (p = dq.elements[i]) != 0; i++)
- {
- if (p < 0)
- continue;
- if (!MAPTST(installedm, p))
- continue;
- if (p == ip || MAPTST(userinstalled, p - pool->installed->start))
- continue;
-#ifdef CLEANDEPSDEBUG
- printf("%s requires/recommends %s\n", pool_solvid2str(pool, ip), pool_solvid2str(pool, p));
-#endif
- MAPSET(im, p);
- queue_push(iq, p);
- }
- }
- while (dq.elements[i])
- i++;
- }
- queue_free(&dq);
-}
-
-#endif
-
-/*
- * Find all installed packages that are no longer
- * needed regarding the current solver job.
- *
- * The algorithm is:
- * - remove pass: remove all packages that could have
- * been dragged in by the obsoleted packages.
- * i.e. if package A is obsolete and contains "Requires: B",
- * also remove B, as installing A will have pulled in B.
- * after this pass, we have a set of still installed packages
- * with broken dependencies.
- * - add back pass:
- * now add back all packages that the still installed packages
- * require.
- *
- * The cleandeps packages are the packages removed in the first
- * pass and not added back in the second pass.
- *
- * If we search for unneeded packages (unneeded is true), we
- * simply remove all packages except the userinstalled ones in
- * the first pass.
- */
-static void
-solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded)
-{
- Pool *pool = solv->pool;
- Repo *installed = solv->installed;
- Queue *job = &solv->job;
- Map userinstalled;
- Map im;
- Map installedm;
- Rule *r;
- Id rid, how, what, select;
- Id p, pp, ip, jp;
- Id req, *reqp, sup, *supp;
- Solvable *s;
- Queue iq, iqcopy, xsuppq;
- int i;
-
- map_empty(cleandepsmap);
- if (!installed || installed->end == installed->start)
- return;
- map_init(&userinstalled, installed->end - installed->start);
- map_init(&im, pool->nsolvables);
- map_init(&installedm, pool->nsolvables);
- queue_init(&iq);
- queue_init(&xsuppq);
-
- for (i = 0; i < job->count; i += 2)
- {
- how = job->elements[i];
- if ((how & SOLVER_JOBMASK) == SOLVER_USERINSTALLED)
- {
- what = job->elements[i + 1];
- select = how & SOLVER_SELECTMASK;
- if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid))
- FOR_REPO_SOLVABLES(installed, p, s)
- MAPSET(&userinstalled, p - installed->start);
- FOR_JOB_SELECT(p, pp, select, what)
- if (pool->solvables[p].repo == installed)
- MAPSET(&userinstalled, p - installed->start);
- }
- if ((how & (SOLVER_JOBMASK | SOLVER_SELECTMASK)) == (SOLVER_ERASE | SOLVER_SOLVABLE_PROVIDES))
- {
- what = job->elements[i + 1];
- if (ISRELDEP(what))
- {
- Reldep *rd = GETRELDEP(pool, what);
- if (rd->flags != REL_NAMESPACE)
- continue;
- if (rd->evr == 0)
- {
- queue_pushunique(&iq, rd->name);
- continue;
- }
- FOR_PROVIDES(p, pp, what)
- if (p)
- break;
- if (p)
- continue;
- queue_pushunique(&iq, what);
- }
- }
- }
-
- /* have special namespace cleandeps erases */
- if (iq.count)
- {
- for (ip = installed->start; ip < installed->end; ip++)
- {
- s = pool->solvables + ip;
- if (s->repo != installed)
- continue;
- if (!s->supplements)
- continue;
- supp = s->repo->idarraydata + s->supplements;
- while ((sup = *supp++) != 0)
- if (ISRELDEP(sup) && check_xsupp(solv, &iq, sup) && !check_xsupp(solv, 0, sup))
- {
-#ifdef CLEANDEPSDEBUG
- printf("xsupp %s from %s\n", pool_dep2str(pool, sup), pool_solvid2str(pool, ip));
-#endif
- queue_pushunique(&xsuppq, sup);
- }
- }
- queue_empty(&iq);
- }
-
- /* also add visible patterns to userinstalled for openSUSE */
- if (1)
- {
- Dataiterator di;
- dataiterator_init(&di, pool, 0, 0, SOLVABLE_ISVISIBLE, 0, 0);
- while (dataiterator_step(&di))
- {
- Id *dp;
- if (di.solvid <= 0)
- continue;
- s = pool->solvables + di.solvid;
- if (!s->repo || !s->requires)
- continue;
- if (s->repo != installed && !pool_installable(pool, s))
- continue;
- if (strncmp(pool_id2str(pool, s->name), "pattern:", 8) != 0)
- continue;
- dp = s->repo->idarraydata + s->requires;
- for (dp = s->repo->idarraydata + s->requires; *dp; dp++)
- FOR_PROVIDES(p, pp, *dp)
- if (pool->solvables[p].repo == installed)
- {
- if (strncmp(pool_id2str(pool, pool->solvables[p].name), "pattern", 7) != 0)
- continue;
- MAPSET(&userinstalled, p - installed->start);
- }
- }
- dataiterator_free(&di);
- }
- if (1)
- {
- /* all products and their buddies are userinstalled */
- for (p = installed->start; p < installed->end; p++)
- {
- Solvable *s = pool->solvables + p;
- if (s->repo != installed)
- continue;
- if (!strncmp("product:", pool_id2str(pool, s->name), 8))
- {
- MAPSET(&userinstalled, p - installed->start);
-#ifdef ENABLE_LINKED_PKGS
- if (solv->instbuddy && solv->instbuddy[p - installed->start] > 1)
- {
- Id buddy = solv->instbuddy[p - installed->start];
- if (buddy >= installed->start && buddy < installed->end)
- MAPSET(&userinstalled, buddy - installed->start);
- }
-#endif
- }
- }
- }
-
- /* add all positive elements (e.g. locks) to "userinstalled" */
- for (rid = solv->jobrules; rid < solv->jobrules_end; rid++)
- {
- r = solv->rules + rid;
- if (r->d < 0)
- continue;
- i = solv->ruletojob.elements[rid - solv->jobrules];
- if ((job->elements[i] & SOLVER_CLEANDEPS) == SOLVER_CLEANDEPS)
- continue;
- FOR_RULELITERALS(p, jp, r)
- if (p > 0 && pool->solvables[p].repo == installed)
- MAPSET(&userinstalled, p - installed->start);
- }
-
- /* add all cleandeps candidates to iq */
- for (rid = solv->jobrules; rid < solv->jobrules_end; rid++)
- {
- r = solv->rules + rid;
- if (r->d < 0) /* disabled? */
- continue;
- if (r->d == 0 && r->p < 0 && r->w2 == 0) /* negative assertion (erase job)? */
- {
- p = -r->p;
- if (pool->solvables[p].repo != installed)
- continue;
- MAPCLR(&userinstalled, p - installed->start);
- if (unneeded)
- continue;
- i = solv->ruletojob.elements[rid - solv->jobrules];
- how = job->elements[i];
- if ((how & (SOLVER_JOBMASK|SOLVER_CLEANDEPS)) == (SOLVER_ERASE|SOLVER_CLEANDEPS))
- queue_push(&iq, p);
- }
- else if (r->p > 0) /* install job */
- {
- if (unneeded)
- continue;
- i = solv->ruletojob.elements[rid - solv->jobrules];
- if ((job->elements[i] & SOLVER_CLEANDEPS) == SOLVER_CLEANDEPS)
- {
- /* check if the literals all obsolete some installed package */
- Map om;
- int iqstart;
-
- /* just one installed literal */
- if (r->d == 0 && r->w2 == 0 && pool->solvables[r->p].repo == installed)
- continue;
- /* multiversion is bad */
- if (solv->multiversion.size && !solv->keepexplicitobsoletes)
- {
- FOR_RULELITERALS(p, jp, r)
- if (MAPTST(&solv->multiversion, p))
- break;
- if (p)
- continue;
- }
-
- om.size = 0;
- iqstart = iq.count;
- FOR_RULELITERALS(p, jp, r)
- {
- if (p < 0)
- {
- queue_truncate(&iq, iqstart); /* abort */
- break;
- }
- if (pool->solvables[p].repo == installed)
- {
- if (iq.count == iqstart)
- queue_push(&iq, p);
- else
- {
- for (i = iqstart; i < iq.count; i++)
- if (iq.elements[i] == p)
- break;
- queue_truncate(&iq, iqstart);
- if (i < iq.count)
- queue_push(&iq, p);
- }
- }
- else
- intersect_obsoletes(solv, p, &iq, iqstart, &om);
- if (iq.count == iqstart)
- break;
- }
- if (om.size)
- map_free(&om);
- }
- }
- }
- queue_init_clone(&iqcopy, &iq);
-
- if (!unneeded)
- {
- if (solv->cleandeps_updatepkgs)
- for (i = 0; i < solv->cleandeps_updatepkgs->count; i++)
- queue_push(&iq, solv->cleandeps_updatepkgs->elements[i]);
- }
-
- if (unneeded)
- queue_empty(&iq); /* just in case... */
-
- /* clear userinstalled bit for the packages we really want to delete/update */
- for (i = 0; i < iq.count; i++)
- {
- p = iq.elements[i];
- if (pool->solvables[p].repo != installed)
- continue;
- MAPCLR(&userinstalled, p - installed->start);
- }
-
- for (p = installed->start; p < installed->end; p++)
- {
- if (pool->solvables[p].repo != installed)
- continue;
- MAPSET(&installedm, p);
- if (unneeded && !MAPTST(&userinstalled, p - installed->start))
- continue;
- MAPSET(&im, p);
- }
- MAPSET(&installedm, SYSTEMSOLVABLE);
- MAPSET(&im, SYSTEMSOLVABLE);
-
-#ifdef CLEANDEPSDEBUG
- printf("REMOVE PASS\n");
-#endif
-
- for (;;)
- {
- if (!iq.count)
- {
- if (unneeded)
- break;
- /* supplements pass */
- for (ip = installed->start; ip < installed->end; ip++)
- {
- if (!MAPTST(&installedm, ip))
- continue;
- s = pool->solvables + ip;
- if (!s->supplements)
- continue;
- if (!MAPTST(&im, ip))
- continue;
- if (MAPTST(&userinstalled, ip - installed->start))
- continue;
- supp = s->repo->idarraydata + s->supplements;
- while ((sup = *supp++) != 0)
- if (dep_possible(solv, sup, &im))
- break;
- if (!sup)
- {
- supp = s->repo->idarraydata + s->supplements;
- while ((sup = *supp++) != 0)
- if (dep_possible(solv, sup, &installedm) || (xsuppq.count && queue_contains(&xsuppq, sup)))
- {
- /* no longer supplemented, also erase */
- int iqcount = iq.count;
- /* pin packages, see comment above dep_pkgcheck */
- dep_pkgcheck(solv, sup, &im, &iq);
- for (i = iqcount; i < iq.count; i++)
- {
- Id pqp = iq.elements[i];
- if (pool->solvables[pqp].repo == installed)
- MAPSET(&userinstalled, pqp - installed->start);
- }
- queue_truncate(&iq, iqcount);
-#ifdef CLEANDEPSDEBUG
- printf("%s supplemented [%s]\n", pool_solvid2str(pool, ip), pool_dep2str(pool, sup));
-#endif
- queue_push(&iq, ip);
- }
- }
- }
- if (!iq.count)
- break; /* no supplementing package found, we're done */
- }
- ip = queue_shift(&iq);
- s = pool->solvables + ip;
- if (!MAPTST(&im, ip))
- continue;
- if (!MAPTST(&installedm, ip))
- continue;
- if (s->repo == installed && MAPTST(&userinstalled, ip - installed->start))
- continue;
- MAPCLR(&im, ip);
-#ifdef CLEANDEPSDEBUG
- printf("removing %s\n", pool_solvable2str(pool, s));
-#endif
- if (s->requires)
- {
- reqp = s->repo->idarraydata + s->requires;
- while ((req = *reqp++) != 0)
- {
- if (req == SOLVABLE_PREREQMARKER)
- continue;
-#ifdef ENABLE_COMPLEX_DEPS
- if (pool_is_complex_dep(pool, req))
- {
- complex_cleandeps_remove(pool, ip, req, &im, &installedm, &iq);
- continue;
- }
-#endif
- FOR_PROVIDES(p, pp, req)
- {
- if (p != SYSTEMSOLVABLE && MAPTST(&im, p))
- {
-#ifdef CLEANDEPSDEBUG
- printf("%s requires %s\n", pool_solvid2str(pool, ip), pool_solvid2str(pool, p));
-#endif
- queue_push(&iq, p);
- }
- }
- }
- }
- if (s->recommends)
- {
- reqp = s->repo->idarraydata + s->recommends;
- while ((req = *reqp++) != 0)
- {
-#ifdef ENABLE_COMPLEX_DEPS
- if (pool_is_complex_dep(pool, req))
- {
- complex_cleandeps_remove(pool, ip, req, &im, &installedm, &iq);
- continue;
- }
-#endif
- FOR_PROVIDES(p, pp, req)
- {
- if (p != SYSTEMSOLVABLE && MAPTST(&im, p))
- {
-#ifdef CLEANDEPSDEBUG
- printf("%s recommends %s\n", pool_solvid2str(pool, ip), pool_solvid2str(pool, p));
-#endif
- queue_push(&iq, p);
- }
- }
- }
- }
- }
-
- /* turn userinstalled into remove set for pruning */
- map_empty(&userinstalled);
- for (rid = solv->jobrules; rid < solv->jobrules_end; rid++)
- {
- r = solv->rules + rid;
- if (r->p >= 0 || r->d != 0 || r->w2 != 0)
- continue; /* disabled or not erase */
- p = -r->p;
- MAPCLR(&im, p);
- if (pool->solvables[p].repo == installed)
- MAPSET(&userinstalled, p - installed->start);
- }
- if (!unneeded && solv->cleandeps_updatepkgs)
- {
- for (i = 0; i < solv->cleandeps_updatepkgs->count; i++)
- {
- p = solv->cleandeps_updatepkgs->elements[i];
- if (pool->solvables[p].repo == installed)
- MAPSET(&userinstalled, p - installed->start);
- }
- }
- MAPSET(&im, SYSTEMSOLVABLE); /* in case we cleared it above */
- for (p = installed->start; p < installed->end; p++)
- if (MAPTST(&im, p))
- queue_push(&iq, p);
- for (rid = solv->jobrules; rid < solv->jobrules_end; rid++)
- {
- r = solv->rules + rid;
- if (r->d < 0)
- continue;
- FOR_RULELITERALS(p, jp, r)
- if (p > 0)
- queue_push(&iq, p);
- }
- /* also put directly addressed packages on the install queue
- * so we can mark patterns as installed */
- for (i = 0; i < job->count; i += 2)
- {
- how = job->elements[i];
- if ((how & SOLVER_JOBMASK) == SOLVER_USERINSTALLED)
- {
- what = job->elements[i + 1];
- select = how & SOLVER_SELECTMASK;
- if (select == SOLVER_SOLVABLE && pool->solvables[what].repo != installed)
- queue_push(&iq, what);
- }
- }
-
-#ifdef CLEANDEPSDEBUG
- printf("ADDBACK PASS\n");
-#endif
- for (;;)
- {
- if (!iq.count)
- {
- /* supplements pass */
- for (ip = installed->start; ip < installed->end; ip++)
- {
- if (!MAPTST(&installedm, ip))
- continue;
- if (MAPTST(&userinstalled, ip - installed->start))
- continue;
- s = pool->solvables + ip;
- if (!s->supplements)
- continue;
- if (MAPTST(&im, ip))
- continue;
- supp = s->repo->idarraydata + s->supplements;
- while ((sup = *supp++) != 0)
- if (dep_possible(solv, sup, &im))
- break;
- if (sup)
- {
-#ifdef CLEANDEPSDEBUG
- printf("%s supplemented\n", pool_solvid2str(pool, ip));
-#endif
- MAPSET(&im, ip);
- queue_push(&iq, ip);
- }
- }
- if (!iq.count)
- break;
- }
- ip = queue_shift(&iq);
- s = pool->solvables + ip;
-#ifdef CLEANDEPSDEBUG
- printf("adding back %s\n", pool_solvable2str(pool, s));
-#endif
- if (s->requires)
- {
- reqp = s->repo->idarraydata + s->requires;
- while ((req = *reqp++) != 0)
- {
-#ifdef ENABLE_COMPLEX_DEPS
- if (pool_is_complex_dep(pool, req))
- {
- complex_cleandeps_addback(pool, ip, req, &im, &installedm, &iq, &userinstalled);
- continue;
- }
-#endif
- FOR_PROVIDES(p, pp, req)
- if (MAPTST(&im, p))
- break;
- if (p)
- continue;
- FOR_PROVIDES(p, pp, req)
- {
- if (MAPTST(&installedm, p))
- {
- if (p == ip)
- continue;
- if (MAPTST(&userinstalled, p - installed->start))
- continue;
-#ifdef CLEANDEPSDEBUG
- printf("%s requires %s\n", pool_solvid2str(pool, ip), pool_solvid2str(pool, p));
-#endif
- MAPSET(&im, p);
- queue_push(&iq, p);
- }
- }
- }
- }
- if (s->recommends)
- {
- reqp = s->repo->idarraydata + s->recommends;
- while ((req = *reqp++) != 0)