// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: depcache.cc,v 1.10 1998/12/08 01:34:07 jgg Exp $
+// $Id: depcache.cc,v 1.25 2001/05/27 05:36:04 jgg Exp $
/* ######################################################################
Dependency Cache - Caches Dependency information.
#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/sptr.h>
+#include <apt-pkg/algorithms.h>
+
+#include <apt-pkg/fileutl.h>
+#include <apt-pkg/configuration.h>
+#include <apt-pkg/tagfile.h>
+
+#include <iostream>
+#include <sstream>
+#include <apti18n.h>
/*}}}*/
// DepCache::pkgDepCache - Constructors /*{{{*/
// ---------------------------------------------------------------------
/* */
-pkgDepCache::pkgDepCache(MMap &Map,OpProgress &Prog) :
- pkgCache(Map), PkgState(0), DepState(0)
-{
- if (_error->PendingError() == false)
- Init(&Prog);
-}
-pkgDepCache::pkgDepCache(MMap &Map) :
- pkgCache(Map), PkgState(0), DepState(0)
+pkgDepCache::pkgDepCache(pkgCache *pCache,Policy *Plcy) :
+ Cache(pCache), PkgState(0), DepState(0)
{
- if (_error->PendingError() == false)
- Init(0);
+ delLocalPolicy = 0;
+ LocalPolicy = Plcy;
+ if (LocalPolicy == 0)
+ delLocalPolicy = LocalPolicy = new Policy;
}
/*}}}*/
// DepCache::~pkgDepCache - Destructor /*{{{*/
{
delete [] PkgState;
delete [] DepState;
+ delete delLocalPolicy;
}
/*}}}*/
// DepCache::Init - Generate the initial extra structures. /*{{{*/
DepState = new unsigned char[Head().DependsCount];
memset(PkgState,0,sizeof(*PkgState)*Head().PackageCount);
memset(DepState,0,sizeof(*DepState)*Head().DependsCount);
-
+
if (Prog != 0)
{
Prog->OverallProgress(0,2*Head().PackageCount,Head().PackageCount,
- "Building Dependency Tree");
- Prog->SubProgress(Head().PackageCount,"Candidate Versions");
+ _("Building dependency tree"));
+ Prog->SubProgress(Head().PackageCount,_("Candidate versions"));
}
/* Set the current state of everything. In this state all of the
// Find the proper cache slot
StateCache &State = PkgState[I->ID];
State.iFlags = 0;
-
+
// Figure out the install version
State.CandidateVer = GetCandidateVer(I);
State.InstallVer = I.CurrentVer();
Prog->OverallProgress(Head().PackageCount,2*Head().PackageCount,
Head().PackageCount,
- "Building Dependency Tree");
- Prog->SubProgress(Head().PackageCount,"Dependency Generation");
+ _("Building dependency tree"));
+ Prog->SubProgress(Head().PackageCount,_("Dependency generation"));
}
Update(Prog);
+
+ if(Prog != 0)
+ Prog->Done();
return true;
}
/*}}}*/
-// DepCache::GetCandidateVer - Returns the Candidate install version /*{{{*/
-// ---------------------------------------------------------------------
-/* The default just returns the target version if it exists or the
- highest version. */
-pkgDepCache::VerIterator pkgDepCache::GetCandidateVer(PkgIterator Pkg)
+
+bool pkgDepCache::readStateFile(OpProgress *Prog)
{
- // Try to use an explicit target
- if (Pkg->TargetVer == 0)
- {
- /* Not source versions cannot be a candidate version unless they
- are already installed */
- 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)
- return I;
+ FileFd state_file;
+ string state = _config->FindDir("Dir::State") + "pkgstates";
+ if(FileExists(state)) {
+ state_file.Open(state, FileFd::ReadOnly);
+ int file_size = state_file.Size();
+ if(Prog != NULL)
+ Prog->OverallProgress(0, file_size, 1,
+ _("Reading state information"));
+
+ pkgTagFile tagfile(&state_file);
+ pkgTagSection section;
+ int amt=0;
+ while(tagfile.Step(section)) {
+ string pkgname = section.FindS("Package");
+ pkgCache::PkgIterator pkg=Cache->FindPkg(pkgname);
+ // Silently ignore unknown packages and packages with no actual
+ // version.
+ if(!pkg.end() && !pkg.VersionList().end()) {
+ 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;
+ 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"));
}
-
- return VerIterator(*this,0);
}
- else
- return Pkg.TargetVer();
+
+ return true;
}
- /*}}}*/
-// DepCache::IsImportantDep - True if the dependency is important /*{{{*/
-// ---------------------------------------------------------------------
-/* */
-bool pkgDepCache::IsImportantDep(DepIterator Dep)
+
+bool pkgDepCache::writeStateFile(OpProgress *prog)
{
- return Dep.IsCritical();
+ FileFd StateFile;
+ string state = _config->FindDir("Dir::State") + "pkgstates";
+
+ if(_config->FindB("Debug::pkgAutoRemove",false))
+ std::clog << "pkgDepCache::writeStateFile()" << std::endl;
+
+ if(!StateFile.Open(state, FileFd::WriteEmpty))
+ return _error->Error(_("Failed to write StateFile %s"),
+ state.c_str());
+
+ std::ostringstream ostr;
+ for(pkgCache::PkgIterator pkg=Cache->PkgBegin(); !pkg.end();pkg++) {
+
+ if(PkgState[pkg->ID].Flags & Flag::Auto) {
+ if(_config->FindB("Debug::pkgAutoRemove",false))
+ std::clog << "AutoInstal: " << 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());
+ }
+ }
+ return true;
}
- /*}}}*/
// DepCache::CheckDep - Checks a single dependency /*{{{*/
// ---------------------------------------------------------------------
/* Check simple depends. A depends -should- never self match but
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)
+ if (Dep.TargetPkg() != Dep.ParentPkg() ||
+ (Dep->Type != Dep::Conflicts && Dep->Type != Dep::Obsoletes))
{
PkgIterator Pkg = Dep.TargetPkg();
// Check the base package
if (Type == NowVersion && Pkg->CurrentVer != 0)
- if (pkgCheckDep(Dep.TargetVer(),
- Pkg.CurrentVer().VerStr(),Dep->CompareOp) == true)
+ if (VS().CheckDep(Pkg.CurrentVer().VerStr(),Dep->CompareOp,
+ Dep.TargetVer()) == true)
return true;
if (Type == InstallVersion && PkgState[Pkg->ID].InstallVer != 0)
- if (pkgCheckDep(Dep.TargetVer(),
- PkgState[Pkg->ID].InstVerIter(*this).VerStr(),
- Dep->CompareOp) == true)
+ if (VS().CheckDep(PkgState[Pkg->ID].InstVerIter(*this).VerStr(),
+ Dep->CompareOp,Dep.TargetVer()) == true)
return true;
if (Type == CandidateVersion && PkgState[Pkg->ID].CandidateVer != 0)
- if (pkgCheckDep(Dep.TargetVer(),
- PkgState[Pkg->ID].CandidateVerIter(*this).VerStr(),
- Dep->CompareOp) == true)
+ if (VS().CheckDep(PkgState[Pkg->ID].CandidateVerIter(*this).VerStr(),
+ Dep->CompareOp,Dep.TargetVer()) == true)
return true;
}
+ if (Dep->Type == Dep::Obsoletes)
+ return false;
+
// Check the providing packages
PrvIterator P = Dep.TargetPkg().ProvidesList();
PkgIterator Pkg = Dep.ParentPkg();
}
// Compare the versions.
- if (pkgCheckDep(Dep.TargetVer(),P.ProvideVersion(),Dep->CompareOp) == true)
+ if (VS().CheckDep(P.ProvideVersion(),Dep->CompareOp,Dep.TargetVer()) == true)
{
Res = P.OwnerPkg();
return true;
// DepCache::AddSizes - Add the packages sizes to the counters /*{{{*/
// ---------------------------------------------------------------------
/* Call with Mult = -1 to preform the inverse opration */
-void pkgDepCache::AddSizes(const PkgIterator &Pkg,long Mult)
+void pkgDepCache::AddSizes(const PkgIterator &Pkg,signed long Mult)
{
StateCache &P = PkgState[Pkg->ID];
- if (Pkg.State() == pkgCache::PkgIterator::NeedsConfigure)
- {
- iUsrSize += Mult*P.InstVerIter(*this)->InstalledSize;
+ if (Pkg->VersionList == 0)
+ return;
+
+ if (Pkg.State() == pkgCache::PkgIterator::NeedsConfigure &&
+ P.Keep() == true)
return;
- }
// Compute the size data
if (P.NewInstall() == true)
{
- iUsrSize += Mult*P.InstVerIter(*this)->InstalledSize;
- iDownloadSize += Mult*P.InstVerIter(*this)->Size;
+ iUsrSize += (signed)(Mult*P.InstVerIter(*this)->InstalledSize);
+ iDownloadSize += (signed)(Mult*P.InstVerIter(*this)->Size);
return;
}
// Upgrading
- if (Pkg->CurrentVer != 0 && P.InstallVer != (Version *)Pkg.CurrentVer() &&
- P.InstallVer != 0)
+ if (Pkg->CurrentVer != 0 &&
+ (P.InstallVer != (Version *)Pkg.CurrentVer() ||
+ (P.iFlags & ReInstall) == ReInstall) && P.InstallVer != 0)
{
- iUsrSize += Mult*((signed)P.InstVerIter(*this)->InstalledSize -
- (signed)Pkg.CurrentVer()->InstalledSize);
- iDownloadSize += Mult*P.InstVerIter(*this)->Size;
+ iUsrSize += (signed)(Mult*((signed)P.InstVerIter(*this)->InstalledSize -
+ (signed)Pkg.CurrentVer()->InstalledSize));
+ iDownloadSize += (signed)(Mult*P.InstVerIter(*this)->Size);
return;
}
if (Pkg.State() == pkgCache::PkgIterator::NeedsUnpack &&
P.Delete() == false)
{
- iDownloadSize += Mult*P.InstVerIter(*this)->Size;
+ iDownloadSize += (signed)(Mult*P.InstVerIter(*this)->Size);
return;
}
// Removing
if (Pkg->CurrentVer != 0 && P.InstallVer == 0)
{
- iUsrSize -= Mult*Pkg.CurrentVer()->InstalledSize;
+ iUsrSize -= (signed)(Mult*Pkg.CurrentVer()->InstalledSize);
return;
}
}
// Not installed
if (Pkg->CurrentVer == 0)
{
+ if (State.Mode == ModeDelete &&
+ (State.iFlags | Purge) == Purge && Pkg.Purge() == false)
+ iDelCount += Add;
+
if (State.Mode == ModeInstall)
iInstCount += Add;
return;
}
// Installed, no upgrade
- if (State.Upgradable() == false)
- {
+ if (State.Status == 0)
+ {
if (State.Mode == ModeDelete)
iDelCount += Add;
+ else
+ if ((State.iFlags & ReInstall) == ReInstall)
+ iInstCount += Add;
+
return;
}
/* Invert for Conflicts. We have to do this twice to get the
right sense for a conflicts group */
- if (D->Type == Dep::Conflicts)
+ if (D->Type == Dep::Conflicts || 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)
+ if (D->Type == Dep::Conflicts || D->Type == Dep::Obsoletes)
State = ~State;
}
}
{
// Build the dependency state.
unsigned char &State = DepState[D->ID];
- State = DependencyState(D);;
+ State = DependencyState(D);
// Add to the group if we are within an or..
Group |= State;
Group = 0;
// Invert for Conflicts
- if (D->Type == Dep::Conflicts)
+ if (D->Type == Dep::Conflicts || D->Type == Dep::Obsoletes)
State = ~State;
}
}
AddStates(I);
}
+ readStateFile(Prog);
+
if (Prog != 0)
Prog->Progress(Done);
}
State = DependencyState(D);
// Invert for Conflicts
- if (D->Type == Dep::Conflicts)
+ if (D->Type == Dep::Conflicts || D->Type == Dep::Obsoletes)
State = ~State;
-
+
RemoveStates(D.ParentPkg());
BuildGroupOrs(D.ParentVer());
UpdateVerState(D.ParentPkg());
/* This is called whenever the state of a package changes. It updates
all cached dependencies related to this package. */
void pkgDepCache::Update(PkgIterator const &Pkg)
-{
+{
// Recompute the dep of the package
RemoveStates(Pkg);
UpdateVerState(Pkg);
Update(P.ParentPkg().RevDependsList());
// Update the provides map for the candidate ver
- for (PrvIterator P = PkgState[Pkg->ID].CandidateVerIter(*this).ProvidesList();
- P.end() != true; P++)
- Update(P.ParentPkg().RevDependsList());
+ if (PkgState[Pkg->ID].CandidateVer != 0)
+ for (PrvIterator P = PkgState[Pkg->ID].CandidateVerIter(*this).ProvidesList();
+ P.end() != true; P++)
+ Update(P.ParentPkg().RevDependsList());
}
/*}}}*/
// Simplifies other routines.
if (Pkg.end() == true)
return;
+
+ /* Reject an attempt to keep a non-source broken installed package, those
+ must be upgraded */
+ if (Pkg.State() == PkgIterator::NeedsUnpack &&
+ Pkg.CurrentVer().Downloadable() == false)
+ return;
/* We changed the soft state all the time so the UI is a bit nicer
to use */
// DepCache::MarkDelete - Put the package in the delete state /*{{{*/
// ---------------------------------------------------------------------
/* */
-void pkgDepCache::MarkDelete(PkgIterator const &Pkg)
+void pkgDepCache::MarkDelete(PkgIterator const &Pkg, bool rPurge)
{
// Simplifies other routines.
if (Pkg.end() == true)
// Check that it is not already marked for delete
StateCache &P = PkgState[Pkg->ID];
- P.iFlags &= ~AutoKept;
- if (P.Mode == ModeDelete || P.InstallVer == 0)
+ P.iFlags &= ~(AutoKept | Purge);
+ if (rPurge == true)
+ P.iFlags |= Purge;
+
+ if ((P.Mode == ModeDelete || P.InstallVer == 0) &&
+ (Pkg.Purge() == true || rPurge == false))
return;
-
+
// We dont even try to delete virtual packages..
if (Pkg->VersionList == 0)
return;
RemoveSizes(Pkg);
RemoveStates(Pkg);
- P.Mode = ModeDelete;
+ if (Pkg->CurrentVer == 0 && (Pkg.Purge() == true || rPurge == false))
+ P.Mode = ModeKeep;
+ else
+ P.Mode = ModeDelete;
P.InstallVer = 0;
- P.Flags &= Flag::Auto;
+ // This was not inverted before, but I think it should be
+ P.Flags &= ~Flag::Auto;
AddStates(Pkg);
Update(Pkg);
// DepCache::MarkInstall - Put the package in the install state /*{{{*/
// ---------------------------------------------------------------------
/* */
-void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst)
-{
+void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
+ unsigned long Depth)
+{
+ if (Depth > 100)
+ return;
+
// Simplifies other routines.
if (Pkg.end() == true)
return;
MarkKeep(Pkg);
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)
// Grok or groups
DepIterator Start = Dep;
bool Result = true;
- for (bool LastOR = true; Dep.end() == false && LastOR == true; Dep++)
+ unsigned Ors = 0;
+ for (bool LastOR = true; Dep.end() == false && LastOR == true; Dep++,Ors++)
{
LastOR = (Dep->CompareOp & Dep::Or) == Dep::Or;
continue;
if (Pkg->CurrentVer != 0 && Start.IsCritical() == false)
continue;
-
- // Now we have to take action...
- PkgIterator P = Start.SmartTargetPkg();
+
+ /* If we are in an or group locate the first or that can
+ succeed. We have already cached this.. */
+ for (; Ors > 1 && (DepState[Start->ID] & DepCVer) != DepCVer; Ors--)
+ Start++;
+
+ /* 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)
{
- MarkInstall(P,true);
+ // Right, find the best version to install..
+ Version **Cur = List;
+ PkgIterator P = Start.TargetPkg();
+ PkgIterator InstPkg(*Cache,0);
+
+ // See if there are direct matches (at the start of the list)
+ for (; *Cur != 0 && (*Cur)->ParentPkg == P.Index(); Cur++)
+ {
+ PkgIterator Pkg(*Cache,Cache->PkgP + (*Cur)->ParentPkg);
+ if (PkgState[Pkg->ID].CandidateVer != *Cur)
+ continue;
+ InstPkg = Pkg;
+ break;
+ }
+
+ // Select the highest priority providing package
+ if (InstPkg.end() == true)
+ {
+ pkgPrioSortList(*Cache,Cur);
+ for (; *Cur != 0; Cur++)
+ {
+ PkgIterator Pkg(*Cache,Cache->PkgP + (*Cur)->ParentPkg);
+ if (PkgState[Pkg->ID].CandidateVer != *Cur)
+ continue;
+ InstPkg = Pkg;
+ break;
+ }
+ }
- // Set the autoflag, after MarkInstall because MarkInstall unsets it
- if (P->CurrentVer == 0)
- PkgState[P->ID].Flags |= Flag::Auto;
+ 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;
+ }
+
continue;
}
- // For conflicts we just de-install the package and mark as auto
- if (Start->Type == Dep::Conflicts)
+ /* 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)
{
- Version **List = Start.AllTargets();
for (Version **I = List; *I != 0; I++)
{
VerIterator Ver(*this,*I);
MarkDelete(Pkg);
PkgState[Pkg->ID].Flags |= Flag::Auto;
}
- delete [] List;
continue;
}
}
}
/*}}}*/
+// DepCache::SetReInstall - Set the reinstallation flag /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+void pkgDepCache::SetReInstall(PkgIterator const &Pkg,bool To)
+{
+ RemoveSizes(Pkg);
+ RemoveStates(Pkg);
+
+ StateCache &P = PkgState[Pkg->ID];
+ if (To == true)
+ P.iFlags |= ReInstall;
+ else
+ P.iFlags &= ~ReInstall;
+
+ AddStates(Pkg);
+ AddSizes(Pkg);
+}
+ /*}}}*/
+// DepCache::SetCandidateVersion - Change the candidate version /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+void pkgDepCache::SetCandidateVersion(VerIterator TargetVer)
+{
+ pkgCache::PkgIterator Pkg = TargetVer.ParentPkg();
+ StateCache &P = PkgState[Pkg->ID];
+
+ RemoveSizes(Pkg);
+ RemoveStates(Pkg);
+ if (P.CandidateVer == P.InstallVer)
+ P.InstallVer = (Version *)TargetVer;
+ P.CandidateVer = (Version *)TargetVer;
+ P.Update(Pkg,*this);
+
+ AddStates(Pkg);
+ Update(Pkg);
+ AddSizes(Pkg);
+}
+ /*}}}*/
// StateCache::Update - Compute the various static display things /*{{{*/
// ---------------------------------------------------------------------
/* This is called whenever the Candidate version changes. */
return Ver;
}
/*}}}*/
+
+// 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;
+}
+ /*}}}*/
+// Policy::IsImportantDep - True if the dependency is important /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool pkgDepCache::Policy::IsImportantDep(DepIterator Dep)
+{
+ return Dep.IsCritical();
+}
+ /*}}}*/