]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/algorithms.cc
Merge remote-tracking branch 'mvo/bugfix/bts-712433' into debian/sid
[apt.git] / apt-pkg / algorithms.cc
index 47bdd4abafaa827138d4d6db1f6f9a679b70bde7..85799a11b9cbc17f955c22df05d929f03c716dce 100644 (file)
@@ -14,6 +14,8 @@
    ##################################################################### */
                                                                        /*}}}*/
 // Include Files                                                       /*{{{*/
+#include <config.h>
+
 #include <apt-pkg/algorithms.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/configuration.h>
 #include <apt-pkg/sptr.h>
 #include <apt-pkg/acquire-item.h>
 #include <apt-pkg/edsp.h>
+#include <apt-pkg/sourcelist.h>
+#include <apt-pkg/fileutl.h>
+#include <apt-pkg/progress.h>
 
-#include <apti18n.h>
 #include <sys/types.h>
 #include <cstdlib>
 #include <algorithm>
 #include <iostream>
-
 #include <stdio.h>
+
+#include <apti18n.h>
                                                                        /*}}}*/
 using namespace std;
 
@@ -53,6 +58,12 @@ pkgSimulate::pkgSimulate(pkgDepCache *Cache) : pkgPackageManager(Cache),
       FileNames[I] = Jnk;
 }
                                                                        /*}}}*/
+// Simulate::~Simulate - Destructor                                    /*{{{*/
+pkgSimulate::~pkgSimulate()
+{
+   delete[] Flags;
+}
+                                                                       /*}}}*/
 // Simulate::Describe - Describe a package                             /*{{{*/
 // ---------------------------------------------------------------------
 /* Parameter Current == true displays the current package version,
@@ -94,7 +105,7 @@ bool pkgSimulate::Install(PkgIterator iPkg,string /*File*/)
    Sim.MarkInstall(Pkg,false);
 
    // Look for broken conflicts+predepends.
