]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/algorithms.cc
Fixed doc reference
[apt.git] / apt-pkg / algorithms.cc
index e3012489d376878cf2f80b837d948c75d25db44b..350b574682a5881c5da7d9a4345904a9080e8257 100644 (file)
@@ -1,19 +1,25 @@
 // -*- mode: cpp; mode: fold -*-
 // Description                                                         /*{{{*/
-// $Id: algorithms.cc,v 1.1 1998/07/07 04:17:00 jgg Exp $
+// $Id: algorithms.cc,v 1.8 1998/10/24 04:58:04 jgg Exp $
 /* ######################################################################
 
    Algorithms - A set of misc algorithms
 
+   The pkgProblemResolver class has become insanely complex and
+   very sophisticated, it handles every test case I have thrown at it
+   to my satisfaction. Understanding exactly why all the steps the class
+   does are required is difficult and changing though not very risky
+   may result in other cases not working.
+   
    ##################################################################### */
                                                                        /*}}}*/
 // Include Files                                                       /*{{{*/
 #ifdef __GNUG__
-#pragma implementation "pkglib/algorithms.h"
+#pragma implementation "apt-pkg/algorithms.h"
 #endif 
-#include <pkglib/algorithms.h>
-#include <pkglib/error.h>
-#include <pkglib/pkgelement.h>
+#include <apt-pkg/algorithms.h>
+#include <apt-pkg/error.h>
+#include <apt-pkg/configuration.h>
 #include <iostream.h>
                                                                        /*}}}*/
 
@@ -23,7 +29,7 @@ pkgProblemResolver *pkgProblemResolver::This = 0;
 // ---------------------------------------------------------------------
 /* */
 pkgSimulate::pkgSimulate(pkgDepCache &Cache) : pkgPackageManager(Cache), 
-                            Sim(true,true)
+                            Sim(Cache)
 {
    Flags = new unsigned char[Cache.HeaderP->PackageCount];
    memset(Flags,0,sizeof(*Flags)*Cache.HeaderP->PackageCount);
@@ -38,7 +44,7 @@ bool pkgSimulate::Install(PkgIterator iPkg,string /*File*/)
    PkgIterator Pkg = Sim.FindPkg(iPkg.Name());
    Flags[Pkg->ID] = 1;
    
-   cout << "Inst " << Pkg.Name();
+   clog << "Inst " << Pkg.Name();
    Sim.MarkInstall(Pkg,false);
    
    // Look for broken conflicts+predepends.
@@ -48,12 +54,12 @@ bool pkgSimulate::Install(PkgIterator iPkg,string /*File*/)
         continue;
       
       for (DepIterator D = Sim[I].InstVerIter(Sim).DependsList(); D.end() == false; D++)
-        if (D->Type == pkgDEP_Conflicts || D->Type == pkgDEP_PreDepends)
+        if (D->Type == pkgCache::Dep::Conflicts || D->Type == pkgCache::Dep::PreDepends)
          {
            if ((Sim[D] & pkgDepCache::DepInstall) == 0)
            {
-              cout << " [" << I.Name() << " on " << D.TargetPkg().Name() << ']';
-              if (D->Type == pkgDEP_Conflicts)
+              clog << " [" << I.Name() << " on " << D.TargetPkg().Name() << ']';
+              if (D->Type == pkgCache::Dep::Conflicts)
                  _error->Error("Fatal, conflicts violated %s",I.Name());
            }       
         }      
@@ -62,7 +68,7 @@ bool pkgSimulate::Install(PkgIterator iPkg,string /*File*/)
    if (Sim.BrokenCount() != 0)
       ShortBreaks();
    else
-      cout << endl;
+      clog << endl;
    return true;
 }
                                                                        /*}}}*/
@@ -80,7 +86,7 @@ bool pkgSimulate::Configure(PkgIterator iPkg)
 //   Sim.MarkInstall(Pkg,false);
    if (Sim[Pkg].InstBroken() == true)
    {
-      cout << "Conf " << Pkg.Name() << " broken" << endl;
+      clog << "Conf " << Pkg.Name() << " broken" << endl;
 
       Sim.Update();
       
@@ -91,22 +97,22 @@ bool pkgSimulate::Configure(PkgIterator iPkg)
             (Sim[D] & pkgDepCache::DepInstall) != 0)
            continue;
         
