]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/depcache.cc
Perl glitch in the problem resolver
[apt.git] / apt-pkg / depcache.cc
index a7784c0a528e12d80be3229fbb05bb50a5353cd2..36abcddd4359406ecce3543c1ce2cd2c4c2a847c 100644 (file)
@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description                                                         /*{{{*/
-// $Id: depcache.cc,v 1.1 1998/07/07 04:17:01 jgg Exp $
+// $Id: depcache.cc,v 1.18 1999/04/28 22:48:45 jgg Exp $
 /* ######################################################################
 
    Dependency Cache - Caches Dependency information.
@@ -9,22 +9,28 @@
                                                                        /*}}}*/
 // Include Files                                                       /*{{{*/
 #ifdef __GNUG__
-#pragma implementation "pkglib/depcache.h"
+#pragma implementation "apt-pkg/depcache.h"
 #endif
-#include <pkglib/depcache.h>
+#include <apt-pkg/depcache.h>
 
-#include <pkglib/version.h>
-#include <pkglib/error.h>
+#include <apt-pkg/version.h>
+#include <apt-pkg/error.h>
                                                                        /*}}}*/
 
 // DepCache::pkgDepCache - Constructors                                        /*{{{*/
 // ---------------------------------------------------------------------
 /* */
+pkgDepCache::pkgDepCache(MMap &Map,OpProgress &Prog) :
+             pkgCache(Map), PkgState(0), DepState(0)
+{
+   if (_error->PendingError() == false)
+      Init(&Prog);
+}
 pkgDepCache::pkgDepCache(MMap &Map) :
-             pkgCache(Map), PkgState(0), DepState(0) 
+             pkgCache(Map), PkgState(0), DepState(0)
 {
    if (_error->PendingError() == false)
-      Init();
+      Init(0);
 }
                                                                        /*}}}*/
 // DepCache::~pkgDepCache - Destructor                                 /*{{{*/
@@ -36,23 +42,10 @@ pkgDepCache::~pkgDepCache()
    delete [] DepState;
 }
                                                                        /*}}}*/
-// DepCache::ReMap - Regenerate the extra data for the new cache       /*{{{*/
-// ---------------------------------------------------------------------
-/* pkgCache's constructors call this function, but because the object is not
-   fully constructed at that point it will not result in this function being
-   called but pkgCache::ReMap will be instead.*/
-bool pkgDepCache::ReMap()
-{
-   if (pkgCache::ReMap() == false)
-      return false;
-   
-   return Init();
-}
-                                                                       /*}}}*/
 // DepCache::Init - Generate the initial extra structures.             /*{{{*/
 // ---------------------------------------------------------------------
 /* This allocats the extension buffers and initializes them. */
-bool pkgDepCache::Init()
+bool pkgDepCache::Init(OpProgress *Prog)
 {
    delete [] PkgState;
    delete [] DepState;
@@ -61,10 +54,21 @@ bool pkgDepCache::Init()
    memset(PkgState,0,sizeof(*PkgState)*Head().PackageCount);
    memset(DepState,0,sizeof(*DepState)*Head().DependsCount); 
    
+   if (Prog != 0)
+   {
+      Prog->OverallProgress(0,2*Head().PackageCount,Head().PackageCount,
+                           "Building Dependency Tree");
+      Prog->SubProgress(Head().PackageCount,"Candidate Versions");
+   }
+   
    /* Set the current state of everything. In this state all of the
       packages are kept exactly as is. See AllUpgrade */
-   for (PkgIterator I = PkgBegin(); I.end() != true; I++)
+   int Done = 0;
+   for (PkgIterator I = PkgBegin(); I.end() != true; I++,Done++)
    {
+      if (Prog != 0)
+        Prog->Progress(Done);
+      
       // Find the proper cache slot
       StateCache &State = PkgState[I->ID];
       State.iFlags = 0;
@@ -77,7 +81,16 @@ bool pkgDepCache::Init()
       State.Update(I,*this);
    }   
    
-   Update();
+   if (Prog != 0)
+   {
+      
+      Prog->OverallProgress(Head().PackageCount,2*Head().PackageCount,
+                           Head().PackageCount,
+                           "Building Dependency Tree");
+      Prog->SubProgress(Head().PackageCount,"Dependency Generation");
+   }
+   
+   Update(Prog);
    
    return true;
 } 
