]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/depcache.cc
merge the AutoInstOk patch from debian-experimental
[apt.git] / apt-pkg / depcache.cc
index 4d193dc2e81fd0fc19e567cd15f46d10278ba145..b1b8f970f0938081c53dc732283498fa64e63c58 100644 (file)
@@ -8,9 +8,6 @@
    ##################################################################### */
                                                                        /*}}}*/
 // Include Files                                                       /*{{{*/
-#ifdef __GNUG__
-#pragma implementation "apt-pkg/depcache.h"
-#endif
 #include <apt-pkg/depcache.h>
 #include <apt-pkg/version.h>
 #include <apt-pkg/error.h>
@@ -18,6 +15,7 @@
 #include <apt-pkg/algorithms.h>
 
 #include <apt-pkg/fileutl.h>
+#include <apt-pkg/strutl.h>
 #include <apt-pkg/configuration.h>
 #include <apt-pkg/pkgsystem.h>
 #include <apt-pkg/tagfile.h>
 #include <sstream>    
 #include <set>
 
+#include <sys/stat.h>
+
 #include <apti18n.h>    
 
+// helper for Install-Recommends-Sections and Never-MarkAuto-Sections
+static bool 
+ConfigValueInSubTree(const char* SubTree, const char *needle)
+{
+   Configuration::Item const *Opts;
+   Opts = _config->Tree(SubTree);
+   if (Opts != 0 && Opts->Child != 0)
+   {
+      Opts = Opts->Child;
+      for (; Opts != 0; Opts = Opts->Next)
+      {
+        if (Opts->Value.empty() == true)
+           continue;
+        if (strcmp(needle, Opts->Value.c_str()) == 0)
+           return true;
+      }
+   }
+   return false;
+}
+
 pkgDepCache::ActionGroup::ActionGroup(pkgDepCache &cache) :
   cache(cache), released(false)
 {
@@ -63,6 +83,8 @@ pkgDepCache::ActionGroup::~ActionGroup()
 pkgDepCache::pkgDepCache(pkgCache *pCache,Policy *Plcy) :
   group_level(0), Cache(pCache), PkgState(0), DepState(0)
 {
+   DebugMarker = _config->FindB("Debug::pkgDepCache::Marker", false);
+   DebugAutoInstall = _config->FindB("Debug::pkgDepCache::AutoInstall", false);
    delLocalPolicy = 0;
    LocalPolicy = Plcy;
    if (LocalPolicy == 0)
@@ -179,7 +201,7 @@ bool pkgDepCache::readStateFile(OpProgress *Prog)
    return true;
 }
 
-bool pkgDepCache::writeStateFile(OpProgress *prog)
+bool pkgDepCache::writeStateFile(OpProgress *prog, bool InstalledOnly)
 {
    if(_config->FindB("Debug::pkgAutoRemove",false))
       std::clog << "pkgDepCache::writeStateFile()" << std::endl;
@@ -217,7 +239,6 @@ bool pkgDepCache::writeStateFile(OpProgress *prog)
         pkgCache::PkgIterator pkg=Cache->FindPkg(pkgname);
         if(pkg.end() || pkg.VersionList().end()) 
            continue;
-        bool oldAuto = section.FindI("Auto-Installed");
         bool newAuto = (PkgState[pkg->ID].Flags & Flag::Auto);
         if(_config->FindB("Debug::pkgAutoRemove",false))
            std::clog << "Update exisiting AutoInstall info: " 
@@ -241,20 +262,24 @@ bool pkgDepCache::writeStateFile(OpProgress *prog)
               std::clog << "Skipping already written " << pkg.Name() << std::endl;
            continue;
         }
+         // skip not installed ones if requested
+         if(InstalledOnly && pkg->CurrentVer == 0)
+            continue;
         if(_config->FindB("Debug::pkgAutoRemove",false))
            std::clog << "Writing new AutoInstall: " 
                      << pkg.Name() << std::endl;
         ostr.str(string(""));
         ostr << "Package: " << pkg.Name() 
              << "\nAuto-Installed: 1\n\n";
-        fprintf(OutFile,ostr.str().c_str());
+        fprintf(OutFile,"%s",ostr.str().c_str());
         fprintf(OutFile,"\n");
       }
    }
    fclose(OutFile);
 
