]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/algorithms.cc
Open 0.5.31
[apt.git] / apt-pkg / algorithms.cc
index fb85d12f9cf182ff29d609ae9263cfec425b7c26..9b37385bf87ae59b3179604ca87b69ad28c06660 100644 (file)
@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description                                                         /*{{{*/
-// $Id: algorithms.cc,v 1.32 2001/02/20 07:03:17 jgg Exp $
+// $Id: algorithms.cc,v 1.44 2002/11/28 18:49:16 jgg Exp $
 /* ######################################################################
 
    Algorithms - A set of misc algorithms
@@ -24,8 +24,9 @@
     
 #include <apti18n.h>
     
-#include <iostream.h>
+#include <iostream>
                                                                        /*}}}*/
+using namespace std;
 
 pkgProblemResolver *pkgProblemResolver::This = 0;
 
@@ -49,17 +50,22 @@ pkgSimulate::pkgSimulate(pkgDepCache *Cache) : pkgPackageManager(Cache),
                                                                        /*}}}*/
 // Simulate::Describe - Describe a package                             /*{{{*/
 // ---------------------------------------------------------------------
-/* */
+/* Parameter Now == true gives both current and available varsion,
+   Parameter Now == false gives only the available package version */
 void pkgSimulate::Describe(PkgIterator Pkg,ostream &out,bool Now)
 {
    VerIterator Ver(Sim);
+   out << Pkg.Name();
+
    if (Now == true)
+   {
       Ver = Pkg.CurrentVer();
-   else
-      Ver = Sim[Pkg].CandidateVerIter(Sim);
+      if (Ver.end() == false)
+         out << " [" << Ver.VerStr() << ']';
+   }
 
-   out << Pkg.Name();
-   
+   Ver = Sim[Pkg].CandidateVerIter(Sim);
    if (Ver.end() == true)
       return;
    
@@ -76,7 +82,7 @@ bool pkgSimulate::Install(PkgIterator iPkg,string /*File*/)
    Flags[Pkg->ID] = 1;
    
    cout << "Inst ";
-   Describe(Pkg,cout,false);
+   Describe(Pkg,cout,true);
    Sim.MarkInstall(Pkg,false);
    
    // Look for broken conflicts+predepends.
@@ -213,16 +219,20 @@ bool pkgApplyStatus(pkgDepCache &Cache)
 {
    for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
    {
+      if (I->VersionList == 0)
+        continue;
+        
       // Only choice for a ReInstReq package is to reinstall
       if (I->InstState == pkgCache::State::ReInstReq ||
          I->InstState == pkgCache::State::HoldReInstReq)
       {
-        if (I.CurrentVer().Downloadable() == true)
+        if (I->CurrentVer != 0 && I.CurrentVer().Downloadable() == true)
            Cache.MarkKeep(I);
         else
         {
            // Is this right? Will dpkg choke on an upgrade?
-           if (Cache[I].CandidateVerIter(Cache).Downloadable() == true)
+           if (Cache[I].CandidateVer != 0 &&
+                Cache[I].CandidateVerIter(Cache).Downloadable() == true)
               Cache.MarkInstall(I);
            else
               return _error->Error(_("The package %s needs to be reinstalled, "
@@ -238,12 +248,13 @@ bool pkgApplyStatus(pkgDepCache &Cache)
            re-unpacked (probably) */
         case pkgCache::State::UnPacked:
         case pkgCache::State::HalfConfigured:
-        if (I.CurrentVer().Downloadable() == true || 
+        if ((I->CurrentVer != 0 && I.CurrentVer().Downloadable() == true) ||
             I.State() != pkgCache::PkgIterator::NeedsUnpack)
            Cache.MarkKeep(I);
         else
         {
-           if (Cache[I].CandidateVerIter(Cache).Downloadable() == true)
+           if (Cache[I].CandidateVer != 0 &&
+                Cache[I].CandidateVerIter(Cache).Downloadable() == true)
               Cache.MarkInstall(I);
            else
               Cache.MarkDelete(I);
@@ -378,7 +389,7 @@ bool pkgMinimizeUpgrade(pkgDepCache &Cache)
    if (Cache.BrokenCount() != 0)
       return false;
    
-   // We loop indefinately to get the minimal set size.
+   // We loop for 10 tries to get the minimal set size.
    bool Change = false;
    unsigned int Count = 0;
    do
@@ -553,6 +564,8 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg)
 {
    if ((Flags[Pkg->ID] & Upgradable) == 0 || Cache[Pkg].Upgradable() == false)
       return false;
+   if ((Flags[Pkg->ID] & Protected) == Protected)
+      return false;
    
    Flags[Pkg->ID] &= ~Upgradable;
    
@@ -795,6 +808,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
                        if (Debug == true)
                           clog << "  Or group remove for " << I.Name() << endl;
                        Cache.MarkDelete(I);
+                       Change = true;
                     }               
                  }               
                  if (OldEnd == LEnd && OrOp == OrKeep)
@@ -802,6 +816,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
                     if (Debug == true)
                        clog << "  Or group keep for " << I.Name() << endl;
                     Cache.MarkKeep(I);
+                    Change = true;
                  }
               }
               
@@ -812,21 +827,24 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
               D.GlobOr(Start,End);
               if (Start.end() == true)
                  break;
-              
+
               // We only worry about critical deps.
               if (End.IsCritical() != true)
                  continue;
-              
+
               InOr = Start != End;
               OldEnd = LEnd;
-           }       
+           }
            else
               Start++;
-           
+
            // Dep is ok
            if ((Cache[End] & pkgDepCache::DepGInstall) == pkgDepCache::DepGInstall)
+           {
+              InOr = false;
               continue;
-                   
+           }
+           
            if (Debug == true)
               clog << "Package " << I.Name() << " has broken dep on " << Start.TargetPkg().Name() << endl;
 
@@ -856,10 +874,13 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
            {
               pkgCache::VerIterator Ver(Cache,*V);
               pkgCache::PkgIterator Pkg = Ver.ParentPkg();
-           
+
               if (Debug == true)
                  clog << "  Considering " << Pkg.Name() << ' ' << (int)Scores[Pkg->ID] <<
                  " as a solution to " << I.Name() << ' ' << (int)Scores[I->ID] << endl;
+
+              /* Try to fix the package under consideration rather than
+                 fiddle with the VList package */
               if (Scores[I->ID] <= Scores[Pkg->ID] ||
                   ((Cache[Start] & pkgDepCache::DepNow) == 0 &&
                    End->Type != pkgCache::Dep::Conflicts &&
@@ -920,11 +941,21 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
               }
               else
               {
-                 if (Debug == true)
-                    clog << "  Added " << Pkg.Name() << " to the remove list" << endl;
+                 /* This is a conflicts, and the version we are looking
+                    at is not the currently selected version of the 
+                    package, which means it is not necessary to 
+                    remove/keep */
+                 if (Cache[Pkg].InstallVer != Ver &&
+                     (Start->Type == pkgCache::Dep::Conflicts ||
+                      Start->Type == pkgCache::Dep::Obsoletes))
+                    continue;
+                 
                  // Skip adding to the kill list if it is protected
                  if ((Flags[Pkg->ID] & Protected) != 0)
                     continue;
+               
+                 if (Debug == true)
+                    clog << "  Added " << Pkg.Name() << " to the remove list" << endl;
                  
                  LEnd->Pkg = Pkg;
                  LEnd->Dep = End;
@@ -1081,18 +1112,10 @@ bool pkgProblemResolver::ResolveByKeep()
       // 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;
-        }
-        
+        DepIterator Start;
+        DepIterator End;
+        D.GlobOr(Start,End);
+
         // We only worry about critical deps.
         if (End.IsCritical() != true)
            continue;
@@ -1100,42 +1123,47 @@ bool pkgProblemResolver::ResolveByKeep()
         // 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
-        SPtrArray<pkgCache::Version *> VList = End.AllTargets();
-        for (pkgCache::Version **V = VList; *V != 0; V++)
+
+        /* Hm, the group is broken.. I suppose the best thing to do is to
+           is to try every combination of keep/not-keep for the set, but thats
+           slow, and this never happens, just be conservative and assume the
+           list of ors is in preference and keep till it starts to work. */
+        while (true)
         {
-           pkgCache::VerIterator Ver(Cache,*V);
-           pkgCache::PkgIterator Pkg = Ver.ParentPkg();
-           
-           // It is not keepable
-           if (Cache[Pkg].InstallVer == 0 || 
-               Pkg->CurrentVer == 0)
-              continue;
+           if (Debug == true)
+              clog << "Package " << I.Name() << " has broken dep on " << Start.TargetPkg().Name() << endl;
            
-           if ((Flags[I->ID] & Protected) == 0)
+           // Look at all the possible provides on this package
+           SPtrArray<pkgCache::Version *> VList = Start.AllTargets();
+           for (pkgCache::Version **V = VList; *V != 0; V++)
            {
-              if (Debug == true)
-                 clog << "  Keeping Package " << Pkg.Name() << " due to dep" << endl;
-              Cache.MarkKeep(Pkg);
+              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 (Start == End)
+              break;
+           Start++;
+        }
+             
         if (Cache[I].InstBroken() == false)
            break;
       }
@@ -1182,14 +1210,14 @@ static int PrioComp(const void *A,const void *B)
    pkgCache::VerIterator R(*PrioCache,*(pkgCache::Version **)B);
    
    if ((L.ParentPkg()->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential &&
-       (L.ParentPkg()->Flags & pkgCache::Flag::Essential) != pkgCache::Flag::Essential)
-   return 1;
+       (R.ParentPkg()->Flags & pkgCache::Flag::Essential) != pkgCache::Flag::Essential)
+     return 1;
    if ((L.ParentPkg()->Flags & pkgCache::Flag::Essential) != pkgCache::Flag::Essential &&
-       (L.ParentPkg()->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
-   return -1;
+       (R.ParentPkg()->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
+     return -1;
    
    if (L->Priority != R->Priority)
-      return L->Priority - R->Priority;
+      return R->Priority - L->Priority;
    return strcmp(L.ParentPkg().Name(),R.ParentPkg().Name());
 }
 void pkgPrioSortList(pkgCache &Cache,pkgCache::Version **List)