-        if (D->Type == pkgDEP_Conflicts)
-           cout << " Conflicts:" << D.TargetPkg().Name();
+        if (D->Type == pkgCache::Dep::Conflicts)
+           clog << " Conflicts:" << D.TargetPkg().Name();
         else
-           cout << " Depends:" << D.TargetPkg().Name();
+           clog << " Depends:" << D.TargetPkg().Name();
       }            
-      cout << endl;
+      clog << endl;
 
       _error->Error("Conf Broken %s",Pkg.Name());
    }   
    else
-      cout << "Conf " <<  Pkg.Name();
+      clog << "Conf " <<  Pkg.Name();
 
    if (Sim.BrokenCount() != 0)
       ShortBreaks();
    else
-      cout << endl;
+      clog << endl;
    
    return true;
 }
@@ -121,12 +127,12 @@ bool pkgSimulate::Remove(PkgIterator iPkg)
 
    Flags[Pkg->ID] = 3;
    Sim.MarkDelete(Pkg);
-   cout << "Remv " << Pkg.Name();
+   clog << "Remv " << Pkg.Name();
 
    if (Sim.BrokenCount() != 0)
       ShortBreaks();
    else
-      cout << endl;
+      clog << endl;
 
    return true;
 }
@@ -136,18 +142,18 @@ bool pkgSimulate::Remove(PkgIterator iPkg)
 /* */
 void pkgSimulate::ShortBreaks()
 {
-   cout << " [";
+   clog << " [";
    for (PkgIterator I = Sim.PkgBegin(); I.end() == false; I++)
    {
       if (Sim[I].InstBroken() == true)
       {
         if (Flags[I->ID] == 0)
-           cout << I.Name() << ' ';
+           clog << I.Name() << ' ';
 /*      else
-           cout << I.Name() << "! ";*/
+           clog << I.Name() << "! ";*/
       }      
    }
-   cout << ']' << endl;
+   clog << ']' << endl;
 }
                                                                        /*}}}*/
 // ApplyStatus - Adjust for non-ok packages                            /*{{{*/
@@ -162,18 +168,18 @@ bool pkgApplyStatus(pkgDepCache &Cache)
       switch (I->CurrentState)
       {
         // This means installation failed somehow
-        case pkgSTATE_UnPacked:
-        case pkgSTATE_HalfConfigured:
+        case pkgCache::State::UnPacked:
+        case pkgCache::State::HalfConfigured:
         Cache.MarkKeep(I);
         break;
 
         // This means removal failed
-        case pkgSTATE_HalfInstalled:
+        case pkgCache::State::HalfInstalled:
         Cache.MarkDelete(I);
         break;
         
         default:
-        if (I->InstState != pkgSTATE_Ok)
+        if (I->InstState != pkgCache::State::Ok)
            return _error->Error("The package %s is not ok and I "
                                 "don't know how to fix it!",I.Name());
       }
@@ -183,15 +189,15 @@ bool pkgApplyStatus(pkgDepCache &Cache)
                                                                        /*}}}*/
 // FixBroken - Fix broken packages                                     /*{{{*/
 // ---------------------------------------------------------------------
-/* This autoinstalls every broken package and then runs ScoredFix on the 
-   result. */
+/* This autoinstalls every broken package and then runs the problem resolver
+   on the result. */
 bool pkgFixBroken(pkgDepCache &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);
