X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/e6549dfd43ccf76b6adbe0149b1aa42ea61cb962..6ae0cde915102bb4b0d272de4342ff6f62840d63:/apt-pkg/depcache.cc

diff --git a/apt-pkg/depcache.cc b/apt-pkg/depcache.cc
index 446bbe402..859e64ea1 100644
--- a/apt-pkg/depcache.cc
+++ b/apt-pkg/depcache.cc
@@ -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>
@@ -26,8 +23,31 @@
 #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)
 {
@@ -179,7 +199,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 +237,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,6 +260,9 @@ 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;
@@ -253,8 +275,9 @@ bool pkgDepCache::writeStateFile(OpProgress *prog)
    }
    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;
 }
@@ -273,7 +296,7 @@ bool pkgDepCache::CheckDep(DepIterator Dep,int Type,PkgIterator &Res)
       we allow it anyhow because dpkg does. Technically it is a packaging
       bug. Conflicts may never self match */
    if (Dep.TargetPkg() != Dep.ParentPkg() || 
-       (Dep->Type != Dep::Conflicts && Dep->Type != Dep::Obsoletes))
+       (Dep->Type != Dep::Conflicts && Dep->Type != Dep::DpkgBreaks && Dep->Type != Dep::Obsoletes))
    {
       PkgIterator Pkg = Dep.TargetPkg();
       // Check the base package
@@ -303,7 +326,8 @@ bool pkgDepCache::CheckDep(DepIterator Dep,int Type,PkgIterator &Res)
    {
       /* Provides may never be applied against the same package if it is
          a conflicts. See the comment above. */
-      if (P.OwnerPkg() == Pkg && Dep->Type == Dep::Conflicts)
+      if (P.OwnerPkg() == Pkg &&
+	  (Dep->Type == Dep::Conflicts || Dep->Type == Dep::DpkgBreaks))
 	 continue;
       
       // Check if the provides is a hit
@@ -457,7 +481,9 @@ void pkgDepCache::BuildGroupOrs(VerIterator const &V)
 
       /* Invert for Conflicts. We have to do this twice to get the
          right sense for a conflicts group */
-      if (D->Type == Dep::Conflicts || D->Type == Dep::Obsoletes)
+      if (D->Type == Dep::Conflicts ||
+	  D->Type == Dep::DpkgBreaks ||
+	  D->Type == Dep::Obsoletes)
 	 State = ~State;
       
       // Add to the group if we are within an or..
@@ -468,7 +494,9 @@ void pkgDepCache::BuildGroupOrs(VerIterator const &V)
 	 Group = 0;
       
       // Invert for Conflicts
-      if (D->Type == Dep::Conflicts || D->Type == Dep::Obsoletes)
+      if (D->Type == Dep::Conflicts ||
+	  D->Type == Dep::DpkgBreaks ||
+	  D->Type == Dep::Obsoletes)
 	 State = ~State;
    }	 
 }
@@ -601,7 +629,9 @@ void pkgDepCache::Update(OpProgress *Prog)
 	       Group = 0;
 
 	    // Invert for Conflicts
-	    if (D->Type == Dep::Conflicts || D->Type == Dep::Obsoletes)
+	    if (D->Type == Dep::Conflicts ||
+		D->Type == Dep::DpkgBreaks ||
+		D->Type == Dep::Obsoletes)
 	       State = ~State;
 	 }	 
       }
@@ -631,7 +661,9 @@ void pkgDepCache::Update(DepIterator D)
       State = DependencyState(D);
     
       // Invert for Conflicts
-      if (D->Type == Dep::Conflicts || D->Type == Dep::Obsoletes)
+      if (D->Type == Dep::Conflicts ||
+	  D->Type == Dep::DpkgBreaks ||
+	  D->Type == Dep::Obsoletes)
 	 State = ~State;
 
       RemoveStates(D.ParentPkg());
@@ -703,9 +735,17 @@ 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
+
    RemoveSizes(Pkg);
    RemoveStates(Pkg);
 
@@ -855,24 +895,42 @@ 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;
-	    }
+
+	       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;
@@ -882,10 +940,15 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
 	 if(_config->FindB("Debug::pkgDepCache::AutoInstall",false) == true)
 	    std::clog << "new important dependency: " 
 		      << Start.TargetPkg().Name() << std::endl;
+      if(isPreviouslySatisfiedImportantDep)
+	if(_config->FindB("Debug::pkgDepCache::AutoInstall", false) == true)
+	  std::clog << "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 
@@ -896,7 +959,8 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
       /* This bit is for processing the possibilty of an install/upgrade
          fixing the problem */
       SPtrArray<Version *> List = Start.AllTargets();
-      if ((DepState[Start->ID] & DepCVer) == DepCVer)
+      if (Start->Type != Dep::DpkgBreaks &&
+	  (DepState[Start->ID] & DepCVer) == DepCVer)
       {
 	 // Right, find the best version to install..
 	 Version **Cur = List;
@@ -933,25 +997,41 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
 	       std::clog << "Installing " << InstPkg.Name() 
 			 << " as dep 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(_config->FindB("Debug::pkgDepCache::AutoInstall",false) == true)
+ 		  std::clog << "Setting NOT as auto-installed (direct dep 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;
       }
-      
+
       /* For conflicts we just de-install the package and mark as auto,
-         Conflicts may not have or groups */
-      if (Start->Type == Dep::Conflicts || Start->Type == Dep::Obsoletes)
+         Conflicts may not have or groups.  For dpkg's Breaks we try to
+         upgrade the package. */
+      if (Start->Type == Dep::Conflicts || Start->Type == Dep::Obsoletes ||
+	  Start->Type == Dep::DpkgBreaks)
       {
 	 for (Version **I = List; *I != 0; I++)
 	 {
 	    VerIterator Ver(*this,*I);
 	    PkgIterator Pkg = Ver.ParentPkg();
-      
-	    MarkDelete(Pkg);
+
+	    if (Start->Type != Dep::DpkgBreaks)
+	       MarkDelete(Pkg);
+	    else
+	       if (PkgState[Pkg->ID].CandidateVer != *I)
+		  MarkInstall(Pkg,true,Depth + 1, false, ForceImportantDeps);
 	 }
 	 continue;
       }      
@@ -1094,6 +1174,7 @@ pkgCache::VerIterator pkgDepCache::Policy::GetCandidateVer(PkgIterator Pkg)
    return Last;
 }
 									/*}}}*/
+
 // Policy::IsImportantDep - True if the dependency is important		/*{{{*/
 // ---------------------------------------------------------------------
 /* */
@@ -1109,13 +1190,9 @@ bool pkgDepCache::Policy::IsImportantDep(DepIterator Dep)
       // sections
       // FIXME: this is a meant as a temporarly solution until the 
       //        recommends are cleaned up
-      string s = _config->Find("APT::Install-Recommends-Section","");
-      if(s.size() > 0) 
-      {
-	 const char *sec = Dep.TargetPkg().Section();
-	 if (sec && strcmp(sec, s.c_str()) == 0)
-	    return true;
-      }
+      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);
@@ -1229,7 +1306,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())
@@ -1248,6 +1325,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);
 
@@ -1268,16 +1346,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())
@@ -1297,6 +1388,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);
 	      }
@@ -1308,6 +1412,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);
 	      }
@@ -1324,9 +1445,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))