##################################################################### */
/*}}}*/
// Include Files /*{{{*/
+#include<config.h>
+
#include <apt-pkg/orderlist.h>
#include <apt-pkg/depcache.h>
#include <apt-pkg/error.h>
// OrderList::pkgOrderList - Constructor /*{{{*/
// ---------------------------------------------------------------------
/* */
-pkgOrderList::pkgOrderList(pkgDepCache *pCache) : Cache(*pCache)
+pkgOrderList::pkgOrderList(pkgDepCache *pCache) : Cache(*pCache),
+ Primary(NULL), Secondary(NULL),
+ RevDepends(NULL), Remove(NULL),
+ AfterEnd(NULL), FileList(NULL),
+ LoopCount(-1), Depth(0)
{
- FileList = 0;
- Primary = 0;
- Secondary = 0;
- RevDepends = 0;
- Remove = 0;
- LoopCount = -1;
Debug = _config->FindB("Debug::pkgOrderList",false);
-
+
/* Construct the arrays, egcs 1.0.1 bug requires the package count
hack */
unsigned long Size = Cache.Head().PackageCount;
Depth = 0;
WipeFlags(Added | AddPending | Loop | InList);
- for (iterator I = List; I != End; I++)
+ for (iterator I = List; I != End; ++I)
Flag(*I,InList);
// Rebuild the main list into the temp list.
iterator OldEnd = End;
End = NList;
- for (iterator I = List; I != OldEnd; I++)
- if (VisitNode(PkgIterator(Cache,*I)) == false)
+ for (iterator I = List; I != OldEnd; ++I)
+ if (VisitNode(PkgIterator(Cache,*I), "DoRun") == false)
{
End = OldEnd;
return false;
{
clog << "** Critical Unpack ordering done" << endl;
- for (iterator I = List; I != End; I++)
+ for (iterator I = List; I != End; ++I)
{
PkgIterator P(Cache,*I);
if (IsNow(P) == true)
WipeFlags(After);
// Set the inlist flag
- for (iterator I = List; I != End; I++)
+ for (iterator I = List; I != End; ++I)
{
PkgIterator P(Cache,*I);
if (IsMissing(P) == true && IsNow(P) == true)
{
clog << "** Unpack ordering done" << endl;
- for (iterator I = List; I != End; I++)
+ for (iterator I = List; I != End; ++I)
{
PkgIterator P(Cache,*I);
if (IsNow(P) == true)
/* Higher scores order earlier */
int pkgOrderList::Score(PkgIterator Pkg)
{
- static int const ScoreDelete = _config->FindI("OrderList::Score::Delete", 500);
-
- // Removal is always done first
+ // Removals should be done after we dealt with essentials
+ static int const ScoreDelete = _config->FindI("OrderList::Score::Delete", 100);
if (Cache[Pkg].Delete() == true)
return ScoreDelete;
Score += ScoreImmediate;
for (DepIterator D = Cache[Pkg].InstVerIter(Cache).DependsList();
- D.end() == false; D++)
+ D.end() == false; ++D)
if (D->Type == pkgCache::Dep::PreDepends)
{
Score += ScorePreDepends;
}
// Important Required Standard Optional Extra
- signed short PrioMap[] = {0,5,4,3,1,0};
if (Cache[Pkg].InstVerIter(Cache)->Priority <= 5)
+ {
+ signed short PrioMap[] = {0,5,4,3,1,0};
Score += PrioMap[Cache[Pkg].InstVerIter(Cache)->Priority];
+ }
return Score;
}
/*}}}*/
return true;
bool Res = true;
- for (PrvIterator P = Ver.ProvidesList(); P.end() == false; P++)
+ for (PrvIterator P = Ver.ProvidesList(); P.end() == false; ++P)
Res &= (this->*F)(P.ParentPkg().RevDependsList());
return Res;
}
/*}}}*/
// OrderList::VisitProvides - Visit all of the providing packages /*{{{*/
// ---------------------------------------------------------------------
-/* This routine calls visit on all providing packages. */
+/* This routine calls visit on all providing packages.
+
+ If the dependency is negative it first visits packages which are
+ intended to be removed and after that all other packages.
+ It does so to avoid situations in which this package is used to
+ satisfy a (or-group/provides) dependency of another package which
+ could have been satisfied also by upgrading another package -
+ otherwise we have more broken packages dpkg needs to auto-
+ deconfigure and in very complicated situations it even decides
+ against it! */
bool pkgOrderList::VisitProvides(DepIterator D,bool Critical)
-{
+{
SPtrArray<Version *> List = D.AllTargets();
- for (Version **I = List; *I != 0; I++)
+ for (Version **I = List; *I != 0; ++I)
{
VerIterator Ver(Cache,*I);
PkgIterator Pkg = Ver.ParentPkg();
+ if (D.IsNegative() == true && Cache[Pkg].Delete() == false)
+ continue;
+
if (Cache[Pkg].Keep() == true && Pkg.State() == PkgIterator::NeedsNothing)
continue;
-
+
if (D.IsNegative() == false &&
Cache[Pkg].InstallVer != *I)
continue;
-
+
if (D.IsNegative() == true &&
(Version *)Pkg.CurrentVer() != *I)
continue;
-
+
// Skip over missing files
if (Critical == false && IsMissing(D.ParentPkg()) == true)
continue;
- if (VisitNode(Pkg) == false)
+ if (VisitNode(Pkg, "Provides-1") == false)
return false;
}
+ if (D.IsNegative() == false)
+ return true;
+ for (Version **I = List; *I != 0; ++I)
+ {
+ VerIterator Ver(Cache,*I);
+ PkgIterator Pkg = Ver.ParentPkg();
+
+ if (Cache[Pkg].Delete() == true)
+ continue;
+
+ if (Cache[Pkg].Keep() == true && Pkg.State() == PkgIterator::NeedsNothing)
+ continue;
+
+ if ((Version *)Pkg.CurrentVer() != *I)
+ continue;
+
+ // Skip over missing files
+ if (Critical == false && IsMissing(D.ParentPkg()) == true)
+ continue;
+
+ if (VisitNode(Pkg, "Provides-2") == false)
+ return false;
+ }
+
return true;
}
/*}}}*/
/* This is the core ordering routine. It calls the set dependency
consideration functions which then potentialy call this again. Finite
depth is achived through the colouring mechinism. */
-bool pkgOrderList::VisitNode(PkgIterator Pkg)
+bool pkgOrderList::VisitNode(PkgIterator Pkg, char const* from)
{
// Looping or irrelevent.
// This should probably trancend not installed packages
if (Debug == true)
{
for (int j = 0; j != Depth; j++) clog << ' ';
- clog << "Visit " << Pkg.FullName() << endl;
+ clog << "Visit " << Pkg.FullName() << " from " << from << endl;
}
Depth++;
Loops are preprocessed and logged. */
bool pkgOrderList::DepUnPackCrit(DepIterator D)
{
- for (; D.end() == false; D++)
+ for (; D.end() == false; ++D)
{
if (D.Reverse() == true)
{
if (CheckDep(D) == true)
continue;
- if (VisitNode(D.ParentPkg()) == false)
+ if (VisitNode(D.ParentPkg(), "UnPackCrit") == false)
return false;
}
else
if (D.Reverse() == true)
return DepUnPackCrit(D);
- for (; D.end() == false; D++)
+ for (; D.end() == false; ++D)
{
if (D.IsCritical() == false)
continue;
if (D.Reverse() == true)
return true;
- for (; D.end() == false; D++)
+ for (; D.end() == false; ++D)
{
/* Only consider the PreDepends or Depends. Depends are only
considered at the lowest depth or in the case of immediate
bool pkgOrderList::DepUnPackDep(DepIterator D)
{
- for (; D.end() == false; D++)
+ for (; D.end() == false; ++D)
if (D.IsCritical() == true)
{
if (D.Reverse() == true)
if (IsMissing(D.ParentPkg()) == true)
continue;
- if (VisitNode(D.ParentPkg()) == false)
+ if (VisitNode(D.ParentPkg(), "UnPackDep-Parent") == false)
return false;
}
else
if (CheckDep(D) == true)
continue;
- if (VisitNode(D.TargetPkg()) == false)
+ if (VisitNode(D.TargetPkg(), "UnPackDep-Target") == false)
return false;
}
}
if (D.Reverse() == true)
return true;
- for (; D.end() == false; D++)
+ for (; D.end() == false; ++D)
if (D->Type == pkgCache::Dep::Depends)
if (VisitProvides(D,false) == false)
return false;
/*}}}*/
// OrderList::DepRemove - Removal ordering /*{{{*/
// ---------------------------------------------------------------------
-/* Removal visits all reverse depends. It considers if the dependency
- of the Now state version to see if it is okay with removing this
- package. This check should always fail, but is provided for symetery
- with the other critical handlers.
-
- Loops are preprocessed and logged. Removal loops can also be
- detected in the critical handler. They are characterized by an
- old version of A depending on B but the new version of A conflicting
- with B, thus either A or B must break to install. */
-bool pkgOrderList::DepRemove(DepIterator D)
+/* Checks all given dependencies if they are broken by the remove of a
+ package and if so fix it by visiting another provider or or-group
+ member to ensure that the dependee keeps working which is especially
+ important for Immediate packages like e.g. those depending on an
+ awk implementation. If the dependency can't be fixed with another
+ package this means an upgrade of the package will solve the problem. */
+bool pkgOrderList::DepRemove(DepIterator Broken)
{
- if (D.Reverse() == false)
+ if (Broken.Reverse() == false)
return true;
- for (; D.end() == false; D++)
- if (D->Type == pkgCache::Dep::Depends || D->Type == pkgCache::Dep::PreDepends)
+
+ for (; Broken.end() == false; ++Broken)
+ {
+ if (Broken->Type != pkgCache::Dep::Depends &&
+ Broken->Type != pkgCache::Dep::PreDepends)
+ continue;
+
+ PkgIterator BrokenPkg = Broken.ParentPkg();
+ // uninstalled packages can't break via a remove
+ if (BrokenPkg->CurrentVer == 0)
+ continue;
+
+ // if its already added, we can't do anything useful
+ if (IsFlag(BrokenPkg, AddPending) == true || IsFlag(BrokenPkg, Added) == true)
+ continue;
+
+ // if the dependee is going to be removed, visit it now
+ if (Cache[BrokenPkg].Delete() == true)
+ return VisitNode(BrokenPkg, "Remove-Dependee");
+
+ // The package stays around, so find out how this is possible
+ for (DepIterator D = BrokenPkg.CurrentVer().DependsList(); D.end() == false;)
{
- // Duplication elimination, consider the current version only
- if (D.ParentPkg().CurrentVer() != D.ParentVer())
+ // only important or-groups need fixing
+ if (D->Type != pkgCache::Dep::Depends &&
+ D->Type != pkgCache::Dep::PreDepends)
+ {
+ ++D;
continue;
+ }
- /* We wish to see if the dep on the parent package is okay
- in the removed (install) state of the target pkg. */
- bool tryFixDeps = false;
- if (CheckDep(D) == true)
+ // Start is the beginning of the or-group, D is the first one after or
+ DepIterator Start = D;
+ bool foundBroken = false;
+ for (bool LastOR = true; D.end() == false && LastOR == true; ++D)
{
- // We want to catch loops with the code below.
- if (IsFlag(D.ParentPkg(),AddPending) == false)
- continue;
+ LastOR = (D->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or;
+ if (D == Broken)
+ foundBroken = true;
}
- else
- tryFixDeps = true;
- // This is the loop detection
- if (IsFlag(D.ParentPkg(),Added) == true ||
- IsFlag(D.ParentPkg(),AddPending) == true)
- {
- if (IsFlag(D.ParentPkg(),AddPending) == true)
- AddLoop(D);
+ // this or-group isn't the broken one: keep searching
+ if (foundBroken == false)
continue;
+
+ // iterate over all members of the or-group searching for a ready replacement
+ bool readyReplacement = false;
+ for (DepIterator OrMember = Start; OrMember != D && readyReplacement == false; ++OrMember)
+ {
+ Version ** Replacements = OrMember.AllTargets();
+ for (Version **R = Replacements; *R != 0; ++R)
+ {
+ VerIterator Ver(Cache,*R);
+ // only currently installed packages can be a replacement
+ PkgIterator RPkg = Ver.ParentPkg();
+ if (RPkg.CurrentVer() != Ver)
+ continue;
+
+ // packages going to be removed can't be a replacement
+ if (Cache[RPkg].Delete() == true)
+ continue;
+
+ readyReplacement = true;
+ break;
+ }
+ delete[] Replacements;
}
- if (tryFixDeps == true)
+ // something else is ready to take over, do nothing
+ if (readyReplacement == true)
+ continue;
+
+ // see if we can visit a replacement
+ bool visitReplacement = false;
+ for (DepIterator OrMember = Start; OrMember != D && visitReplacement == false; ++OrMember)
{
- for (pkgCache::DepIterator F = D.ParentPkg().CurrentVer().DependsList();
- F.end() == false; ++F)
+ Version ** Replacements = OrMember.AllTargets();
+ for (Version **R = Replacements; *R != 0; ++R)
{
- if (F->Type != pkgCache::Dep::Depends && F->Type != pkgCache::Dep::PreDepends)
+ VerIterator Ver(Cache,*R);
+ // consider only versions we plan to install
+ PkgIterator RPkg = Ver.ParentPkg();
+ if (Cache[RPkg].Install() == false || Cache[RPkg].InstallVer != Ver)
continue;
- // Check the Providers
- if (F.TargetPkg()->ProvidesList != 0)
- {
- pkgCache::PrvIterator Prov = F.TargetPkg().ProvidesList();
- for (; Prov.end() == false; ++Prov)
- {
- pkgCache::PkgIterator const P = Prov.OwnerPkg();
- if (IsFlag(P, InList) == true &&
- IsFlag(P, AddPending) == true &&
- IsFlag(P, Added) == false &&
- Cache[P].InstallVer == 0)
- break;
- }
- if (Prov.end() == false)
- for (pkgCache::PrvIterator Prv = F.TargetPkg().ProvidesList();
- Prv.end() == false; ++Prv)
- {
- pkgCache::PkgIterator const P = Prv.OwnerPkg();
- if (IsFlag(P, InList) == true &&
- IsFlag(P, AddPending) == false &&
- Cache[P].InstallVer != 0 &&
- VisitNode(P) == true)
- {
- Flag(P, Immediate);
- tryFixDeps = false;
- break;
- }
- }
- if (tryFixDeps == false)
- break;
- }
- // Check for Or groups
- if ((F->CompareOp & pkgCache::Dep::Or) != pkgCache::Dep::Or)
+ // loops are not going to help us, so don't create them
+ if (IsFlag(RPkg, AddPending) == true)
continue;
- // Lets see if the package is part of the Or group
- pkgCache::DepIterator S = F;
- for (; S.end() == false; ++S)
+
+ if (IsMissing(RPkg) == true)
+ continue;
+
+ visitReplacement = true;
+ if (IsFlag(BrokenPkg, Immediate) == false)
{
- if (S.TargetPkg() == D.TargetPkg())
+ if (VisitNode(RPkg, "Remove-Rep") == true)
break;
- if ((S->CompareOp & pkgCache::Dep::Or) != pkgCache::Dep::Or ||
- CheckDep(S)) // Or group is satisfied by another package
- for (;S.end() == false; ++S);
}
- if (S.end() == true)
- continue;
- // skip to the end of the or group
- for (;S.end() == false && (S->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or; ++S);
- ++S;
- // The soon to be removed is part of the Or group
- // start again in the or group and find something which will serve as replacement
- for (; F.end() == false && F != S; ++F)
+ else
{
- if (IsFlag(F.TargetPkg(), InList) == true &&
- IsFlag(F.TargetPkg(), AddPending) == false &&
- Cache[F.TargetPkg()].InstallVer != 0 &&
- VisitNode(F.TargetPkg()) == true)
- {
- Flag(F.TargetPkg(), Immediate);
- tryFixDeps = false;
+ Flag(RPkg, Immediate);
+ if (VisitNode(RPkg, "Remove-ImmRep") == true)
break;
- }
- else if (F.TargetPkg()->ProvidesList != 0)
- {
- pkgCache::PrvIterator Prv = F.TargetPkg().ProvidesList();
- for (; Prv.end() == false; ++Prv)
- {
- if (IsFlag(Prv.OwnerPkg(), InList) == true &&
- IsFlag(Prv.OwnerPkg(), AddPending) == false &&
- Cache[Prv.OwnerPkg()].InstallVer != 0 &&
- VisitNode(Prv.OwnerPkg()) == true)
- {
- Flag(Prv.OwnerPkg(), Immediate);
- tryFixDeps = false;
- break;
- }
- }
- if (Prv.end() == false)
- break;
- }
}
- if (tryFixDeps == false)
- break;
+ visitReplacement = false;
}
+ delete[] Replacements;
}
-
- // Skip over missing files
- if (IsMissing(D.ParentPkg()) == true)
+ if (visitReplacement == true)
continue;
-
- if (VisitNode(D.ParentPkg()) == false)
+
+ // the broken package in current version can't be fixed, so install new version
+ if (IsMissing(BrokenPkg) == true)
+ break;
+
+ if (VisitNode(BrokenPkg, "Remove-Upgrade") == false)
return false;
}
-
+ }
+
return true;
}
/*}}}*/
// Mark the packages as being part of a loop.
//Flag(D.TargetPkg(),Loop);
//Flag(D.ParentPkg(),Loop);
+ /* This is currently disabled because the Loop flag is being used for
+ loop management in the package manager. Check the orderlist.h file for more info */
return true;
}
/*}}}*/