@@ -86,24 +99,13 @@ bool pkgDepCache::Init()
 // ---------------------------------------------------------------------
 /* The default just returns the target version if it exists or the
    highest version. */
-pkgDepCache::VerIterator pkgDepCache::GetCandidateVer(PkgIterator Pkg)
+pkgDepCache::VerIterator pkgDepCache::GetCandidateVer(PkgIterator Pkg,
+                                                     bool AllowCurrent)
 {
    // Try to use an explicit target
-   if (Pkg->TargetVer == 0)
-   {
-      /* Not source versions cannot be a candidate version unless they
-         are already installed */
-      for (VerIterator I = Pkg.VersionList(); I.end() == false; I++)
-      {
-        if (Pkg.CurrentVer() == I)
-           return I;
-        for (VerFileIterator J = I.FileList(); J.end() == false; J++)
-           if ((J.File()->Flags & Flag::NotSource) == 0)
-               return I;
-      }
-        
-      return VerIterator(*this,0);
-   }
+   if (Pkg->TargetVer == 0 || 
+       (AllowCurrent == false && Pkg.TargetVer() == Pkg.CurrentVer()))
+      return pkgCache::GetCandidateVer(Pkg,AllowCurrent);
    else
       return Pkg.TargetVer(); 
 }
@@ -201,25 +203,42 @@ void pkgDepCache::AddSizes(const PkgIterator &Pkg,long Mult)
 {
    StateCache &P = PkgState[Pkg->ID];
    
+   if (Pkg.State() == pkgCache::PkgIterator::NeedsConfigure && 
+       P.Keep() == true)
+      return;
+   
    // Compute the size data
    if (P.NewInstall() == true)
    {
       iUsrSize += Mult*P.InstVerIter(*this)->InstalledSize;
       iDownloadSize += Mult*P.InstVerIter(*this)->Size;
+      return;
    }
    
    // Upgrading
    if (Pkg->CurrentVer != 0 && P.InstallVer != (Version *)Pkg.CurrentVer() &&
        P.InstallVer != 0)
    {
-      iUsrSize += Mult*(P.InstVerIter(*this)->InstalledSize - 
-                       Pkg.CurrentVer()->InstalledSize);
+      iUsrSize += Mult*((signed)P.InstVerIter(*this)->InstalledSize - 
+                       (signed)Pkg.CurrentVer()->InstalledSize);
+      iDownloadSize += Mult*P.InstVerIter(*this)->Size;
+      return;
+   }
+   
+   // Reinstall
+   if (Pkg.State() == pkgCache::PkgIterator::NeedsUnpack &&
+       P.Delete() == false)
+   {
       iDownloadSize += Mult*P.InstVerIter(*this)->Size;
+      return;
    }
    
    // Removing
    if (Pkg->CurrentVer != 0 && P.InstallVer == 0)
+   {
       iUsrSize -= Mult*Pkg.CurrentVer()->InstalledSize;
+      return;
+   }   
 }
                                                                        /*}}}*/
 // DepCache::AddStates - Add the package to the state counter          /*{{{*/
@@ -286,6 +305,7 @@ void pkgDepCache::BuildGroupOrs(VerIterator const &V)
         State = ~State;
       
       // Add to the group if we are within an or..
+      State &= 0x7;
       Group |= State;
       State |= Group << 3;
       if ((D->CompareOp & Dep::Or) != Dep::Or)
@@ -392,7 +412,7 @@ void pkgDepCache::UpdateVerState(PkgIterator Pkg)
 // ---------------------------------------------------------------------
 /* This will figure out the state of all the packages and all the 
    dependencies based on the current policy. */
