]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/algorithms.cc
* Install-Reason -> Auto-Installed in pkgstates
[apt.git] / apt-pkg / algorithms.cc
index c28317b720d63f0e5339f1adec1fe0b7fef48c2a..8626d33dc4e8f850ff85f0031f666d8ff73d9444 100644 (file)
@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description                                                         /*{{{*/
-// $Id: algorithms.cc,v 1.39 2002/04/02 05:55:24 jgg Exp $
+// $Id: algorithms.cc,v 1.44 2002/11/28 18:49:16 jgg Exp $
 /* ######################################################################
 
    Algorithms - A set of misc algorithms
 #include <apt-pkg/algorithms.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/configuration.h>
+#include <apt-pkg/pkgsystem.h>
+#include <apt-pkg/version.h>
 #include <apt-pkg/sptr.h>
+
     
 #include <apti18n.h>
-    
+#include <sys/types.h>
+#include <regex.h>
 #include <iostream>
                                                                        /*}}}*/
+using namespace std;
 
 pkgProblemResolver *pkgProblemResolver::This = 0;
 
@@ -49,21 +54,29 @@ pkgSimulate::pkgSimulate(pkgDepCache *Cache) : pkgPackageManager(Cache),
                                                                        /*}}}*/
 // Simulate::Describe - Describe a package                             /*{{{*/
 // ---------------------------------------------------------------------
-/* */
-void pkgSimulate::Describe(PkgIterator Pkg,ostream &out,bool Now)
+/* Parameter Current == true displays the current package version,
+   Parameter Candidate == true displays the candidate package version */
+void pkgSimulate::Describe(PkgIterator Pkg,ostream &out,bool Current,bool Candidate)
 {
    VerIterator Ver(Sim);
-   if (Now == true)
+   out << Pkg.Name();
+
+   if (Current == true)
+   {
       Ver = Pkg.CurrentVer();
-   else
-      Ver = Sim[Pkg].CandidateVerIter(Sim);
+      if (Ver.end() == false)
+         out << " [" << Ver.VerStr() << ']';
+   }
 
-   out << Pkg.Name();
-   
-   if (Ver.end() == true)
-      return;
+   if (Candidate == true)
+   {
+      Ver = Sim[Pkg].CandidateVerIter(Sim);
+      if (Ver.end() == true)
+         return;
    
-   out << " (" << Ver.VerStr() << ' ' << Ver.RelStr() << ')';
+      out << " (" << Ver.VerStr() << ' ' << Ver.RelStr() << ')';
+   }
 }
                                                                        /*}}}*/
 // Simulate::Install - Simulate unpacking of a package                 /*{{{*/
@@ -76,7 +89,7 @@ bool pkgSimulate::Install(PkgIterator iPkg,string /*File*/)
    Flags[Pkg->ID] = 1;
    
    cout << "Inst ";
-   Describe(Pkg,cout,false);
+   Describe(Pkg,cout,true,true);
    Sim.MarkInstall(Pkg,false);
    
    // Look for broken conflicts+predepends.
@@ -150,7 +163,7 @@ bool pkgSimulate::Configure(PkgIterator iPkg)
    else
    {
       cout << "Conf "; 
-      Describe(Pkg,cout,false);
+      Describe(Pkg,cout,false,true);
    }
 
    if (Sim.BrokenCount() != 0)
@@ -175,7 +188,7 @@ bool pkgSimulate::Remove(PkgIterator iPkg,bool Purge)
       cout << "Purg ";
    else
       cout << "Remv ";
-   Describe(Pkg,cout,false);
+   Describe(Pkg,cout,true,false);
 
    if (Sim.BrokenCount() != 0)
       ShortBreaks();
@@ -558,6 +571,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;
    
@@ -800,6 +815,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)
@@ -807,6 +823,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
                     if (Debug == true)
                        clog << "  Or group keep for " << I.Name() << endl;
                     Cache.MarkKeep(I);
+                    Change = true;
                  }
               }
               
@@ -817,21 +834,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;
 
@@ -1045,6 +1065,20 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
       return _error->Error(_("Unable to correct problems, you have held broken packages."));
    }
    
+   // set the auto-flags (mvo: I'm not sure if we _really_ need this, but
+   // I didn't managed 
+   pkgCache::PkgIterator I = Cache.PkgBegin();
+   for (;I.end() != true; I++) {
+      if (Cache[I].NewInstall() && !(Flags[I->ID] & PreInstalled)) {
+        if(_config->FindI("Debug::pkgAutoRemove",false)) {
+           std::clog << "Resolve installed new pkg: " << I.Name() 
+                     << " (now marking it as auto)" << std::endl;
+        }
+        Cache[I].Flags |= pkgCache::Flag::Auto;
+      }
+   }
+
+
    return true;
 }
                                                                        /*}}}*/
