ordering.
Each of the features can be enabled in the sorting routine at an
- arbitary priority to give quite abit of control over the final unpacking
+ arbitrary priority to give quite abit of control over the final unpacking
order.
The rules listed above may never be violated and are called Critical.
return false;
// Skip Packages that need configure only.
- if (Pkg.State() == pkgCache::PkgIterator::NeedsConfigure &&
+ if ((Pkg.State() == pkgCache::PkgIterator::NeedsConfigure ||
+ Pkg.State() == pkgCache::PkgIterator::NeedsNothing) &&
Cache[Pkg].Keep() == true)
return false;
if (FileList[Pkg->ID].empty() == false)
return false;
+
return true;
}
/*}}}*/
-
// OrderList::DoRun - Does an order run /*{{{*/
// ---------------------------------------------------------------------
/* The caller is expeted to have setup the desired probe state */
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;
bool pkgOrderList::OrderCritical()
{
FileList = 0;
-
- Primary = &pkgOrderList::DepUnPackPre;
+
+ Primary = &pkgOrderList::DepUnPackPreD;
Secondary = 0;
RevDepends = 0;
Remove = 0;
LoopCount = 0;
-
+
// Sort
Me = this;
- qsort(List,End - List,sizeof(*List),&OrderCompareB);
-
+ qsort(List,End - List,sizeof(*List),&OrderCompareB);
+
if (DoRun() == false)
return false;
-
+
if (LoopCount != 0)
return _error->Error("Fatal, predepends looping detected");
+
+ if (Debug == true)
+ {
+ clog << "** Critical Unpack ordering done" << endl;
+
+ for (iterator I = List; I != End; ++I)
+ {
+ PkgIterator P(Cache,*I);
+ if (IsNow(P) == true)
+ clog << " " << P.FullName() << ' ' << IsMissing(P) << ',' << IsFlag(P,After) << endl;
+ }
+ }
+
return true;
}
/*}}}*/
if (FileList != 0)
{
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)
Flag(*I,After);
}
}
-
+
Primary = &pkgOrderList::DepUnPackCrit;
Secondary = &pkgOrderList::DepConfigure;
RevDepends = &pkgOrderList::DepUnPackDep;
clog << "** Pass A" << endl;
if (DoRun() == false)
return false;
-
+
if (Debug == true)
clog << "** Pass B" << endl;
Secondary = 0;
Remove = 0; // Otherwise the libreadline remove problem occures
if (DoRun() == false)
return false;
-
+
if (Debug == true)
clog << "** Pass D" << endl;
LoopCount = 0;
{
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)
- clog << P.Name() << ' ' << IsMissing(P) << ',' << IsFlag(P,After) << endl;
+ clog << " " << P.FullName() << ' ' << IsMissing(P) << ',' << IsFlag(P,After) << endl;
}
- }
+ }
return true;
}
return DoRun();
}
/*}}}*/
-
// OrderList::Score - Score the package for sorting /*{{{*/
// ---------------------------------------------------------------------
/* Higher scores order earlier */
int pkgOrderList::Score(PkgIterator Pkg)
{
+ static int const ScoreDelete = _config->FindI("OrderList::Score::Delete", 500);
+
// Removal is always done first
if (Cache[Pkg].Delete() == true)
- return 200;
-
+ return ScoreDelete;
+
// This should never happen..
if (Cache[Pkg].InstVerIter(Cache).end() == true)
return -1;
-
+
+ static int const ScoreEssential = _config->FindI("OrderList::Score::Essential", 200);
+ static int const ScoreImmediate = _config->FindI("OrderList::Score::Immediate", 10);
+ static int const ScorePreDepends = _config->FindI("OrderList::Score::PreDepends", 50);
+
int Score = 0;
if ((Pkg->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
- Score += 100;
+ Score += ScoreEssential;
if (IsFlag(Pkg,Immediate) == true)
- Score += 10;
-
- for (DepIterator D = Cache[Pkg].InstVerIter(Cache).DependsList();
- D.end() == false; D++)
+ Score += ScoreImmediate;
+
+ for (DepIterator D = Cache[Pkg].InstVerIter(Cache).DependsList();
+ D.end() == false; ++D)
if (D->Type == pkgCache::Dep::PreDepends)
{
- Score += 50;
+ Score += ScorePreDepends;
break;
}
-
+
// Important Required Standard Optional Extra
signed short PrioMap[] = {0,5,4,3,1,0};
if (Cache[Pkg].InstVerIter(Cache)->Priority <= 5)
int ScoreA = Me->Score(A);
int ScoreB = Me->Score(B);
+
if (ScoreA > ScoreB)
return -1;
int ScoreA = Me->Score(A);
int ScoreB = Me->Score(B);
+
if (ScoreA > ScoreB)
return -1;
return strcmp(A.Name(),B.Name());
}
/*}}}*/
-
// OrderList::VisitDeps - Visit forward install dependencies /*{{{*/
// ---------------------------------------------------------------------
/* This calls the dependency function for the normal forwards dependencies
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 true;
+ 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->Type != pkgCache::Dep::Conflicts &&
- D->Type != pkgCache::Dep::DpkgBreaks &&
- D->Type != pkgCache::Dep::Obsoletes &&
+
+ if (D.IsNegative() == false &&
Cache[Pkg].InstallVer != *I)
continue;
-
- if ((D->Type == pkgCache::Dep::Conflicts ||
- D->Type == pkgCache::Dep::DpkgBreaks ||
- D->Type == pkgCache::Dep::Obsoletes) &&
+
+ if (D.IsNegative() == true &&
(Version *)Pkg.CurrentVer() != *I)
continue;
-
+
+ // Skip over missing files
+ if (Critical == false && IsMissing(D.ParentPkg()) == true)
+ continue;
+
+ 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) == false)
+ 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.Name() << endl;
+ clog << "Visit " << Pkg.FullName() << " from " << from << endl;
}
Depth++;
if (Debug == true)
{
for (int j = 0; j != Depth; j++) clog << ' ';
- clog << "Leave " << Pkg.Name() << ' ' << IsFlag(Pkg,Added) << ',' << IsFlag(Pkg,AddPending) << endl;
+ clog << "Leave " << Pkg.FullName() << ' ' << IsFlag(Pkg,Added) << ',' << IsFlag(Pkg,AddPending) << endl;
}
return true;
}
/*}}}*/
-
// OrderList::DepUnPackCrit - Critical UnPacking ordering /*{{{*/
// ---------------------------------------------------------------------
/* Critical unpacking ordering strives to satisfy Conflicts: and
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
{
/* Forward critical dependencies MUST be correct before the
package can be unpacked. */
- if (D->Type != pkgCache::Dep::Conflicts &&
- D->Type != pkgCache::Dep::DpkgBreaks &&
- D->Type != pkgCache::Dep::Obsoletes &&
+ if (D.IsNegative() == false &&
D->Type != pkgCache::Dep::PreDepends)
continue;
}
return true;
}
-
+ /*}}}*/
// OrderList::DepUnPackPreD - Critical UnPacking ordering with depends /*{{{*/
// ---------------------------------------------------------------------
/* Critical PreDepends (also configure immediate and essential) strives to
ensure not only that all conflicts+predepends are met but that this
- package will be immediately configurable when it is unpacked.
-
+ package will be immediately configurable when it is unpacked.
Loops are preprocessed and logged. */
bool pkgOrderList::DepUnPackPreD(DepIterator D)
{
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;
{
if (D.Reverse() == false)
return true;
- for (; D.end() == false; D++)
+ for (; D.end() == false; ++D)
if (D->Type == pkgCache::Dep::Depends || D->Type == pkgCache::Dep::PreDepends)
{
// Duplication elimination, consider the current version only
continue;
/* We wish to see if the dep on the parent package is okay
- in the removed (install) state of the target pkg. */
+ in the removed (install) state of the target pkg. */
+ bool tryFixDeps = false;
if (CheckDep(D) == true)
{
// We want to catch loops with the code below.
if (IsFlag(D.ParentPkg(),AddPending) == false)
continue;
}
+ else
+ tryFixDeps = true;
// This is the loop detection
if (IsFlag(D.ParentPkg(),Added) == true ||
continue;
}
+ if (tryFixDeps == true)
+ {
+ for (pkgCache::DepIterator F = D.ParentPkg().CurrentVer().DependsList();
+ F.end() == false; ++F)
+ {
+ if (F->Type != pkgCache::Dep::Depends && F->Type != pkgCache::Dep::PreDepends)
+ 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, "Remove-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)
+ continue;
+ // Lets see if the package is part of the Or group
+ pkgCache::DepIterator S = F;
+ for (; S.end() == false; ++S)
+ {
+ if (S.TargetPkg() == D.TargetPkg())
+ 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)
+ {
+ if (IsFlag(F.TargetPkg(), InList) == true &&
+ IsFlag(F.TargetPkg(), AddPending) == false &&
+ Cache[F.TargetPkg()].InstallVer != 0 &&
+ VisitNode(F.TargetPkg(), "Remove-Target") == true)
+ {
+ Flag(F.TargetPkg(), Immediate);
+ tryFixDeps = false;
+ 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(), "Remove-Owner") == true)
+ {
+ Flag(Prv.OwnerPkg(), Immediate);
+ tryFixDeps = false;
+ break;
+ }
+ }
+ if (Prv.end() == false)
+ break;
+ }
+ }
+ if (tryFixDeps == false)
+ break;
+ }
+ }
+
// Skip over missing files
if (IsMissing(D.ParentPkg()) == true)
continue;
- if (VisitNode(D.ParentPkg()) == false)
+ if (VisitNode(D.ParentPkg(), "Remove-Parent") == false)
return false;
}
return true;
}
/*}}}*/
-
// OrderList::AddLoop - Add a loop to the loop list /*{{{*/
// ---------------------------------------------------------------------
/* We record the loops. This is a relic since loop breaking is done
/* Conflicts requires that all versions are not present, depends
just needs one */
- if (D->Type != pkgCache::Dep::Conflicts &&
- D->Type != pkgCache::Dep::DpkgBreaks &&
- D->Type != pkgCache::Dep::Obsoletes)
+ if (D.IsNegative() == false)
{
+ // ignore provides by older versions of this package
+ if (((D.Reverse() == false && Pkg == D.ParentPkg()) ||
+ (D.Reverse() == true && Pkg == D.TargetPkg())) &&
+ Cache[Pkg].InstallVer != *I)
+ continue;
+
/* Try to find something that does not have the after flag set
if at all possible */
if (IsFlag(Pkg,After) == true)