-void pkgDepCache::Update()
+void pkgDepCache::Update(OpProgress *Prog)
 {   
    iUsrSize = 0;
    iDownloadSize = 0;
@@ -403,8 +423,11 @@ void pkgDepCache::Update()
    iBadCount = 0;
    
    // Perform the depends pass
-   for (PkgIterator I = PkgBegin(); I.end() != true; I++)
+   int Done = 0;
+   for (PkgIterator I = PkgBegin(); I.end() != true; I++,Done++)
    {
+      if (Prog != 0 && Done%20 == 0)
+        Prog->Progress(Done);
       for (VerIterator V = I.VersionList(); V.end() != true; V++)
       {
         unsigned char Group = 0;
@@ -432,6 +455,9 @@ void pkgDepCache::Update()
       UpdateVerState(I);
       AddStates(I);
    }
+
+   if (Prog != 0)      
+      Prog->Progress(Done);
 }
                                                                        /*}}}*/
 // DepCache::Update - Update the deps list of a package                        /*{{{*/
@@ -493,6 +519,12 @@ void pkgDepCache::MarkKeep(PkgIterator const &Pkg,bool Soft)
    // Simplifies other routines.
    if (Pkg.end() == true)
       return;
+
+   /* Reject an attempt to keep a non-source broken installed package, those
+      must be upgraded */
+   if (Pkg.State() == PkgIterator::NeedsUnpack && 
+       Pkg.CurrentVer().Downloadable() == false)
+      return;
    
    /* We changed the soft state all the time so the UI is a bit nicer
       to use */
@@ -549,7 +581,10 @@ void pkgDepCache::MarkDelete(PkgIterator const &Pkg)
    RemoveSizes(Pkg);
    RemoveStates(Pkg);
    
-   P.Mode = ModeDelete;
+   if (Pkg->CurrentVer == 0)
+      P.Mode = ModeKeep;
+   else
+      P.Mode = ModeDelete;
    P.InstallVer = 0;
    P.Flags &= Flag::Auto;
 
@@ -660,203 +695,6 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst)
 }
                                                                        /*}}}*/
 
