]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/algorithms.cc
implement StringSplit() as we need this to fix the dpkg status-fd output parsing
[apt.git] / apt-pkg / algorithms.cc
index 44cba8d929709725c466c54063461b364ce6cdea..69d4acd83d621a8776d4124940f8fb8b1d697d56 100644 (file)
    ##################################################################### */
                                                                        /*}}}*/
 // Include Files                                                       /*{{{*/
    ##################################################################### */
                                                                        /*}}}*/
 // Include Files                                                       /*{{{*/
+#include <config.h>
+
 #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 <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 <apt-pkg/edsp.h>
+#include <apt-pkg/sourcelist.h>
+#include <apt-pkg/fileutl.h>
+#include <apt-pkg/progress.h>
+
 #include <sys/types.h>
 #include <cstdlib>
 #include <algorithm>
 #include <iostream>
 #include <sys/types.h>
 #include <cstdlib>
 #include <algorithm>
 #include <iostream>
+#include <stdio.h>
+
+#include <apti18n.h>
                                                                        /*}}}*/
 using namespace std;
 
                                                                        /*}}}*/
 using namespace std;
 
@@ -50,6 +58,12 @@ pkgSimulate::pkgSimulate(pkgDepCache *Cache) : pkgPackageManager(Cache),
       FileNames[I] = Jnk;
 }
                                                                        /*}}}*/
       FileNames[I] = Jnk;
 }
                                                                        /*}}}*/
+// Simulate::~Simulate - Destructor                                    /*{{{*/
+pkgSimulate::~pkgSimulate()
+{
+   delete[] Flags;
+}
+                                                                       /*}}}*/
 // Simulate::Describe - Describe a package                             /*{{{*/
 // ---------------------------------------------------------------------
 /* Parameter Current == true displays the current package version,
 // Simulate::Describe - Describe a package                             /*{{{*/
 // ---------------------------------------------------------------------
 /* Parameter Current == true displays the current package version,
@@ -180,6 +194,11 @@ bool pkgSimulate::Remove(PkgIterator iPkg,bool Purge)
 {
    // Adapt the iterator
    PkgIterator Pkg = Sim.FindPkg(iPkg.Name(), iPkg.Arch());
 {
    // 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);
 
    Flags[Pkg->ID] = 3;
    Sim.MarkDelete(Pkg);
@@ -268,13 +287,13 @@ bool pkgApplyStatus(pkgDepCache &Cache)
                 Cache[I].CandidateVerIter(Cache).Downloadable() == true)
               Cache.MarkInstall(I, true, 0, false);
            else
                 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:
         }
         break;
 
         // This means removal failed
         case pkgCache::State::HalfInstalled:
-        Cache.MarkDelete(I);
+        Cache.MarkDelete(I, false, 0, false);
         break;
         
         default:
         break;
         
         default:
@@ -327,6 +346,12 @@ bool pkgFixBroken(pkgDepCache &Cache)
  */
 bool pkgDistUpgrade(pkgDepCache &Cache)
 {
  */
 bool pkgDistUpgrade(pkgDepCache &Cache)
 {
+   std::string const solver = _config->Find("APT::Solver", "internal");
+   if (solver != "internal") {
+      OpTextProgress Prog(*_config);
+      return EDSP::ResolveExternal(solver.c_str(), Cache, false, true, false, &Prog);
+   }
+
    pkgDepCache::ActionGroup group(Cache);
 
    /* Upgrade all installed packages first without autoinst to help the resolver
    pkgDepCache::ActionGroup group(Cache);
 
    /* Upgrade all installed packages first without autoinst to help the resolver
@@ -342,11 +367,36 @@ bool pkgDistUpgrade(pkgDepCache &Cache)
       if (I->CurrentVer != 0)
         Cache.MarkInstall(I, true, 0, false);
 
       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. */
    
    /* We do it again over all previously installed packages to force 
       conflict resolution on them all. */
@@ -379,6 +429,12 @@ bool pkgDistUpgrade(pkgDepCache &Cache)
    to install packages not marked for install */
 bool pkgAllUpgrade(pkgDepCache &Cache)
 {
    to install packages not marked for install */
 bool pkgAllUpgrade(pkgDepCache &Cache)
 {
+   std::string const solver = _config->Find("APT::Solver", "internal");
+   if (solver != "internal") {
+      OpTextProgress Prog(*_config);
+      return EDSP::ResolveExternal(solver.c_str(), Cache, true, false, false, &Prog);
+   }
+
    pkgDepCache::ActionGroup group(Cache);
 
    pkgProblemResolver Fix(&Cache);
    pkgDepCache::ActionGroup group(Cache);
 
    pkgProblemResolver Fix(&Cache);
@@ -400,6 +456,49 @@ bool pkgAllUpgrade(pkgDepCache &Cache)
         Cache.MarkInstall(I, false, 0, false);
    }
       
         Cache.MarkInstall(I, false, 0, false);
    }
       
+   return Fix.ResolveByKeep();
+}
+                                                                       /*}}}*/
+// AllUpgradeNoDelete - Upgrade without removing packages              /*{{{*/
+// ---------------------------------------------------------------------
+/* Right now the system must be consistent before this can be called.
+ * Upgrade as much as possible without deleting anything (useful for
+ * stable systems)
+ */
+bool pkgAllUpgradeNoDelete(pkgDepCache &Cache)
+{
+   pkgDepCache::ActionGroup group(Cache);
+
+   pkgProblemResolver Fix(&Cache);
+
+   if (Cache.BrokenCount() != 0)
+      return false;
+
+   // provide the initial set of stuff we want to upgrade by marking
+   // all upgradable packages for upgrade
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
+   {
+      if (I->CurrentVer != 0 && Cache[I].InstallVer != 0)
+      {
+         if (_config->FindB("APT::Ignore-Hold",false) == false)
+            if (I->SelectedState == pkgCache::State::Hold)
+               continue;
+
+        Cache.MarkInstall(I, false, 0, false);
+      }
+   }
+
+   // then let auto-install loose
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
+      if (Cache[I].Install())
+        Cache.MarkInstall(I, true, 0, false);
+
+   // ... but it may remove stuff, we we need to clean up afterwards again
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
+      if (Cache[I].Delete() == true)
+        Cache.MarkKeep(I, false, false);
+
+   // resolve remaining issues via keep
    return Fix.ResolveByKeep();
 }
                                                                        /*}}}*/
    return Fix.ResolveByKeep();
 }
                                                                        /*}}}*/
