summaryrefslogtreecommitdiff
path: root/apt-pkg
diff options
context:
space:
mode:
authorMichael Vogt <michael.vogt@ubuntu.com>2005-11-09 11:39:27 +0000
committerMichael Vogt <michael.vogt@ubuntu.com>2005-11-09 11:39:27 +0000
commit74a05226eff7041cd8f2380fe599862d350a1ac3 (patch)
tree6881f515e054666354a51928fae0657beb02b15e /apt-pkg
parent331956f9b59c8c30cce977e8729991559d46005c (diff)
* merged daniel burrows fixes for the auto-mark code
Patches applied: * dburrows@debian.org--2005/apt--auto-mark--0--base-0 tag of michael.vogt@ubuntu.com--2005/apt--auto-mark--0--patch-22 * dburrows@debian.org--2005/apt--auto-mark--0--patch-1 doxygenize the new automark stuff * dburrows@debian.org--2005/apt--auto-mark--0--patch-2 Automatically update package markings after every state-changing public operation, and allow users of the dep-cache to group actions into a single action. * dburrows@debian.org--2005/apt--auto-mark--0--patch-3 Automatically update package markings after every state-changing public operation, and allow users of the dep-cache to group actions into a single action. * dburrows@debian.org--2005/apt--auto-mark--0--patch-4 Make action groups noncopyable * dburrows@debian.org--2005/apt--auto-mark--0--patch-5 Typo fix * dburrows@debian.org--2005/apt--auto-mark--0--patch-6 Add a FromUser flag to MarkKeep. * dburrows@debian.org--2005/apt--auto-mark--0--patch-7 Somehow the ActionGroup definition got duplicated; kill the duplicate. * dburrows@debian.org--2005/apt--auto-mark--0--patch-8 Cancel the automatic flag on packages that are being kept only if they are garbage. * dburrows@debian.org--2005/apt--auto-mark--0--patch-9 Don't clear the 'automatically installed' flag in MarkDelete. * dburrows@debian.org--2005/apt--auto-mark--0--patch-10 Add a FromUser flag to MarkInstall, and fix its handling of the Auto flag. * dburrows@debian.org--2005/apt--auto-mark--0--patch-11 Only clear the Auto flag on manual changes in MarkKeep. * dburrows@debian.org--2005/apt--auto-mark--0--patch-12 Make changes from the internal algorithms automatic. * dburrows@debian.org--2005/apt--auto-mark--0--patch-13 Use ActionGroups in algorithms that make lots of changes, and fix a compile error. * dburrows@debian.org--2005/apt--auto-mark--0--patch-14 Split the sweep code into a separate routine from pkgMarkUsed * dburrows@debian.org--2005/apt--auto-mark--0--patch-15 Update another call of MarkKeep to indicate that it's automatic. * dburrows@debian.org--2005/apt--auto-mark--0--patch-16 Move the mark-and-sweep code into pkgDepCache; call Sweep and document what it and Garbage are for; add a hook that can be used to generate a custom root-set function; move the big blob of regexp stuff into the custom root-set; fix the memory leak in the regexp stuff. * dburrows@debian.org--2005/apt--auto-mark--0--patch-17 Make ActionGroup take a reference instead of a pointer to the cache. * dburrows@debian.org--2005/apt--auto-mark--0--patch-18 Don't mark already-to-be-deleted packages as garbage, to imitate aptitude's behavior. * dburrows@debian.org--2005/apt--auto-mark--0--patch-19 Update apt-get for the new auto-mark protocol. * dburrows@debian.org--2005/apt--auto-mark--0--patch-20 Add a setter method for the Auto flag. * dburrows@debian.org--2005/apt--auto-mark--0--patch-21 Fix the test in apt-get about what to delete. * dburrows@debian.org--2005/apt--auto-mark--0--patch-22 Add a zero-argument mark-and-sweep routine and use it to do a mark-and-sweep on startup (so the garbage flags are initialized properly). * dburrows@debian.org--2005/apt--auto-mark--0--patch-23 Right, Status is 2 for new installs, not 0. * dburrows@debian.org--2005/apt--auto-mark--0--patch-24 POT updates. * dburrows@debian.org--2005/apt--auto-mark--0--patch-25 Actually initialize group_level to 0. * dburrows@debian.org--2005/apt--auto-mark--0--patch-26 Don't make an ActionGroup in Sweep, since there's no point and it also is an infinite loop. * dburrows@debian.org--2005/apt--auto-mark--0--patch-27 Add virtual hooks to control whether the garbage collector considers recommends and/or suggests to be strong links. * dburrows@debian.org--2005/apt--auto-mark--0--patch-28 Call the progress methods in the right order so we don't generate nonsensical progress notifications. * dburrows@debian.org--2005/apt--auto-mark--0--patch-29 Typo fix. * dburrows@debian.org--2005/apt--auto-mark--0--patch-30 Make RecommendsImportant default to true in apt, too. * dburrows@debian.org--2005/apt--auto-mark--0--patch-31 Add a release() method to action groups. * dburrows@debian.org--2005/apt--auto-mark--0--patch-32 Add an 'autoremove' command that is synonymous to '--auto-remove remove'.
Diffstat (limited to 'apt-pkg')
-rw-r--r--apt-pkg/algorithms.cc318
-rw-r--r--apt-pkg/algorithms.h23
-rw-r--r--apt-pkg/depcache.cc322
-rw-r--r--apt-pkg/depcache.h212
-rw-r--r--apt-pkg/packagemanager.cc2
5 files changed, 550 insertions, 327 deletions
diff --git a/apt-pkg/algorithms.cc b/apt-pkg/algorithms.cc
index 82ea19c93..ac9d3be0b 100644
--- a/apt-pkg/algorithms.cc
+++ b/apt-pkg/algorithms.cc
@@ -20,14 +20,12 @@
#include <apt-pkg/algorithms.h>
#include <apt-pkg/error.h>
#include <apt-pkg/configuration.h>
-#include <apt-pkg/pkgsystem.h>
#include <apt-pkg/version.h>
#include <apt-pkg/sptr.h>
#include <apti18n.h>
#include <sys/types.h>
-#include <regex.h>
#include <iostream>
/*}}}*/
using namespace std;
@@ -224,6 +222,8 @@ void pkgSimulate::ShortBreaks()
the necessary calculations to deal with the problems. */
bool pkgApplyStatus(pkgDepCache &Cache)
{
+ pkgDepCache::ActionGroup group(Cache);
+
for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
{
if (I->VersionList == 0)
@@ -234,13 +234,13 @@ bool pkgApplyStatus(pkgDepCache &Cache)
I->InstState == pkgCache::State::HoldReInstReq)
{
if (I->CurrentVer != 0 && I.CurrentVer().Downloadable() == true)
- Cache.MarkKeep(I);
+ Cache.MarkKeep(I, false, false);
else
{
// Is this right? Will dpkg choke on an upgrade?
if (Cache[I].CandidateVer != 0 &&
Cache[I].CandidateVerIter(Cache).Downloadable() == true)
- Cache.MarkInstall(I);
+ Cache.MarkInstall(I, false, 0, false);
else
return _error->Error(_("The package %s needs to be reinstalled, "
"but I can't find an archive for it."),I.Name());
@@ -257,12 +257,12 @@ bool pkgApplyStatus(pkgDepCache &Cache)
case pkgCache::State::HalfConfigured:
if ((I->CurrentVer != 0 && I.CurrentVer().Downloadable() == true) ||
I.State() != pkgCache::PkgIterator::NeedsUnpack)
- Cache.MarkKeep(I);
+ Cache.MarkKeep(I, false, false);
else
{
if (Cache[I].CandidateVer != 0 &&
Cache[I].CandidateVerIter(Cache).Downloadable() == true)
- Cache.MarkInstall(I);
+ Cache.MarkInstall(I, true, 0, false);
else
Cache.MarkDelete(I);
}
@@ -288,10 +288,12 @@ bool pkgApplyStatus(pkgDepCache &Cache)
on the result. */
bool pkgFixBroken(pkgDepCache &Cache)
{
+ pkgDepCache::ActionGroup group(Cache);
+
// Auto upgrade all broken packages
for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
if (Cache[I].NowBroken() == true)
- Cache.MarkInstall(I,true);
+ Cache.MarkInstall(I, true, 0, false);
/* Fix packages that are in a NeedArchive state but don't have a
downloadable install version */
@@ -304,7 +306,7 @@ bool pkgFixBroken(pkgDepCache &Cache)
if (Cache[I].InstVerIter(Cache).Downloadable() == false)
continue;
- Cache.MarkInstall(I,true);
+ Cache.MarkInstall(I, true, 0, false);
}
pkgProblemResolver Fix(&Cache);
@@ -321,23 +323,25 @@ bool pkgFixBroken(pkgDepCache &Cache)
*/
bool pkgDistUpgrade(pkgDepCache &Cache)
{
+ pkgDepCache::ActionGroup group(Cache);
+
/* Auto upgrade all installed packages, this provides the basis
for the installation */
for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
if (I->CurrentVer != 0)
- Cache.MarkInstall(I,true);
+ Cache.MarkInstall(I, true, 0, false);
/* Now, auto upgrade all essential packages - this ensures that
the essential packages are present and working */
for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
if ((I->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
- Cache.MarkInstall(I,true);
+ Cache.MarkInstall(I, true, 0, false);
/* We do it again over all previously installed packages to force
conflict resolution on them all. */
for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
if (I->CurrentVer != 0)
- Cache.MarkInstall(I,false);
+ Cache.MarkInstall(I, false, 0, false);
pkgProblemResolver Fix(&Cache);
@@ -349,7 +353,7 @@ bool pkgDistUpgrade(pkgDepCache &Cache)
if (I->SelectedState == pkgCache::State::Hold)
{
Fix.Protect(I);
- Cache.MarkKeep(I);
+ Cache.MarkKeep(I, false, false);
}
}
}
@@ -364,6 +368,8 @@ bool pkgDistUpgrade(pkgDepCache &Cache)
to install packages not marked for install */
bool pkgAllUpgrade(pkgDepCache &Cache)
{
+ pkgDepCache::ActionGroup group(Cache);
+
pkgProblemResolver Fix(&Cache);
if (Cache.BrokenCount() != 0)
@@ -380,7 +386,7 @@ bool pkgAllUpgrade(pkgDepCache &Cache)
continue;
if (I->CurrentVer != 0 && Cache[I].InstallVer != 0)
- Cache.MarkInstall(I,false);
+ Cache.MarkInstall(I, false, 0, false);
}
return Fix.ResolveByKeep();
@@ -393,6 +399,8 @@ bool pkgAllUpgrade(pkgDepCache &Cache)
the package is restored. */
bool pkgMinimizeUpgrade(pkgDepCache &Cache)
{
+ pkgDepCache::ActionGroup group(Cache);
+
if (Cache.BrokenCount() != 0)
return false;
@@ -409,9 +417,9 @@ bool pkgMinimizeUpgrade(pkgDepCache &Cache)
continue;
// Keep it and see if that is OK
- Cache.MarkKeep(I);
+ Cache.MarkKeep(I, false, false);
if (Cache.BrokenCount() != 0)
- Cache.MarkInstall(I,false);
+ Cache.MarkInstall(I, false, 0, false);
else
{
// If keep didnt actually do anything then there was no change..
@@ -569,6 +577,8 @@ void pkgProblemResolver::MakeScores()
installable */
bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg)
{
+ pkgDepCache::ActionGroup group(Cache);
+
if ((Flags[Pkg->ID] & Upgradable) == 0 || Cache[Pkg].Upgradable() == false)
return false;
if ((Flags[Pkg->ID] & Protected) == Protected)
@@ -577,7 +587,7 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg)
Flags[Pkg->ID] &= ~Upgradable;
bool WasKept = Cache[Pkg].Keep();
- Cache.MarkInstall(Pkg,false);
+ Cache.MarkInstall(Pkg, false, 0, false);
// This must be a virtual package or something like that.
if (Cache[Pkg].InstVerIter(Cache).end() == true)
@@ -662,7 +672,7 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg)
if (Fail == true)
{
if (WasKept == true)
- Cache.MarkKeep(Pkg);
+ Cache.MarkKeep(Pkg, false, false);
else
Cache.MarkDelete(Pkg);
return false;
@@ -689,6 +699,8 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg)
upgrade packages to advoid problems. */
bool pkgProblemResolver::Resolve(bool BrokenFix)
{
+ pkgDepCache::ActionGroup group(Cache);
+
unsigned long Size = Cache.Head().PackageCount;
// Record which packages are marked for install
@@ -704,7 +716,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
{
if (Cache[I].InstBroken() == true && BrokenFix == true)
{
- Cache.MarkInstall(I,false);
+ Cache.MarkInstall(I, false, 0, false);
if (Cache[I].Install() == true)
Again = true;
}
@@ -770,14 +782,14 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
pkgCache::Version *OldVer = Cache[I].InstallVer;
Flags[I->ID] &= ReInstateTried;
- Cache.MarkInstall(I,false);
+ Cache.MarkInstall(I, false, 0, false);
if (Cache[I].InstBroken() == true ||
OldBreaks < Cache.BrokenCount())
{
if (OldVer == 0)
Cache.MarkDelete(I);
else
- Cache.MarkKeep(I);
+ Cache.MarkKeep(I, false, false);
}
else
if (Debug == true)
@@ -822,7 +834,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
{
if (Debug == true)
clog << " Or group keep for " << I.Name() << endl;
- Cache.MarkKeep(I);
+ Cache.MarkKeep(I, false, false);
Change = true;
}
}
@@ -872,7 +884,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
}
Change = true;
- Cache.MarkKeep(I);
+ Cache.MarkKeep(I, false, false);
break;
}
@@ -909,7 +921,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
/* See if a keep will do, unless the package is protected,
then installing it will be necessary */
bool Installed = Cache[I].Install();
- Cache.MarkKeep(I);
+ Cache.MarkKeep(I, false, false);
if (Cache[I].InstBroken() == false)
{
// Unwind operation will be keep now
@@ -918,7 +930,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
// Restore
if (InOr == true && Installed == true)
- Cache.MarkInstall(I,false);
+ Cache.MarkInstall(I, false, 0, false);
if (Debug == true)
clog << " Holding Back " << I.Name() << " rather than change " << Start.TargetPkg().Name() << endl;
@@ -990,7 +1002,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
// Restore
if (InOr == true && Installed == true)
- Cache.MarkInstall(I,false);
+ Cache.MarkInstall(I, false, 0, false);
if (Debug == true)
clog << " Holding Back " << I.Name() << " because I can't find " << Start.TargetPkg().Name() << endl;
@@ -1035,7 +1047,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
{
if (Debug == true)
clog << " Fixing " << I.Name() << " via keep of " << J->Pkg.Name() << endl;
- Cache.MarkKeep(J->Pkg);
+ Cache.MarkKeep(J->Pkg, false, false);
}
if (Counter > 1)
@@ -1089,6 +1101,8 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
system was non-broken previously. */
bool pkgProblemResolver::ResolveByKeep()
{
+ pkgDepCache::ActionGroup group(Cache);
+
unsigned long Size = Cache.Head().PackageCount;
if (Debug == true)
@@ -1122,7 +1136,7 @@ bool pkgProblemResolver::ResolveByKeep()
{
if (Debug == true)
clog << "Keeping package " << I.Name() << endl;
- Cache.MarkKeep(I);
+ Cache.MarkKeep(I, false, false);
if (Cache[I].InstBroken() == false)
{
K = PList - 1;
@@ -1170,7 +1184,7 @@ bool pkgProblemResolver::ResolveByKeep()
{
if (Debug == true)
clog << " Keeping Package " << Pkg.Name() << " due to dep" << endl;
- Cache.MarkKeep(Pkg);
+ Cache.MarkKeep(Pkg, false, false);
}
if (Cache[I].InstBroken() == false)
@@ -1207,6 +1221,8 @@ bool pkgProblemResolver::ResolveByKeep()
/* This is used to make sure protected packages are installed */
void pkgProblemResolver::InstallProtect()
{
+ pkgDepCache::ActionGroup group(Cache);
+
for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
{
if ((Flags[I->ID] & Protected) == Protected)
@@ -1214,7 +1230,7 @@ void pkgProblemResolver::InstallProtect()
if ((Flags[I->ID] & ToRemove) == ToRemove)
Cache.MarkDelete(I);
else
- Cache.MarkInstall(I,false);
+ Cache.MarkInstall(I, false, 0, false);
}
}
}
@@ -1251,247 +1267,3 @@ void pkgPrioSortList(pkgCache &Cache,pkgCache::Version **List)
}
/*}}}*/
-
-// 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);
- }
- }
- }
- }
- }
-}
-
-
-// Helper for APT::NeverAutoRemove, always include the packages matching
-// this regexp into the root-set
-inline bool
-pkgMarkAlwaysInclude(pkgCache::PkgIterator p, vector<regex_t*> alwaysMark)
-{
- for(unsigned int i=0;i<alwaysMark.size();i++)
- if (regexec(alwaysMark[i],p.Name(),0,0,0) == 0)
- return true;
-
- return false;
-}
-
-bool pkgMarkUsed(pkgDepCache &Cache)
-{
- InRootSetFunc f;
- return pkgMarkUsed(Cache, f);
-}
-
-// the main mark algorithm
-bool pkgMarkUsed(pkgDepCache &Cache, InRootSetFunc &userFunc)
-{
- 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;
-
- // debug output
- if(_config->FindB("Debug::pkgAutoRemove",false)
- && Cache[p].Flags & pkgCache::Flag::Auto)
- std::clog << "AutoDep: " << p.Name() << std::endl;
- }
-
- // init vars
- follow_recommends=_config->FindB("APT::AutoRemove::RecommendsImportant",false);
- follow_suggests=_config->FindB("APT::AutoRemove::SuggestsImportant", false);
-
-
- // init the "NeverAutoRemove" variable
- vector<regex_t *> 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)
- {
- 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;i<neverAutoRemoveRegexp.size();i++)
- regfree(neverAutoRemoveRegexp[i]);
- return _error->Error("Regex compilation error for APT::NeverAutoRemove");
- }
- neverAutoRemoveRegexp.push_back(p);
- }
- }
-
-
- // do the mark part, this is the core bit of the algorithm
- for(pkgCache::PkgIterator p=Cache.PkgBegin(); !p.end(); ++p)
- {
- if( userFunc.InRootSet(p) ||
- 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);
- }
- }
-
-
- // do the sweep
- for(pkgCache::PkgIterator p=Cache.PkgBegin(); !p.end(); ++p)
- {
- pkgDepCache::StateCache &state=Cache[p];
-
- // if it is not marked and it is installed, it's garbage
- if(!state.Marked && !p.CurrentVer().end())
- {
- state.Garbage=true;
- if(_config->FindB("Debug::pkgAutoRemove",false))
- 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<neverAutoRemoveRegexp.size();i++)
- regfree(neverAutoRemoveRegexp[i]);
-
-
- return true;
-}
diff --git a/apt-pkg/algorithms.h b/apt-pkg/algorithms.h
index e539a410e..174a7f58d 100644
--- a/apt-pkg/algorithms.h
+++ b/apt-pkg/algorithms.h
@@ -132,28 +132,5 @@ bool pkgAllUpgrade(pkgDepCache &Cache);
bool pkgMinimizeUpgrade(pkgDepCache &Cache);
void pkgPrioSortList(pkgCache &Cache,pkgCache::Version **List);
-
-
-// class that can be subclassed by the client to bring in
-// certain own packages into the root set (if the client returns
-// True the package will be considered as part of the root set)
-class InRootSetFunc
-{
- public:
- virtual bool InRootSet(const pkgCache::PkgIterator &pkg) {return false;};
- virtual ~InRootSetFunc() {};
-};
-
-
-// Mark all reachable packages with "pkgDepCache::StateCache.Marked=1"
-// the root-set are all essential packages+everything that was not
-// installed automatically
-//
-// If InRootSetFunc is set, it will be called for each PkgIterator. This
-// is usefull for clients that have there own idea about the root-set
-//
-// Everything that is not reach can be removed
-bool pkgMarkUsed(pkgDepCache &Cache);
-bool pkgMarkUsed(pkgDepCache &Cache, InRootSetFunc &f);
#endif
diff --git a/apt-pkg/depcache.cc b/apt-pkg/depcache.cc
index 4c52c6c71..22dd53f97 100644
--- a/apt-pkg/depcache.cc
+++ b/apt-pkg/depcache.cc
@@ -19,18 +19,47 @@
#include <apt-pkg/fileutl.h>
#include <apt-pkg/configuration.h>
+#include <apt-pkg/pkgsystem.h>
#include <apt-pkg/tagfile.h>
#include <iostream>
#include <sstream>
#include <apti18n.h>
- /*}}}*/
+
+pkgDepCache::ActionGroup::ActionGroup(pkgDepCache &cache) :
+ cache(cache), released(false)
+{
+ ++cache.group_level;
+}
+
+void pkgDepCache::ActionGroup::release()
+{
+ if(!released)
+ {
+ if(cache.group_level == 0)
+ std::cerr << "W: Unbalanced action groups, expect badness" << std::endl;
+ else
+ {
+ --cache.group_level;
+
+ if(cache.group_level == 0)
+ cache.MarkAndSweep();
+ }
+
+ released = false;
+ }
+}
+
+pkgDepCache::ActionGroup::~ActionGroup()
+{
+ release();
+}
// DepCache::pkgDepCache - Constructors /*{{{*/
// ---------------------------------------------------------------------
/* */
pkgDepCache::pkgDepCache(pkgCache *pCache,Policy *Plcy) :
- Cache(pCache), PkgState(0), DepState(0)
+ group_level(0), Cache(pCache), PkgState(0), DepState(0)
{
delLocalPolicy = 0;
LocalPolicy = Plcy;
@@ -53,6 +82,10 @@ pkgDepCache::~pkgDepCache()
/* This allocats the extension buffers and initializes them. */
bool pkgDepCache::Init(OpProgress *Prog)
{
+ // Suppress mark updates during this operation (just in case) and
+ // run a mark operation when Init terminates.
+ ActionGroup actions(*this);
+
delete [] PkgState;
delete [] DepState;
PkgState = new StateCache[Head().PackageCount];
@@ -100,7 +133,7 @@ bool pkgDepCache::Init(OpProgress *Prog)
if(Prog != 0)
Prog->Done();
-
+
return true;
}
/*}}}*/
@@ -161,7 +194,7 @@ bool pkgDepCache::writeStateFile(OpProgress *prog)
if(PkgState[pkg->ID].Flags & Flag::Auto) {
if(_config->FindB("Debug::pkgAutoRemove",false))
- std::clog << "AutoInstal: " << pkg.Name() << std::endl;
+ std::clog << "AutoInstall: " << pkg.Name() << std::endl;
ostr.str(string(""));
ostr << "Package: " << pkg.Name()
<< "\nAuto-Installed: 1\n\n";
@@ -522,16 +555,16 @@ void pkgDepCache::Update(OpProgress *Prog)
AddStates(I);
}
- readStateFile(Prog);
-
if (Prog != 0)
Prog->Progress(Done);
+
+ readStateFile(Prog);
}
/*}}}*/
// DepCache::Update - Update the deps list of a package /*{{{*/
// ---------------------------------------------------------------------
/* This is a helper for update that only does the dep portion of the scan.
- It is mainly ment to scan reverse dependencies. */
+ It is mainly meant to scan reverse dependencies. */
void pkgDepCache::Update(DepIterator D)
{
// Update the reverse deps
@@ -583,7 +616,7 @@ void pkgDepCache::Update(PkgIterator const &Pkg)
// DepCache::MarkKeep - Put the package in the keep state /*{{{*/
// ---------------------------------------------------------------------
/* */
-void pkgDepCache::MarkKeep(PkgIterator const &Pkg,bool Soft)
+void pkgDepCache::MarkKeep(PkgIterator const &Pkg, bool Soft, bool FromUser)
{
// Simplifies other routines.
if (Pkg.end() == true)
@@ -595,6 +628,9 @@ void pkgDepCache::MarkKeep(PkgIterator const &Pkg,bool Soft)
Pkg.CurrentVer().Downloadable() == false)
return;
+ /** \todo Can this be moved later in the method? */
+ ActionGroup group(*this);
+
/* We changed the soft state all the time so the UI is a bit nicer
to use */
StateCache &P = PkgState[Pkg->ID];
@@ -611,7 +647,8 @@ void pkgDepCache::MarkKeep(PkgIterator const &Pkg,bool Soft)
if (Pkg->VersionList == 0)
return;
- P.Flags &= ~Flag::Auto;
+ if(FromUser && !P.Marked)
+ P.Flags &= ~Flag::Auto;
RemoveSizes(Pkg);
RemoveStates(Pkg);
@@ -637,6 +674,8 @@ void pkgDepCache::MarkDelete(PkgIterator const &Pkg, bool rPurge)
if (Pkg.end() == true)
return;
+ ActionGroup group(*this);
+
// Check that it is not already marked for delete
StateCache &P = PkgState[Pkg->ID];
P.iFlags &= ~(AutoKept | Purge);
@@ -659,8 +698,6 @@ void pkgDepCache::MarkDelete(PkgIterator const &Pkg, bool rPurge)
else
P.Mode = ModeDelete;
P.InstallVer = 0;
- // This was not inverted before, but I think it should be
- P.Flags &= ~Flag::Auto;
AddStates(Pkg);
Update(Pkg);
@@ -671,7 +708,7 @@ void pkgDepCache::MarkDelete(PkgIterator const &Pkg, bool rPurge)
// ---------------------------------------------------------------------
/* */
void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
- unsigned long Depth)
+ unsigned long Depth, bool FromUser)
{
if (Depth > 100)
return;
@@ -680,6 +717,8 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
if (Pkg.end() == true)
return;
+ ActionGroup group(*this);
+
/* Check that it is not already marked for install and that it can be
installed */
StateCache &P = PkgState[Pkg->ID];
@@ -688,7 +727,7 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
P.CandidateVer == (Version *)Pkg.CurrentVer()))
{
if (P.CandidateVer == (Version *)Pkg.CurrentVer() && P.InstallVer == 0)
- MarkKeep(Pkg);
+ MarkKeep(Pkg, false, FromUser);
return;
}
@@ -708,9 +747,20 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
P.Mode = ModeInstall;
P.InstallVer = P.CandidateVer;
- // invert the auto-flag only for new installs, not for upgrades
- if(P.Status == 0)
- P.Flags &= ~Flag::Auto;
+
+ if(FromUser)
+ {
+ // Set it to manual if it's a new install or cancelling the
+ // removal of a garbage package.
+ if(P.Status == 2 || (!Pkg.CurrentVer().end() && !P.Marked))
+ P.Flags &= ~Flag::Auto;
+ }
+ else
+ {
+ // Set it to auto if this is a new install.
+ if(P.Status == 2)
+ P.Flags |= Flag::Auto;
+ }
if (P.CandidateVer == (Version *)Pkg.CurrentVer())
P.Mode = ModeKeep;
@@ -788,13 +838,7 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
}
if (InstPkg.end() == false)
- {
- MarkInstall(InstPkg,true,Depth + 1);
-
- // Set the autoflag, after MarkInstall because MarkInstall unsets it
- if (P->CurrentVer == 0)
- PkgState[InstPkg->ID].Flags |= Flag::Auto;
- }
+ MarkInstall(InstPkg, true, Depth + 1, false);
continue;
}
@@ -809,7 +853,6 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
PkgIterator Pkg = Ver.ParentPkg();
MarkDelete(Pkg);
- PkgState[Pkg->ID].Flags |= Flag::Auto;
}
continue;
}
@@ -821,6 +864,8 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
/* */
void pkgDepCache::SetReInstall(PkgIterator const &Pkg,bool To)
{
+ ActionGroup group(*this);
+
RemoveSizes(Pkg);
RemoveStates(Pkg);
@@ -839,9 +884,11 @@ void pkgDepCache::SetReInstall(PkgIterator const &Pkg,bool To)
/* */
void pkgDepCache::SetCandidateVersion(VerIterator TargetVer)
{
+ ActionGroup group(*this);
+
pkgCache::PkgIterator Pkg = TargetVer.ParentPkg();
StateCache &P = PkgState[Pkg->ID];
-
+
RemoveSizes(Pkg);
RemoveStates(Pkg);
@@ -854,6 +901,18 @@ void pkgDepCache::SetCandidateVersion(VerIterator TargetVer)
Update(Pkg);
AddSizes(Pkg);
}
+
+void pkgDepCache::MarkAuto(const PkgIterator &Pkg, bool Auto)
+{
+ StateCache &state = PkgState[Pkg->ID];
+
+ ActionGroup group(*this);
+
+ if(Auto)
+ state.Flags |= Flag::Auto;
+ else
+ state.Flags &= ~Flag::Auto;
+}
/*}}}*/
// StateCache::Update - Compute the various static display things /*{{{*/
// ---------------------------------------------------------------------
@@ -944,3 +1003,216 @@ bool pkgDepCache::Policy::IsImportantDep(DepIterator Dep)
return Dep.IsCritical();
}
/*}}}*/
+
+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.Delete())
+ {
+ state.Garbage=true;
+ if(_config->FindB("Debug::pkgAutoRemove",false))
+ std::cout << "Garbage: " << p.Name() << std::endl;
+ }
+ }
+
+ return true;
+}
diff --git a/apt-pkg/depcache.h b/apt-pkg/depcache.h
index 619daf8f6..fd935c268 100644
--- a/apt-pkg/depcache.h
+++ b/apt-pkg/depcache.h
@@ -1,4 +1,4 @@
-// -*- mode: cpp; mode: fold -*-
+// -*- mode: c++; mode: fold -*-
// Description /*{{{*/
// $Id: depcache.h,v 1.14 2001/02/20 07:03:17 jgg Exp $
/* ######################################################################
@@ -45,9 +45,71 @@
#include <apt-pkg/pkgcache.h>
#include <apt-pkg/progress.h>
+#include <regex.h>
+
+#include <vector>
+
class pkgDepCache : protected pkgCache::Namespace
{
public:
+
+ /** \brief An arbitrary predicate on packages. */
+ class InRootSetFunc
+ {
+ public:
+ virtual bool InRootSet(const pkgCache::PkgIterator &pkg) {return false;};
+ virtual ~InRootSetFunc() {};
+ };
+
+ private:
+ /** \brief Mark a single package and all its unmarked important
+ * dependencies during mark-and-sweep.
+ *
+ * Recursively invokes itself to mark all dependencies of the
+ * package.
+ *
+ * \param pkg The package to mark.
+ *
+ * \param ver The version of the package that is to be marked.
+ *
+ * \param follow_recommends If \b true, recommendations of the
+ * package will be recursively marked.
+ *
+ * \param follow_suggests If \b true, suggestions of the package
+ * will be recursively marked.
+ */
+ void MarkPackage(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver,
+ bool follow_recommends,
+ bool follow_suggests);
+
+ /** \brief Update the Marked field of all packages.
+ *
+ * Each package's StateCache::Marked field will be set to \b true
+ * if and only if it can be reached from the root set. By
+ * default, the root set consists of the set of manually installed
+ * or essential packages, but it can be extended using the
+ * parameter #rootFunc.
+ *
+ * \param rootFunc A callback that can be used to add extra
+ * packages to the root set.
+ *
+ * \return \b false if an error occured.
+ */
+ bool MarkRequired(InRootSetFunc &rootFunc);
+
+ /** \brief Set the StateCache::Garbage flag on all packages that
+ * should be removed.
+ *
+ * Packages that were not marked by the last call to #MarkRequired
+ * are tested to see whether they are actually garbage. If so,
+ * they are marked as such.
+ *
+ * \return \b false if an error occured.
+ */
+ bool Sweep();
+
+ public:
// These flags are used in DepState
enum DepFlags {DepNow = (1 << 0),DepInstall = (1 << 1),DepCVer = (1 << 2),
@@ -64,6 +126,83 @@ class pkgDepCache : protected pkgCache::Namespace
enum VersionTypes {NowVersion, InstallVersion, CandidateVersion};
enum ModeList {ModeDelete = 0, ModeKeep = 1, ModeInstall = 2};
+ /** \brief Represents an active action group.
+ *
+ * An action group is a group of actions that are currently being
+ * performed. While an active group is active, certain routine
+ * clean-up actions that would normally be performed after every
+ * cache operation are delayed until the action group is
+ * completed. This is necessary primarily to avoid inefficiencies
+ * when modifying a large number of packages at once.
+ *
+ * This class represents an active action group. Creating an
+ * instance will create an action group; destroying one will
+ * destroy the corresponding action group.
+ *
+ * The following operations are suppressed by this class:
+ *
+ * - Keeping the Marked and Garbage flags up to date.
+ *
+ * \note This can be used in the future to easily accumulate
+ * atomic actions for undo or to display "what apt did anyway";
+ * e.g., change the counter of how many action groups are active
+ * to a std::set of pointers to them and use those to store
+ * information about what happened in a group in the group.
+ */
+ class ActionGroup
+ {
+ pkgDepCache &cache;
+
+ bool released;
+
+ /** Action groups are noncopyable. */
+ ActionGroup(const ActionGroup &other);
+ public:
+ /** \brief Create a new ActionGroup.
+ *
+ * \param cache The cache that this ActionGroup should
+ * manipulate.
+ *
+ * As long as this object exists, no automatic cleanup
+ * operations will be undertaken.
+ */
+ ActionGroup(pkgDepCache &cache);
+
+ /** \brief Clean up the action group before it is destroyed.
+ *
+ * If it is destroyed later, no second cleanup wil be run.
+ */
+ void release();
+
+ /** \brief Destroy the action group.
+ *
+ * If this is the last action group, the automatic cache
+ * cleanup operations will be undertaken.
+ */
+ ~ActionGroup();
+ };
+
+ /** \brief Returns \b true for packages matching a regular
+ * expression in APT::NeverAutoRemove.
+ */
+ class DefaultRootSetFunc : public InRootSetFunc
+ {
+ std::vector<regex_t *> rootSetRegexp;
+ bool constructedSuccessfully;
+
+ public:
+ DefaultRootSetFunc();
+ ~DefaultRootSetFunc();
+
+ /** \return \b true if the class initialized successfully, \b
+ * false otherwise. Used to avoid throwing an exception, since
+ * APT classes generally don't.
+ */
+ bool wasConstructedSuccessfully() const { return constructedSuccessfully; }
+
+ bool InRootSet(const pkgCache::PkgIterator &pkg);
+ };
+
struct StateCache
{
// Epoch stripped text versions of the two version fields
@@ -80,8 +219,15 @@ class pkgDepCache : protected pkgCache::Namespace
unsigned short Flags;
unsigned short iFlags; // Internal flags
- // mark and sweep flags
+ /** \brief \b true if this package can be reached from the root set. */
bool Marked;
+
+ /** \brief \b true if this package is unused and should be removed.
+ *
+ * This differs from !#Marked, because it is possible that some
+ * unreachable packages will be protected from becoming
+ * garbage.
+ */
bool Garbage;
// Various tree indicators
@@ -124,6 +270,14 @@ class pkgDepCache : protected pkgCache::Namespace
virtual ~Policy() {};
};
+
+ private:
+ /** The number of open "action groups"; certain post-action
+ * operations are suppressed if this number is > 0.
+ */
+ int group_level;
+
+ friend class ActionGroup;
protected:
@@ -187,13 +341,61 @@ class pkgDepCache : protected pkgCache::Namespace
inline StateCache &operator [](PkgIterator const &I) {return PkgState[I->ID];};
inline unsigned char &operator [](DepIterator const &I) {return DepState[I->ID];};
- // Manipulators
- void MarkKeep(PkgIterator const &Pkg,bool Soft = false);
+ /** \return A function identifying packages in the root set other
+ * than manually installed packages and essential packages, or \b
+ * NULL if an error occurs.
+ *
+ * \todo Is this the best place for this function? Perhaps the
+ * settings for mark-and-sweep should be stored in a single
+ * external class?
+ */
+ virtual InRootSetFunc *GetRootSetFunc();
+
+ /** \return \b true if the garbage collector should follow recommendations.
+ */
+ virtual bool MarkFollowsRecommends();
+
+ /** \return \b true if the garbage collector should follow suggestions.
+ */
+ virtual bool MarkFollowsSuggests();
+
+ /** \brief Update the Marked and Garbage fields of all packages.
+ *
+ * This routine is implicitly invoked after all state manipulators
+ * and when an ActionGroup is destroyed. It invokes #MarkRequired
+ * and #Sweep to do its dirty work.
+ *
+ * \param rootFunc A predicate that returns \b true for packages
+ * that should be added to the root set.
+ */
+ bool MarkAndSweep(InRootSetFunc &rootFunc)
+ {
+ return MarkRequired(rootFunc) && Sweep();
+ }
+
+ bool MarkAndSweep()
+ {
+ std::auto_ptr<InRootSetFunc> f(GetRootSetFunc());
+ if(f.get() != NULL)
+ return MarkAndSweep(*f.get());
+ else
+ return false;
+ }
+
+ /** \name State Manipulators
+ */
+ // @{
+ void MarkKeep(PkgIterator const &Pkg, bool Soft = false,
+ bool FromUser = true);
void MarkDelete(PkgIterator const &Pkg,bool Purge = false);
void MarkInstall(PkgIterator const &Pkg,bool AutoInst = true,
- unsigned long Depth = 0);
+ unsigned long Depth = 0, bool FromUser = true);
void SetReInstall(PkgIterator const &Pkg,bool To);
void SetCandidateVersion(VerIterator TargetVer);
+
+ /** Set the "is automatically installed" flag of Pkg. */
+ void MarkAuto(const PkgIterator &Pkg, bool Auto);
+ // @}
// This is for debuging
void Update(OpProgress *Prog = 0);
diff --git a/apt-pkg/packagemanager.cc b/apt-pkg/packagemanager.cc
index 87a21004f..05615db79 100644
--- a/apt-pkg/packagemanager.cc
+++ b/apt-pkg/packagemanager.cc
@@ -106,7 +106,7 @@ bool pkgPackageManager::FixMissing()
// Okay, this file is missing and we need it. Mark it for keep
Bad = true;
- Cache.MarkKeep(I);
+ Cache.MarkKeep(I, false, false);
}
// We have to empty the list otherwise it will not have the new changes