-
+   
    /* 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++)
@@ -200,10 +206,10 @@ bool pkgFixBroken(pkgDepCache &Cache)
          Cache[I].Delete() == true)
         continue;
       
-      if ((Cache[I].InstVerIter(Cache).File()->Flags & pkgFLAG_NotSource) == 0)
+      if (Cache[I].InstVerIter(Cache).Downloadable() == false)
         continue;
 
-      Cache.MarkInstall(I,true);
+      Cache.MarkInstall(I,true);      
    }
    
    pkgProblemResolver Fix(Cache);
@@ -216,7 +222,7 @@ bool pkgFixBroken(pkgDepCache &Cache)
    pre-existing package. This creates the initial set of conditions which 
    most likely contain problems because too many things were installed.
    
-   ScoredFix is used to resolve the problems.
+   The problem resolver is used to resolve the problems.
  */
 bool pkgDistUpgrade(pkgDepCache &Cache)
 {
@@ -229,7 +235,7 @@ bool pkgDistUpgrade(pkgDepCache &Cache)
    /* 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 & pkgFLAG_Essential) == pkgFLAG_Essential)
+      if ((I->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
         Cache.MarkInstall(I,true);
    
    /* We do it again over all previously installed packages to force 
@@ -239,20 +245,89 @@ bool pkgDistUpgrade(pkgDepCache &Cache)
         Cache.MarkInstall(I,false);
 
    pkgProblemResolver Fix(Cache);
-   
+
    // Hold back held packages.
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   if (_config->FindB("APT::Ingore-Hold",false) == false)
    {
-      if (I->SelectedState == pkgSTATE_Hold)
+      for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
       {
-        Fix.Protect(I);
-        Cache.MarkKeep(I);
+        if (I->SelectedState == pkgCache::State::Hold)
+        {
+           Fix.Protect(I);
+           Cache.MarkKeep(I);
+        }
       }
    }
    
    return Fix.Resolve();
 }
                                                                        /*}}}*/
+// AllUpgrade - Upgrade as many packages as possible                   /*{{{*/
+// ---------------------------------------------------------------------
+/* Right now the system must be consistent before this can be called.
+   It also will not change packages marked for install, it only tries
+   to install packages not marked for install */
+bool pkgAllUpgrade(pkgDepCache &Cache)
+{
+   pkgProblemResolver Fix(Cache);
+
+   if (Cache.BrokenCount() != 0)
+      return false;
+   
+   // Upgrade all installed packages
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   {
+      if (Cache[I].Install() == true)
+        Fix.Protect(I);
+         
+      if (_config->FindB("APT::Ingore-Hold",false) == false)
+        if (I->SelectedState == pkgCache::State::Hold)
+           continue;
+      
+      if (I->CurrentVer != 0 && Cache[I].InstallVer != 0)
+        Cache.MarkInstall(I,false);
+   }
+      
+   return Fix.ResolveByKeep();
+}
+                                                                       /*}}}*/
+// MinimizeUpgrade - Minimizes the set of packages to be upgraded      /*{{{*/
+// ---------------------------------------------------------------------
+/* This simply goes over the entire set of packages and tries to keep 
+   each package marked for upgrade. If a conflict is generated then 
+   the package is restored. */
+bool pkgMinimizeUpgrade(pkgDepCache &Cache)
+{   
+   if (Cache.BrokenCount() != 0)
+      return false;
+   
+   // We loop indefinately to get the minimal set size.
+   bool Change = false;
+   do
+   {
+      Change = false;
+      for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+      {
+        // Not interesting
+        if (Cache[I].Upgrade() == false || Cache[I].NewInstall() == true)
+           continue;
+        
+        // Keep it and see if that is OK
+        Cache.MarkKeep(I);
+        if (Cache.BrokenCount() != 0)
+           Cache.MarkInstall(I,false);
+        else
+           Change = true;
+      }      
+   }
+   while (Change == true);
+
+   if (Cache.BrokenCount() != 0)
+      return _error->Error("Internal Error in pkgMinimizeUpgrade");
+   
+   return true;
+}
+                                                                       /*}}}*/
 
 // ProblemResolver::pkgProblemResolver - Constructor                   /*{{{*/
 // ---------------------------------------------------------------------
@@ -266,7 +341,7 @@ pkgProblemResolver::pkgProblemResolver(pkgDepCache &Cache) : Cache(Cache)
    memset(Flags,0,sizeof(*Flags)*Size);
    
    // Set debug to true to see its decision logic
-   Debug = false;
+   Debug = _config->FindB("Debug::pkgProblemResolver",false);
 }
                                                                        /*}}}*/
 // ProblemResolver::ScoreSort - Sort the list by score                 /*{{{*/