@@ -451,11 +550,11 @@ bool pkgMinimizeUpgrade(pkgDepCache &Cache)
 // ProblemResolver::pkgProblemResolver - Constructor                   /*{{{*/
 // ---------------------------------------------------------------------
 /* */
 // 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;
 {
    // 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);
    
    Flags = new unsigned char[Size];
    memset(Flags,0,sizeof(*Flags)*Size);
    
@@ -494,29 +593,30 @@ void pkgProblemResolver::MakeScores()
    unsigned long Size = Cache.Head().PackageCount;
    memset(Scores,0,sizeof(*Scores)*Size);
 
    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: 
+   //    Required Important Standard Optional Extra
+   int PrioMap[] = {
       0,
       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::Required",3),
+      _config->FindI("pkgProblemResolver::Scores::Important",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);
+   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
 
    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
          << "  Essentials => " << PrioEssentials << endl
          << "  InstalledAndNotObsolete => " << PrioInstalledAndNotObsolete << endl
          << "  Depends => " << PrioDepends << endl
@@ -530,13 +630,14 @@ void pkgProblemResolver::MakeScores()
       if (Cache[I].InstallVer == 0)
         continue;
       
       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) */
       
       /* 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
         Score += PrioEssentials;
 
       // We transform the priority
@@ -568,7 +669,7 @@ void pkgProblemResolver::MakeScores()
    }   
    
    // Copy the scores to advoid additive looping
    }   
    
    // 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 
    memcpy(OldScores,Scores,sizeof(*Scores)*Size);
       
    /* Now we cause 1 level of dependency inheritance, that is we add the 
@@ -588,7 +689,10 @@ void pkgProblemResolver::MakeScores()
              D->Type != pkgCache::Dep::Recommends))
            continue;    
         
              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];
       }      
    }
 
       }      
    }
 
@@ -611,7 +715,8 @@ void pkgProblemResolver::MakeScores()
    {
       if ((Flags[I->ID] & Protected) != 0)
         Scores[I->ID] += AddProtected;
    {
       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;
    }
 }
         Scores[I->ID] += AddEssential;
    }
 }
@@ -716,7 +821,7 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg)
       if (WasKept == true)
         Cache.MarkKeep(Pkg, false, false);
       else
       if (WasKept == true)
         Cache.MarkKeep(Pkg, false, false);
       else
-        Cache.MarkDelete(Pkg);
+        Cache.MarkDelete(Pkg, false, 0, false);
       return false;
    }    
    
       return false;
    }    
    
@@ -725,7 +830,20 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg)
    return true;
 }
                                                                        /*}}}*/
    return true;
 }
                                                                        /*}}}*/
