X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/b0a6debfa93f547ce843732962314743d8282567..115ba31b90e0d6643670d7d079f9f27b0e05f1c2:/apt-pkg/algorithms.cc?ds=sidebyside diff --git a/apt-pkg/algorithms.cc b/apt-pkg/algorithms.cc index ddfda754d..f17c76d6c 100644 --- a/apt-pkg/algorithms.cc +++ b/apt-pkg/algorithms.cc @@ -14,18 +14,17 @@ ##################################################################### */ /*}}}*/ // Include Files /*{{{*/ -#ifdef __GNUG__ -#pragma implementation "apt-pkg/algorithms.h" -#endif #include #include #include #include #include - +#include #include #include +#include +#include #include /*}}}*/ using namespace std; @@ -38,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]; @@ -83,13 +83,28 @@ void pkgSimulate::Describe(PkgIterator Pkg,ostream &out,bool Current,bool Candid 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,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++) { @@ -131,9 +146,22 @@ bool pkgSimulate::Install(PkgIterator iPkg,string /*File*/) 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) { @@ -181,10 +209,26 @@ bool pkgSimulate::Configure(PkgIterator iPkg) 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 @@ -258,6 +302,8 @@ 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, false, false); @@ -440,7 +486,6 @@ bool pkgMinimizeUpgrade(pkgDepCache &Cache) return true; } /*}}}*/ - // ProblemResolver::pkgProblemResolver - Constructor /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -487,6 +532,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, + (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++) { @@ -495,23 +570,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 @@ -522,8 +597,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; } } @@ -543,7 +621,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]); @@ -568,10 +648,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 /*{{{*/ @@ -747,19 +827,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 @@ -804,7 +886,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]; @@ -859,7 +941,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) @@ -869,7 +956,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 @@ -951,12 +1038,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]; + } } } @@ -977,16 +1061,17 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) if (Start->Type == pkgCache::Dep::DpkgBreaks) { - /* Would it help if we upgraded? */ - if (Cache[End] & pkgDepCache::DepGCVer) { + // 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; } - if (Debug) - clog << " Will not break " << Pkg.Name() << " as stated in Breaks field in " << I.Name() <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) @@ -1098,8 +1184,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)) { @@ -1126,9 +1211,6 @@ bool pkgProblemResolver::ResolveByKeep() 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 @@ -1141,7 +1223,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++) @@ -1187,8 +1283,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++) @@ -1204,7 +1300,7 @@ bool pkgProblemResolver::ResolveByKeep() if ((Flags[I->ID] & Protected) == 0) { if (Debug == true) - clog << " Keeping Package " << Pkg.Name() << " due to dep" << endl; + clog << " Keeping Package " << Pkg.Name() << " due to " << Start.DepType() << endl; Cache.MarkKeep(Pkg, false, false); } @@ -1252,8 +1348,8 @@ void pkgProblemResolver::InstallProtect() Cache.MarkDelete(I); else { - // preserver the information if the package was auto - // or manual installed + // 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); } @@ -1261,7 +1357,6 @@ void pkgProblemResolver::InstallProtect() } } /*}}}*/ - // PrioSortList - Sort a list of versions by priority /*{{{*/ // --------------------------------------------------------------------- /* This is ment to be used in conjunction with AllTargets to get a list @@ -1292,4 +1387,87 @@ 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; +} + /*}}}*/