-   for (PkgIterator I = Sim.PkgBegin(); I.end() == false; I++)
+   for (PkgIterator I = Sim.PkgBegin(); I.end() == false; ++I)
    {
       if (Sim[I].InstallVer == 0)
         continue;
@@ -143,7 +154,7 @@ bool pkgSimulate::Configure(PkgIterator iPkg)
       Sim.Update();
       
       // Print out each package and the failed dependencies
-      for (pkgCache::DepIterator D = Sim[Pkg].InstVerIter(Sim).DependsList(); D.end() == false; D++)
+      for (pkgCache::DepIterator D = Sim[Pkg].InstVerIter(Sim).DependsList(); D.end() == false; ++D)
       {
         if (Sim.IsImportantDep(D) == false || 
             (Sim[D] & pkgDepCache::DepInstall) != 0)
@@ -183,6 +194,11 @@ bool pkgSimulate::Remove(PkgIterator iPkg,bool Purge)
 {
    // Adapt the iterator
    PkgIterator Pkg = Sim.FindPkg(iPkg.Name(), iPkg.Arch());
+   if (Pkg.end() == true)
+   {
+      std::cerr << (Purge ? "Purg" : "Remv") << " invalid package " << iPkg.FullName() << std::endl;
+      return false;
+   }
 
    Flags[Pkg->ID] = 3;
    Sim.MarkDelete(Pkg);
@@ -207,7 +223,7 @@ bool pkgSimulate::Remove(PkgIterator iPkg,bool Purge)
 void pkgSimulate::ShortBreaks()
 {
    cout << " [";
-   for (PkgIterator I = Sim.PkgBegin(); I.end() == false; I++)
+   for (PkgIterator I = Sim.PkgBegin(); I.end() == false; ++I)
    {
       if (Sim[I].InstBroken() == true)
       {
@@ -229,7 +245,7 @@ bool pkgApplyStatus(pkgDepCache &Cache)
 {
    pkgDepCache::ActionGroup group(Cache);
 
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
    {
       if (I->VersionList == 0)
         continue;
@@ -271,13 +287,13 @@ bool pkgApplyStatus(pkgDepCache &Cache)
                 Cache[I].CandidateVerIter(Cache).Downloadable() == true)
               Cache.MarkInstall(I, true, 0, false);
            else
-              Cache.MarkDelete(I);
+              Cache.MarkDelete(I, false, 0, false);
         }
         break;
 
         // This means removal failed
         case pkgCache::State::HalfInstalled:
-        Cache.MarkDelete(I);
+        Cache.MarkDelete(I, false, 0, false);
         break;
         
         default:
@@ -298,13 +314,13 @@ bool pkgFixBroken(pkgDepCache &Cache)
    pkgDepCache::ActionGroup group(Cache);
 
    // Auto upgrade all broken packages
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
       if (Cache[I].NowBroken() == true)
         Cache.MarkInstall(I, true, 0, false);
    
    /* Fix packages that are in a NeedArchive state but don't have a
       downloadable install version */
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
    {
       if (I.State() != pkgCache::PkgIterator::NeedsUnpack ||
          Cache[I].Delete() == true)
@@ -347,19 +363,44 @@ bool pkgDistUpgrade(pkgDepCache &Cache)
 
    /* Auto upgrade all installed packages, this provides the basis 
       for the installation */
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
       if (I->CurrentVer != 0)
         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, 0, false);
+   /* Now, install each essential package which is not installed
+      (and not provided by another package in the same name group) */
+   std::string essential = _config->Find("pkgCacheGen::Essential", "all");
+   if (essential == "all")
+   {
+      for (pkgCache::GrpIterator G = Cache.GrpBegin(); G.end() == false; ++G)
+      {
+        bool isEssential = false;
+        bool instEssential = false;
+        for (pkgCache::PkgIterator P = G.PackageList(); P.end() == false; P = G.NextPkg(P))
+        {
+           if ((P->Flags & pkgCache::Flag::Essential) != pkgCache::Flag::Essential)
+              continue;
+           isEssential = true;
+           if (Cache[P].Install() == true)
+           {
+              instEssential = true;
+              break;
+           }
+        }
+        if (isEssential == false || instEssential == true)
+           continue;
+        pkgCache::PkgIterator P = G.FindPreferredPkg();
+        Cache.MarkInstall(P, true, 0, false);
+      }
+   }
+   else if (essential != "none")
+      for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
+        if ((I->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
+           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++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
       if (I->CurrentVer != 0)
         Cache.MarkInstall(I, false, 0, false);
 
@@ -368,7 +409,7 @@ bool pkgDistUpgrade(pkgDepCache &Cache)
    // Hold back held packages.
    if (_config->FindB("APT::Ignore-Hold",false) == false)
    {
-      for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+      for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
       {
         if (I->SelectedState == pkgCache::State::Hold)
         {
@@ -402,7 +443,7 @@ bool pkgAllUpgrade(pkgDepCache &Cache)
       return false;
    
    // Upgrade all installed packages
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
    {
       if (Cache[I].Install() == true)
         Fix.Protect(I);
@@ -436,7 +477,7 @@ bool pkgMinimizeUpgrade(pkgDepCache &Cache)
    do
    {
       Change = false;
-      for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+      for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
       {
         // Not interesting
         if (Cache[I].Upgrade() == false || Cache[I].NewInstall() == true)
@@ -453,7 +494,7 @@ bool pkgMinimizeUpgrade(pkgDepCache &Cache)
               Change = true;
         }       
       }      
-      Count++;
+      ++Count;
    }
    while (Change == true && Count < 10);
 
@@ -466,11 +507,11 @@ bool pkgMinimizeUpgrade(pkgDepCache &Cache)
 // ProblemResolver::pkgProblemResolver - Constructor                   /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-pkgProblemResolver::pkgProblemResolver(pkgDepCache *pCache) : Cache(*pCache)
+pkgProblemResolver::pkgProblemResolver(pkgDepCache *pCache) : d(NULL), Cache(*pCache)
 {
    // Allocate memory
    unsigned long Size = Cache.Head().PackageCount;
-   Scores = new signed short[Size];
+   Scores = new int[Size];
    Flags = new unsigned char[Size];
    memset(Flags,0,sizeof(*Flags)*Size);
    
@@ -509,29 +550,32 @@ void pkgProblemResolver::MakeScores()
    unsigned long Size = Cache.Head().PackageCount;
    memset(Scores,0,sizeof(*Scores)*Size);
 
-   // Important Required Standard Optional Extra
-   signed short PrioMap[] = {
+   // Maps to pkgCache::State::VerPriority
+   //   which is "Important Required Standard Optional Extra"
+   // (yes, that is confusing, the order of pkgCache::State::VerPriority
+   //  needs to be adjusted but that requires a ABI break)
+   int 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)
+      _config->FindI("pkgProblemResolver::Scores::Important",2),
+      _config->FindI("pkgProblemResolver::Scores::Required",3),
+      _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);
+   int PrioEssentials = _config->FindI("pkgProblemResolver::Scores::Essentials",100);
+   int PrioInstalledAndNotObsolete = _config->FindI("pkgProblemResolver::Scores::NotObsolete",1);
+   int PrioDepends = _config->FindI("pkgProblemResolver::Scores::Depends",1);
+   int PrioRecommends = _config->FindI("pkgProblemResolver::Scores::Recommends",1);
+   int AddProtected = _config->FindI("pkgProblemResolver::Scores::AddProtected",10000);
+   int 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
+         << "  Required => " << PrioMap[pkgCache::State::Required] << endl
+         << "  Important => " << PrioMap[pkgCache::State::Important] << endl
+         << "  Standard => " << PrioMap[pkgCache::State::Standard] << endl
+         << "  Optional => " << PrioMap[pkgCache::State::Optional] << endl
+         << "  Extra => " << PrioMap[pkgCache::State::Extra] << endl
          << "  Essentials => " << PrioEssentials << endl
          << "  InstalledAndNotObsolete => " << PrioInstalledAndNotObsolete << endl
          << "  Depends => " << PrioDepends << endl
@@ -540,18 +584,19 @@ void pkgProblemResolver::MakeScores()
          << "  AddEssential => " << AddEssential << endl;
 
    // Generate the base scores for a package based on its properties
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
    {
       if (Cache[I].InstallVer == 0)
         continue;
       
-      signed short &Score = Scores[I->ID];
+      int &Score = Scores[I->ID];
       
       /* 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)
+      if ((I->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential
+         || (I->Flags & pkgCache::Flag::Important) == pkgCache::Flag::Important)
         Score += PrioEssentials;
 
       // We transform the priority
@@ -567,12 +612,12 @@ void pkgProblemResolver::MakeScores()
    }
 
    // Now that we have the base scores we go and propogate dependencies
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
    {
       if (Cache[I].InstallVer == 0)
         continue;
       
-      for (pkgCache::DepIterator D = Cache[I].InstVerIter(Cache).DependsList(); D.end() == false; D++)
+      for (pkgCache::DepIterator D = Cache[I].InstVerIter(Cache).DependsList(); D.end() == false; ++D)
       {
         if (D->Type == pkgCache::Dep::Depends || 
             D->Type == pkgCache::Dep::PreDepends)
@@ -583,18 +628,18 @@ void pkgProblemResolver::MakeScores()
    }   
    
    // Copy the scores to advoid additive looping
-   SPtrArray<signed short> OldScores = new signed short[Size];
+   SPtrArray<int> OldScores = new int[Size];
    memcpy(OldScores,Scores,sizeof(*Scores)*Size);
       
    /* Now we cause 1 level of dependency inheritance, that is we add the 
       score of the packages that depend on the target Package. This 
       fortifies high scoring packages */
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
    {
       if (Cache[I].InstallVer == 0)
         continue;
       
-      for (pkgCache::DepIterator D = I.RevDependsList(); D.end() == false; D++)
+      for (pkgCache::DepIterator D = I.RevDependsList(); D.end() == false; ++D)
       {
         // Only do it for the install version
         if ((pkgCache::Version *)D.ParentVer() != Cache[D.ParentPkg()].InstallVer ||
@@ -603,15 +648,18 @@ void pkgProblemResolver::MakeScores()
              D->Type != pkgCache::Dep::Recommends))
            continue;    
         
-        Scores[I->ID] += abs(OldScores[D.ParentPkg()->ID]);
+        // Do not propagate negative scores otherwise
+        // an extra (-2) package might score better than an optional (-1)
+        if (OldScores[D.ParentPkg()->ID] > 0)
+            Scores[I->ID] += OldScores[D.ParentPkg()->ID];
       }      
    }
 
    /* Now we propogate along provides. This makes the packages that 
       provide important packages extremely important */
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
    {
-      for (pkgCache::PrvIterator P = I.ProvidesList(); P.end() == false; P++)
+      for (pkgCache::PrvIterator P = I.ProvidesList(); P.end() == false; ++P)
       {
         // Only do it once per package
         if ((pkgCache::Version *)P.OwnerVer() != Cache[P.OwnerPkg()].InstallVer)
@@ -622,11 +670,12 @@ void pkgProblemResolver::MakeScores()
 
    /* Protected things are pushed really high up. This number should put them
       ahead of everything */
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
    {
       if ((Flags[I->ID] & Protected) != 0)
         Scores[I->ID] += AddProtected;
-      if ((I->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
+      if ((I->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential ||
+          (I->Flags & pkgCache::Flag::Important) == pkgCache::Flag::Important)
         Scores[I->ID] += AddEssential;
    }
 }
@@ -719,7 +768,7 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg)
         
         if (Start == End)
            break;
-        Start++;
+        ++Start;
       }
       if (Fail == true)
         break;
@@ -731,7 +780,7 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg)
       if (WasKept == true)
         Cache.MarkKeep(Pkg, false, false);
       else
-        Cache.MarkDelete(Pkg);
+        Cache.MarkDelete(Pkg, false, 0, false);
       return false;
    }    
    
@@ -776,7 +825,7 @@ bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
    do
    {
       Again = false;
-      for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+      for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
       {
         if (Cache[I].Install() == true)
            Flags[I->ID] |= PreInstalled;
@@ -796,8 +845,10 @@ bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
    }
    while (Again == true);
 
-   if (Debug == true)
-      clog << "Starting" << endl;
+   if (Debug == true) {
+      clog << "Starting pkgProblemResolver with broken count: " 
+           << Cache.BrokenCount() << endl;
+   }
    
    MakeScores();
 
@@ -809,7 +860,7 @@ bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
       would cause the removal of even lower score packages. */
    SPtrArray<pkgCache::Package *> PList = new pkgCache::Package *[Size];
    pkgCache::Package **PEnd = PList;
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
       *PEnd++ = I;
    This = this;
    qsort(PList,PEnd - PList,sizeof(*PList),&ScoreSort);
@@ -825,8 +876,10 @@ bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
          }
    }
 
-   if (Debug == true)
-      clog << "Starting 2" << endl;
+   if (Debug == true) {
+      clog << "Starting 2 pkgProblemResolver with broken count: " 
+           << Cache.BrokenCount() << 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
@@ -860,7 +913,7 @@ bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
                OldBreaks < Cache.BrokenCount())
            {
               if (OldVer == 0)
-                 Cache.MarkDelete(I);
+                 Cache.MarkDelete(I, false, 0, false);
               else
                  Cache.MarkKeep(I, false, false);
            }       
@@ -899,7 +952,7 @@ bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
                     {
                        if (Debug == true)
                           clog << "  Or group remove for " << I.FullName(false) << endl;
-                       Cache.MarkDelete(I);
+                       Cache.MarkDelete(I, false, 0, false);
                        Change = true;
                     }
                  }
@@ -929,7 +982,7 @@ bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
            }
            else
             {
-              Start++;
+              ++Start;
               // We only worry about critical deps.
               if (Start.IsCritical() != true)
                   continue;
@@ -1030,11 +1083,11 @@ bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
                     if (BrokenFix == false || DoUpgrade(I) == false)
                     {
                        // Consider other options
-                       if (InOr == false)
+                       if (InOr == false || Cache[I].Garbage == true)
                        {
                           if (Debug == true)
                              clog << "  Removing " << I.FullName(false) << " rather than change " << Start.TargetPkg().FullName(false) << endl;
-                          Cache.MarkDelete(I);
+                          Cache.MarkDelete(I, false, 0, false);
                           if (Counter > 1 && Scores[Pkg->ID] > Scores[I->ID])
                              Scores[I->ID] = Scores[Pkg->ID];
                        }
@@ -1093,8 +1146,7 @@ bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
                  LEnd->Dep = End;
                  LEnd++;
                  
-                 if (Start->Type != pkgCache::Dep::Conflicts &&
-                     Start->Type != pkgCache::Dep::Obsoletes)
+                 if (Start.IsNegative() == false)
                     break;
               }
            }
@@ -1124,7 +1176,7 @@ bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
                  if (Debug == true)
                     clog << "  Removing " << I.FullName(false) << " because I can't find " << Start.TargetPkg().FullName(false) << endl;
                  if (InOr == false)
-                    Cache.MarkDelete(I);
+                    Cache.MarkDelete(I, false, 0, false);
               }
 
               Change = true;
@@ -1151,7 +1203,7 @@ bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
                  {
                     if (Debug == true)
                        clog << "  Fixing " << I.FullName(false) << " via remove of " << J->Pkg.FullName(false) << endl;
-                    Cache.MarkDelete(J->Pkg);
+                    Cache.MarkDelete(J->Pkg, false, 0, false);
                  }
               }
               else
@@ -1178,7 +1230,7 @@ bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
    {
       // See if this is the result of a hold
       pkgCache::PkgIterator I = Cache.PkgBegin();
-      for (;I.end() != true; I++)
+      for (;I.end() != true; ++I)
       {
         if (Cache[I].InstBroken() == false)
            continue;
@@ -1190,7 +1242,7 @@ bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
    
    // set the auto-flags (mvo: I'm not sure if we _really_ need this)
    pkgCache::PkgIterator I = Cache.PkgBegin();
-   for (;I.end() != true; I++) {
+   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.FullName(false) 
@@ -1204,6 +1256,37 @@ bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
    return true;
 }
                                                                        /*}}}*/
+// ProblemResolver::BreaksInstOrPolicy - Check if the given pkg is broken/*{{{*/
+// ---------------------------------------------------------------------
+/* This checks if the given package is broken either by a hard dependency
+   (InstBroken()) or by introducing a new policy breakage e.g. new
+   unsatisfied recommends for a package that was in "policy-good" state
+
+   Note that this is not perfect as it will ignore further breakage
+   for already broken policy (recommends)
+*/
+bool pkgProblemResolver::InstOrNewPolicyBroken(pkgCache::PkgIterator I)
+{
+   // a broken install is always a problem
+   if (Cache[I].InstBroken() == true)
+   {
+      if (Debug == true)
+        std::clog << "  Dependencies are not satisfied for " << I << std::endl;
+      return true;
+   }
+
+   // a newly broken policy (recommends/suggests) is a problem
+   if (Cache[I].NowPolicyBroken() == false &&
+       Cache[I].InstPolicyBroken() == true)
+   {
+      if (Debug == true)
+        std::clog << "  Policy breaks with upgrade of " << I << std::endl;
+      return true;
+   }
+
+   return false;
+}
+                                                                       /*}}}*/
 // ProblemResolver::ResolveByKeep - Resolve problems using keep                /*{{{*/
 // ---------------------------------------------------------------------
 /* This is the work horse of the soft upgrade routine. It is very gental 
@@ -1238,7 +1321,7 @@ bool pkgProblemResolver::ResolveByKeepInternal()
       would cause the removal of even lower score packages. */
    pkgCache::Package **PList = new pkgCache::Package *[Size];
    pkgCache::Package **PEnd = PList;
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
       *PEnd++ = I;
    This = this;
    qsort(PList,PEnd - PList,sizeof(*PList),&ScoreSort);
@@ -1263,9 +1346,12 @@ bool pkgProblemResolver::ResolveByKeepInternal()
    {
       pkgCache::PkgIterator I(Cache,*K);
 
-      if (Cache[I].InstallVer == 0 || Cache[I].InstBroken() == false)
+      if (Cache[I].InstallVer == 0)
         continue;
 
+      if (InstOrNewPolicyBroken(I) == false)
+         continue;
+
       /* Keep the package. If this works then great, otherwise we have
                 to be significantly more agressive and manipulate its dependencies */
       if ((Flags[I->ID] & Protected) == 0)
@@ -1273,7 +1359,7 @@ bool pkgProblemResolver::ResolveByKeepInternal()
         if (Debug == true)
            clog << "Keeping package " << I.FullName(false) << endl;
         Cache.MarkKeep(I, false, false);
-        if (Cache[I].InstBroken() == false)
+        if (InstOrNewPolicyBroken(I) == false)
         {
            K = PList - 1;
            continue;
@@ -1323,43 +1409,51 @@ bool pkgProblemResolver::ResolveByKeepInternal()
                  Cache.MarkKeep(Pkg, false, false);
               }
               
-              if (Cache[I].InstBroken() == false)
+              if (InstOrNewPolicyBroken(I) == false)
                  break;
            }
            
-           if (Cache[I].InstBroken() == false)
+           if (InstOrNewPolicyBroken(I) == false)
               break;
 
            if (Start == End)
               break;
-           Start++;
+           ++Start;
         }
              
-        if (Cache[I].InstBroken() == false)
+        if (InstOrNewPolicyBroken(I) == false)
            break;
       }
 
-      if (Cache[I].InstBroken() == true)
+      if (InstOrNewPolicyBroken(I) == true)
         continue;
       
       // Restart again.
-      if (K == LastStop)
-        return _error->Error("Internal Error, pkgProblemResolver::ResolveByKeep is looping on package %s.",I.FullName(false).c_str());
+      if (K == LastStop) {
+          // I is an iterator based off our temporary package list,
+          // so copy the name we need before deleting the temporary list
+          std::string const LoopingPackage = I.FullName(false);
+          delete[] PList;
+          return _error->Error("Internal Error, pkgProblemResolver::ResolveByKeep is looping on package %s.", LoopingPackage.c_str());
+      }
       LastStop = K;
       K = PList - 1;
-   }   
+   }
 
+   delete[] PList;
    return true;
 }
                                                                        /*}}}*/
-// ProblemResolver::InstallProtect - Install all protected packages    /*{{{*/
+// ProblemResolver::InstallProtect - deprecated cpu-eating no-op       /*{{{*/
 // ---------------------------------------------------------------------
-/* This is used to make sure protected packages are installed */
+/* Actions issued with FromUser bit set are protected from further
+   modification (expect by other calls with FromUser set) nowadays , so we
+   don't need to reissue actions here, they are already set in stone. */
 void pkgProblemResolver::InstallProtect()
 {
    pkgDepCache::ActionGroup group(Cache);
 
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
    {
       if ((Flags[I->ID] & Protected) == Protected)
       {
@@ -1392,6 +1486,13 @@ static int PrioComp(const void *A,const void *B)
    if ((L.ParentPkg()->Flags & pkgCache::Flag::Essential) != pkgCache::Flag::Essential &&
        (R.ParentPkg()->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
      return -1;
+
+   if ((L.ParentPkg()->Flags & pkgCache::Flag::Important) == pkgCache::Flag::Important &&
+       (R.ParentPkg()->Flags & pkgCache::Flag::Important) != pkgCache::Flag::Important)
+     return 1;
+   if ((L.ParentPkg()->Flags & pkgCache::Flag::Important) != pkgCache::Flag::Important &&
+       (R.ParentPkg()->Flags & pkgCache::Flag::Important) == pkgCache::Flag::Important)
+     return -1;
    
    if (L->Priority != R->Priority)
       return R->Priority - L->Priority;
@@ -1406,7 +1507,7 @@ void pkgPrioSortList(pkgCache &Cache,pkgCache::Version **List)
    qsort(List,Count,sizeof(*List),PrioComp);
 }
                                                                        /*}}}*/
-// CacheFile::ListUpdate - update the cache files                      /*{{{*/
+// ListUpdate - construct Fetcher and 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)
@@ -1415,7 +1516,6 @@ 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;
@@ -1424,11 +1524,24 @@ bool ListUpdate(pkgAcquireStatus &Stat,
    if (List.GetIndexes(&Fetcher) == false)
         return false;
 
+   return AcquireUpdate(Fetcher, PulseInterval, true);
+}
+                                                                       /*}}}*/
+// AcquireUpdate - take Fetcher and update the cache files             /*{{{*/
+// ---------------------------------------------------------------------
+/* This is a simple wrapper to update the cache with a provided acquire
+ * If you only need control over Status and the used SourcesList use
+ * ListUpdate method instead.
+ */
+bool AcquireUpdate(pkgAcquire &Fetcher, int const PulseInterval,
+                  bool const RunUpdateScripts, bool const ListCleanup)
+{
    // Run scripts
-   RunScripts("APT::Update::Pre-Invoke");
-   
-   // check arguments
-   if(PulseInterval>0)
+   if (RunUpdateScripts == true)
+      RunScripts("APT::Update::Pre-Invoke");
+
+   pkgAcquire::RunResult res;
+   if(PulseInterval > 0)
       res = Fetcher.Run(PulseInterval);
    else
       res = Fetcher.Run();
@@ -1439,7 +1552,7 @@ bool ListUpdate(pkgAcquireStatus &Stat,
    bool Failed = false;
    bool TransientNetworkFailure = false;
    for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin(); 
-       I != Fetcher.ItemsEnd(); I++)
+       I != Fetcher.ItemsEnd(); ++I)
    {
       if ((*I)->Status == pkgAcquire::Item::StatDone)
         continue;
@@ -1465,7 +1578,7 @@ bool ListUpdate(pkgAcquireStatus &Stat,
    // 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 &&
+   if (!TransientNetworkFailure && !Failed && ListCleanup == true &&
        (_config->FindB("APT::Get::List-Cleanup",true) == true &&
        _config->FindB("APT::List-Cleanup",true) == true))
    {
@@ -1482,11 +1595,14 @@ bool ListUpdate(pkgAcquireStatus &Stat,
 
 
    // Run the success scripts if all was fine
-   if(!TransientNetworkFailure && !Failed)
-      RunScripts("APT::Update::Post-Invoke-Success");
+   if (RunUpdateScripts == true)
+   {
+      if(!TransientNetworkFailure && !Failed)
+        RunScripts("APT::Update::Post-Invoke-Success");
 
-   // Run the other scripts
-   RunScripts("APT::Update::Post-Invoke");
+      // Run the other scripts
+      RunScripts("APT::Update::Post-Invoke");
+   }
    return true;
 }
                                                                        /*}}}*/