X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/db1e7193fa7d5b86656c05112b9d6ad6e75845b8..fc5aece9d8600b68cf8d654b379b6d840f2a5524:/apt-pkg/algorithms.cc diff --git a/apt-pkg/algorithms.cc b/apt-pkg/algorithms.cc index 98bd8dd8b..8626d33dc 100644 --- a/apt-pkg/algorithms.cc +++ b/apt-pkg/algorithms.cc @@ -20,10 +20,14 @@ #include #include #include +#include +#include #include + #include - +#include +#include #include /*}}}*/ using namespace std; @@ -1066,7 +1070,10 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) pkgCache::PkgIterator I = Cache.PkgBegin(); for (;I.end() != true; I++) { if (Cache[I].NewInstall() && !(Flags[I->ID] & PreInstalled)) { - std::cout << "Resolve installed new pkg: " << I.Name() << " (now marking it as auto)" << std::endl; + if(_config->FindI("Debug::pkgAutoRemove",false)) { + std::clog << "Resolve installed new pkg: " << I.Name() + << " (now marking it as auto)" << std::endl; + } Cache[I].Flags |= pkgCache::Flag::Auto; } } @@ -1245,105 +1252,236 @@ void pkgPrioSortList(pkgCache &Cache,pkgCache::Version **List) /*}}}*/ -// pkgMarkPkgUsed - Mark used packages as dirty /*{{{*/ -// --------------------------------------------------------------------- -/* Mark all reachable packages as dirty. */ -void pkgMarkPkgUsed(pkgDepCache &Cache, pkgCache::PkgIterator Pkg, - pkgCache::State::PkgRemoveState DirtLevel) +// 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) { - // If it is not installed, and we are in manual mode, ignore it - if ((Pkg->CurrentVer == 0 && Cache[Pkg].Install() == false || Cache[Pkg].Delete() == true) && - DirtLevel == pkgCache::State::RemoveManual) + 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) { -// fprintf(stdout,"This one is not installed/virtual %s %d %d\n", Pkg.Name(), Pkg->AutomaticRemove, DirtLevel); - return; + if(ver==candver) + mark_install(pkg, false, false, NULL); + else if(ver==pkg.CurrentVer()) + MarkKeep(pkg); + + instver=state.InstVerIter(*this); } +#endif - // If it is not installed, and it is not virtual, ignore it - if ((Pkg->CurrentVer == 0 && Cache[Pkg].Install() == false || Cache[Pkg].Delete() == true) && - Pkg->VersionList != 0) - { -// fprintf(stdout,"This one is not installed %s %d %d\n", Pkg.Name(), Pkg->AutomaticRemove, DirtLevel); + // 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 it is similar or more dirty than we are ;-), because we've been here already, don't mark it - // This is necessary because virtual packages just relay the current level, - // so it may be possible e.g. that this was already seen with ::RemoveSuggested, but - // we are ::RemoveRequired - if (Cache[Pkg].Dirty() >= DirtLevel) - { - //fprintf(stdout,"Seen already %s %d %d\n", Pkg.Name(), Pkg->AutomaticRemove, DirtLevel); + // if we are marked already we are done + if(state.Marked) return; - } - - // If it is less important than the current DirtLevel, don't mark it - if (Cache[Pkg].AutomaticRemove != pkgCache::State::RemoveManual && - Cache[Pkg].AutomaticRemove > DirtLevel) + + //std::cout << "Setting Marked for: " << pkg.Name() << std::endl; + state.Marked=true; + + if(!ver.end()) { -// fprintf(stdout,"We don't need %s %d %d %d\n", Pkg.Name(), Pkg->AutomaticRemove, DirtLevel, Cache[Pkg].Dirty()); - return; + 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); + } + } + } + } } +} - // Mark it as used - Cache.SetDirty(Pkg, DirtLevel); - - //fprintf(stdout,"We keep %s %d %d\n", Pkg.Name(), Pkg->AutomaticRemove, DirtLevel); - // We are a virtual package - if (Pkg->VersionList == 0) +// Helper for APT::NeverAutoRemove, always include the packages matching +// this regexp into the root-set +inline bool +pkgMarkAlwaysInclude(pkgCache::PkgIterator p, vector alwaysMark) +{ + for(unsigned int i=0;iAutomaticRemove, DirtLevel); - for (pkgCache::PrvIterator Prv = Pkg.ProvidesList(); ! Prv.end(); ++Prv) - pkgMarkPkgUsed (Cache, Prv.OwnerPkg(), DirtLevel); - return; + Cache[p].Marked=false; + Cache[p].Garbage=false; } - // Depending on the type of dependency, follow it - for (pkgCache::DepIterator D = Cache[Pkg].InstVerIter(Cache).DependsList(); ! D.end(); ++D) - { -// fprintf(stdout,"We depend on %s %s\n", D.TargetPkg().Name(), D.DepType()); + // init vars + follow_recommends=_config->FindB("APT::AutoRemove::RecommendsImportant",false); + follow_suggests=_config->FindB("APT::AutoRemove::SuggestsImportant", false); - switch(D->Type) + + // init the "NeverAutoRemove" variable + vector neverAutoRemoveRegexp; + Configuration::Item const *Opts; + Opts = _config->Tree("APT::NeverAutoRemove"); + if (Opts != 0 && Opts->Child != 0) + { + Opts = Opts->Child; + for (; Opts != 0; Opts = Opts->Next) { - case pkgCache::Dep::Depends: - case pkgCache::Dep::PreDepends: - pkgMarkPkgUsed (Cache, D.TargetPkg(), pkgCache::State::RemoveRequired); - break; - case pkgCache::Dep::Recommends: - pkgMarkPkgUsed (Cache, D.TargetPkg(), pkgCache::State::RemoveRecommended); - break; - case pkgCache::Dep::Suggests: - pkgMarkPkgUsed (Cache, D.TargetPkg(), pkgCache::State::RemoveSuggested); - break; - case pkgCache::Dep::Conflicts: - case pkgCache::Dep::Replaces: - case pkgCache::Dep::Obsoletes: - // We don't handle these here - break; + 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); + for(unsigned int i=0;iError("Regex compilation error for APT::NeverAutoRemove"); + } + neverAutoRemoveRegexp.push_back(p); } } -// fprintf(stdout,"We keep %s %d %d \n", Pkg.Name(), Pkg->AutomaticRemove, DirtLevel); -} - /*}}}*/ -bool pkgMarkUsed(pkgDepCache &Cache) -{ - // debug only - for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); ! Pkg.end(); ++Pkg) - if(!Cache[Pkg].Dirty() && Cache[Pkg].AutomaticRemove > 0) - std::cout << "has auto-remove information: " << Pkg.Name() - << " " << (int)Cache[Pkg].AutomaticRemove - << std::endl; - // init with defaults - for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); ! Pkg.end(); ++Pkg) - Cache.SetDirty(Pkg, pkgCache::State::RemoveUnknown); + // do the mark part, this is the core bit of the algorithm + for(pkgCache::PkgIterator p=Cache.PkgBegin(); !p.end(); ++p) + { + if( (func != NULL ? (*func)(p) : false) || + pkgMarkAlwaysInclude(p, neverAutoRemoveRegexp) || + !(Cache[p].Flags & pkgCache::Flag::Auto) || + (p->Flags & pkgCache::Flag::Essential)) + + { + // the package is installed (and set to keep) + if(Cache[p].Keep() && !p.CurrentVer().end()) + pkgMarkPackage(Cache, p, p.CurrentVer(), + follow_recommends, follow_suggests); + // the package is to be installed + else if(Cache[p].Install()) + pkgMarkPackage(Cache, p, Cache[p].InstVerIter(Cache), + follow_recommends, follow_suggests); + } + } + - // go recursive over the cache - for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); ! Pkg.end(); ++Pkg) - pkgMarkPkgUsed (Cache, Pkg, pkgCache::State::RemoveManual); + // 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 + } + } + // cleanup + for(unsigned int i=0;i