@@ -303,7 +378,7 @@ void pkgProblemResolver::MakeScores()
          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 & pkgFLAG_Essential) == pkgFLAG_Essential)
+      if ((I->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
         Score += 100;
 
       // We transform the priority
@@ -326,7 +401,7 @@ void pkgProblemResolver::MakeScores()
       
       for (pkgCache::DepIterator D = Cache[I].InstVerIter(Cache).DependsList(); D.end() == false; D++)
       {
-        if (D->Type == pkgDEP_Depends || D->Type == pkgDEP_PreDepends)
+        if (D->Type == pkgCache::Dep::Depends || D->Type == pkgCache::Dep::PreDepends)
            Scores[D.TargetPkg()->ID]++;
       }
    }   
@@ -347,7 +422,7 @@ void pkgProblemResolver::MakeScores()
       {
         // Only do it for the install version
         if ((pkgCache::Version *)D.ParentVer() != Cache[D.ParentPkg()].InstallVer ||
-            (D->Type != pkgDEP_Depends && D->Type != pkgDEP_PreDepends))
+            (D->Type != pkgCache::Dep::Depends && D->Type != pkgCache::Dep::PreDepends))
            continue;    
         
         Scores[I->ID] += abs(OldScores[D.ParentPkg()->ID]);
@@ -384,11 +459,16 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg)
 {
    if ((Flags[Pkg->ID] & Upgradable) == 0 || Cache[Pkg].Upgradable() == false)
       return false;
+   
    Flags[Pkg->ID] &= ~Upgradable;
    
    bool WasKept = Cache[Pkg].Keep();
    Cache.MarkInstall(Pkg,false);
 
+   // This must be a virtual package or something like that.
+   if (Cache[Pkg].InstVerIter(Cache).end() == true)
+      return false;
+   
    // Isolate the problem dependency
    bool Fail = false;
    for (pkgCache::DepIterator D = Cache[Pkg].InstVerIter(Cache).DependsList(); D.end() == false;)
@@ -400,7 +480,7 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg)
       for (bool LastOR = true; D.end() == false && LastOR == true; D++)
       {
         State |= Cache[D];
-        LastOR = (D->CompareOp & pkgOP_OR) == pkgOP_OR;
+        LastOR = (D->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or;
         if (LastOR == true)
            End = D;
       }
@@ -416,19 +496,28 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg)
       // Hm, the group is broken.. I have no idea how to handle this
       if (Start != End)
       {
-        cout << "Note, a broken or group was found in " << Pkg.Name() << "." << endl;
+        clog << "Note, a broken or group was found in " << Pkg.Name() << "." << endl;
         Fail = true;
         break;
       }
-            
+
+      // Do not change protected packages
+      PkgIterator P = Start.SmartTargetPkg();
+      if ((Flags[P->ID] & Protected) == Protected)
+      {
+        if (Debug == true)
+           clog << "    Reinet Failed because of protected " << P.Name() << endl;
+        Fail = true;
+        break;
+      }      
+      
       // Upgrade the package if the candidate version will fix the problem.
       if ((Cache[Start] & pkgDepCache::DepCVer) == pkgDepCache::DepCVer)
       {
-        PkgIterator P = Start.SmartTargetPkg();
         if (DoUpgrade(P) == false)
         {
            if (Debug == true)
-              cout << "    Reinst Failed because of " << P.Name() << endl;
+              clog << "    Reinst Failed because of " << P.Name() << endl;
            Fail = true;
            break;
         }       
@@ -437,11 +526,11 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg)
       {
         /* We let the algorithm deal with conflicts on its next iteration,
            it is much smarter than us */
-        if (End->Type == pkgDEP_Conflicts)
+        if (End->Type == pkgCache::Dep::Conflicts)
            continue;
         
         if (Debug == true)
-           cout << "    Reinst Failed early because of " << Start.TargetPkg().Name() << endl;
+           clog << "    Reinst Failed early because of " << Start.TargetPkg().Name() << endl;
         Fail = true;
         break;
       }      
