// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: algorithms.cc,v 1.36 2001/05/27 03:46:10 jgg Exp $
+// $Id: algorithms.cc,v 1.44 2002/11/28 18:49:16 jgg Exp $
/* ######################################################################
Algorithms - A set of misc algorithms
##################################################################### */
/*}}}*/
// Include Files /*{{{*/
-#ifdef __GNUG__
-#pragma implementation "apt-pkg/algorithms.h"
-#endif
#include <apt-pkg/algorithms.h>
#include <apt-pkg/error.h>
#include <apt-pkg/configuration.h>
+#include <apt-pkg/version.h>
#include <apt-pkg/sptr.h>
+#include <apt-pkg/acquire-item.h>
#include <apti18n.h>
-
-#include <iostream.h>
+#include <sys/types.h>
+#include <cstdlib>
+#include <algorithm>
+#include <iostream>
/*}}}*/
+using namespace std;
pkgProblemResolver *pkgProblemResolver::This = 0;
this is not necessary since the pkgCaches are fully shared now. */
pkgSimulate::pkgSimulate(pkgDepCache *Cache) : pkgPackageManager(Cache),
iPolicy(Cache),
- Sim(&Cache->GetCache(),&iPolicy)
+ Sim(&Cache->GetCache(),&iPolicy),
+ group(Sim)
{
Sim.Init(0);
Flags = new unsigned char[Cache->Head().PackageCount];
/*}}}*/
// Simulate::Describe - Describe a package /*{{{*/
// ---------------------------------------------------------------------
-/* */
-void pkgSimulate::Describe(PkgIterator Pkg,ostream &out,bool Now)
+/* Parameter Current == true displays the current package version,
+ Parameter Candidate == true displays the candidate package version */
+void pkgSimulate::Describe(PkgIterator Pkg,ostream &out,bool Current,bool Candidate)
{
VerIterator Ver(Sim);
- if (Now == true)
+
+ out << Pkg.Name();
+
+ if (Current == true)
+ {
Ver = Pkg.CurrentVer();
- else
- Ver = Sim[Pkg].CandidateVerIter(Sim);
+ if (Ver.end() == false)
+ out << " [" << Ver.VerStr() << ']';
+ }
- out << Pkg.Name();
-
- if (Ver.end() == true)
- return;
+ if (Candidate == true)
+ {
+ Ver = Sim[Pkg].CandidateVerIter(Sim);
+ if (Ver.end() == true)
+ return;
- out << " (" << Ver.VerStr() << ' ' << Ver.RelStr() << ')';
+ out << " (" << Ver.VerStr() << ' ' << Ver.RelStr() << ')';
+ }
}
/*}}}*/
// Simulate::Install - Simulate unpacking of a package /*{{{*/
bool pkgSimulate::Install(PkgIterator iPkg,string /*File*/)
{
// Adapt the iterator
- PkgIterator Pkg = Sim.FindPkg(iPkg.Name());
+ PkgIterator Pkg = Sim.FindPkg(iPkg.Name(), iPkg.Arch());
Flags[Pkg->ID] = 1;
cout << "Inst ";
- Describe(Pkg,cout,false);
+ Describe(Pkg,cout,true,true);
Sim.MarkInstall(Pkg,false);
-
+
+ if (strcmp(Pkg.Arch(),"all") == 0)
+ {
+ pkgCache::GrpIterator G = Pkg.Group();
+ pkgCache::GrpIterator iG = iPkg.Group();
+ for (pkgCache::PkgIterator P = G.FindPkg("any"); P.end() != true; P = G.NextPkg(P))
+ {
+ if (strcmp(P.Arch(), "all") == 0)
+ continue;
+ if (iG.FindPkg(P.Arch())->CurrentVer == 0)
+ continue;
+ Flags[P->ID] = 1;
+ Sim.MarkInstall(P, false);
+ }
+ }
+
// Look for broken conflicts+predepends.
for (PkgIterator I = Sim.PkgBegin(); I.end() == false; I++)
{
DepIterator End;
D.GlobOr(Start,End);
if (Start->Type == pkgCache::Dep::Conflicts ||
+ Start->Type == pkgCache::Dep::DpkgBreaks ||
Start->Type == pkgCache::Dep::Obsoletes ||
End->Type == pkgCache::Dep::PreDepends)
{
bool pkgSimulate::Configure(PkgIterator iPkg)
{
// Adapt the iterator
- PkgIterator Pkg = Sim.FindPkg(iPkg.Name());
+ PkgIterator Pkg = Sim.FindPkg(iPkg.Name(), iPkg.Arch());
Flags[Pkg->ID] = 2;
+
+ if (strcmp(Pkg.Arch(),"all") == 0)
+ {
+ pkgCache::GrpIterator G = Pkg.Group();
+ for (pkgCache::PkgIterator P = G.FindPkg("any"); P.end() != true; P = G.NextPkg(P))
+ {
+ if (strcmp(P.Arch(), "all") == 0)
+ continue;
+ if (Flags[P->ID] == 1)
+ Flags[P->ID] = 2;
+ }
+ }
+
// Sim.MarkInstall(Pkg,false);
if (Sim[Pkg].InstBroken() == true)
{
cout << " Obsoletes:" << D.TargetPkg().Name();
else if (D->Type == pkgCache::Dep::Conflicts)
cout << " Conflicts:" << D.TargetPkg().Name();
+ else if (D->Type == pkgCache::Dep::DpkgBreaks)
+ cout << " Breaks:" << D.TargetPkg().Name();
else
cout << " Depends:" << D.TargetPkg().Name();
}
else
{
cout << "Conf ";
- Describe(Pkg,cout,false);
+ Describe(Pkg,cout,false,true);
}
if (Sim.BrokenCount() != 0)
bool pkgSimulate::Remove(PkgIterator iPkg,bool Purge)
{
// Adapt the iterator
- PkgIterator Pkg = Sim.FindPkg(iPkg.Name());
+ PkgIterator Pkg = Sim.FindPkg(iPkg.Name(), iPkg.Arch());
Flags[Pkg->ID] = 3;
Sim.MarkDelete(Pkg);
+
+ if (strcmp(Pkg.Arch(),"all") == 0)
+ {
+ pkgCache::GrpIterator G = Pkg.Group();
+ pkgCache::GrpIterator iG = iPkg.Group();
+ for (pkgCache::PkgIterator P = G.FindPkg("any"); P.end() != true; P = G.NextPkg(P))
+ {
+ if (strcmp(P.Arch(), "all") == 0)
+ continue;
+ if (iG.FindPkg(P.Arch())->CurrentVer == 0)
+ continue;
+ Flags[P->ID] = 3;
+ Sim.MarkDelete(P);
+ }
+ }
+
if (Purge == true)
cout << "Purg ";
else
cout << "Remv ";
- Describe(Pkg,cout,false);
+ Describe(Pkg,cout,true,false);
if (Sim.BrokenCount() != 0)
ShortBreaks();
the necessary calculations to deal with the problems. */
bool pkgApplyStatus(pkgDepCache &Cache)
{
+ pkgDepCache::ActionGroup group(Cache);
+
for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
{
if (I->VersionList == 0)
I->InstState == pkgCache::State::HoldReInstReq)
{
if (I->CurrentVer != 0 && I.CurrentVer().Downloadable() == true)
- Cache.MarkKeep(I);
+ Cache.MarkKeep(I, false, false);
else
{
// Is this right? Will dpkg choke on an upgrade?
- if (Cache[I].CandidateVerIter(Cache).Downloadable() == true)
- Cache.MarkInstall(I);
+ if (Cache[I].CandidateVer != 0 &&
+ Cache[I].CandidateVerIter(Cache).Downloadable() == true)
+ Cache.MarkInstall(I, false, 0, false);
else
return _error->Error(_("The package %s needs to be reinstalled, "
"but I can't find an archive for it."),I.Name());
re-unpacked (probably) */
case pkgCache::State::UnPacked:
case pkgCache::State::HalfConfigured:
+ case pkgCache::State::TriggersAwaited:
+ case pkgCache::State::TriggersPending:
if ((I->CurrentVer != 0 && I.CurrentVer().Downloadable() == true) ||
I.State() != pkgCache::PkgIterator::NeedsUnpack)
- Cache.MarkKeep(I);
+ Cache.MarkKeep(I, false, false);
else
{
- if (Cache[I].CandidateVerIter(Cache).Downloadable() == true)
- Cache.MarkInstall(I);
+ if (Cache[I].CandidateVer != 0 &&
+ Cache[I].CandidateVerIter(Cache).Downloadable() == true)
+ Cache.MarkInstall(I, true, 0, false);
else
Cache.MarkDelete(I);
}
on the result. */
bool pkgFixBroken(pkgDepCache &Cache)
{
+ pkgDepCache::ActionGroup group(Cache);
+
// Auto upgrade all broken packages
for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
if (Cache[I].NowBroken() == true)
- Cache.MarkInstall(I,true);
+ Cache.MarkInstall(I, true, 0, false);
/* Fix packages that are in a NeedArchive state but don't have a
downloadable install version */
if (Cache[I].InstVerIter(Cache).Downloadable() == false)
continue;
- Cache.MarkInstall(I,true);
+ Cache.MarkInstall(I, true, 0, false);
}
pkgProblemResolver Fix(&Cache);
*/
bool pkgDistUpgrade(pkgDepCache &Cache)
{
+ pkgDepCache::ActionGroup group(Cache);
+
/* Auto upgrade all installed packages, this provides the basis
for the installation */
for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
if (I->CurrentVer != 0)
- Cache.MarkInstall(I,true);
+ Cache.MarkInstall(I, true, 0, false);
/* Now, auto upgrade all essential packages - this ensures that
the essential packages are present and working */
for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
if ((I->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
- Cache.MarkInstall(I,true);
+ Cache.MarkInstall(I, true, 0, false);
/* We do it again over all previously installed packages to force
conflict resolution on them all. */
for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
if (I->CurrentVer != 0)
- Cache.MarkInstall(I,false);
+ Cache.MarkInstall(I, false, 0, false);
pkgProblemResolver Fix(&Cache);
if (I->SelectedState == pkgCache::State::Hold)
{
Fix.Protect(I);
- Cache.MarkKeep(I);
+ Cache.MarkKeep(I, false, false);
}
}
}
to install packages not marked for install */
bool pkgAllUpgrade(pkgDepCache &Cache)
{
+ pkgDepCache::ActionGroup group(Cache);
+
pkgProblemResolver Fix(&Cache);
if (Cache.BrokenCount() != 0)
continue;
if (I->CurrentVer != 0 && Cache[I].InstallVer != 0)
- Cache.MarkInstall(I,false);
+ Cache.MarkInstall(I, false, 0, false);
}
return Fix.ResolveByKeep();
the package is restored. */
bool pkgMinimizeUpgrade(pkgDepCache &Cache)
{
+ pkgDepCache::ActionGroup group(Cache);
+
if (Cache.BrokenCount() != 0)
return false;
continue;
// Keep it and see if that is OK
- Cache.MarkKeep(I);
+ Cache.MarkKeep(I, false, false);
if (Cache.BrokenCount() != 0)
- Cache.MarkInstall(I,false);
+ Cache.MarkInstall(I, false, 0, false);
else
{
// If keep didnt actually do anything then there was no change..
return true;
}
/*}}}*/
-
// ProblemResolver::pkgProblemResolver - Constructor /*{{{*/
// ---------------------------------------------------------------------
/* */
unsigned long Size = Cache.Head().PackageCount;
memset(Scores,0,sizeof(*Scores)*Size);
+ // Important Required Standard Optional Extra
+ signed short PrioMap[] = {
+ 0,
+ (signed short) _config->FindI("pkgProblemResolver::Scores::Important",3),
+ (signed short) _config->FindI("pkgProblemResolver::Scores::Required",2),
+ (signed short) _config->FindI("pkgProblemResolver::Scores::Standard",1),
+ (signed short) _config->FindI("pkgProblemResolver::Scores::Optional",-1),
+ (signed short) _config->FindI("pkgProblemResolver::Scores::Extra",-2)
+ };
+ signed short PrioEssentials = _config->FindI("pkgProblemResolver::Scores::Essentials",100);
+ signed short PrioInstalledAndNotObsolete = _config->FindI("pkgProblemResolver::Scores::NotObsolete",1);
+ signed short PrioDepends = _config->FindI("pkgProblemResolver::Scores::Depends",1);
+ signed short PrioRecommends = _config->FindI("pkgProblemResolver::Scores::Recommends",1);
+ signed short AddProtected = _config->FindI("pkgProblemResolver::Scores::AddProtected",10000);
+ signed short AddEssential = _config->FindI("pkgProblemResolver::Scores::AddEssential",5000);
+
+ if (_config->FindB("Debug::pkgProblemResolver::ShowScores",false) == true)
+ clog << "Settings used to calculate pkgProblemResolver::Scores::" << endl
+ << " Important => " << PrioMap[1] << endl
+ << " Required => " << PrioMap[2] << endl
+ << " Standard => " << PrioMap[3] << endl
+ << " Optional => " << PrioMap[4] << endl
+ << " Extra => " << PrioMap[5] << endl
+ << " Essentials => " << PrioEssentials << endl
+ << " InstalledAndNotObsolete => " << PrioInstalledAndNotObsolete << endl
+ << " Depends => " << PrioDepends << endl
+ << " Recommends => " << PrioRecommends << endl
+ << " AddProtected => " << AddProtected << endl
+ << " AddEssential => " << AddEssential << endl;
+
// Generate the base scores for a package based on its properties
for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
{
signed short &Score = Scores[I->ID];
- /* This is arbitary, it should be high enough to elevate an
+ /* This is arbitrary, it should be high enough to elevate an
essantial package above most other packages but low enough
to allow an obsolete essential packages to be removed by
a conflicts on a powerfull normal package (ie libc6) */
if ((I->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
- Score += 100;
+ Score += PrioEssentials;
// We transform the priority
- // Important Required Standard Optional Extra
- signed short PrioMap[] = {0,3,2,1,-1,-2};
if (Cache[I].InstVerIter(Cache)->Priority <= 5)
Score += PrioMap[Cache[I].InstVerIter(Cache)->Priority];
/* This helps to fix oddball problems with conflicting packages
- on the same level. We enhance the score of installed packages */
- if (I->CurrentVer != 0)
- Score += 1;
+ on the same level. We enhance the score of installed packages
+ if those are not obsolete
+ */
+ if (I->CurrentVer != 0 && Cache[I].CandidateVer != 0 && Cache[I].CandidateVerIter(Cache).Downloadable())
+ Score += PrioInstalledAndNotObsolete;
}
// Now that we have the base scores we go and propogate dependencies
for (pkgCache::DepIterator D = Cache[I].InstVerIter(Cache).DependsList(); D.end() == false; D++)
{
- if (D->Type == pkgCache::Dep::Depends || D->Type == pkgCache::Dep::PreDepends)
- Scores[D.TargetPkg()->ID]++;
+ if (D->Type == pkgCache::Dep::Depends ||
+ D->Type == pkgCache::Dep::PreDepends)
+ Scores[D.TargetPkg()->ID] += PrioDepends;
+ else if (D->Type == pkgCache::Dep::Recommends)
+ Scores[D.TargetPkg()->ID] += PrioRecommends;
}
}
{
// Only do it for the install version
if ((pkgCache::Version *)D.ParentVer() != Cache[D.ParentPkg()].InstallVer ||
- (D->Type != pkgCache::Dep::Depends && D->Type != pkgCache::Dep::PreDepends))
+ (D->Type != pkgCache::Dep::Depends &&
+ D->Type != pkgCache::Dep::PreDepends &&
+ D->Type != pkgCache::Dep::Recommends))
continue;
Scores[I->ID] += abs(OldScores[D.ParentPkg()->ID]);
for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
{
if ((Flags[I->ID] & Protected) != 0)
- Scores[I->ID] += 10000;
+ Scores[I->ID] += AddProtected;
if ((I->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
- Scores[I->ID] += 5000;
- }
+ Scores[I->ID] += AddEssential;
+ }
}
/*}}}*/
// ProblemResolver::DoUpgrade - Attempt to upgrade this package /*{{{*/
installable */
bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg)
{
+ pkgDepCache::ActionGroup group(Cache);
+
if ((Flags[Pkg->ID] & Upgradable) == 0 || Cache[Pkg].Upgradable() == false)
return false;
+ if ((Flags[Pkg->ID] & Protected) == Protected)
+ return false;
Flags[Pkg->ID] &= ~Upgradable;
bool WasKept = Cache[Pkg].Keep();
- Cache.MarkInstall(Pkg,false);
+ Cache.MarkInstall(Pkg, false, 0, false);
// This must be a virtual package or something like that.
if (Cache[Pkg].InstVerIter(Cache).end() == true)
/* We let the algorithm deal with conflicts on its next iteration,
it is much smarter than us */
if (Start->Type == pkgCache::Dep::Conflicts ||
+ Start->Type == pkgCache::Dep::DpkgBreaks ||
Start->Type == pkgCache::Dep::Obsoletes)
break;
if (Fail == true)
{
if (WasKept == true)
- Cache.MarkKeep(Pkg);
+ Cache.MarkKeep(Pkg, false, false);
else
Cache.MarkDelete(Pkg);
return false;
upgrade packages to advoid problems. */
bool pkgProblemResolver::Resolve(bool BrokenFix)
{
+ pkgDepCache::ActionGroup group(Cache);
+
unsigned long Size = Cache.Head().PackageCount;
// Record which packages are marked for install
{
if (Cache[I].InstBroken() == true && BrokenFix == true)
{
- Cache.MarkInstall(I,false);
+ Cache.MarkInstall(I, false, 0, false);
if (Cache[I].Install() == true)
Again = true;
}
*PEnd++ = I;
This = this;
qsort(PList,PEnd - PList,sizeof(*PList),&ScoreSort);
-
-/* for (pkgCache::Package **K = PList; K != PEnd; K++)
- if (Scores[(*K)->ID] != 0)
- {
- pkgCache::PkgIterator Pkg(Cache,*K);
- clog << Scores[(*K)->ID] << ' ' << Pkg.Name() <<
- ' ' << (pkgCache::Version *)Pkg.CurrentVer() << ' ' <<
- Cache[Pkg].InstallVer << ' ' << Cache[Pkg].CandidateVer << endl;
- } */
+
+ if (_config->FindB("Debug::pkgProblemResolver::ShowScores",false) == true)
+ {
+ clog << "Show Scores" << endl;
+ for (pkgCache::Package **K = PList; K != PEnd; K++)
+ if (Scores[(*K)->ID] != 0)
+ {
+ pkgCache::PkgIterator Pkg(Cache,*K);
+ clog << Scores[(*K)->ID] << ' ' << Pkg << std::endl;
+ }
+ }
if (Debug == true)
clog << "Starting 2" << endl;
-
+
/* Now consider all broken packages. For each broken package we either
remove the package or fix it's problem. We do this once, it should
not be possible for a loop to form (that is a < b < c and fixing b by
pkgCache::Version *OldVer = Cache[I].InstallVer;
Flags[I->ID] &= ReInstateTried;
- Cache.MarkInstall(I,false);
+ Cache.MarkInstall(I, false, 0, false);
if (Cache[I].InstBroken() == true ||
OldBreaks < Cache.BrokenCount())
{
if (OldVer == 0)
Cache.MarkDelete(I);
else
- Cache.MarkKeep(I);
+ Cache.MarkKeep(I, false, false);
}
else
if (Debug == true)
continue;
if (Debug == true)
- cout << "Investigating " << I.Name() << endl;
+ clog << "Investigating " << I.Name() << endl;
// Isolate the problem dependency
PackageKill KillList[100];
if (Debug == true)
clog << " Or group remove for " << I.Name() << endl;
Cache.MarkDelete(I);
+ Change = true;
}
}
if (OldEnd == LEnd && OrOp == OrKeep)
{
if (Debug == true)
clog << " Or group keep for " << I.Name() << endl;
- Cache.MarkKeep(I);
+ Cache.MarkKeep(I, false, false);
+ Change = true;
}
}
D.GlobOr(Start,End);
if (Start.end() == true)
break;
-
+
// We only worry about critical deps.
if (End.IsCritical() != true)
continue;
-
+
InOr = Start != End;
OldEnd = LEnd;
- }
+ }
else
+ {
Start++;
-
+ // We only worry about critical deps.
+ if (Start.IsCritical() != true)
+ continue;
+ }
+
// Dep is ok
if ((Cache[End] & pkgDepCache::DepGInstall) == pkgDepCache::DepGInstall)
+ {
+ InOr = false;
continue;
-
+ }
+
if (Debug == true)
- clog << "Package " << I.Name() << " has broken dep on " << Start.TargetPkg().Name() << endl;
+ clog << "Package " << I.Name() << " has broken " << Start.DepType() << " on " << Start.TargetPkg().Name() << endl;
/* Look across the version list. If there are no possible
targets then we keep the package and bail. This is necessary
SPtrArray<pkgCache::Version *> VList = Start.AllTargets();
if (*VList == 0 && (Flags[I->ID] & Protected) != Protected &&
Start->Type != pkgCache::Dep::Conflicts &&
+ Start->Type != pkgCache::Dep::DpkgBreaks &&
Start->Type != pkgCache::Dep::Obsoletes &&
Cache[I].NowBroken() == false)
{
}
Change = true;
- Cache.MarkKeep(I);
+ Cache.MarkKeep(I, false, false);
break;
}
if (Scores[I->ID] <= Scores[Pkg->ID] ||
((Cache[Start] & pkgDepCache::DepNow) == 0 &&
End->Type != pkgCache::Dep::Conflicts &&
+ End->Type != pkgCache::Dep::DpkgBreaks &&
End->Type != pkgCache::Dep::Obsoletes))
{
// Try a little harder to fix protected packages..
/* See if a keep will do, unless the package is protected,
then installing it will be necessary */
bool Installed = Cache[I].Install();
- Cache.MarkKeep(I);
+ Cache.MarkKeep(I, false, false);
if (Cache[I].InstBroken() == false)
{
// Unwind operation will be keep now
// Restore
if (InOr == true && Installed == true)
- Cache.MarkInstall(I,false);
+ Cache.MarkInstall(I, false, 0, false);
if (Debug == true)
clog << " Holding Back " << I.Name() << " rather than change " << Start.TargetPkg().Name() << endl;
if (Debug == true)
clog << " Removing " << I.Name() << " rather than change " << Start.TargetPkg().Name() << endl;
Cache.MarkDelete(I);
- if (Counter > 1)
- {
- if (Scores[Pkg->ID] > Scores[I->ID])
- Scores[I->ID] = Scores[Pkg->ID];
- }
- }
+ if (Counter > 1 && Scores[Pkg->ID] > Scores[I->ID])
+ Scores[I->ID] = Scores[Pkg->ID];
+ }
}
}
(Start->Type == pkgCache::Dep::Conflicts ||
Start->Type == pkgCache::Dep::Obsoletes))
continue;
-
+
+ if (Start->Type == pkgCache::Dep::DpkgBreaks)
+ {
+ // first, try upgradring the package, if that
+ // does not help, the breaks goes onto the
+ // kill list
+ // FIXME: use DoUpgrade(Pkg) instead?
+ if (Cache[End] & pkgDepCache::DepGCVer)
+ {
+ if (Debug)
+ clog << " Upgrading " << Pkg.Name() << " due to Breaks field in " << I.Name() << endl;
+ Cache.MarkInstall(Pkg, false, 0, false);
+ continue;
+ }
+ }
+
// Skip adding to the kill list if it is protected
if ((Flags[Pkg->ID] & Protected) != 0)
continue;
// Hm, nothing can possibly satisify this dep. Nuke it.
if (VList[0] == 0 &&
Start->Type != pkgCache::Dep::Conflicts &&
+ Start->Type != pkgCache::Dep::DpkgBreaks &&
Start->Type != pkgCache::Dep::Obsoletes &&
(Flags[I->ID] & Protected) != Protected)
{
// Restore
if (InOr == true && Installed == true)
- Cache.MarkInstall(I,false);
+ Cache.MarkInstall(I, false, 0, false);
if (Debug == true)
clog << " Holding Back " << I.Name() << " because I can't find " << Start.TargetPkg().Name() << endl;
if ((Cache[J->Dep] & pkgDepCache::DepGNow) == 0)
{
if (J->Dep->Type == pkgCache::Dep::Conflicts ||
+ J->Dep->Type == pkgCache::Dep::DpkgBreaks ||
J->Dep->Type == pkgCache::Dep::Obsoletes)
{
if (Debug == true)
{
if (Debug == true)
clog << " Fixing " << I.Name() << " via keep of " << J->Pkg.Name() << endl;
- Cache.MarkKeep(J->Pkg);
+ Cache.MarkKeep(J->Pkg, false, false);
}
if (Counter > 1)
return _error->Error(_("Unable to correct problems, you have held broken packages."));
}
+ // set the auto-flags (mvo: I'm not sure if we _really_ need this)
+ pkgCache::PkgIterator I = Cache.PkgBegin();
+ for (;I.end() != true; I++) {
+ if (Cache[I].NewInstall() && !(Flags[I->ID] & PreInstalled)) {
+ if(_config->FindI("Debug::pkgAutoRemove",false)) {
+ std::clog << "Resolve installed new pkg: " << I.Name()
+ << " (now marking it as auto)" << std::endl;
+ }
+ Cache[I].Flags |= pkgCache::Flag::Auto;
+ }
+ }
+
+
return true;
}
/*}}}*/
system was non-broken previously. */
bool pkgProblemResolver::ResolveByKeep()
{
+ pkgDepCache::ActionGroup group(Cache);
+
unsigned long Size = Cache.Head().PackageCount;
- if (Debug == true)
- clog << "Entering ResolveByKeep" << endl;
-
MakeScores();
/* We have to order the packages so that the broken fixing pass
*PEnd++ = I;
This = this;
qsort(PList,PEnd - PList,sizeof(*PList),&ScoreSort);
-
+
+ if (_config->FindB("Debug::pkgProblemResolver::ShowScores",false) == true)
+ {
+ clog << "Show Scores" << endl;
+ for (pkgCache::Package **K = PList; K != PEnd; K++)
+ if (Scores[(*K)->ID] != 0)
+ {
+ pkgCache::PkgIterator Pkg(Cache,*K);
+ clog << Scores[(*K)->ID] << ' ' << Pkg << std::endl;
+ }
+ }
+
+ if (Debug == true)
+ clog << "Entering ResolveByKeep" << endl;
+
// Consider each broken package
pkgCache::Package **LastStop = 0;
for (pkgCache::Package **K = PList; K != PEnd; K++)
{
if (Debug == true)
clog << "Keeping package " << I.Name() << endl;
- Cache.MarkKeep(I);
+ Cache.MarkKeep(I, false, false);
if (Cache[I].InstBroken() == false)
{
K = PList - 1;
// Isolate the problem dependencies
for (pkgCache::DepIterator D = Cache[I].InstVerIter(Cache).DependsList(); D.end() == false;)
{
- // Compute a single dependency element (glob or)
- pkgCache::DepIterator Start = D;
- pkgCache::DepIterator End = D;
- unsigned char State = 0;
- for (bool LastOR = true; D.end() == false && LastOR == true; D++)
- {
- State |= Cache[D];
- LastOR = (D->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or;
- if (LastOR == true)
- End = D;
- }
-
+ DepIterator Start;
+ DepIterator End;
+ D.GlobOr(Start,End);
+
// We only worry about critical deps.
if (End.IsCritical() != true)
continue;
// Dep is ok
if ((Cache[End] & pkgDepCache::DepGInstall) == pkgDepCache::DepGInstall)
continue;
-
- // Hm, the group is broken.. I have no idea how to handle this
- if (Start != End)
- {
- clog << "Note, a broken or group was found in " << I.Name() << "." << endl;
- if ((Flags[I->ID] & Protected) == 0)
- Cache.MarkKeep(I);
- break;
- }
-
- if (Debug == true)
- clog << "Package " << I.Name() << " has broken dep on " << End.TargetPkg().Name() << endl;
-
- // Look at all the possible provides on this package
- SPtrArray<pkgCache::Version *> VList = End.AllTargets();
- for (pkgCache::Version **V = VList; *V != 0; V++)
+
+ /* Hm, the group is broken.. I suppose the best thing to do is to
+ is to try every combination of keep/not-keep for the set, but thats
+ slow, and this never happens, just be conservative and assume the
+ list of ors is in preference and keep till it starts to work. */
+ while (true)
{
- pkgCache::VerIterator Ver(Cache,*V);
- pkgCache::PkgIterator Pkg = Ver.ParentPkg();
-
- // It is not keepable
- if (Cache[Pkg].InstallVer == 0 ||
- Pkg->CurrentVer == 0)
- continue;
-
- if ((Flags[I->ID] & Protected) == 0)
+ if (Debug == true)
+ clog << "Package " << I.Name() << " has broken " << Start.DepType() << " on " << Start.TargetPkg().Name() << endl;
+
+ // Look at all the possible provides on this package
+ SPtrArray<pkgCache::Version *> VList = Start.AllTargets();
+ for (pkgCache::Version **V = VList; *V != 0; V++)
{
- if (Debug == true)
- clog << " Keeping Package " << Pkg.Name() << " due to dep" << endl;
- Cache.MarkKeep(Pkg);
+ pkgCache::VerIterator Ver(Cache,*V);
+ pkgCache::PkgIterator Pkg = Ver.ParentPkg();
+
+ // It is not keepable
+ if (Cache[Pkg].InstallVer == 0 ||
+ Pkg->CurrentVer == 0)
+ continue;
+
+ if ((Flags[I->ID] & Protected) == 0)
+ {
+ if (Debug == true)
+ clog << " Keeping Package " << Pkg.Name() << " due to " << Start.DepType() << endl;
+ Cache.MarkKeep(Pkg, false, false);
+ }
+
+ if (Cache[I].InstBroken() == false)
+ break;
}
if (Cache[I].InstBroken() == false)
break;
- }
+ if (Start == End)
+ break;
+ Start++;
+ }
+
if (Cache[I].InstBroken() == false)
break;
}
/* This is used to make sure protected packages are installed */
void pkgProblemResolver::InstallProtect()
{
+ pkgDepCache::ActionGroup group(Cache);
+
for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
{
if ((Flags[I->ID] & Protected) == Protected)
{
if ((Flags[I->ID] & ToRemove) == ToRemove)
Cache.MarkDelete(I);
- else
- Cache.MarkInstall(I,false);
+ else
+ {
+ // preserve the information whether the package was auto
+ // or manually installed
+ bool autoInst = (Cache[I].Flags & pkgCache::Flag::Auto);
+ Cache.MarkInstall(I, false, 0, !autoInst);
+ }
}
}
}
/*}}}*/
-
// PrioSortList - Sort a list of versions by priority /*{{{*/
// ---------------------------------------------------------------------
/* This is ment to be used in conjunction with AllTargets to get a list
pkgCache::VerIterator R(*PrioCache,*(pkgCache::Version **)B);
if ((L.ParentPkg()->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential &&
- (L.ParentPkg()->Flags & pkgCache::Flag::Essential) != pkgCache::Flag::Essential)
- return 1;
+ (R.ParentPkg()->Flags & pkgCache::Flag::Essential) != pkgCache::Flag::Essential)
+ return 1;
if ((L.ParentPkg()->Flags & pkgCache::Flag::Essential) != pkgCache::Flag::Essential &&
- (L.ParentPkg()->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
- return -1;
+ (R.ParentPkg()->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
+ return -1;
if (L->Priority != R->Priority)
- return L->Priority - R->Priority;
+ return R->Priority - L->Priority;
return strcmp(L.ParentPkg().Name(),R.ParentPkg().Name());
}
void pkgPrioSortList(pkgCache &Cache,pkgCache::Version **List)
qsort(List,Count,sizeof(*List),PrioComp);
}
/*}}}*/
+// CacheFile::ListUpdate - update the cache files /*{{{*/
+// ---------------------------------------------------------------------
+/* This is a simple wrapper to update the cache. it will fetch stuff
+ * from the network (or any other sources defined in sources.list)
+ */
+bool ListUpdate(pkgAcquireStatus &Stat,
+ pkgSourceList &List,
+ int PulseInterval)
+{
+ pkgAcquire::RunResult res;
+ pkgAcquire Fetcher;
+ if (Fetcher.Setup(&Stat, _config->FindDir("Dir::State::Lists")) == false)
+ return false;
+
+ // Populate it with the source selection
+ if (List.GetIndexes(&Fetcher) == false)
+ return false;
+
+ // Run scripts
+ RunScripts("APT::Update::Pre-Invoke");
+
+ // check arguments
+ if(PulseInterval>0)
+ res = Fetcher.Run(PulseInterval);
+ else
+ res = Fetcher.Run();
+
+ if (res == pkgAcquire::Failed)
+ return false;
+
+ bool Failed = false;
+ bool TransientNetworkFailure = false;
+ for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin();
+ I != Fetcher.ItemsEnd(); I++)
+ {
+ if ((*I)->Status == pkgAcquire::Item::StatDone)
+ continue;
+
+ (*I)->Finished();
+
+ ::URI uri((*I)->DescURI());
+ uri.User.clear();
+ uri.Password.clear();
+ string descUri = string(uri);
+ _error->Warning(_("Failed to fetch %s %s\n"), descUri.c_str(),
+ (*I)->ErrorText.c_str());
+
+ if ((*I)->Status == pkgAcquire::Item::StatTransientNetworkError)
+ {
+ TransientNetworkFailure = true;
+ continue;
+ }
+
+ Failed = true;
+ }
+
+ // Clean out any old list files
+ // Keep "APT::Get::List-Cleanup" name for compatibility, but
+ // this is really a global option for the APT library now
+ if (!TransientNetworkFailure && !Failed &&
+ (_config->FindB("APT::Get::List-Cleanup",true) == true &&
+ _config->FindB("APT::List-Cleanup",true) == true))
+ {
+ if (Fetcher.Clean(_config->FindDir("Dir::State::lists")) == false ||
+ Fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/") == false)
+ // something went wrong with the clean
+ return false;
+ }
+
+ if (TransientNetworkFailure == true)
+ _error->Warning(_("Some index files failed to download, they have been ignored, or old ones used instead."));
+ else if (Failed == true)
+ return _error->Error(_("Some index files failed to download, they have been ignored, or old ones used instead."));
+
+
+ // Run the success scripts if all was fine
+ if(!TransientNetworkFailure && !Failed)
+ RunScripts("APT::Update::Post-Invoke-Success");
+
+ // Run the other scripts
+ RunScripts("APT::Update::Post-Invoke");
+ return true;
+}
+ /*}}}*/