@@ -1197,14 +1231,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)
@@ -1216,3 +1250,238 @@ void pkgPrioSortList(pkgCache &Cache,pkgCache::Version **List)
    qsort(List,Count,sizeof(*List),PrioComp);
 }
                                                                        /*}}}*/
+
+
+// mark a single package in Mark-and-Sweep
+void pkgMarkPackage(pkgDepCache &Cache,
+                   const pkgCache::PkgIterator &pkg,
+                   const pkgCache::VerIterator &ver,
+                   bool follow_recommends,
+                   bool follow_suggests)
+{
+   pkgDepCache::StateCache &state=Cache[pkg];
+   pkgCache::VerIterator candver=state.CandidateVerIter(Cache);
+   pkgCache::VerIterator instver=state.InstVerIter(Cache);
+
+#if 0
+   // If a package was garbage-collected but is now being marked, we
+   // should re-select it 
+   // For cases when a pkg is set to upgrade and this trigger the
+   // removal of a no-longer used dependency.  if the pkg is set to
+   // keep again later it will result in broken deps
+   if(state.Delete() && state.RemoveReason=pkgDepCache::Unused) 
+   {
+      if(ver==candver)
+        mark_install(pkg, false, false, NULL);
+      else if(ver==pkg.CurrentVer())
+        MarkKeep(pkg);
+      
+      instver=state.InstVerIter(*this);
+   }
+#endif
+
+   // Ignore versions other than the InstVer, and ignore packages
+   // that are already going to be removed or just left uninstalled.
+   if(!(ver==instver && !instver.end()))
+      return;
+
+   // if we are marked already we are done
+   if(state.Marked)
+      return;
+
+   //std::cout << "Setting Marked for: " << pkg.Name() << std::endl;
+   state.Marked=true;
+
+   if(!ver.end())
+   {
+     for(pkgCache::DepIterator d=ver.DependsList(); !d.end(); ++d)
+     {
+       if(d->Type==pkgCache::Dep::Depends ||
+          d->Type==pkgCache::Dep::PreDepends ||
+          (follow_recommends &&
+           d->Type==pkgCache::Dep::Recommends) ||
+          (follow_suggests &&
+           d->Type==pkgCache::Dep::Suggests))
+        {
+          // Try all versions of this package.
+          for(pkgCache::VerIterator V=d.TargetPkg().VersionList(); 
+              !V.end(); ++V)
+          {
+             if(_system->VS->CheckDep(V.VerStr(),d->CompareOp, d.TargetVer()))
+             {
+                pkgMarkPackage(Cache, V.ParentPkg(), V, 
+                               follow_recommends, follow_suggests);
+             }
+          }
+          // Now try virtual packages
+          for(pkgCache::PrvIterator prv=d.TargetPkg().ProvidesList(); 
+              !prv.end(); ++prv)
+          {
+             if(_system->VS->CheckDep(prv.ProvideVersion(), d->CompareOp, 
+                                      d.TargetVer()))
+             {
+                pkgMarkPackage(Cache, prv.OwnerPkg(), prv.OwnerVer(),
+                               follow_recommends, follow_suggests);
+             }
+          }
+       }
+     }
+   }
+}
+
+
+// Helper for APT::NeverAutoRemove, always include the packages matching
+// this regexp into the root-set
+inline bool 
+pkgMarkAlwaysInclude(pkgCache::PkgIterator p, vector<regex_t*> alwaysMark)
+{
+   for(unsigned int i=0;i<alwaysMark.size();i++)
+      if (regexec(alwaysMark[i],p.Name(),0,0,0) == 0)
+        return true;
+
+   return false;
+}
+
+// the main mark algorithm
+bool pkgMarkUsed(pkgDepCache &Cache, InRootSetFunc func)
+{
+   bool follow_recommends;
+   bool follow_suggests;
+
+   // init the states
+   for(pkgCache::PkgIterator p=Cache.PkgBegin(); !p.end(); ++p)
+   {
+      Cache[p].Marked=false;
+      Cache[p].Garbage=false;
+   }
+
+   // init vars
+   follow_recommends=_config->FindB("APT::AutoRemove::RecommendsImportant",false);
+   follow_suggests=_config->FindB("APT::AutoRemove::SuggestsImportant", false);
+
+
+   // init the "NeverAutoRemove" variable
+   vector<regex_t *> neverAutoRemoveRegexp;
+   Configuration::Item const *Opts;
+   Opts = _config->Tree("APT::NeverAutoRemove");
+   if (Opts != 0 && Opts->Child != 0)
+   {
+      Opts = Opts->Child;
+      for (; Opts != 0; Opts = Opts->Next)
+      {
+        if (Opts->Value.empty() == true)
+           continue;
+
+        regex_t *p = new regex_t;
+        if(regcomp(p,Opts->Value.c_str(),
+                   REG_EXTENDED | REG_ICASE |  REG_NOSUB) != 0)
+        {
+           regfree(p);
+           for(unsigned int i=0;i<neverAutoRemoveRegexp.size();i++)
+              regfree(neverAutoRemoveRegexp[i]);
+           return _error->Error("Regex compilation error for APT::NeverAutoRemove");
+        }
+        neverAutoRemoveRegexp.push_back(p);
+      }
+   }
+
+
+   // do the mark part, this is the core bit of the algorithm
+   for(pkgCache::PkgIterator p=Cache.PkgBegin(); !p.end(); ++p)
+   {
+      if( (func != NULL ? (*func)(p) : false) ||
+          pkgMarkAlwaysInclude(p, neverAutoRemoveRegexp) ||
+        !(Cache[p].Flags & pkgCache::Flag::Auto) ||
+         (p->Flags & pkgCache::Flag::Essential))
+          
+      {
+        // the package is installed (and set to keep)
+        if(Cache[p].Keep() && !p.CurrentVer().end())
+           pkgMarkPackage(Cache, p, p.CurrentVer(),
+                          follow_recommends, follow_suggests);
+        // the package is to be installed 
+        else if(Cache[p].Install())
+           pkgMarkPackage(Cache, p, Cache[p].InstVerIter(Cache),
+                          follow_recommends, follow_suggests);
+      }
+   }
+
+
+   // do the sweep
+   for(pkgCache::PkgIterator p=Cache.PkgBegin(); !p.end(); ++p)
+  {
+     pkgDepCache::StateCache &state=Cache[p];
+
+     if(!state.Marked)
+     {
+       // mark installed but not yet marked stuff as garbage
+       if(p->CurrentVer != 0) {
+          state.Garbage=true;
+          std::cout << "Garbage: " << p.Name() << std::endl;
+       }
+
+#if 0   // mvo: the below bits still needs to be ported
+
+       // Be sure not to re-delete already deleted packages.
+       if(delete_unused && (!p.CurrentVer().end() || state.Install()) &&
+          !state.Delete())
+       {
+             bool do_delete=true;
+
+             // If the package is being upgraded, check if we're
+             // losing a versioned dep.  If the dependency matches
+             // the previous version and not the new version, keep
+             // the package back instead of removing it.
+             if(!p.CurrentVer().end() && state.Install())
+               {
+                 const char *vs=p.CurrentVer().VerStr();
+
+                 // Check direct revdeps only.  THIS ASSUMES NO
+                 // VERSIONED PROVIDES, but Debian probably won't
+                 // have them for ages if ever.
+                 for(pkgCache::DepIterator revdep=p.RevDependsList();
+                     !revdep.end(); ++revdep)
+                   {
+                     pkgCache::PkgIterator depender=revdep.ParentPkg();
+                     // Find which version of the depending package
+                     // will be installed.
+                     pkgCache::VerIterator instver=(*this)[depender].InstVerIter(*this);
+
+                     // Only pay attention to strong positive
+                     // dependencies whose parents will be installed.
+                     if(revdep.ParentVer()==instver &&
+                        (revdep->Type==pkgCache::Dep::Depends ||
+                         revdep->Type==pkgCache::Dep::PreDepends ||
+                         (revdep->Type==pkgCache::Dep::Recommends &&
+                          follow_recommends)))
+                       {
+                         // If the previous version matched, cancel the
+                         // deletion.  (note that I assume that the new
+                         // version does NOT match; otherwise it would
+                         // not be unused!)
+                         if(_system->VS->CheckDep(vs,
+                                                  revdep->CompareOp,
+                                                  revdep.TargetVer()))
+                           {
+                             mark_keep(p, false, false, undo);
+                             do_delete=false;
+                             break;
+                           }
+                       }
+                   }
+               }
+
+             if(do_delete)
+               mark_delete(p, false, true, undo);
+           }
+#endif
+     }
+  }
+
+   // cleanup
+   for(unsigned int i=0;i<neverAutoRemoveRegexp.size();i++)
+      regfree(neverAutoRemoveRegexp[i]);
+   
+
+   return true;
+}