@@ -458,7 +547,7 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg)
    }    
    
    if (Debug == true)
-      cout << "  Re-Instated " << Pkg.Name() << endl;
+      clog << "  Re-Instated " << Pkg.Name() << endl;
    return true;
 }
                                                                        /*}}}*/
@@ -478,7 +567,7 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg)
    upgrade packages to advoid problems. */
 bool pkgProblemResolver::Resolve(bool BrokenFix)
 {
- unsigned long Size = Cache.HeaderP->PackageCount;
  unsigned long Size = Cache.HeaderP->PackageCount;
 
    // Record which packages are marked for install
    bool Again = false;
@@ -506,7 +595,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
    while (Again == true);
 
    if (Debug == true)
-      cout << "Starting" << endl;
+      clog << "Starting" << endl;
    
    MakeScores();
    
@@ -525,13 +614,13 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
       if (Scores[(*K)->ID] != 0)
       {
         pkgCache::PkgIterator Pkg(Cache,*K);
-        cout << Scores[(*K)->ID] << ' ' << Pkg.Name() <<
+        clog << Scores[(*K)->ID] << ' ' << Pkg.Name() <<
            ' ' << (pkgCache::Version *)Pkg.CurrentVer() << ' ' << 
            Cache[Pkg].InstallVer << ' ' << Cache[Pkg].CandidateVer << endl;
       } */
 
    if (Debug == true)
-      cout << "Starting 2" << endl;
+      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
@@ -550,13 +639,15 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
         if (Cache[I].CandidateVer != Cache[I].InstallVer &&
             I->CurrentVer != 0 && Cache[I].InstallVer != 0 &&
             (Flags[I->ID] & PreInstalled) != 0 &&
-            (Flags[I->ID] & Protected) == 0)
+            (Flags[I->ID] & Protected) == 0 &&
+            (Flags[I->ID] & ReInstateTried) == 0)
         {
            if (Debug == true)
-              cout << " Try to Re-Instate " << I.Name() << endl;
+              clog << " Try to Re-Instate " << I.Name() << endl;
            int OldBreaks = Cache.BrokenCount();
            pkgCache::Version *OldVer = Cache[I].InstallVer;
-
+           Flags[I->ID] &= ReInstateTried;
+           
            Cache.MarkInstall(I,false);
            if (Cache[I].InstBroken() == true || 
                OldBreaks < Cache.BrokenCount())
@@ -568,7 +659,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
            }       
            else
               if (Debug == true)
-                 cout << "Re-Instated " << I.Name() << endl;
+                 clog << "Re-Instated " << I.Name() << " (" << OldBreaks << " vs " << Cache.BrokenCount() << ')' << endl;
         }
            
         if (Cache[I].InstallVer == 0 || Cache[I].InstBroken() == false)