-   // move the outfile over the real file
+   // move the outfile over the real file and set permissions
    rename(outfile.c_str(), state.c_str());
+   chmod(state.c_str(), 0644);
 
    return true;
 }
@@ -682,7 +707,8 @@ void pkgDepCache::Update(PkgIterator const &Pkg)
 // DepCache::MarkKeep - Put the package in the keep state              /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-void pkgDepCache::MarkKeep(PkgIterator const &Pkg, bool Soft, bool FromUser)
+void pkgDepCache::MarkKeep(PkgIterator const &Pkg, bool Soft, bool FromUser,
+                           unsigned long Depth)
 {
    // Simplifies other routines.
    if (Pkg.end() == true)
@@ -712,9 +738,20 @@ void pkgDepCache::MarkKeep(PkgIterator const &Pkg, bool Soft, bool FromUser)
    // We dont even try to keep virtual packages..
    if (Pkg->VersionList == 0)
       return;
-   
+#if 0 // reseting the autoflag here means we lose the 
+      // auto-mark information if a user selects a package for removal
+      // but changes  his mind then and sets it for keep again
+      // - this makes sense as default when all Garbage dependencies
+      //   are automatically marked for removal (as aptitude does).
+      //   setting a package for keep then makes it no longer autoinstalled
+      //   for all other use-case this action is rather suprising
    if(FromUser && !P.Marked)
      P.Flags &= ~Flag::Auto;
+#endif
+
+   if (DebugMarker == true)
+      std::clog << OutputInDepth(Depth) << "MarkKeep " << Pkg << std::endl;
+
    RemoveSizes(Pkg);
    RemoveStates(Pkg);
 
@@ -734,7 +771,8 @@ void pkgDepCache::MarkKeep(PkgIterator const &Pkg, bool Soft, bool FromUser)
 // DepCache::MarkDelete - Put the package in the delete state          /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-void pkgDepCache::MarkDelete(PkgIterator const &Pkg, bool rPurge)
+void pkgDepCache::MarkDelete(PkgIterator const &Pkg, bool rPurge,
+                             unsigned long Depth)
 {
    // Simplifies other routines.
    if (Pkg.end() == true)
@@ -756,6 +794,9 @@ void pkgDepCache::MarkDelete(PkgIterator const &Pkg, bool rPurge)
    if (Pkg->VersionList == 0)
       return;
 
+   if (DebugMarker == true)
+      std::clog << OutputInDepth(Depth) << "MarkDelete " << Pkg << std::endl;
+
    RemoveSizes(Pkg);
    RemoveStates(Pkg);
    
@@ -795,7 +836,7 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
        P.CandidateVer == (Version *)Pkg.CurrentVer()))
    {
       if (P.CandidateVer == (Version *)Pkg.CurrentVer() && P.InstallVer == 0)
-        MarkKeep(Pkg, false, FromUser);
+        MarkKeep(Pkg, false, FromUser, Depth+1);
       return;
    }
 
@@ -837,6 +878,9 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
    if (AutoInst == false)
       return;
 