-// ProblemResolver::Resolve - Run the resolution pass                  /*{{{*/
+// ProblemResolver::Resolve - calls a resolver to fix the situation    /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool pkgProblemResolver::Resolve(bool BrokenFix)
+{
+   std::string const solver = _config->Find("APT::Solver", "internal");
+   if (solver != "internal") {
+      OpTextProgress Prog(*_config);
+      return EDSP::ResolveExternal(solver.c_str(), Cache, false, false, false, &Prog);
+   }
+   return ResolveInternal(BrokenFix);
+}
+                                                                       /*}}}*/
+// ProblemResolver::ResolveInternal - Run the resolution pass          /*{{{*/
 // ---------------------------------------------------------------------
 /* This routines works by calculating a score for each package. The score
    is derived by considering the package's priority and all reverse 
 // ---------------------------------------------------------------------
 /* This routines works by calculating a score for each package. The score
    is derived by considering the package's priority and all reverse 
@@ -739,12 +857,10 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg)
  
    The BrokenFix flag enables a mode where the algorithm tries to 
    upgrade packages to advoid problems. */
  
    The BrokenFix flag enables a mode where the algorithm tries to 
    upgrade packages to advoid problems. */
-bool pkgProblemResolver::Resolve(bool BrokenFix)
+bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
 {
    pkgDepCache::ActionGroup group(Cache);
 
 {
    pkgDepCache::ActionGroup group(Cache);
 
-   unsigned long Size = Cache.Head().PackageCount;
-
    // Record which packages are marked for install
    bool Again = false;
    do
    // Record which packages are marked for install
    bool Again = false;
    do
@@ -770,11 +886,15 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
    }
    while (Again == true);
 
    }
    while (Again == true);
 
-   if (Debug == true)
-      clog << "Starting" << endl;
+   if (Debug == true) {
+      clog << "Starting pkgProblemResolver with broken count: " 
+           << Cache.BrokenCount() << endl;
+   }
    
    MakeScores();
    
    MakeScores();
-   
+
+   unsigned long const Size = Cache.Head().PackageCount;
+
    /* We have to order the packages so that the broken fixing pass 
       operates from highest score to lowest. This prevents problems when
       high score packages cause the removal of lower score packages that
    /* We have to order the packages so that the broken fixing pass 
       operates from highest score to lowest. This prevents problems when
       high score packages cause the removal of lower score packages that
@@ -797,8 +917,10 @@ bool pkgProblemResolver::Resolve(bool 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
 
    /* 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
@@ -832,7 +954,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
                OldBreaks < Cache.BrokenCount())
            {
               if (OldVer == 0)
                OldBreaks < Cache.BrokenCount())
            {
               if (OldVer == 0)
-                 Cache.MarkDelete(I);
+                 Cache.MarkDelete(I, false, 0, false);
               else
                  Cache.MarkKeep(I, false, false);
            }       
               else
                  Cache.MarkKeep(I, false, false);
            }       
@@ -871,7 +993,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
                     {
                        if (Debug == true)
                           clog << "  Or group remove for " << I.FullName(false) << endl;
                     {
                        if (Debug == true)
                           clog << "  Or group remove for " << I.FullName(false) << endl;
-                       Cache.MarkDelete(I);
+                       Cache.MarkDelete(I, false, 0, false);
                        Change = true;
                     }
                  }
                        Change = true;
                     }
                  }
@@ -1006,7 +1128,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
                        {
                           if (Debug == true)
                              clog << "  Removing " << I.FullName(false) << " rather than change " << Start.TargetPkg().FullName(false) << endl;
                        {
                           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];
                        }
                           if (Counter > 1 && Scores[Pkg->ID] > Scores[I->ID])
                              Scores[I->ID] = Scores[Pkg->ID];
                        }
@@ -1065,8 +1187,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
                  LEnd->Dep = End;
                  LEnd++;
                  
                  LEnd->Dep = End;
                  LEnd++;
                  
-                 if (Start->Type != pkgCache::Dep::Conflicts &&
-                     Start->Type != pkgCache::Dep::Obsoletes)
+                 if (Start.IsNegative() == false)
                     break;
               }
            }
                     break;
               }
            }
@@ -1096,7 +1217,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
                  if (Debug == true)
                     clog << "  Removing " << I.FullName(false) << " because I can't find " << Start.TargetPkg().FullName(false) << endl;
                  if (InOr == false)
                  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;
               }
 
               Change = true;
@@ -1123,7 +1244,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
                  {
                     if (Debug == true)
                        clog << "  Fixing " << I.FullName(false) << " via remove of " << J->Pkg.FullName(false) << endl;
                  {
                     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
                  }
               }
               else
@@ -1176,7 +1297,6 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
    return true;
 }
                                                                        /*}}}*/
    return true;
 }
                                                                        /*}}}*/