-#if 0
-// DepCache::ResolveConflicts - Figure the auto upgrades               /*{{{*/
-// ---------------------------------------------------------------------
-/* This routine attempts to resolve conflicts generated by automatic 
-   upgrading. It is known as 'Stage 1' but that name isn't as proper anymore.
-   
-   It's most important function is during the initial load of APT. The 
-   loading code will mark every package for upgrade to it's candidate version
-   and then call this routine. This routine will then 'soft keep' every
-   package that causes conflict, is conflicted, or so on. It is a bit
-   agressive in that it may unselect more packages in some odd cases
-   than are strictly necessary but in the case where no packages were
-   conflicting before it will always produce a system with no packages
-   conflicting after.
-   This routine is also used during state changes that require autoupgrade
-   scanning. That is, if a new package is marked for install then all packages
-   that have been soft kept are reconsidered for upgrade. 
-   
-   It is called with state information about what can be un-upgraded and
-   what the pre-upgrade install state was. It is expected that the caller
-   has already marked the desired packages to the install state. Bit 0 is
-   the original install state and Bit 1 is controls whether the package
-   should be touched.
-*/
-void pkgDepCache::ResolveConflicts(unsigned char *Touched)
-{
-   bool Again = false;
-   do
-   {
-      Again = false;
-      for (PkgIterator I = PkgBegin(); I.end() != true; I++)
-      {
-        // The package will install OK
-        if ((PkgState[I->ID].DepState & DepInstMin) == DepInstMin)
-           continue;
-        
-        /* The package was broken before and this upgrade will not
-           make things better. We simply mark the package for keep
-           and assume an upgrade attempt will be hopeless. This might
-           not be ideal. */
-        if ((Touched[I->ID] & (1 << 0)) != (1 << 0))
-        {
-           // The package isnt to be touched
-           if ((Touched[I->ID] & (1 << 1)) == (1 << 1))
-              MarkKeep(I,true);
-           
-           continue;
-        }       
-        
-        // Check to see if not upgrading it will solve the problem
-        if (I->CurrentVer != 0)
-        {          
-           // The package isnt to be touched
-           if ((Touched[I->ID] & (1 << 1)) == (1 << 1))
-           {
-              if (PkgState[I->ID].Mode != ModeKeep)
-                 Again = true;
-              
-              MarkKeep(I,true);
-           }
-           
-           /* Check if the package is sill broken. If so then we cant leave 
-              it as is and get a working system. Lets try marking some 
-              depends for 'keep'. This is brutal, it keeps everything in 
-              sight to fix the problem. */
-           DepIterator D = I.CurrentVer().DependsList();
-           for (;(PkgState[I->ID].DepState & DepInstMin) != DepInstMin && 
-                  D.end() != true; D++)
-           {
-              // We only worry about critical deps.
-              if (D.IsCritical() != true)
-                 continue;
-              
-              unsigned char State = DepState[D->ID];
-              
-              // This dep never was set before so we dont need to set it now
-              if ((State & DepNow) != DepNow)
-                 continue;
-
-              // The dep is okay now no worries.
-              if ((State & DepInstall) == DepInstall)
-                 continue;
-
-              // Locate a target to keep
-              PkgIterator P(*this);
-              if (CheckDep(D,NowVersion,P) == true)
-              {
-                 // We cant touch this package
-                 if ((Touched[P->ID] & (1 << 1)) == (1 << 1))
-                    MarkKeep(P,true);
-              }
-           }
-        }
-      }
-   }
-   while (Again == true);
-}
-                                                                       /*}}}*/
-// DepCache::PromoteAutoKeep - Gentler version of the above            /*{{{*/
-// ---------------------------------------------------------------------
-/* This is used when installing packages, all it does is attempt to promote
-   everything that has been auto-kept. It simply promotes everything
-   irregardless of it having a chance to work and then runs ResolveConflicts
-   on the result. This allows circular depends loops to work but isn't
-   terribly fast. */
-void pkgDepCache::PromoteAutoKeep()
-{
-   /* Initialize the touchd array. Bit 0 is the old install state bit 1
-      is the touch value */
-   unsigned char *Touch = new unsigned char[Head().PackageCount];
-   for (unsigned int I = 0; I != Head().PackageCount; I++)
-   {
-      if ((PkgState[I].DepState & DepInstMin) == DepInstMin)
-        Touch[I] = 1 << 0;
-      else
-        Touch[I] = 0;
-   }
-
-   // This allows circular depends to work
-   for (PkgIterator I = PkgBegin(); I.end() != true; I++)
-   {
-      /* It wasnt installed before or it is not autokept or it is not
-       upgradeable */
-      StateCache &P = PkgState[I->ID];
-      if (I->CurrentVer == 0 || P.Mode != ModeKeep || I->VersionList == 0 ||
-         P.CandidateVer == (Version *)I.CurrentVer() || 
-         (P.iFlags & AutoKept) != AutoKept)
-        continue;
-
-      P.Mode = ModeInstall;
-      P.InstallVer = P.CandidateVer;
-      if (P.CandidateVer == (Version *)I.CurrentVer())
-        P.Mode = ModeKeep;
-      
-      // Okay autoupgrade it.
-      Touch[I->ID] |= 1 << 1;
-   }
-   
-   Update();   
-   ResolveConflicts(Touch);
-   
-   delete [] Touch;
-}
-                                                                       /*}}}*/
-// DepCache::AllUpgrade - Try to upgrade everything                    /*{{{*/
-// ---------------------------------------------------------------------
-/* */
-void pkgDepCache::AllUpgrade()
-{
-   // Set everything to an upgrade mode 
-   for (PkgIterator I = PkgBegin(); I.end() != true; I++)
-   {
-      StateCache &State = PkgState[I->ID];
-      
-      /* We dont upgrade packages marked for deletion or that are
-         not installed or that don't have an upgrade */
-      if (State.Mode == ModeDelete || I->CurrentVer == 0 ||
-         (Version *)I.CurrentVer() == State.CandidateVer)
-        continue;
-       
-      // Set the state to upgrade
-      State.iFlags = 0;
-      State.Mode = ModeInstall;
-      State.InstallVer = State.CandidateVer;
-      if (State.CandidateVer == (Version *)I.CurrentVer())
-        State.Mode = ModeKeep;
-      
-      // Do not upgrade things that have the hold flag set.
-      if (I->SelectedState == State::Hold)
-      {
-        State.InstallVer = I.CurrentVer();
-        State.Mode = ModeKeep;
-      }
-      State.Update(I,*this);
-   }   
-   
-   Update();
-
-   /* Initialize the touchd array. Bit 0 is the old install state bit 1
-      is the touch value */
-   unsigned char *Touch = new unsigned char[Head().PackageCount];
-   for (unsigned int I = 0; I != Head().PackageCount; I++)
-   {
-      if ((PkgState[I].DepState & DepNowMin) == DepNowMin)
-        Touch[I] = (1 << 0) | (1 << 1);
-      else
-        Touch[I] = 1 << 1;
-   }
-
-   // Now downgrade everything that is broken
-   ResolveConflicts(Touch);
-   delete [] Touch;
-}
-                                                                       /*}}}*/
-#endif
-
 // StateCache::Update - Compute the various static display things      /*{{{*/
 // ---------------------------------------------------------------------
 /* This is called whenever the Candidate version changes. */