+   if (DebugMarker == true)
+      std::clog << OutputInDepth(Depth) << "MarkInstall " << Pkg << std::endl;
+
    DepIterator Dep = P.InstVerIter(*this).DependsList();
    for (; Dep.end() != true;)
    {
@@ -864,35 +908,60 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
       if (IsImportantDep(Start) == false)
         continue;
       
-      /* check if any ImportantDep() (but not Critial) where added
-       * since we installed the package
+      /* Check if any ImportantDep() (but not Critical) were added
+       * since we installed the package.  Also check for deps that
+       * were satisfied in the past: for instance, if a version
+       * restriction in a Recommends was tightened, upgrading the
+       * package should follow that Recommends rather than causing the
+       * dependency to be removed. (bug #470115)
        */
       bool isNewImportantDep = false;
+      bool isPreviouslySatisfiedImportantDep = false;
       if(!ForceImportantDeps && !Start.IsCritical())
       {
         bool found=false;
         VerIterator instVer = Pkg.CurrentVer();
         if(!instVer.end())
-           for (DepIterator D = instVer.DependsList(); D.end() != true; D++)
-           {
+        {
+          for (DepIterator D = instVer.DependsList(); D.end() != true; D++)
+            {
               //FIXME: deal better with or-groups(?)
               DepIterator LocalStart = D;
-              
-              if(IsImportantDep(D) && Start.TargetPkg() == D.TargetPkg())
-                 found=true;
-           }
-        // this is a new dep if it was not found to be already
-        // a important dep of the installed pacakge
-        isNewImportantDep = !found;
+
+              if(IsImportantDep(D) && !D.IsCritical() &&
+                 Start.TargetPkg() == D.TargetPkg())
+                {
+                  if(!isPreviouslySatisfiedImportantDep)
+                    {
+                      DepIterator D2 = D;
+                      while((D2->CompareOp & Dep::Or) != 0)
+                        ++D2;
+
+                      isPreviouslySatisfiedImportantDep =
+                        (((*this)[D2] & DepGNow) != 0);
+                    }
+
+                  found=true;
+                }
+            }
+           // this is a new dep if it was not found to be already
+           // a important dep of the installed pacakge
+           isNewImportantDep = !found;
+        }
       }
       if(isNewImportantDep)
-        if(_config->FindB("Debug::pkgDepCache::AutoInstall",false) == true)
-           std::clog << "new important dependency: " 
+        if(DebugAutoInstall == true)
+           std::clog << OutputInDepth(Depth) << "new important dependency: "
                      << Start.TargetPkg().Name() << std::endl;
+      if(isPreviouslySatisfiedImportantDep)
+       if(DebugAutoInstall == true)
+         std::clog << OutputInDepth(Depth) << "previously satisfied important dependency on "
+                   << Start.TargetPkg().Name() << std::endl;
 
       // skip important deps if the package is already installed
       if (Pkg->CurrentVer != 0 && Start.IsCritical() == false 
-         && !isNewImportantDep && !ForceImportantDeps)
+         && !isNewImportantDep && !isPreviouslySatisfiedImportantDep
+         && !ForceImportantDeps)
         continue;
       
       /* If we are in an or group locate the first or that can 
@@ -935,17 +1004,29 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
            }
         }
         
-        if (InstPkg.end() == false) 
+        if (InstPkg.end() == false &&
+            AutoInstOk(InstPkg, (*this)[InstPkg].CandidateVerIter(*this), Start))
         {
-           if(_config->FindB("Debug::pkgDepCache::AutoInstall",false) == true)
-              std::clog << "Installing " << InstPkg.Name() 
-                        << " as dep of " << Pkg.Name() 
+           if(DebugAutoInstall == true)
+              std::clog << OutputInDepth(Depth) << "Installing " << InstPkg.Name()
+                        << " as " << Start.DepType() << " of " << Pkg.Name()
                         << std::endl;
-           MarkInstall(InstPkg,true,Depth + 1, false, ForceImportantDeps);
-
-           // Set the autoflag, after MarkInstall because MarkInstall unsets it
-           if (P->CurrentVer == 0)
-              PkgState[InstPkg->ID].Flags |= Flag::Auto;
+           // now check if we should consider it a automatic dependency or not
+           if(Pkg.Section() && ConfigValueInSubTree("APT::Never-MarkAuto-Sections", Pkg.Section()))
+           {
+              if(DebugAutoInstall == true)
+                 std::clog << OutputInDepth(Depth) << "Setting NOT as auto-installed (direct "
+                            << Start.DepType() << " of pkg in APT::Never-MarkAuto-Sections)" << std::endl;
+              MarkInstall(InstPkg,true,Depth + 1, true);
+           }
+           else 
+           {
+              // mark automatic dependency
+              MarkInstall(InstPkg,true,Depth + 1, false, ForceImportantDeps);
+              // Set the autoflag, after MarkInstall because MarkInstall unsets it
+              if (P->CurrentVer == 0)
+                 PkgState[InstPkg->ID].Flags |= Flag::Auto;
+           }
         }
         continue;
       }
@@ -962,15 +1043,31 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
            PkgIterator Pkg = Ver.ParentPkg();
 
            if (Start->Type != Dep::DpkgBreaks)
-              MarkDelete(Pkg);
+           {
+              if(AutoInstOk(Pkg, VerIterator(*this), Start))
+                 MarkDelete(Pkg);
+           }
            else
-              if (PkgState[Pkg->ID].CandidateVer != *I)
+              if (PkgState[Pkg->ID].CandidateVer != *I &&
+                  AutoInstOk(Pkg, VerIterator(*this, PkgState[Pkg->ID].CandidateVer), Start))
                  MarkInstall(Pkg,true,Depth + 1, false, ForceImportantDeps);
         }
         continue;
       }      
    }
 }
+
+// DepCache::AutoInstOk - check if it is to install this package       /*{{{*/
+// ---------------------------------------------------------------------
+/* The default implementation just honors dpkg hold
+   But an application using this  library can override this method
+   to control the MarkInstall behaviour */
+bool pkgDepCache::AutoInstOk(const PkgIterator &Pkg, 
+                             const VerIterator &v,
+                             const DepIterator &d)
+{
+   return (Pkg->SelectedState != pkgCache::State::Hold);
+}
                                                                        /*}}}*/
 // DepCache::SetReInstall - Set the reinstallation flag                        /*{{{*/
 // ---------------------------------------------------------------------
