]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/depcache.cc
* merged from the apt--install-recommends branch
[apt.git] / apt-pkg / depcache.cc
index 4e94881217dc7730f5301a706e531157f1741e41..446bbe402d75e99340a6a31882908eb3393f12b0 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <iostream>
 #include <sstream>    
+#include <set>
 
 #include <apti18n.h>    
 
@@ -180,28 +181,81 @@ bool pkgDepCache::readStateFile(OpProgress *Prog)
 
 bool pkgDepCache::writeStateFile(OpProgress *prog)
 {
+   if(_config->FindB("Debug::pkgAutoRemove",false))
+      std::clog << "pkgDepCache::writeStateFile()" << std::endl;
+
    FileFd StateFile;
    string state = _config->FindDir("Dir::State") + "extended_states";
 
-   if(_config->FindB("Debug::pkgAutoRemove",false))
-      std::clog << "pkgDepCache::writeStateFile()" << std::endl;
+   // if it does not exist, create a empty one
+   if(!FileExists(state)) 
+   {
+      StateFile.Open(state, FileFd::WriteEmpty);
+      StateFile.Close();
+   }
 
-   if(!StateFile.Open(state, FileFd::WriteEmpty))
-      return _error->Error(_("Failed to write StateFile %s"),
+   // open it
+   if(!StateFile.Open(state, FileFd::ReadOnly))
+      return _error->Error(_("Failed to open StateFile %s"),
                           state.c_str());
 
+   FILE *OutFile;
+   string outfile = state + ".tmp";
+   if((OutFile = fopen(outfile.c_str(),"w")) == NULL)
+      return _error->Error(_("Failed to write temporary StateFile %s"),
+                          outfile.c_str());
+
+   // first merge with the existing sections
+   pkgTagFile tagfile(&StateFile);
+   pkgTagSection section;
+   std::set<string> pkgs_seen;
+   const char *nullreorderlist[] = {0};
+   while(tagfile.Step(section)) {
+        string pkgname = section.FindS("Package");
+        // Silently ignore unknown packages and packages with no actual
+        // version.
+        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: " 
+                     << pkg.Name() << std::endl;
+        TFRewriteData rewrite[2];
+        rewrite[0].Tag = "Auto-Installed";
+        rewrite[0].Rewrite = newAuto ? "1" : "0";
+        rewrite[0].NewTag = 0;
+        rewrite[1].Tag = 0;
+        TFRewrite(OutFile, section, nullreorderlist, rewrite);
+        fprintf(OutFile,"\n");
+        pkgs_seen.insert(pkgname);
+   }
+   
+   // then write the ones we have not seen yet
    std::ostringstream ostr;
-   for(pkgCache::PkgIterator pkg=Cache->PkgBegin(); !pkg.end();pkg++) {
-
+   for(pkgCache::PkgIterator pkg=Cache->PkgBegin(); !pkg.end(); pkg++) {
       if(PkgState[pkg->ID].Flags & Flag::Auto) {
+        if (pkgs_seen.find(pkg.Name()) != pkgs_seen.end()) {
+           if(_config->FindB("Debug::pkgAutoRemove",false))
+              std::clog << "Skipping already written " << pkg.Name() << std::endl;
+           continue;
+        }
         if(_config->FindB("Debug::pkgAutoRemove",false))
-           std::clog << "AutoInstall: " << pkg.Name() << std::endl;
+           std::clog << "Writing new AutoInstall: " 
+                     << pkg.Name() << std::endl;
         ostr.str(string(""));
         ostr << "Package: " << pkg.Name() 
              << "\nAuto-Installed: 1\n\n";
-        StateFile.Write(ostr.str().c_str(), ostr.str().size());
+        fprintf(OutFile,ostr.str().c_str());
+        fprintf(OutFile,"\n");
       }
    }
+   fclose(OutFile);
+
+   // move the outfile over the real file
+   rename(outfile.c_str(), state.c_str());
+
    return true;
 }
 
@@ -345,9 +399,11 @@ void pkgDepCache::AddStates(const PkgIterator &Pkg,int Add)
 {
    StateCache &State = PkgState[Pkg->ID];
    
-   // The Package is broken
+   // The Package is broken (either minimal dep or policy dep)
    if ((State.DepState & DepInstMin) != DepInstMin)
       iBrokenCount += Add;
+   if ((State.DepState & DepInstPolicy) != DepInstPolicy)
+      iPolicyBrokenCount += Add;
    
    // Bad state
    if (Pkg.State() != PkgIterator::NeedsNothing)
@@ -709,7 +765,8 @@ void pkgDepCache::MarkDelete(PkgIterator const &Pkg, bool rPurge)
 // ---------------------------------------------------------------------
 /* */
 void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
-                             unsigned long Depth, bool FromUser)
+                             unsigned long Depth, bool FromUser,
+                             bool ForceImportantDeps)
 {
    if (Depth > 100)
       return;
@@ -724,7 +781,8 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
       installed */
    StateCache &P = PkgState[Pkg->ID];
    P.iFlags &= ~AutoKept;
-   if (P.InstBroken() == false && (P.Mode == ModeInstall ||
+   if ((P.InstPolicyBroken() == false && P.InstBroken() == false) && 
+       (P.Mode == ModeInstall ||
        P.CandidateVer == (Version *)Pkg.CurrentVer()))
    {
       if (P.CandidateVer == (Version *)Pkg.CurrentVer() && P.InstallVer == 0)
@@ -735,11 +793,9 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
    // See if there is even any possible instalation candidate
    if (P.CandidateVer == 0)
       return;
-   
    // We dont even try to install virtual packages..
    if (Pkg->VersionList == 0)
       return;
-   
    /* Target the candidate version and remove the autoflag. We reset the
       autoflag below if this was called recursively. Otherwise the user
       should have the ability to de-auto a package by changing its state */
@@ -793,10 +849,43 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
 
       /* Check if this dep should be consider for install. If it is a user
          defined important dep and we are installed a new package then 
-        it will be installed. Otherwise we only worry about critical deps */
+        it will be installed. Otherwise we only check for important
+         deps that have changed from the installed version
+      */
       if (IsImportantDep(Start) == false)
         continue;
-      if (Pkg->CurrentVer != 0 && Start.IsCritical() == false)
+      
+      /* check if any ImportantDep() (but not Critial) where added
+       * since we installed the package
+       */
+      bool isNewImportantDep = false;
+      if(!ForceImportantDeps && !Start.IsCritical())
+      {
+        bool found=false;
+        VerIterator instVer = Pkg.CurrentVer();
+        if(!instVer.end())
+        {
+           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(isNewImportantDep)
+        if(_config->FindB("Debug::pkgDepCache::AutoInstall",false) == true)
+           std::clog << "new important dependency: " 
+                     << Start.TargetPkg().Name() << std::endl;
+
+      // skip important deps if the package is already installed
+      if (Pkg->CurrentVer != 0 && Start.IsCritical() == false 
+         && !isNewImportantDep && !ForceImportantDeps)
         continue;
       
       /* If we are in an or group locate the first or that can 
@@ -844,7 +933,11 @@ 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);
+          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;
       }
@@ -1006,7 +1099,28 @@ pkgCache::VerIterator pkgDepCache::Policy::GetCandidateVer(PkgIterator Pkg)
 /* */
 bool pkgDepCache::Policy::IsImportantDep(DepIterator Dep)
 {
-   return Dep.IsCritical();
+   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
+      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;
+      }
+   }
+   else if(Dep->Type == pkgCache::Dep::Suggests)
+     return _config->FindB("APT::Install-Suggests", false);
+
+   return false;
 }
                                                                        /*}}}*/