X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/899d08fea9e10d617afaa42f51f4abda76fc508f..89504deb355453e2022cafe54b3b235588bea7d7:/apt-pkg/algorithms.cc?ds=sidebyside diff --git a/apt-pkg/algorithms.cc b/apt-pkg/algorithms.cc index 8626d33dc..a3963d546 100644 --- a/apt-pkg/algorithms.cc +++ b/apt-pkg/algorithms.cc @@ -14,20 +14,17 @@ ##################################################################### */ /*}}}*/ // Include Files /*{{{*/ -#ifdef __GNUG__ -#pragma implementation "apt-pkg/algorithms.h" -#endif #include #include #include -#include #include #include - +#include #include #include -#include +#include +#include #include /*}}}*/ using namespace std; @@ -40,7 +37,8 @@ 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]; @@ -104,6 +102,7 @@ bool pkgSimulate::Install(PkgIterator iPkg,string /*File*/) 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) { @@ -153,6 +152,8 @@ bool pkgSimulate::Configure(PkgIterator iPkg) 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(); } @@ -224,6 +225,8 @@ void pkgSimulate::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) @@ -234,13 +237,13 @@ bool pkgApplyStatus(pkgDepCache &Cache) 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].CandidateVer != 0 && Cache[I].CandidateVerIter(Cache).Downloadable() == true) - Cache.MarkInstall(I); + 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()); @@ -255,14 +258,16 @@ bool pkgApplyStatus(pkgDepCache &Cache) 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].CandidateVer != 0 && Cache[I].CandidateVerIter(Cache).Downloadable() == true) - Cache.MarkInstall(I); + Cache.MarkInstall(I, true, 0, false); else Cache.MarkDelete(I); } @@ -288,10 +293,12 @@ bool pkgApplyStatus(pkgDepCache &Cache) 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 */ @@ -304,7 +311,7 @@ bool pkgFixBroken(pkgDepCache &Cache) if (Cache[I].InstVerIter(Cache).Downloadable() == false) continue; - Cache.MarkInstall(I,true); + Cache.MarkInstall(I, true, 0, false); } pkgProblemResolver Fix(&Cache); @@ -321,23 +328,25 @@ bool pkgFixBroken(pkgDepCache &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); @@ -349,7 +358,7 @@ bool pkgDistUpgrade(pkgDepCache &Cache) if (I->SelectedState == pkgCache::State::Hold) { Fix.Protect(I); - Cache.MarkKeep(I); + Cache.MarkKeep(I, false, false); } } } @@ -364,6 +373,8 @@ bool pkgDistUpgrade(pkgDepCache &Cache) to install packages not marked for install */ bool pkgAllUpgrade(pkgDepCache &Cache) { + pkgDepCache::ActionGroup group(Cache); + pkgProblemResolver Fix(&Cache); if (Cache.BrokenCount() != 0) @@ -380,7 +391,7 @@ bool pkgAllUpgrade(pkgDepCache &Cache) continue; if (I->CurrentVer != 0 && Cache[I].InstallVer != 0) - Cache.MarkInstall(I,false); + Cache.MarkInstall(I, false, 0, false); } return Fix.ResolveByKeep(); @@ -393,6 +404,8 @@ bool pkgAllUpgrade(pkgDepCache &Cache) the package is restored. */ bool pkgMinimizeUpgrade(pkgDepCache &Cache) { + pkgDepCache::ActionGroup group(Cache); + if (Cache.BrokenCount() != 0) return false; @@ -409,9 +422,9 @@ bool pkgMinimizeUpgrade(pkgDepCache &Cache) 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.. @@ -429,7 +442,6 @@ bool pkgMinimizeUpgrade(pkgDepCache &Cache) return true; } /*}}}*/ - // ProblemResolver::pkgProblemResolver - Constructor /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -476,6 +488,36 @@ void pkgProblemResolver::MakeScores() unsigned long Size = Cache.Head().PackageCount; memset(Scores,0,sizeof(*Scores)*Size); + // Important Required Standard Optional Extra + signed short PrioMap[] = { + 0, + _config->FindI("pkgProblemResolver::Scores::Important",3), + _config->FindI("pkgProblemResolver::Scores::Required",2), + _config->FindI("pkgProblemResolver::Scores::Standard",1), + _config->FindI("pkgProblemResolver::Scores::Optional",-1), + _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++) { @@ -484,23 +526,23 @@ void pkgProblemResolver::MakeScores() 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 @@ -511,8 +553,11 @@ void pkgProblemResolver::MakeScores() 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; } } @@ -532,7 +577,9 @@ void pkgProblemResolver::MakeScores() { // 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]); @@ -557,10 +604,10 @@ void pkgProblemResolver::MakeScores() 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 /*{{{*/ @@ -569,6 +616,8 @@ void pkgProblemResolver::MakeScores() 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) @@ -577,7 +626,7 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg) 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) @@ -641,6 +690,7 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg) /* 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; @@ -662,7 +712,7 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg) if (Fail == true) { if (WasKept == true) - Cache.MarkKeep(Pkg); + Cache.MarkKeep(Pkg, false, false); else Cache.MarkDelete(Pkg); return false; @@ -689,6 +739,8 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg) 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 @@ -704,7 +756,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) { if (Cache[I].InstBroken() == true && BrokenFix == true) { - Cache.MarkInstall(I,false); + Cache.MarkInstall(I, false, 0, false); if (Cache[I].Install() == true) Again = true; } @@ -731,19 +783,21 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) *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 @@ -770,14 +824,14 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) 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) @@ -788,7 +842,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) continue; if (Debug == true) - cout << "Investigating " << I.Name() << endl; + clog << "Investigating " << I.Name() << endl; // Isolate the problem dependency PackageKill KillList[100]; @@ -822,7 +876,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) { if (Debug == true) clog << " Or group keep for " << I.Name() << endl; - Cache.MarkKeep(I); + Cache.MarkKeep(I, false, false); Change = true; } } @@ -843,7 +897,12 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) 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) @@ -853,7 +912,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) } 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 @@ -861,6 +920,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) SPtrArray 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) { @@ -872,7 +932,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) } Change = true; - Cache.MarkKeep(I); + Cache.MarkKeep(I, false, false); break; } @@ -891,6 +951,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) 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.. @@ -909,7 +970,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) /* 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 @@ -918,7 +979,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) // 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; @@ -933,12 +994,9 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) 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]; + } } } @@ -956,7 +1014,22 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) (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; @@ -977,6 +1050,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) // 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) { @@ -990,7 +1064,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) // 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; @@ -1024,6 +1098,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) 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) @@ -1035,7 +1110,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) { 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) @@ -1065,8 +1140,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) 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, but - // I didn't managed + // 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)) { @@ -1089,11 +1163,10 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) 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 @@ -1106,7 +1179,21 @@ bool pkgProblemResolver::ResolveByKeep() *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++) @@ -1122,7 +1209,7 @@ bool pkgProblemResolver::ResolveByKeep() { 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; @@ -1152,8 +1239,8 @@ bool pkgProblemResolver::ResolveByKeep() while (true) { 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 at all the possible provides on this package SPtrArray VList = Start.AllTargets(); for (pkgCache::Version **V = VList; *V != 0; V++) @@ -1169,8 +1256,8 @@ bool pkgProblemResolver::ResolveByKeep() if ((Flags[I->ID] & Protected) == 0) { if (Debug == true) - clog << " Keeping Package " << Pkg.Name() << " due to dep" << endl; - Cache.MarkKeep(Pkg); + clog << " Keeping Package " << Pkg.Name() << " due to " << Start.DepType() << endl; + Cache.MarkKeep(Pkg, false, false); } if (Cache[I].InstBroken() == false) @@ -1207,19 +1294,25 @@ bool pkgProblemResolver::ResolveByKeep() /* 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 @@ -1250,238 +1343,85 @@ void pkgPrioSortList(pkgCache &Cache,pkgCache::Version **List) qsort(List,Count,sizeof(*List),PrioComp); } /*}}}*/ - - -// mark a single package in Mark-and-Sweep -void pkgMarkPackage(pkgDepCache &Cache, - const pkgCache::PkgIterator &pkg, - const pkgCache::VerIterator &ver, - bool follow_recommends, - bool follow_suggests) +// 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) { - pkgDepCache::StateCache &state=Cache[pkg]; - pkgCache::VerIterator candver=state.CandidateVerIter(Cache); - pkgCache::VerIterator instver=state.InstVerIter(Cache); - -#if 0 - // If a package was garbage-collected but is now being marked, we - // should re-select it - // For cases when a pkg is set to upgrade and this trigger the - // removal of a no-longer used dependency. if the pkg is set to - // keep again later it will result in broken deps - if(state.Delete() && state.RemoveReason=pkgDepCache::Unused) - { - if(ver==candver) - mark_install(pkg, false, false, NULL); - else if(ver==pkg.CurrentVer()) - MarkKeep(pkg); - - instver=state.InstVerIter(*this); - } -#endif - - // Ignore versions other than the InstVer, and ignore packages - // that are already going to be removed or just left uninstalled. - if(!(ver==instver && !instver.end())) - return; + pkgAcquire::RunResult res; + pkgAcquire Fetcher(&Stat); - // if we are marked already we are done - if(state.Marked) - return; + // Populate it with the source selection + if (List.GetIndexes(&Fetcher) == false) + return false; - //std::cout << "Setting Marked for: " << pkg.Name() << std::endl; - state.Marked=true; - - if(!ver.end()) - { - for(pkgCache::DepIterator d=ver.DependsList(); !d.end(); ++d) - { - if(d->Type==pkgCache::Dep::Depends || - d->Type==pkgCache::Dep::PreDepends || - (follow_recommends && - d->Type==pkgCache::Dep::Recommends) || - (follow_suggests && - d->Type==pkgCache::Dep::Suggests)) - { - // Try all versions of this package. - for(pkgCache::VerIterator V=d.TargetPkg().VersionList(); - !V.end(); ++V) - { - if(_system->VS->CheckDep(V.VerStr(),d->CompareOp, d.TargetVer())) - { - pkgMarkPackage(Cache, V.ParentPkg(), V, - follow_recommends, follow_suggests); - } - } - // Now try virtual packages - for(pkgCache::PrvIterator prv=d.TargetPkg().ProvidesList(); - !prv.end(); ++prv) - { - if(_system->VS->CheckDep(prv.ProvideVersion(), d->CompareOp, - d.TargetVer())) - { - pkgMarkPackage(Cache, prv.OwnerPkg(), prv.OwnerVer(), - follow_recommends, follow_suggests); - } - } - } - } - } -} - - -// Helper for APT::NeverAutoRemove, always include the packages matching -// this regexp into the root-set -inline bool -pkgMarkAlwaysInclude(pkgCache::PkgIterator p, vector alwaysMark) -{ - for(unsigned int i=0;i0) + res = Fetcher.Run(PulseInterval); + else + res = Fetcher.Run(); -// the main mark algorithm -bool pkgMarkUsed(pkgDepCache &Cache, InRootSetFunc func) -{ - bool follow_recommends; - bool follow_suggests; + if (res == pkgAcquire::Failed) + return false; - // init the states - for(pkgCache::PkgIterator p=Cache.PkgBegin(); !p.end(); ++p) + bool Failed = false; + bool TransientNetworkFailure = false; + for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin(); + I != Fetcher.ItemsEnd(); I++) { - Cache[p].Marked=false; - Cache[p].Garbage=false; - } + if ((*I)->Status == pkgAcquire::Item::StatDone) + continue; - // init vars - follow_recommends=_config->FindB("APT::AutoRemove::RecommendsImportant",false); - follow_suggests=_config->FindB("APT::AutoRemove::SuggestsImportant", false); + (*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()); - // init the "NeverAutoRemove" variable - vector neverAutoRemoveRegexp; - Configuration::Item const *Opts; - Opts = _config->Tree("APT::NeverAutoRemove"); - if (Opts != 0 && Opts->Child != 0) - { - Opts = Opts->Child; - for (; Opts != 0; Opts = Opts->Next) + if ((*I)->Status == pkgAcquire::Item::StatTransientNetworkError) { - if (Opts->Value.empty() == true) - continue; - - regex_t *p = new regex_t; - if(regcomp(p,Opts->Value.c_str(), - REG_EXTENDED | REG_ICASE | REG_NOSUB) != 0) - { - regfree(p); - for(unsigned int i=0;iError("Regex compilation error for APT::NeverAutoRemove"); - } - neverAutoRemoveRegexp.push_back(p); + TransientNetworkFailure = true; + continue; } - } - - // do the mark part, this is the core bit of the algorithm - for(pkgCache::PkgIterator p=Cache.PkgBegin(); !p.end(); ++p) + 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( (func != NULL ? (*func)(p) : false) || - pkgMarkAlwaysInclude(p, neverAutoRemoveRegexp) || - !(Cache[p].Flags & pkgCache::Flag::Auto) || - (p->Flags & pkgCache::Flag::Essential)) - - { - // the package is installed (and set to keep) - if(Cache[p].Keep() && !p.CurrentVer().end()) - pkgMarkPackage(Cache, p, p.CurrentVer(), - follow_recommends, follow_suggests); - // the package is to be installed - else if(Cache[p].Install()) - pkgMarkPackage(Cache, p, Cache[p].InstVerIter(Cache), - follow_recommends, follow_suggests); - } + 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.")); - // do the sweep - for(pkgCache::PkgIterator p=Cache.PkgBegin(); !p.end(); ++p) - { - pkgDepCache::StateCache &state=Cache[p]; - - if(!state.Marked) - { - // mark installed but not yet marked stuff as garbage - if(p->CurrentVer != 0) { - state.Garbage=true; - std::cout << "Garbage: " << p.Name() << std::endl; - } - -#if 0 // mvo: the below bits still needs to be ported - - // Be sure not to re-delete already deleted packages. - if(delete_unused && (!p.CurrentVer().end() || state.Install()) && - !state.Delete()) - { - bool do_delete=true; - - // If the package is being upgraded, check if we're - // losing a versioned dep. If the dependency matches - // the previous version and not the new version, keep - // the package back instead of removing it. - if(!p.CurrentVer().end() && state.Install()) - { - const char *vs=p.CurrentVer().VerStr(); - - // Check direct revdeps only. THIS ASSUMES NO - // VERSIONED PROVIDES, but Debian probably won't - // have them for ages if ever. - for(pkgCache::DepIterator revdep=p.RevDependsList(); - !revdep.end(); ++revdep) - { - pkgCache::PkgIterator depender=revdep.ParentPkg(); - // Find which version of the depending package - // will be installed. - pkgCache::VerIterator instver=(*this)[depender].InstVerIter(*this); - - // Only pay attention to strong positive - // dependencies whose parents will be installed. - if(revdep.ParentVer()==instver && - (revdep->Type==pkgCache::Dep::Depends || - revdep->Type==pkgCache::Dep::PreDepends || - (revdep->Type==pkgCache::Dep::Recommends && - follow_recommends))) - { - // If the previous version matched, cancel the - // deletion. (note that I assume that the new - // version does NOT match; otherwise it would - // not be unused!) - if(_system->VS->CheckDep(vs, - revdep->CompareOp, - revdep.TargetVer())) - { - mark_keep(p, false, false, undo); - do_delete=false; - break; - } - } - } - } - - if(do_delete) - mark_delete(p, false, true, undo); - } -#endif - } - } - - // cleanup - for(unsigned int i=0;i