+ if (_config->Find("APT::Solver", "internal") != "internal")
+ return true;
+
+ bool const debug_autoremove = _config->FindB("Debug::pkgAutoRemove",false);
+
+ // init the states
+ map_id_t const PackagesCount = Head().PackageCount;
+ for(map_id_t i = 0; i < PackagesCount; ++i)
+ {
+ PkgState[i].Marked = false;
+ PkgState[i].Garbage = false;
+ }
+ if (debug_autoremove)
+ for(PkgIterator p = PkgBegin(); !p.end(); ++p)
+ if(PkgState[p->ID].Flags & Flag::Auto)
+ std::clog << "AutoDep: " << p.FullName() << std::endl;
+
+ bool const follow_recommends = MarkFollowsRecommends();
+ bool const follow_suggests = MarkFollowsSuggests();
+
+ // do the mark part, this is the core bit of the algorithm
+ for(PkgIterator p = PkgBegin(); !p.end(); ++p)
+ {
+ if(!(PkgState[p->ID].Flags & Flag::Auto) ||
+ (p->Flags & Flag::Essential) ||
+ (p->Flags & Flag::Important) ||
+ userFunc.InRootSet(p) ||
+ // be nice even then a required package violates the policy (#583517)
+ // and do the full mark process also for required packages
+ (p.CurrentVer().end() != true &&
+ p.CurrentVer()->Priority == pkgCache::State::Required) ||
+ // packages which can't be changed (like holds) can't be garbage
+ (IsModeChangeOk(ModeGarbage, p, 0, false) == false))
+ {
+ // the package is installed (and set to keep)
+ if(PkgState[p->ID].Keep() && !p.CurrentVer().end())
+ MarkPackage(p, p.CurrentVer(),
+ follow_recommends, follow_suggests);
+ // the package is to be installed
+ else if(PkgState[p->ID].Install())
+ MarkPackage(p, PkgState[p->ID].InstVerIter(*this),
+ follow_recommends, follow_suggests);
+ }
+ }
+
+ return true;
+}
+ /*}}}*/
+// MarkPackage - mark a single package in Mark-and-Sweep /*{{{*/
+void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver,
+ bool const &follow_recommends,
+ bool const &follow_suggests)
+{
+ pkgDepCache::StateCache &state = PkgState[pkg->ID];
+
+ // if we are marked already we are done
+ if(state.Marked)
+ return;
+
+ VerIterator const currver = pkg.CurrentVer();
+ VerIterator const instver = state.InstVerIter(*this);
+
+#if 0
+ VerIterator const candver = state.CandidateVerIter(*this);
+
+ // 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 = Unused)
+ {
+ if(ver==candver)
+ mark_install(pkg, false, false, NULL);
+ else if(ver==pkg.CurrentVer())
+ MarkKeep(pkg, false, false);
+
+ instver=state.InstVerIter(*this);
+ }
+#endif
+
+ // For packages that are not going to be removed, ignore versions
+ // other than the InstVer. For packages that are going to be
+ // removed, ignore versions other than the current version.
+ if(!(ver == instver && !instver.end()) &&
+ !(ver == currver && instver.end() && !ver.end()))
+ return;
+
+ bool const debug_autoremove = _config->FindB("Debug::pkgAutoRemove", false);
+
+ if(debug_autoremove)
+ {
+ std::clog << "Marking: " << pkg.FullName();
+ if(!ver.end())
+ std::clog << " " << ver.VerStr();
+ if(!currver.end())
+ std::clog << ", Curr=" << currver.VerStr();
+ if(!instver.end())
+ std::clog << ", Inst=" << instver.VerStr();
+ std::clog << std::endl;
+ }
+
+ state.Marked=true;
+
+ if(ver.end() == true)
+ return;
+
+ for(DepIterator d = ver.DependsList(); !d.end(); ++d)
+ {
+ if(d->Type == Dep::Depends ||
+ d->Type == Dep::PreDepends ||
+ (follow_recommends &&
+ d->Type == Dep::Recommends) ||
+ (follow_suggests &&
+ d->Type == Dep::Suggests))
+ {
+ // Try all versions of this package.
+ for(VerIterator V = d.TargetPkg().VersionList();
+ !V.end(); ++V)
+ {
+ if(d.IsSatisfied(V))
+ {
+ if(debug_autoremove)
+ {
+ std::clog << "Following dep: " << d.ParentPkg().FullName()
+ << " " << d.ParentVer().VerStr() << " "
+ << d.DepType() << " " << d.TargetPkg().FullName();
+ if((d->CompareOp & ~pkgCache::Dep::Or) != pkgCache::Dep::NoOp)
+ {
+ std::clog << " (" << d.CompType() << " "
+ << d.TargetVer() << ")";
+ }
+ std::clog << std::endl;
+ }
+ MarkPackage(V.ParentPkg(), V,
+ follow_recommends, follow_suggests);
+ }
+ }
+ // Now try virtual packages
+ for(PrvIterator prv=d.TargetPkg().ProvidesList();
+ !prv.end(); ++prv)
+ {
+ if(d.IsSatisfied(prv))
+ {
+ if(debug_autoremove)
+ {
+ std::clog << "Following dep: " << d.ParentPkg().FullName() << " "
+ << d.ParentVer().VerStr() << " "
+ << d.DepType() << " " << d.TargetPkg().FullName() << " ";
+ if((d->CompareOp & ~pkgCache::Dep::Or) != pkgCache::Dep::NoOp)
+ {
+ std::clog << " (" << d.CompType() << " "
+ << d.TargetVer() << ")";
+ }
+ std::clog << ", provided by "
+ << prv.OwnerPkg().FullName() << " "
+ << prv.OwnerVer().VerStr()
+ << std::endl;
+ }
+
+ MarkPackage(prv.OwnerPkg(), prv.OwnerVer(),
+ follow_recommends, follow_suggests);
+ }
+ }
+ }
+ }
+}
+ /*}}}*/
+bool pkgDepCache::Sweep() /*{{{*/
+{
+ bool debug_autoremove = _config->FindB("Debug::pkgAutoRemove",false);
+
+ // do the sweep
+ for(PkgIterator p=PkgBegin(); !p.end(); ++p)
+ {
+ StateCache &state=PkgState[p->ID];
+
+ // skip required packages
+ if (!p.CurrentVer().end() &&
+ (p.CurrentVer()->Priority == pkgCache::State::Required))
+ continue;
+
+ // if it is not marked and it is installed, it's garbage
+ if(!state.Marked && (!p.CurrentVer().end() || state.Install()))
+ {
+ state.Garbage=true;
+ if(debug_autoremove)
+ std::clog << "Garbage: " << p.FullName() << std::endl;
+ }
+ }
+
+ return true;
+}
+ /*}}}*/
+// DepCache::MarkAndSweep /*{{{*/
+bool pkgDepCache::MarkAndSweep(InRootSetFunc &rootFunc)
+{
+ return MarkRequired(rootFunc) && Sweep();
+}
+bool pkgDepCache::MarkAndSweep()
+{
+ std::unique_ptr<InRootSetFunc> f(GetRootSetFunc());
+ if(f.get() != NULL)
+ return MarkAndSweep(*f.get());
+ else
+ return false;