-
 // ProblemResolver::BreaksInstOrPolicy - Check if the given pkg is broken/*{{{*/
 // ---------------------------------------------------------------------
 /* This checks if the given package is broken either by a hard dependency
 // ProblemResolver::BreaksInstOrPolicy - Check if the given pkg is broken/*{{{*/
 // ---------------------------------------------------------------------
 /* This checks if the given package is broken either by a hard dependency
@@ -1207,13 +1327,28 @@ bool pkgProblemResolver::InstOrNewPolicyBroken(pkgCache::PkgIterator I)
 
    return false;
 }
 
    return false;
 }
-
+                                                                       /*}}}*/
 // ProblemResolver::ResolveByKeep - Resolve problems using keep                /*{{{*/
 // ---------------------------------------------------------------------
 /* This is the work horse of the soft upgrade routine. It is very gental 
    in that it does not install or remove any packages. It is assumed that the
    system was non-broken previously. */
 bool pkgProblemResolver::ResolveByKeep()
 // ProblemResolver::ResolveByKeep - Resolve problems using keep                /*{{{*/
 // ---------------------------------------------------------------------
 /* This is the work horse of the soft upgrade routine. It is very gental 
    in that it does not install or remove any packages. It is assumed that the
    system was non-broken previously. */
 bool pkgProblemResolver::ResolveByKeep()
+{
+   std::string const solver = _config->Find("APT::Solver", "internal");
+   if (solver != "internal") {
+      OpTextProgress Prog(*_config);
+      return EDSP::ResolveExternal(solver.c_str(), Cache, true, false, false, &Prog);
+   }
+   return ResolveByKeepInternal();
+}
+                                                                       /*}}}*/
+// ProblemResolver::ResolveByKeepInternal - Resolve problems using keep        /*{{{*/
+// ---------------------------------------------------------------------
+/* This is the work horse of the soft upgrade routine. It is very gental
+   in that it does not install or remove any packages. It is assumed that the
+   system was non-broken previously. */
+bool pkgProblemResolver::ResolveByKeepInternal()
 {
    pkgDepCache::ActionGroup group(Cache);
 
 {
    pkgDepCache::ActionGroup group(Cache);
 
@@ -1335,18 +1470,26 @@ bool pkgProblemResolver::ResolveByKeep()
         continue;
       
       // Restart again.
         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;
       LastStop = K;
       K = PList - 1;
-   }   
+   }
 
 
+   delete[] PList;
    return true;
 }
                                                                        /*}}}*/
    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);
 void pkgProblemResolver::InstallProtect()
 {
    pkgDepCache::ActionGroup group(Cache);
@@ -1384,6 +1527,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::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;
    
    if (L->Priority != R->Priority)
       return R->Priority - L->Priority;
@@ -1398,7 +1548,7 @@ void pkgPrioSortList(pkgCache &Cache,pkgCache::Version **List)
    qsort(List,Count,sizeof(*List),PrioComp);
 }
                                                                        /*}}}*/
    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)
 // ---------------------------------------------------------------------
 /* This is a simple wrapper to update the cache. it will fetch stuff
  * from the network (or any other sources defined in sources.list)
@@ -1407,7 +1557,6 @@ bool ListUpdate(pkgAcquireStatus &Stat,
                pkgSourceList &List, 
                int PulseInterval)
 {
                pkgSourceList &List, 
                int PulseInterval)
 {
-   pkgAcquire::RunResult res;
    pkgAcquire Fetcher;
    if (Fetcher.Setup(&Stat, _config->FindDir("Dir::State::Lists")) == false)
       return false;
    pkgAcquire Fetcher;
    if (Fetcher.Setup(&Stat, _config->FindDir("Dir::State::Lists")) == false)
       return false;
@@ -1416,11 +1565,24 @@ bool ListUpdate(pkgAcquireStatus &Stat,
    if (List.GetIndexes(&Fetcher) == false)
         return false;
 
    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
    // 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();
       res = Fetcher.Run(PulseInterval);
    else
       res = Fetcher.Run();
@@ -1457,7 +1619,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
    // 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))
    {
        (_config->FindB("APT::Get::List-Cleanup",true) == true &&
        _config->FindB("APT::List-Cleanup",true) == true))
    {
@@ -1474,11 +1636,14 @@ bool ListUpdate(pkgAcquireStatus &Stat,
 
 
    // Run the success scripts if all was fine
 
 
    // 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;
 }
                                                                        /*}}}*/
    return true;
 }
                                                                        /*}}}*/