+
+// PrioSortList - Sort a list of versions by priority /*{{{*/
+// ---------------------------------------------------------------------
+/* This is ment to be used in conjunction with AllTargets to get a list
+ of versions ordered by preference. */
+static pkgCache *PrioCache;
+static int PrioComp(const void *A,const void *B)
+{
+ pkgCache::VerIterator L(*PrioCache,*(pkgCache::Version **)A);
+ pkgCache::VerIterator R(*PrioCache,*(pkgCache::Version **)B);
+
+ if ((L.ParentPkg()->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential &&
+ (R.ParentPkg()->Flags & pkgCache::Flag::Essential) != pkgCache::Flag::Essential)
+ return 1;
+ if ((L.ParentPkg()->Flags & pkgCache::Flag::Essential) != pkgCache::Flag::Essential &&
+ (R.ParentPkg()->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
+ return -1;
+
+ if (L->Priority != R->Priority)
+ return R->Priority - L->Priority;
+ return strcmp(L.ParentPkg().Name(),R.ParentPkg().Name());
+}
+void pkgPrioSortList(pkgCache &Cache,pkgCache::Version **List)
+{
+ unsigned long Count = 0;
+ PrioCache = &Cache;
+ for (pkgCache::Version **I = List; *I != 0; I++)
+ Count++;
+ qsort(List,Count,sizeof(*List),PrioComp);
+}
+ /*}}}*/
+
+
+// mark a single package in Mark-and-Sweep
+void pkgMarkPackage(pkgDepCache &Cache,
+ const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver,
+ bool follow_recommends,
+ bool follow_suggests)
+{
+ pkgDepCache::StateCache &state=Cache[pkg];
+ pkgCache::VerIterator candver=state.CandidateVerIter(Cache);
+ pkgCache::VerIterator instver=state.InstVerIter(Cache);
+
+#if 0
+ // If a package was garbage-collected but is now being marked, we
+ // should re-select it
+ // For cases when a pkg is set to upgrade and this trigger the
+ // removal of a no-longer used dependency. if the pkg is set to
+ // keep again later it will result in broken deps
+ if(state.Delete() && state.RemoveReason=pkgDepCache::Unused)
+ {
+ if(ver==candver)
+ mark_install(pkg, false, false, NULL);
+ else if(ver==pkg.CurrentVer())
+ MarkKeep(pkg);
+
+ instver=state.InstVerIter(*this);
+ }
+#endif
+
+ // Ignore versions other than the InstVer, and ignore packages
+ // that are already going to be removed or just left uninstalled.
+ if(!(ver==instver && !instver.end()))
+ return;
+
+ // if we are marked already we are done
+ if(state.Marked)
+ return;
+
+ //std::cout << "Setting Marked for: " << pkg.Name() << std::endl;
+ state.Marked=true;
+
+ if(!ver.end())
+ {
+ for(pkgCache::DepIterator d=ver.DependsList(); !d.end(); ++d)
+ {
+ if(d->Type==pkgCache::Dep::Depends ||
+ d->Type==pkgCache::Dep::PreDepends ||
+ (follow_recommends &&
+ d->Type==pkgCache::Dep::Recommends) ||
+ (follow_suggests &&
+ d->Type==pkgCache::Dep::Suggests))
+ {
+ // Try all versions of this package.
+ for(pkgCache::VerIterator V=d.TargetPkg().VersionList();
+ !V.end(); ++V)
+ {
+ if(_system->VS->CheckDep(V.VerStr(),d->CompareOp, d.TargetVer()))
+ {
+ pkgMarkPackage(Cache, V.ParentPkg(), V,
+ follow_recommends, follow_suggests);
+ }
+ }
+ // Now try virtual packages
+ for(pkgCache::PrvIterator prv=d.TargetPkg().ProvidesList();
+ !prv.end(); ++prv)
+ {
+ if(_system->VS->CheckDep(prv.ProvideVersion(), d->CompareOp,
+ d.TargetVer()))
+ {
+ pkgMarkPackage(Cache, prv.OwnerPkg(), prv.OwnerVer(),
+ follow_recommends, follow_suggests);
+ }
+ }
+ }
+ }
+ }
+}
+
+
+bool pkgMarkUsed(pkgDepCache &Cache)
+{
+ bool follow_recommends;
+ bool follow_suggests;
+
+ // init the states
+ for(pkgCache::PkgIterator p=Cache.PkgBegin(); !p.end(); ++p)
+ {
+ Cache[p].Marked=false;
+ Cache[p].Garbage=false;
+ }
+
+ // init vars
+ follow_recommends=_config->FindB("APT::AutoRemove::RecommendsImportant",false);
+ follow_suggests=_config->FindB("APT::AutoRemove::SuggestsImportend", false);
+
+
+ // do the mark part
+ for(pkgCache::PkgIterator p=Cache.PkgBegin(); !p.end(); ++p)
+ {
+ if(Cache[p].InstallReason==pkgDepCache::Manual ||
+ (p->Flags & pkgCache::Flag::Essential))
+ {
+ if(Cache[p].Keep() && !p.CurrentVer().end())
+ pkgMarkPackage(Cache, p, p.CurrentVer(),
+ follow_recommends, follow_suggests);
+ else if(Cache[p].Install())
+ pkgMarkPackage(Cache, p, Cache[p].InstVerIter(Cache),
+ follow_recommends, follow_suggests);
+ }
+ }
+
+
+ // do the sweep
+ for(pkgCache::PkgIterator p=Cache.PkgBegin(); !p.end(); ++p)
+ {
+ pkgDepCache::StateCache &state=Cache[p];
+
+ if(!state.Marked)
+ {
+ // mark installed but not yet marked stuff as garbage
+ if(p->CurrentVer != 0) {
+ state.Garbage=true;
+ std::cout << "Garbage: " << p.Name() << std::endl;
+ }
+
+#if 0 // mvo: the below bits still needs to be ported
+
+ // Be sure not to re-delete already deleted packages.
+ if(delete_unused && (!p.CurrentVer().end() || state.Install()) &&
+ !state.Delete())
+ {
+ bool do_delete=true;
+
+ // If the package is being upgraded, check if we're
+ // losing a versioned dep. If the dependency matches
+ // the previous version and not the new version, keep
+ // the package back instead of removing it.
+ if(!p.CurrentVer().end() && state.Install())
+ {
+ const char *vs=p.CurrentVer().VerStr();
+
+ // Check direct revdeps only. THIS ASSUMES NO
+ // VERSIONED PROVIDES, but Debian probably won't
+ // have them for ages if ever.
+ for(pkgCache::DepIterator revdep=p.RevDependsList();
+ !revdep.end(); ++revdep)
+ {
+ pkgCache::PkgIterator depender=revdep.ParentPkg();
+ // Find which version of the depending package
+ // will be installed.
+ pkgCache::VerIterator instver=(*this)[depender].InstVerIter(*this);
+
+ // Only pay attention to strong positive
+ // dependencies whose parents will be installed.
+ if(revdep.ParentVer()==instver &&
+ (revdep->Type==pkgCache::Dep::Depends ||
+ revdep->Type==pkgCache::Dep::PreDepends ||
+ (revdep->Type==pkgCache::Dep::Recommends &&
+ follow_recommends)))
+ {
+ // If the previous version matched, cancel the
+ // deletion. (note that I assume that the new
+ // version does NOT match; otherwise it would
+ // not be unused!)
+ if(_system->VS->CheckDep(vs,
+ revdep->CompareOp,
+ revdep.TargetVer()))
+ {
+ mark_keep(p, false, false, undo);
+ do_delete=false;
+ break;
+ }
+ }
+ }
+ }
+
+ if(do_delete)
+ mark_delete(p, false, true, undo);
+ }
+#endif
+ }
+ }
+ return true;
+}