+
+// Policy::GetCandidateVer - Returns the Candidate install version /*{{{*/
+// ---------------------------------------------------------------------
+/* The default just returns the highest available version that is not
+ a source and automatic. */
+pkgCache::VerIterator pkgDepCache::Policy::GetCandidateVer(PkgIterator Pkg)
+{
+ /* Not source/not automatic versions cannot be a candidate version
+ unless they are already installed */
+ VerIterator Last(*(pkgCache *)this,0);
+
+ for (VerIterator I = Pkg.VersionList(); I.end() == false; I++)
+ {
+ if (Pkg.CurrentVer() == I)
+ return I;
+
+ for (VerFileIterator J = I.FileList(); J.end() == false; J++)
+ {
+ if ((J.File()->Flags & Flag::NotSource) != 0)
+ continue;
+
+ /* Stash the highest version of a not-automatic source, we use it
+ if there is nothing better */
+ if ((J.File()->Flags & Flag::NotAutomatic) != 0)
+ {
+ if (Last.end() == true)
+ Last = I;
+ continue;
+ }
+
+ return I;
+ }
+ }
+
+ return Last;
+}
+ /*}}}*/
+ /*}}}*/
+
+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);
+}
+
+// the main mark algorithm
+bool pkgDepCache::MarkRequired(InRootSetFunc &userFunc)
+{
+ bool follow_recommends;
+ bool follow_suggests;
+
+ // init the states
+ for(PkgIterator p = PkgBegin(); !p.end(); ++p)
+ {
+ PkgState[p->ID].Marked = false;
+ PkgState[p->ID].Garbage = false;
+
+ // debug output
+ if(_config->FindB("Debug::pkgAutoRemove",false)
+ && PkgState[p->ID].Flags & Flag::Auto)
+ std::clog << "AutoDep: " << p.Name() << 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;
+}
+
+// mark a single package in Mark-and-Sweep
+void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver,
+ bool follow_recommends,
+ bool follow_suggests)
+{
+ pkgDepCache::StateCache &state = PkgState[pkg->ID];
+ VerIterator candver = state.CandidateVerIter(*this);
+ VerIterator 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
+
+ // 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(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()))
+ {
+ 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()))
+ {
+ MarkPackage(prv.OwnerPkg(), prv.OwnerVer(),
+ follow_recommends, follow_suggests);
+ }
+ }
+ }
+ }
+ }
+}
+
+bool pkgDepCache::Sweep()
+{
+ // do the sweep
+ for(PkgIterator p=PkgBegin(); !p.end(); ++p)
+ {
+ StateCache &state=PkgState[p->ID];
+
+ // if it is not marked and it is installed, it's garbage
+ if(!state.Marked && (!p.CurrentVer().end() || state.Install()))
+ {
+ state.Garbage=true;
+ if(_config->FindB("Debug::pkgAutoRemove",false))
+ std::cout << "Garbage: " << p.Name() << std::endl;
+ }
+ }
+
+ return true;
+}
+
+// Policy::IsImportantDep - True if the dependency is important /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool pkgDepCache::Policy::IsImportantDep(DepIterator Dep)
+{
+ 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
+ string s = _config->Find("APT::Install-Recommends-Section","");
+ if(s.size() > 0)
+ {
+ const char *sec = Dep.ParentVer().Section();
+ if (sec && strcmp(sec, s.c_str()) == 0)
+ return true;
+ }
+ }
+ else if(Dep->Type == pkgCache::Dep::Suggests)
+ return _config->FindB("APT::Install-Suggests", false);
+
+ return false;
+}
+ /*}}}*/