+ if(Dep.IsCritical())
+ return true;
+ else if(Dep->Type == pkgCache::Dep::Recommends)
+ {
+ if ( _config->FindB("APT::Install-Recommends", false))
+ return true;
+ // we suport a special mode to only install-recommends for certain
+ // sections
+ // FIXME: this is a meant as a temporarly solution until the
+ // recommends are cleaned up
+ const char *sec = Dep.ParentVer().Section();
+ if (sec && ConfigValueInSubTree("APT::Install-Recommends-Sections", sec))
+ return true;
+ }
+ else if(Dep->Type == pkgCache::Dep::Suggests)
+ return _config->FindB("APT::Install-Suggests", false);
+
+ return false;
+}
+ /*}}}*/
+pkgDepCache::DefaultRootSetFunc::DefaultRootSetFunc() /*{{{*/
+ : constructedSuccessfully(false)
+{
+ Configuration::Item const *Opts;
+ Opts = _config->Tree("APT::NeverAutoRemove");
+ if (Opts != 0 && Opts->Child != 0)
+ {
+ Opts = Opts->Child;
+ for (; Opts != 0; Opts = Opts->Next)
+ {
+ if (Opts->Value.empty() == true)
+ continue;
+
+ regex_t *p = new regex_t;
+ if(regcomp(p,Opts->Value.c_str(),
+ REG_EXTENDED | REG_ICASE | REG_NOSUB) != 0)
+ {
+ regfree(p);
+ delete p;
+ _error->Error("Regex compilation error for APT::NeverAutoRemove");
+ return;
+ }
+
+ rootSetRegexp.push_back(p);
+ }
+ }
+
+ constructedSuccessfully = true;
+}
+ /*}}}*/
+pkgDepCache::DefaultRootSetFunc::~DefaultRootSetFunc() /*{{{*/
+{
+ for(unsigned int i = 0; i < rootSetRegexp.size(); i++)
+ {
+ regfree(rootSetRegexp[i]);
+ delete rootSetRegexp[i];
+ }
+}
+ /*}}}*/
+bool pkgDepCache::DefaultRootSetFunc::InRootSet(const pkgCache::PkgIterator &pkg) /*{{{*/
+{
+ for(unsigned int i = 0; i < rootSetRegexp.size(); i++)
+ if (regexec(rootSetRegexp[i], pkg.Name(), 0, 0, 0) == 0)
+ return true;
+
+ return false;
+}
+ /*}}}*/
+pkgDepCache::InRootSetFunc *pkgDepCache::GetRootSetFunc() /*{{{*/
+{
+ DefaultRootSetFunc *f = new DefaultRootSetFunc;
+ if(f->wasConstructedSuccessfully())
+ return f;
+ else
+ {
+ delete f;
+ return NULL;
+ }
+}
+ /*}}}*/
+bool pkgDepCache::MarkFollowsRecommends()
+{
+ return _config->FindB("APT::AutoRemove::RecommendsImportant", true);
+}
+
+bool pkgDepCache::MarkFollowsSuggests()
+{
+ return _config->FindB("APT::AutoRemove::SuggestsImportant", false);
+}
+
+// pkgDepCache::MarkRequired - the main mark algorithm /*{{{*/
+bool pkgDepCache::MarkRequired(InRootSetFunc &userFunc)
+{
+ bool follow_recommends;
+ bool follow_suggests;
+ bool debug_autoremove = _config->FindB("Debug::pkgAutoRemove",false);
+
+ // init the states
+ for(PkgIterator p = PkgBegin(); !p.end(); ++p)
+ {
+ PkgState[p->ID].Marked = false;
+ PkgState[p->ID].Garbage = false;
+
+ // debug output
+ if(debug_autoremove && PkgState[p->ID].Flags & Flag::Auto)
+ std::clog << "AutoDep: " << p.FullName() << std::endl;
+ }
+
+ // init vars
+ follow_recommends = MarkFollowsRecommends();
+ 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) ||
+ userFunc.InRootSet(p))
+
+ {
+ // 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 candver = state.CandidateVerIter(*this);
+ VerIterator const instver = state.InstVerIter(*this);
+
+#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 = 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;
+
+ // If the version belongs to a Multi-Arch all package
+ // we will mark all others in this Group with this version also
+ // Beware: We compare versions here the lazy way: string comparision
+ // this is bad if multiple repositories provide different versions
+ // of the package with an identical version number - but even in this
+ // case the dependencies are likely the same.
+ if (ver->MultiArch == pkgCache::Version::All &&
+ strcmp(ver.Arch(true), "all") == 0)
+ {
+ GrpIterator G = pkg.Group();
+ const char* const VerStr = ver.VerStr();
+ for (PkgIterator P = G.FindPkg("any");
+ P.end() != true; P = G.NextPkg(P))
+ {
+ for (VerIterator V = P.VersionList();
+ V.end() != true; ++V)
+ {
+ if (strcmp(VerStr, V.VerStr()) != 0)
+ continue;
+ MarkPackage(P, V, follow_recommends, follow_suggests);
+ break;
+ }
+ }
+ }
+
+ 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(_system->VS->CheckDep(V.VerStr(), d->CompareOp, d.TargetVer()))
+ {
+ 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(_system->VS->CheckDep(prv.ProvideVersion(), d->CompareOp,
+ d.TargetVer()))
+ {
+ 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::cout << "Garbage: " << p.FullName() << std::endl;
+ }
+ }
+
+ return true;