@@ -1108,6 +1205,31 @@ pkgCache::VerIterator pkgDepCache::Policy::GetCandidateVer(PkgIterator Pkg)
    return Last;
 }
                                                                        /*}}}*/
+
+// Policy::IsImportantDep - True if the dependency is important                /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool pkgDepCache::Policy::IsImportantDep(DepIterator Dep)
+{
+   if(Dep.IsCritical())
+      return true;
+   else if(Dep->Type == pkgCache::Dep::Recommends) 
+   {
+      if ( _config->FindB("APT::Install-Recommends", false))
+        return true;
+      // we suport a special mode to only install-recommends for certain
+      // sections
+      // FIXME: this is a meant as a temporarly solution until the 
+      //        recommends are cleaned up
+      const char *sec = Dep.ParentVer().Section();
+      if (sec && ConfigValueInSubTree("APT::Install-Recommends-Sections", sec))
+        return true;
+   }
+   else if(Dep->Type == pkgCache::Dep::Suggests)
+     return _config->FindB("APT::Install-Suggests", false);
+
+   return false;
+}
                                                                        /*}}}*/
 
 pkgDepCache::DefaultRootSetFunc::DefaultRootSetFunc()
@@ -1215,7 +1337,7 @@ bool pkgDepCache::MarkRequired(InRootSetFunc &userFunc)
       {
         // the package is installed (and set to keep)
         if(PkgState[p->ID].Keep() && !p.CurrentVer().end())
-           MarkPackage(p, p.CurrentVer(),
+           MarkPackage(p, p.CurrentVer(),
                        follow_recommends, follow_suggests);
         // the package is to be installed 
         else if(PkgState[p->ID].Install())
@@ -1234,6 +1356,7 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
                              bool follow_suggests)
 {
    pkgDepCache::StateCache &state = PkgState[pkg->ID];
+   VerIterator currver            = pkg.CurrentVer();
    VerIterator candver            = state.CandidateVerIter(*this);
    VerIterator instver            = state.InstVerIter(*this);
 
@@ -1254,16 +1377,29 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
    }
 #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()))
+   // For packages that are not going to be removed, ignore versions
+   // other than the InstVer.  For packages that are going to be
+   // removed, ignore versions other than the current version.
+   if(!(ver == instver && !instver.end()) &&
+      !(ver == currver && instver.end() && !ver.end()))
       return;
 
    // if we are marked already we are done
    if(state.Marked)
       return;
 
-   //std::cout << "Setting Marked for: " << pkg.Name() << std::endl;
+   if(_config->FindB("Debug::pkgAutoRemove",false))
+     {
+       std::clog << "Marking: " << pkg.Name();
+       if(!ver.end())
+        std::clog << " " << ver.VerStr();
+       if(!currver.end())
+        std::clog << ", Curr=" << currver.VerStr();
+       if(!instver.end())
+        std::clog << ", Inst=" << instver.VerStr();
+       std::clog << std::endl;
+     }
+
    state.Marked=true;
 
    if(!ver.end())
@@ -1283,6 +1419,19 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
           {
              if(_system->VS->CheckDep(V.VerStr(), d->CompareOp, d.TargetVer()))
              {
+               if(_config->FindB("Debug::pkgAutoRemove",false))
+                 {
+                   std::clog << "Following dep: " << d.ParentPkg().Name()
+                             << " " << d.ParentVer().VerStr() << " "
+                             << d.DepType() << " "
+                             << d.TargetPkg().Name();
+                   if((d->CompareOp & ~pkgCache::Dep::Or) != pkgCache::Dep::NoOp)
+                     {
+                       std::clog << " (" << d.CompType() << " "
+                                 << d.TargetVer() << ")";
+                     }
+                   std::clog << std::endl;
+                 }
                 MarkPackage(V.ParentPkg(), V, 
                             follow_recommends, follow_suggests);
              }
@@ -1294,6 +1443,23 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
              if(_system->VS->CheckDep(prv.ProvideVersion(), d->CompareOp, 
                                       d.TargetVer()))
              {
+               if(_config->FindB("Debug::pkgAutoRemove",false))
+                 {
+                   std::clog << "Following dep: " << d.ParentPkg().Name()
+                             << " " << d.ParentVer().VerStr() << " "
+                             << d.DepType() << " "
+                             << d.TargetPkg().Name();
+                   if((d->CompareOp & ~pkgCache::Dep::Or) != pkgCache::Dep::NoOp)
+                     {
+                       std::clog << " (" << d.CompType() << " "
+                                 << d.TargetVer() << ")";
+                     }
+                   std::clog << ", provided by "
+                             << prv.OwnerPkg().Name() << " "
+                             << prv.OwnerVer().VerStr()
+                             << std::endl;
+                 }
+
                 MarkPackage(prv.OwnerPkg(), prv.OwnerVer(),
                             follow_recommends, follow_suggests);
              }
@@ -1310,9 +1476,13 @@ bool pkgDepCache::Sweep()
   {
      StateCache &state=PkgState[p->ID];
 
+     // skip required packages
+     if (!p.CurrentVer().end() && 
+        (p.CurrentVer()->Priority == pkgCache::State::Required))
+       continue;
+
      // if it is not marked and it is installed, it's garbage 
-     if(!state.Marked && (!p.CurrentVer().end() || state.Install()) &&
-       !state.Delete())
+     if(!state.Marked && (!p.CurrentVer().end() || state.Install()))
      {
        state.Garbage=true;
        if(_config->FindB("Debug::pkgAutoRemove",false))
@@ -1322,19 +1492,3 @@ bool pkgDepCache::Sweep()
 
    return true;
 }
-
-// Policy::IsImportantDep - True if the dependency is important                /*{{{*/
-// ---------------------------------------------------------------------
-/* */
-bool pkgDepCache::Policy::IsImportantDep(DepIterator Dep)
-{
-   if(Dep.IsCritical())
-      return true;
-   else if(Dep->Type == pkgCache::Dep::Recommends)
-      return  _config->FindB("APT::Install-Recommends", false);
-   else if(Dep->Type == pkgCache::Dep::Suggests)
-     return _config->FindB("APT::Install-Suggests", false);
-
-   return false;
-}
-                                                                       /*}}}*/