@@ -586,7 +677,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
            for (bool LastOR = true; D.end() == false && LastOR == true; D++)
            {
               State |= Cache[D];
-              LastOR = (D->CompareOp & pkgOP_OR) == pkgOP_OR;
+              LastOR = (D->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or;
               if (LastOR == true)
                  End = D;
            }
@@ -602,13 +693,13 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
            // Hm, the group is broken.. I have no idea how to handle this
            if (Start != End)
            {
-              cout << "Note, a broken or group was found in " << I.Name() << "." << endl;
+              clog << "Note, a broken or group was found in " << I.Name() << "." << endl;
               Cache.MarkDelete(I);
               break;
            }
                    
            if (Debug == true)
-              cout << "Package " << I.Name() << " has broken dep on " << End.TargetPkg().Name() << endl;
+              clog << "Package " << I.Name() << " has broken dep on " << End.TargetPkg().Name() << endl;
            
            /* Conflicts is simple, decide if we should remove this package
               or the conflicted one */
@@ -620,32 +711,32 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
               pkgCache::PkgIterator Pkg = Ver.ParentPkg();
            
               if (Debug == true)
-                 cout << "  Considering " << Pkg.Name() << ' ' << (int)Scores[Pkg->ID] << 
+                 clog << "  Considering " << Pkg.Name() << ' ' << (int)Scores[Pkg->ID] << 
                  " as a solution to " << I.Name() << ' ' << (int)Scores[I->ID] << endl;
               if (Scores[I->ID] <= Scores[Pkg->ID] ||
                   ((Cache[End] & pkgDepCache::DepGNow) == 0 &&
-                   End->Type != pkgDEP_Conflicts))
+                   End->Type != pkgCache::Dep::Conflicts))
               {
-                 if ((Flags[I->ID] & Protected) != 0)
+                 if ((Flags[I->ID] & Protected) == Protected)
                     continue;
-                 
+
                  // See if a keep will do
                  Cache.MarkKeep(I);
                  if (Cache[I].InstBroken() == false)
                  {
                     if (Debug == true)
-                       cout << "  Holding Back " << I.Name() << " rather than change " << End.TargetPkg().Name() << endl;
+                       clog << "  Holding Back " << I.Name() << " rather than change " << End.TargetPkg().Name() << endl;
                  }               
                  else
                  {
                     if (BrokenFix == false || DoUpgrade(I) == false)
                     {
                        if (Debug == true)
-                          cout << "  Removing " << I.Name() << " rather than change " << End.TargetPkg().Name() << endl;
+                          clog << "  Removing " << I.Name() << " rather than change " << End.TargetPkg().Name() << endl;
                        Cache.MarkDelete(I);
                        if (Counter > 1)
                           Scores[I->ID] = Scores[Pkg->ID];
-                    }               
+                    }
                  }
 
                  Change = true;
@@ -661,24 +752,26 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
                  LEnd->Pkg = Pkg;
                  LEnd->Dep = End;
                  LEnd++;
-                 if (End->Type != pkgDEP_Conflicts)
+                 
+                 if (End->Type != pkgCache::Dep::Conflicts)
                     break;
               }
            }
 
            // Hm, nothing can possibly satisify this dep. Nuke it.
-           if (VList[0] == 0 && End->Type != pkgDEP_Conflicts)
+           if (VList[0] == 0 && End->Type != pkgCache::Dep::Conflicts &&
+               (Flags[I->ID] & Protected) != Protected)
            {
               Cache.MarkKeep(I);
               if (Cache[I].InstBroken() == false)
               {
                  if (Debug == true)
-                    cout << "  Holding Back " << I.Name() << " because I can't find " << End.TargetPkg().Name() << endl;
+                    clog << "  Holding Back " << I.Name() << " because I can't find " << End.TargetPkg().Name() << endl;
               }               
               else
               {
                  if (Debug == true)
-                    cout << "  Removing " << I.Name() << " because I can't find " << End.TargetPkg().Name() << endl;
+                    clog << "  Removing " << I.Name() << " because I can't find " << End.TargetPkg().Name() << endl;
                  Cache.MarkDelete(I);
               }
 
@@ -698,17 +791,17 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
            Change = true;
            if ((Cache[J->Dep] & pkgDepCache::DepGNow) == 0)
            {
-              if (J->Dep->Type == pkgDEP_Conflicts)
+              if (J->Dep->Type == pkgCache::Dep::Conflicts)
               {
                  if (Debug == true)
-                    cout << "  Fixing " << I.Name() << " via remove of " << J->Pkg.Name() << endl;
+                    clog << "  Fixing " << I.Name() << " via remove of " << J->Pkg.Name() << endl;
                  Cache.MarkDelete(J->Pkg);
               }
            }
            else
            {
               if (Debug == true)
-                 cout << "  Fixing " << I.Name() << " via keep of " << J->Pkg.Name() << endl;
+                 clog << "  Fixing " << I.Name() << " via keep of " << J->Pkg.Name() << endl;
               Cache.MarkKeep(J->Pkg);
            }
            
@@ -719,14 +812,154 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
    }
 
    if (Debug == true)
-      cout << "Done" << endl;
+      clog << "Done" << endl;
    
    delete [] Scores;
    delete [] PList;
    
    if (Cache.BrokenCount() != 0)
