##################################################################### */
/*}}}*/
// Include Files /*{{{*/
-#ifdef __GNUG__
-#pragma implementation "apt-pkg/depcache.h"
-#endif
#include <apt-pkg/depcache.h>
#include <apt-pkg/version.h>
#include <apt-pkg/error.h>
#include <apt-pkg/algorithms.h>
#include <apt-pkg/fileutl.h>
+#include <apt-pkg/strutl.h>
#include <apt-pkg/configuration.h>
#include <apt-pkg/pkgsystem.h>
#include <apt-pkg/tagfile.h>
#include <iostream>
#include <sstream>
-#include <apti18n.h>
+#include <set>
-pkgDepCache::ActionGroup::ActionGroup(pkgDepCache &cache) :
+#include <sys/stat.h>
+
+#include <apti18n.h>
+ /*}}}*/
+// helper for Install-Recommends-Sections and Never-MarkAuto-Sections /*{{{*/
+static bool
+ConfigValueInSubTree(const char* SubTree, const char *needle)
+{
+ Configuration::Item const *Opts;
+ Opts = _config->Tree(SubTree);
+ if (Opts != 0 && Opts->Child != 0)
+ {
+ Opts = Opts->Child;
+ for (; Opts != 0; Opts = Opts->Next)
+ {
+ if (Opts->Value.empty() == true)
+ continue;
+ if (strcmp(needle, Opts->Value.c_str()) == 0)
+ return true;
+ }
+ }
+ return false;
+}
+ /*}}}*/
+pkgDepCache::ActionGroup::ActionGroup(pkgDepCache &cache) : /*{{{*/
cache(cache), released(false)
{
++cache.group_level;
{
release();
}
-
+ /*}}}*/
// DepCache::pkgDepCache - Constructors /*{{{*/
// ---------------------------------------------------------------------
/* */
pkgDepCache::pkgDepCache(pkgCache *pCache,Policy *Plcy) :
group_level(0), Cache(pCache), PkgState(0), DepState(0)
{
+ DebugMarker = _config->FindB("Debug::pkgDepCache::Marker", false);
+ DebugAutoInstall = _config->FindB("Debug::pkgDepCache::AutoInstall", false);
delLocalPolicy = 0;
LocalPolicy = Plcy;
if (LocalPolicy == 0)
int Done = 0;
for (PkgIterator I = PkgBegin(); I.end() != true; I++,Done++)
{
- if (Prog != 0)
+ if (Prog != 0 && Done%20 == 0)
Prog->Progress(Done);
// Find the proper cache slot
return true;
}
/*}}}*/
-
-bool pkgDepCache::readStateFile(OpProgress *Prog)
+bool pkgDepCache::readStateFile(OpProgress *Prog) /*{{{*/
{
FileFd state_file;
- string state = _config->FindDir("Dir::State") + "pkgstates";
+ string state = _config->FindDir("Dir::State") + "extended_states";
if(FileExists(state)) {
state_file.Open(state, FileFd::ReadOnly);
int file_size = state_file.Size();
pkgTagFile tagfile(&state_file);
pkgTagSection section;
int amt=0;
+ bool debug_autoremove=_config->FindB("Debug::pkgAutoRemove",false);
while(tagfile.Step(section)) {
string pkgname = section.FindS("Package");
pkgCache::PkgIterator pkg=Cache->FindPkg(pkgname);
short reason = section.FindI("Auto-Installed", 0);
if(reason > 0)
PkgState[pkg->ID].Flags |= Flag::Auto;
- if(_config->FindB("Debug::pkgAutoRemove",false))
- std::cout << "Auto-Installed : " << pkgname << std::endl;
+ if(debug_autoremove)
+ std::clog << "Auto-Installed : " << pkgname << std::endl;
amt+=section.size();
if(Prog != NULL)
Prog->OverallProgress(amt, file_size, 1,
_("Reading state information"));
}
- if(Prog != NULL)
- Prog->OverallProgress(file_size, file_size, 1,
- _("Reading state information"));
}
+ if(Prog != NULL)
+ Prog->OverallProgress(file_size, file_size, 1,
+ _("Reading state information"));
}
return true;
}
-
-bool pkgDepCache::writeStateFile(OpProgress *prog)
+ /*}}}*/
+bool pkgDepCache::writeStateFile(OpProgress *prog, bool InstalledOnly) /*{{{*/
{
+ bool debug_autoremove = _config->FindB("Debug::pkgAutoRemove",false);
+
+ if(debug_autoremove)
+ std::clog << "pkgDepCache::writeStateFile()" << std::endl;
+
FileFd StateFile;
- string state = _config->FindDir("Dir::State") + "pkgstates";
+ string state = _config->FindDir("Dir::State") + "extended_states";
- if(_config->FindB("Debug::pkgAutoRemove",false))
- std::clog << "pkgDepCache::writeStateFile()" << std::endl;
+ // if it does not exist, create a empty one
+ if(!FileExists(state))
+ {
+ StateFile.Open(state, FileFd::WriteEmpty);
+ StateFile.Close();
+ }
- if(!StateFile.Open(state, FileFd::WriteEmpty))
- return _error->Error(_("Failed to write StateFile %s"),
+ // open it
+ if(!StateFile.Open(state, FileFd::ReadOnly))
+ return _error->Error(_("Failed to open StateFile %s"),
state.c_str());
+ FILE *OutFile;
+ string outfile = state + ".tmp";
+ if((OutFile = fopen(outfile.c_str(),"w")) == NULL)
+ return _error->Error(_("Failed to write temporary StateFile %s"),
+ outfile.c_str());
+
+ // first merge with the existing sections
+ pkgTagFile tagfile(&StateFile);
+ pkgTagSection section;
+ std::set<string> pkgs_seen;
+ const char *nullreorderlist[] = {0};
+ while(tagfile.Step(section)) {
+ string pkgname = section.FindS("Package");
+ // Silently ignore unknown packages and packages with no actual
+ // version.
+ pkgCache::PkgIterator pkg=Cache->FindPkg(pkgname);
+ if(pkg.end() || pkg.VersionList().end())
+ continue;
+ bool newAuto = (PkgState[pkg->ID].Flags & Flag::Auto);
+ if(_config->FindB("Debug::pkgAutoRemove",false))
+ std::clog << "Update existing AutoInstall info: "
+ << pkg.Name() << std::endl;
+ TFRewriteData rewrite[2];
+ rewrite[0].Tag = "Auto-Installed";
+ rewrite[0].Rewrite = newAuto ? "1" : "0";
+ rewrite[0].NewTag = 0;
+ rewrite[1].Tag = 0;
+ TFRewrite(OutFile, section, nullreorderlist, rewrite);
+ fprintf(OutFile,"\n");
+ pkgs_seen.insert(pkgname);
+ }
+
+ // then write the ones we have not seen yet
std::ostringstream ostr;
- for(pkgCache::PkgIterator pkg=Cache->PkgBegin(); !pkg.end();pkg++) {
-
+ for(pkgCache::PkgIterator pkg=Cache->PkgBegin(); !pkg.end(); pkg++) {
if(PkgState[pkg->ID].Flags & Flag::Auto) {
- if(_config->FindB("Debug::pkgAutoRemove",false))
- std::clog << "AutoInstall: " << pkg.Name() << std::endl;
+ if (pkgs_seen.find(pkg.Name()) != pkgs_seen.end()) {
+ if(debug_autoremove)
+ std::clog << "Skipping already written " << pkg.Name() << std::endl;
+ continue;
+ }
+ // skip not installed ones if requested
+ if(InstalledOnly && pkg->CurrentVer == 0)
+ continue;
+ if(debug_autoremove)
+ std::clog << "Writing new AutoInstall: "
+ << pkg.Name() << std::endl;
ostr.str(string(""));
ostr << "Package: " << pkg.Name()
<< "\nAuto-Installed: 1\n\n";
- StateFile.Write(ostr.str().c_str(), ostr.str().size());
+ fprintf(OutFile,"%s",ostr.str().c_str());
+ fprintf(OutFile,"\n");
}
}
+ fclose(OutFile);
+
+ // move the outfile over the real file and set permissions
+ rename(outfile.c_str(), state.c_str());
+ chmod(state.c_str(), 0644);
+
return true;
}
-
+ /*}}}*/
// DepCache::CheckDep - Checks a single dependency /*{{{*/
// ---------------------------------------------------------------------
/* This first checks the dependency against the main target package and
we allow it anyhow because dpkg does. Technically it is a packaging
bug. Conflicts may never self match */
if (Dep.TargetPkg() != Dep.ParentPkg() ||
- (Dep->Type != Dep::Conflicts && Dep->Type != Dep::Obsoletes))
+ (Dep->Type != Dep::Conflicts && Dep->Type != Dep::DpkgBreaks && Dep->Type != Dep::Obsoletes))
{
PkgIterator Pkg = Dep.TargetPkg();
// Check the base package
{
/* Provides may never be applied against the same package if it is
a conflicts. See the comment above. */
- if (P.OwnerPkg() == Pkg && Dep->Type == Dep::Conflicts)
+ if (P.OwnerPkg() == Pkg &&
+ (Dep->Type == Dep::Conflicts || Dep->Type == Dep::DpkgBreaks))
continue;
// Check if the provides is a hit
{
StateCache &State = PkgState[Pkg->ID];
- // The Package is broken
+ // The Package is broken (either minimal dep or policy dep)
if ((State.DepState & DepInstMin) != DepInstMin)
iBrokenCount += Add;
+ if ((State.DepState & DepInstPolicy) != DepInstPolicy)
+ iPolicyBrokenCount += Add;
// Bad state
if (Pkg.State() != PkgIterator::NeedsNothing)
/* Invert for Conflicts. We have to do this twice to get the
right sense for a conflicts group */
- if (D->Type == Dep::Conflicts || D->Type == Dep::Obsoletes)
+ if (D->Type == Dep::Conflicts ||
+ D->Type == Dep::DpkgBreaks ||
+ D->Type == Dep::Obsoletes)
State = ~State;
// Add to the group if we are within an or..
Group = 0;
// Invert for Conflicts
- if (D->Type == Dep::Conflicts || D->Type == Dep::Obsoletes)
+ if (D->Type == Dep::Conflicts ||
+ D->Type == Dep::DpkgBreaks ||
+ D->Type == Dep::Obsoletes)
State = ~State;
}
}
Group = 0;
// Invert for Conflicts
- if (D->Type == Dep::Conflicts || D->Type == Dep::Obsoletes)
+ if (D->Type == Dep::Conflicts ||
+ D->Type == Dep::DpkgBreaks ||
+ D->Type == Dep::Obsoletes)
State = ~State;
}
}
State = DependencyState(D);
// Invert for Conflicts
- if (D->Type == Dep::Conflicts || D->Type == Dep::Obsoletes)
+ if (D->Type == Dep::Conflicts ||
+ D->Type == Dep::DpkgBreaks ||
+ D->Type == Dep::Obsoletes)
State = ~State;
RemoveStates(D.ParentPkg());
P.end() != true; P++)
Update(P.ParentPkg().RevDependsList());
}
-
/*}}}*/
-
// DepCache::MarkKeep - Put the package in the keep state /*{{{*/
// ---------------------------------------------------------------------
/* */
-void pkgDepCache::MarkKeep(PkgIterator const &Pkg, bool Soft, bool FromUser)
+void pkgDepCache::MarkKeep(PkgIterator const &Pkg, bool Soft, bool FromUser,
+ unsigned long Depth)
{
// Simplifies other routines.
if (Pkg.end() == true)
// We dont even try to keep virtual packages..
if (Pkg->VersionList == 0)
return;
-
+#if 0 // reseting the autoflag here means we lose the
+ // auto-mark information if a user selects a package for removal
+ // but changes his mind then and sets it for keep again
+ // - this makes sense as default when all Garbage dependencies
+ // are automatically marked for removal (as aptitude does).
+ // setting a package for keep then makes it no longer autoinstalled
+ // for all other use-case this action is rather suprising
if(FromUser && !P.Marked)
P.Flags &= ~Flag::Auto;
+#endif
+
+ if (DebugMarker == true)
+ std::clog << OutputInDepth(Depth) << "MarkKeep " << Pkg << " FU=" << FromUser << std::endl;
+
RemoveSizes(Pkg);
RemoveStates(Pkg);
// DepCache::MarkDelete - Put the package in the delete state /*{{{*/
// ---------------------------------------------------------------------
/* */
-void pkgDepCache::MarkDelete(PkgIterator const &Pkg, bool rPurge)
+void pkgDepCache::MarkDelete(PkgIterator const &Pkg, bool rPurge,
+ unsigned long Depth, bool FromUser)
{
// Simplifies other routines.
if (Pkg.end() == true)
if (Pkg->VersionList == 0)
return;
+ // check if we are allowed to install the package
+ if (IsDeleteOk(Pkg,rPurge,Depth,FromUser) == false)
+ return;
+
+ if (DebugMarker == true)
+ std::clog << OutputInDepth(Depth) << "MarkDelete " << Pkg << " FU=" << FromUser << std::endl;
+
RemoveSizes(Pkg);
RemoveStates(Pkg);
AddSizes(Pkg);
}
/*}}}*/
+// DepCache::IsDeleteOk - check if it is ok to remove this package /*{{{*/
+// ---------------------------------------------------------------------
+/* The default implementation just honors dpkg hold
+ But an application using this library can override this method
+ to control the MarkDelete behaviour */
+bool pkgDepCache::IsDeleteOk(PkgIterator const &Pkg,bool rPurge,
+ unsigned long Depth, bool FromUser)
+{
+ if (FromUser == false && Pkg->SelectedState == pkgCache::State::Hold && _config->FindB("APT::Ignore-Hold",false) == false)
+ {
+ if (DebugMarker == true)
+ std::clog << OutputInDepth(Depth) << "Hold prevents MarkDelete of " << Pkg << " FU=" << FromUser << std::endl;
+ return false;
+ }
+ return true;
+}
+ /*}}}*/
// DepCache::MarkInstall - Put the package in the install state /*{{{*/
// ---------------------------------------------------------------------
/* */
void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
- unsigned long Depth, bool FromUser)
+ unsigned long Depth, bool FromUser,
+ bool ForceImportantDeps)
{
if (Depth > 100)
return;
installed */
StateCache &P = PkgState[Pkg->ID];
P.iFlags &= ~AutoKept;
- if (P.InstBroken() == false && (P.Mode == ModeInstall ||
+ if ((P.InstPolicyBroken() == false && P.InstBroken() == false) &&
+ (P.Mode == ModeInstall ||
P.CandidateVer == (Version *)Pkg.CurrentVer()))
{
if (P.CandidateVer == (Version *)Pkg.CurrentVer() && P.InstallVer == 0)
- MarkKeep(Pkg, false, FromUser);
+ MarkKeep(Pkg, false, FromUser, Depth+1);
return;
}
// See if there is even any possible instalation candidate
if (P.CandidateVer == 0)
return;
-
// We dont even try to install virtual packages..
if (Pkg->VersionList == 0)
return;
-
+
+ // check if we are allowed to install the package
+ if (IsInstallOk(Pkg,AutoInst,Depth,FromUser) == false)
+ return;
+
/* Target the candidate version and remove the autoflag. We reset the
autoflag below if this was called recursively. Otherwise the user
should have the ability to de-auto a package by changing its state */
AddStates(Pkg);
Update(Pkg);
AddSizes(Pkg);
-
+
if (AutoInst == false)
return;
+ if (DebugMarker == true)
+ std::clog << OutputInDepth(Depth) << "MarkInstall " << Pkg << " FU=" << FromUser << std::endl;
+
DepIterator Dep = P.InstVerIter(*this).DependsList();
for (; Dep.end() != true;)
{
/* Check if this dep should be consider for install. If it is a user
defined important dep and we are installed a new package then
- it will be installed. Otherwise we only worry about critical deps */
+ it will be installed. Otherwise we only check for important
+ deps that have changed from the installed version
+ */
if (IsImportantDep(Start) == false)
continue;
- if (Pkg->CurrentVer != 0 && Start.IsCritical() == false)
+
+ /* Check if any ImportantDep() (but not Critical) were added
+ * since we installed the package. Also check for deps that
+ * were satisfied in the past: for instance, if a version
+ * restriction in a Recommends was tightened, upgrading the
+ * package should follow that Recommends rather than causing the
+ * dependency to be removed. (bug #470115)
+ */
+ bool isNewImportantDep = false;
+ bool isPreviouslySatisfiedImportantDep = false;
+ if(!ForceImportantDeps && !Start.IsCritical())
+ {
+ bool found=false;
+ VerIterator instVer = Pkg.CurrentVer();
+ if(!instVer.end())
+ {
+ for (DepIterator D = instVer.DependsList(); D.end() != true; D++)
+ {
+ //FIXME: deal better with or-groups(?)
+ DepIterator LocalStart = D;
+
+ if(IsImportantDep(D) && !D.IsCritical() &&
+ Start.TargetPkg() == D.TargetPkg())
+ {
+ if(!isPreviouslySatisfiedImportantDep)
+ {
+ DepIterator D2 = D;
+ while((D2->CompareOp & Dep::Or) != 0)
+ ++D2;
+
+ isPreviouslySatisfiedImportantDep =
+ (((*this)[D2] & DepGNow) != 0);
+ }
+
+ found=true;
+ }
+ }
+ // this is a new dep if it was not found to be already
+ // a important dep of the installed pacakge
+ isNewImportantDep = !found;
+ }
+ }
+ if(isNewImportantDep)
+ if(DebugAutoInstall == true)
+ std::clog << OutputInDepth(Depth) << "new important dependency: "
+ << Start.TargetPkg().Name() << std::endl;
+ if(isPreviouslySatisfiedImportantDep)
+ if(DebugAutoInstall == true)
+ std::clog << OutputInDepth(Depth) << "previously satisfied important dependency on "
+ << Start.TargetPkg().Name() << std::endl;
+
+ // skip important deps if the package is already installed
+ if (Pkg->CurrentVer != 0 && Start.IsCritical() == false
+ && !isNewImportantDep && !isPreviouslySatisfiedImportantDep
+ && !ForceImportantDeps)
continue;
/* If we are in an or group locate the first or that can
/* This bit is for processing the possibilty of an install/upgrade
fixing the problem */
SPtrArray<Version *> List = Start.AllTargets();
- if ((DepState[Start->ID] & DepCVer) == DepCVer)
+ if (Start->Type != Dep::DpkgBreaks &&
+ (DepState[Start->ID] & DepCVer) == DepCVer)
{
// Right, find the best version to install..
Version **Cur = List;
}
if (InstPkg.end() == false)
- MarkInstall(InstPkg, true, Depth + 1, false);
-
+ {
+ if(DebugAutoInstall == true)
+ std::clog << OutputInDepth(Depth) << "Installing " << InstPkg.Name()
+ << " as " << Start.DepType() << " of " << Pkg.Name()
+ << std::endl;
+ // now check if we should consider it a automatic dependency or not
+ if(Pkg.Section() && ConfigValueInSubTree("APT::Never-MarkAuto-Sections", Pkg.Section()))
+ {
+ if(DebugAutoInstall == true)
+ std::clog << OutputInDepth(Depth) << "Setting NOT as auto-installed (direct "
+ << Start.DepType() << " of pkg in APT::Never-MarkAuto-Sections)" << std::endl;
+ MarkInstall(InstPkg,true,Depth + 1, true);
+ }
+ else
+ {
+ // mark automatic dependency
+ MarkInstall(InstPkg,true,Depth + 1, false, ForceImportantDeps);
+ // Set the autoflag, after MarkInstall because MarkInstall unsets it
+ if (P->CurrentVer == 0)
+ PkgState[InstPkg->ID].Flags |= Flag::Auto;
+ }
+ }
continue;
}
-
+
/* For conflicts we just de-install the package and mark as auto,
- Conflicts may not have or groups */
- if (Start->Type == Dep::Conflicts || Start->Type == Dep::Obsoletes)
+ Conflicts may not have or groups. For dpkg's Breaks we try to
+ upgrade the package. */
+ if (Start->Type == Dep::Conflicts || Start->Type == Dep::Obsoletes ||
+ Start->Type == Dep::DpkgBreaks)
{
for (Version **I = List; *I != 0; I++)
{
VerIterator Ver(*this,*I);
PkgIterator Pkg = Ver.ParentPkg();
-
- MarkDelete(Pkg);
+
+ if (Start->Type != Dep::DpkgBreaks)
+ MarkDelete(Pkg,false,Depth + 1, false);
+ else if (PkgState[Pkg->ID].CandidateVer != *I)
+ MarkInstall(Pkg,true,Depth + 1, false, ForceImportantDeps);
}
continue;
}
}
}
/*}}}*/
+// DepCache::IsInstallOk - check if it is ok to install this package /*{{{*/
+// ---------------------------------------------------------------------
+/* The default implementation just honors dpkg hold
+ But an application using this library can override this method
+ to control the MarkInstall behaviour */
+bool pkgDepCache::IsInstallOk(PkgIterator const &Pkg,bool AutoInst,
+ unsigned long Depth, bool FromUser)
+{
+ if (FromUser == false && Pkg->SelectedState == pkgCache::State::Hold && _config->FindB("APT::Ignore-Hold",false) == false)
+ {
+ if (DebugMarker == true)
+ std::clog << OutputInDepth(Depth) << "Hold prevents MarkInstall of " << Pkg << " FU=" << FromUser << std::endl;
+ return false;
+ }
+ return true;
+}
+ /*}}}*/
// DepCache::SetReInstall - Set the reinstallation flag /*{{{*/
// ---------------------------------------------------------------------
/* */
return Ver;
}
/*}}}*/
-
// Policy::GetCandidateVer - Returns the Candidate install version /*{{{*/
// ---------------------------------------------------------------------
/* The default just returns the highest available version that is not
/* */
bool pkgDepCache::Policy::IsImportantDep(DepIterator Dep)
{
- return Dep.IsCritical();
+ 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()
+pkgDepCache::DefaultRootSetFunc::DefaultRootSetFunc() /*{{{*/
: constructedSuccessfully(false)
{
Configuration::Item const *Opts;
constructedSuccessfully = true;
}
-
-pkgDepCache::DefaultRootSetFunc::~DefaultRootSetFunc()
+ /*}}}*/
+pkgDepCache::DefaultRootSetFunc::~DefaultRootSetFunc() /*{{{*/
{
for(unsigned int i = 0; i < rootSetRegexp.size(); i++)
{
delete rootSetRegexp[i];
}
}
-
-
-bool pkgDepCache::DefaultRootSetFunc::InRootSet(const pkgCache::PkgIterator &pkg)
+ /*}}}*/
+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 false;
}
-
-pkgDepCache::InRootSetFunc *pkgDepCache::GetRootSetFunc()
+ /*}}}*/
+pkgDepCache::InRootSetFunc *pkgDepCache::GetRootSetFunc() /*{{{*/
{
DefaultRootSetFunc *f = new DefaultRootSetFunc;
if(f->wasConstructedSuccessfully())
return NULL;
}
}
-
+ /*}}}*/
bool pkgDepCache::MarkFollowsRecommends()
{
return _config->FindB("APT::AutoRemove::RecommendsImportant", true);
return _config->FindB("APT::AutoRemove::SuggestsImportant", false);
}
-// the main mark algorithm
+// 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].Garbage = false;
// debug output
- if(_config->FindB("Debug::pkgAutoRemove",false)
- && PkgState[p->ID].Flags & Flag::Auto)
+ if(debug_autoremove && PkgState[p->ID].Flags & Flag::Auto)
std::clog << "AutoDep: " << p.Name() << std::endl;
}
{
// the package is installed (and set to keep)
if(PkgState[p->ID].Keep() && !p.CurrentVer().end())
- MarkPackage(p, p.CurrentVer(),
+ MarkPackage(p, p.CurrentVer(),
follow_recommends, follow_suggests);
// the package is to be installed
else if(PkgState[p->ID].Install())
return true;
}
-
-// mark a single package in Mark-and-Sweep
+ /*}}}*/
+// MarkPackage - 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 currver = pkg.CurrentVer();
VerIterator candver = state.CandidateVerIter(*this);
VerIterator 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()))
+ // 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;
// if we are marked already we are done
if(state.Marked)
return;
- //std::cout << "Setting Marked for: " << pkg.Name() << std::endl;
+ bool debug_autoremove = _config->FindB("Debug::pkgAutoRemove", false);
+
+ if(debug_autoremove)
+ {
+ std::clog << "Marking: " << pkg.Name();
+ 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())
{
if(_system->VS->CheckDep(V.VerStr(), d->CompareOp, d.TargetVer()))
{
+ if(debug_autoremove)
+ {
+ std::clog << "Following dep: " << d.ParentPkg().Name()
+ << " " << d.ParentVer().VerStr() << " "
+ << d.DepType() << " "
+ << d.TargetPkg().Name();
+ 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);
}
if(_system->VS->CheckDep(prv.ProvideVersion(), d->CompareOp,
d.TargetVer()))
{
+ if(debug_autoremove)
+ {
+ std::clog << "Following dep: " << d.ParentPkg().Name()
+ << " " << d.ParentVer().VerStr() << " "
+ << d.DepType() << " "
+ << d.TargetPkg().Name();
+ if((d->CompareOp & ~pkgCache::Dep::Or) != pkgCache::Dep::NoOp)
+ {
+ std::clog << " (" << d.CompType() << " "
+ << d.TargetVer() << ")";
+ }
+ std::clog << ", provided by "
+ << prv.OwnerPkg().Name() << " "
+ << prv.OwnerVer().VerStr()
+ << std::endl;
+ }
+
MarkPackage(prv.OwnerPkg(), prv.OwnerVer(),
follow_recommends, follow_suggests);
}
}
}
}
-
-bool pkgDepCache::Sweep()
+ /*}}}*/
+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.Delete())
+ if(!state.Marked && (!p.CurrentVer().end() || state.Install()))
{
state.Garbage=true;
- if(_config->FindB("Debug::pkgAutoRemove",false))
- std::cout << "Garbage: " << p.Name() << std::endl;
+ if(debug_autoremove)
+ std::clog << "Garbage: " << p.Name() << std::endl;
}
}
return true;
}
+ /*}}}*/