// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: depcache.cc,v 1.1 1998/07/07 04:17:01 jgg Exp $
+// $Id: depcache.cc,v 1.18 1999/04/28 22:48:45 jgg Exp $
/* ######################################################################
Dependency Cache - Caches Dependency information.
/*}}}*/
// Include Files /*{{{*/
#ifdef __GNUG__
-#pragma implementation "pkglib/depcache.h"
+#pragma implementation "apt-pkg/depcache.h"
#endif
-#include <pkglib/depcache.h>
+#include <apt-pkg/depcache.h>
-#include <pkglib/version.h>
-#include <pkglib/error.h>
+#include <apt-pkg/version.h>
+#include <apt-pkg/error.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)
+ pkgCache(Map), PkgState(0), DepState(0)
{
if (_error->PendingError() == false)
- Init();
+ Init(0);
}
/*}}}*/
// DepCache::~pkgDepCache - Destructor /*{{{*/
delete [] DepState;
}
/*}}}*/
-// DepCache::ReMap - Regenerate the extra data for the new cache /*{{{*/
-// ---------------------------------------------------------------------
-/* pkgCache's constructors call this function, but because the object is not
- fully constructed at that point it will not result in this function being
- called but pkgCache::ReMap will be instead.*/
-bool pkgDepCache::ReMap()
-{
- if (pkgCache::ReMap() == false)
- return false;
-
- return Init();
-}
- /*}}}*/
// DepCache::Init - Generate the initial extra structures. /*{{{*/
// ---------------------------------------------------------------------
/* This allocats the extension buffers and initializes them. */
-bool pkgDepCache::Init()
+bool pkgDepCache::Init(OpProgress *Prog)
{
delete [] PkgState;
delete [] DepState;
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");
+ }
+
/* Set the current state of everything. In this state all of the
packages are kept exactly as is. See AllUpgrade */
- for (PkgIterator I = PkgBegin(); I.end() != true; I++)
+ int Done = 0;
+ for (PkgIterator I = PkgBegin(); I.end() != true; I++,Done++)
{
+ if (Prog != 0)
+ Prog->Progress(Done);
+
// Find the proper cache slot
StateCache &State = PkgState[I->ID];
State.iFlags = 0;
State.Update(I,*this);
}
- Update();
+ if (Prog != 0)
+ {
+
+ Prog->OverallProgress(Head().PackageCount,2*Head().PackageCount,
+ Head().PackageCount,
+ "Building Dependency Tree");
+ Prog->SubProgress(Head().PackageCount,"Dependency Generation");
+ }
+
+ Update(Prog);
return true;
}
// ---------------------------------------------------------------------
/* The default just returns the target version if it exists or the
highest version. */
-pkgDepCache::VerIterator pkgDepCache::GetCandidateVer(PkgIterator Pkg)
+pkgDepCache::VerIterator pkgDepCache::GetCandidateVer(PkgIterator Pkg,
+ bool AllowCurrent)
{
// 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;
- }
-
- return VerIterator(*this,0);
- }
+ if (Pkg->TargetVer == 0 ||
+ (AllowCurrent == false && Pkg.TargetVer() == Pkg.CurrentVer()))
+ return pkgCache::GetCandidateVer(Pkg,AllowCurrent);
else
return Pkg.TargetVer();
}
{
StateCache &P = PkgState[Pkg->ID];
+ 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;
+ return;
}
// Upgrading
if (Pkg->CurrentVer != 0 && P.InstallVer != (Version *)Pkg.CurrentVer() &&
P.InstallVer != 0)
{
- iUsrSize += Mult*(P.InstVerIter(*this)->InstalledSize -
- Pkg.CurrentVer()->InstalledSize);
+ iUsrSize += Mult*((signed)P.InstVerIter(*this)->InstalledSize -
+ (signed)Pkg.CurrentVer()->InstalledSize);
+ iDownloadSize += Mult*P.InstVerIter(*this)->Size;
+ return;
+ }
+
+ // Reinstall
+ if (Pkg.State() == pkgCache::PkgIterator::NeedsUnpack &&
+ P.Delete() == false)
+ {
iDownloadSize += Mult*P.InstVerIter(*this)->Size;
+ return;
}
// Removing
if (Pkg->CurrentVer != 0 && P.InstallVer == 0)
+ {
iUsrSize -= Mult*Pkg.CurrentVer()->InstalledSize;
+ return;
+ }
}
/*}}}*/
// DepCache::AddStates - Add the package to the state counter /*{{{*/
State = ~State;
// Add to the group if we are within an or..
+ State &= 0x7;
Group |= State;
State |= Group << 3;
if ((D->CompareOp & Dep::Or) != Dep::Or)
// ---------------------------------------------------------------------
/* This will figure out the state of all the packages and all the
dependencies based on the current policy. */
-void pkgDepCache::Update()
+void pkgDepCache::Update(OpProgress *Prog)
{
iUsrSize = 0;
iDownloadSize = 0;
iBadCount = 0;
// Perform the depends pass
- for (PkgIterator I = PkgBegin(); I.end() != true; I++)
+ int Done = 0;
+ for (PkgIterator I = PkgBegin(); I.end() != true; I++,Done++)
{
+ if (Prog != 0 && Done%20 == 0)
+ Prog->Progress(Done);
for (VerIterator V = I.VersionList(); V.end() != true; V++)
{
unsigned char Group = 0;
UpdateVerState(I);
AddStates(I);
}
+
+ if (Prog != 0)
+ Prog->Progress(Done);
}
/*}}}*/
// DepCache::Update - Update the deps list of a package /*{{{*/
// 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 */
RemoveSizes(Pkg);
RemoveStates(Pkg);
- P.Mode = ModeDelete;
+ if (Pkg->CurrentVer == 0)
+ P.Mode = ModeKeep;
+ else
+ P.Mode = ModeDelete;
P.InstallVer = 0;
P.Flags &= Flag::Auto;
}
/*}}}*/
-#if 0
-// DepCache::ResolveConflicts - Figure the auto upgrades /*{{{*/
-// ---------------------------------------------------------------------
-/* This routine attempts to resolve conflicts generated by automatic
- upgrading. It is known as 'Stage 1' but that name isn't as proper anymore.
-
- It's most important function is during the initial load of APT. The
- loading code will mark every package for upgrade to it's candidate version
- and then call this routine. This routine will then 'soft keep' every
- package that causes conflict, is conflicted, or so on. It is a bit
- agressive in that it may unselect more packages in some odd cases
- than are strictly necessary but in the case where no packages were
- conflicting before it will always produce a system with no packages
- conflicting after.
-
- This routine is also used during state changes that require autoupgrade
- scanning. That is, if a new package is marked for install then all packages
- that have been soft kept are reconsidered for upgrade.
-
- It is called with state information about what can be un-upgraded and
- what the pre-upgrade install state was. It is expected that the caller
- has already marked the desired packages to the install state. Bit 0 is
- the original install state and Bit 1 is controls whether the package
- should be touched.
-*/
-void pkgDepCache::ResolveConflicts(unsigned char *Touched)
-{
- bool Again = false;
- do
- {
- Again = false;
- for (PkgIterator I = PkgBegin(); I.end() != true; I++)
- {
- // The package will install OK
- if ((PkgState[I->ID].DepState & DepInstMin) == DepInstMin)
- continue;
-
- /* The package was broken before and this upgrade will not
- make things better. We simply mark the package for keep
- and assume an upgrade attempt will be hopeless. This might
- not be ideal. */
- if ((Touched[I->ID] & (1 << 0)) != (1 << 0))
- {
- // The package isnt to be touched
- if ((Touched[I->ID] & (1 << 1)) == (1 << 1))
- MarkKeep(I,true);
-
- continue;
- }
-
- // Check to see if not upgrading it will solve the problem
- if (I->CurrentVer != 0)
- {
- // The package isnt to be touched
- if ((Touched[I->ID] & (1 << 1)) == (1 << 1))
- {
- if (PkgState[I->ID].Mode != ModeKeep)
- Again = true;
-
- MarkKeep(I,true);
- }
-
- /* Check if the package is sill broken. If so then we cant leave
- it as is and get a working system. Lets try marking some
- depends for 'keep'. This is brutal, it keeps everything in
- sight to fix the problem. */
- DepIterator D = I.CurrentVer().DependsList();
- for (;(PkgState[I->ID].DepState & DepInstMin) != DepInstMin &&
- D.end() != true; D++)
- {
- // We only worry about critical deps.
- if (D.IsCritical() != true)
- continue;
-
- unsigned char State = DepState[D->ID];
-
- // This dep never was set before so we dont need to set it now
- if ((State & DepNow) != DepNow)
- continue;
-
- // The dep is okay now no worries.
- if ((State & DepInstall) == DepInstall)
- continue;
-
- // Locate a target to keep
- PkgIterator P(*this);
- if (CheckDep(D,NowVersion,P) == true)
- {
- // We cant touch this package
- if ((Touched[P->ID] & (1 << 1)) == (1 << 1))
- MarkKeep(P,true);
- }
- }
- }
- }
- }
- while (Again == true);
-}
- /*}}}*/
-// DepCache::PromoteAutoKeep - Gentler version of the above /*{{{*/
-// ---------------------------------------------------------------------
-/* This is used when installing packages, all it does is attempt to promote
- everything that has been auto-kept. It simply promotes everything
- irregardless of it having a chance to work and then runs ResolveConflicts
- on the result. This allows circular depends loops to work but isn't
- terribly fast. */
-void pkgDepCache::PromoteAutoKeep()
-{
- /* Initialize the touchd array. Bit 0 is the old install state bit 1
- is the touch value */
- unsigned char *Touch = new unsigned char[Head().PackageCount];
- for (unsigned int I = 0; I != Head().PackageCount; I++)
- {
- if ((PkgState[I].DepState & DepInstMin) == DepInstMin)
- Touch[I] = 1 << 0;
- else
- Touch[I] = 0;
- }
-
- // This allows circular depends to work
- for (PkgIterator I = PkgBegin(); I.end() != true; I++)
- {
- /* It wasnt installed before or it is not autokept or it is not
- upgradeable */
- StateCache &P = PkgState[I->ID];
- if (I->CurrentVer == 0 || P.Mode != ModeKeep || I->VersionList == 0 ||
- P.CandidateVer == (Version *)I.CurrentVer() ||
- (P.iFlags & AutoKept) != AutoKept)
- continue;
-
- P.Mode = ModeInstall;
- P.InstallVer = P.CandidateVer;
- if (P.CandidateVer == (Version *)I.CurrentVer())
- P.Mode = ModeKeep;
-
- // Okay autoupgrade it.
- Touch[I->ID] |= 1 << 1;
- }
-
- Update();
- ResolveConflicts(Touch);
-
- delete [] Touch;
-}
- /*}}}*/
-// DepCache::AllUpgrade - Try to upgrade everything /*{{{*/
-// ---------------------------------------------------------------------
-/* */
-void pkgDepCache::AllUpgrade()
-{
- // Set everything to an upgrade mode
- for (PkgIterator I = PkgBegin(); I.end() != true; I++)
- {
- StateCache &State = PkgState[I->ID];
-
- /* We dont upgrade packages marked for deletion or that are
- not installed or that don't have an upgrade */
- if (State.Mode == ModeDelete || I->CurrentVer == 0 ||
- (Version *)I.CurrentVer() == State.CandidateVer)
- continue;
-
- // Set the state to upgrade
- State.iFlags = 0;
- State.Mode = ModeInstall;
- State.InstallVer = State.CandidateVer;
- if (State.CandidateVer == (Version *)I.CurrentVer())
- State.Mode = ModeKeep;
-
- // Do not upgrade things that have the hold flag set.
- if (I->SelectedState == State::Hold)
- {
- State.InstallVer = I.CurrentVer();
- State.Mode = ModeKeep;
- }
- State.Update(I,*this);
- }
-
- Update();
-
- /* Initialize the touchd array. Bit 0 is the old install state bit 1
- is the touch value */
- unsigned char *Touch = new unsigned char[Head().PackageCount];
- for (unsigned int I = 0; I != Head().PackageCount; I++)
- {
- if ((PkgState[I].DepState & DepNowMin) == DepNowMin)
- Touch[I] = (1 << 0) | (1 << 1);
- else
- Touch[I] = 1 << 1;
- }
-
- // Now downgrade everything that is broken
- ResolveConflicts(Touch);
- delete [] Touch;
-}
- /*}}}*/
-#endif
-
// StateCache::Update - Compute the various static display things /*{{{*/
// ---------------------------------------------------------------------
/* This is called whenever the Candidate version changes. */