-      return _error->Error("Internal error, ScoredFix generated breaks.");
+      return _error->Error("Internal error, pkgProblemResolver::Resolve generated breaks.");
+
+   return true;
+}
+                                                                       /*}}}*/
+// 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()
+{
+   unsigned long Size = Cache.HeaderP->PackageCount;
+
+   if (Debug == true)      
+      clog << "Entering ResolveByKeep" << endl;
+   
+   MakeScores();
+   
+   /* 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
+      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++)
+      *PEnd++ = I;
+   This = this;
+   qsort(PList,PEnd - PList,sizeof(*PList),&ScoreSort);
+   
+   // Consider each broken package 
+   pkgCache::Package **LastStop = 0;
+   for (pkgCache::Package **K = PList; K != PEnd; K++)
+   {
+      pkgCache::PkgIterator I(Cache,*K);
+
+      if (Cache[I].InstallVer == 0 || Cache[I].InstBroken() == 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)
+      {
+        if (Debug == true)
+           clog << "Keeping package " << I.Name() << endl;
+        Cache.MarkKeep(I);
+        if (Cache[I].InstBroken() == false)
+        {
+           K = PList;
+           continue;
+        }
+      }
+      
+      // Isolate the problem dependencies
+      for (pkgCache::DepIterator D = Cache[I].InstVerIter(Cache).DependsList(); D.end() == false;)
+      {
+        // Compute a single dependency element (glob or)
+        pkgCache::DepIterator Start = D;
+        pkgCache::DepIterator End = D;
+        unsigned char State = 0;
+        for (bool LastOR = true; D.end() == false && LastOR == true; D++)
+        {
+           State |= Cache[D];
+           LastOR = (D->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or;
+           if (LastOR == true)
+              End = D;
+        }
+        
+        // We only worry about critical deps.
+        if (End.IsCritical() != true)
+           continue;
+        
+        // Dep is ok
+        if ((Cache[End] & pkgDepCache::DepGInstall) == pkgDepCache::DepGInstall)
+           continue;
+        
+        // Hm, the group is broken.. I have no idea how to handle this
+        if (Start != End)
+        {
+           clog << "Note, a broken or group was found in " << I.Name() << "." << endl;
+           if ((Flags[I->ID] & Protected) == 0)
+              Cache.MarkKeep(I);
+           break;
+        }
+        
+        if (Debug == true)
+           clog << "Package " << I.Name() << " has broken dep on " << End.TargetPkg().Name() << endl;
+        
+        // Look at all the possible provides on this package
+        pkgCache::Version **VList = End.AllTargets();
+        for (pkgCache::Version **V = VList; *V != 0; V++)
+        {
+           pkgCache::VerIterator Ver(Cache,*V);
+           pkgCache::PkgIterator Pkg = Ver.ParentPkg();
+           
+           // It is not keepable
+           if (Cache[Pkg].InstallVer == 0 || 
+               Pkg->CurrentVer == 0)
+              continue;
+           
+           if ((Flags[I->ID] & Protected) == 0)
+           {
+              if (Debug == true)
+                 clog << "  Keeping Package " << Pkg.Name() << " due to dep" << endl;
+              Cache.MarkKeep(Pkg);
+           }
+           
+           if (Cache[I].InstBroken() == false)
+              break;
+        }
+
+        if (Cache[I].InstBroken() == false)
+           break;
+      }
+
+      if (Cache[I].InstBroken() == true)
+        continue;
+      
+      // Restart again.
+      if (K == LastStop)
+        return _error->Error("Internal Error, pkgProblemResolver::ResolveByKeep is looping on package %s.",I.Name());
+      LastStop = K;
+      K = PList;
+   }   
 
    return true;
 }
                                                                        /*}}}*/
+// ProblemResolver::InstallProtect - Install all protected packages    /*{{{*/
+// ---------------------------------------------------------------------
+/* This is used to make sure protected packages are installed */
+void pkgProblemResolver::InstallProtect()
+{
+   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);
+      }
+   }   
+}
+                                                                       /*}}}*/