* apt-pkg/depcache.cc:
[ntk/apt.git] / apt-pkg / depcache.cc
index b1b8f97..e9fb5f7 100644 (file)
@@ -27,8 +27,8 @@
 #include <sys/stat.h>
 
 #include <apti18n.h>    
-
-// helper for Install-Recommends-Sections and Never-MarkAuto-Sections
+                                                                       /*}}}*/
+// helper for Install-Recommends-Sections and Never-MarkAuto-Sections  /*{{{*/
 static bool 
 ConfigValueInSubTree(const char* SubTree, const char *needle)
 {
@@ -47,8 +47,8 @@ ConfigValueInSubTree(const char* SubTree, const char *needle)
    }
    return false;
 }
-
-pkgDepCache::ActionGroup::ActionGroup(pkgDepCache &cache) :
+                                                                       /*}}}*/
+pkgDepCache::ActionGroup::ActionGroup(pkgDepCache &cache) :            /*{{{*/
   cache(cache), released(false)
 {
   ++cache.group_level;
@@ -76,7 +76,7 @@ pkgDepCache::ActionGroup::~ActionGroup()
 {
   release();
 }
-
+                                                                       /*}}}*/
 // DepCache::pkgDepCache - Constructors                                        /*{{{*/
 // ---------------------------------------------------------------------
 /* */
@@ -129,7 +129,7 @@ bool pkgDepCache::Init(OpProgress *Prog)
    int Done = 0;
    for (PkgIterator I = PkgBegin(); I.end() != true; I++,Done++)
    {
-      if (Prog != 0)
+      if (Prog != 0 && Done%20 == 0)
         Prog->Progress(Done);
       
       // Find the proper cache slot
@@ -161,8 +161,7 @@ bool pkgDepCache::Init(OpProgress *Prog)
    return true;
 } 
                                                                        /*}}}*/
-
-bool pkgDepCache::readStateFile(OpProgress *Prog)
+bool pkgDepCache::readStateFile(OpProgress *Prog)                      /*{{{*/
 {
    FileFd state_file;
    string state = _config->FindDir("Dir::State") + "extended_states";
@@ -176,6 +175,7 @@ bool pkgDepCache::readStateFile(OpProgress *Prog)
       pkgTagFile tagfile(&state_file);
       pkgTagSection section;
       int amt=0;
+      bool debug_autoremove=_config->FindB("Debug::pkgAutoRemove",false);
       while(tagfile.Step(section)) {
         string pkgname = section.FindS("Package");
         pkgCache::PkgIterator pkg=Cache->FindPkg(pkgname);
@@ -185,25 +185,27 @@ bool pkgDepCache::readStateFile(OpProgress *Prog)
            short reason = section.FindI("Auto-Installed", 0);
            if(reason > 0)
               PkgState[pkg->ID].Flags  |= Flag::Auto;
-           if(_config->FindB("Debug::pkgAutoRemove",false))
+           if(debug_autoremove)
               std::cout << "Auto-Installed : " << pkgname << std::endl;
            amt+=section.size();
            if(Prog != NULL)
               Prog->OverallProgress(amt, file_size, 1, 
                                     _("Reading state information"));
         }
-        if(Prog != NULL)
-           Prog->OverallProgress(file_size, file_size, 1, 
-                                 _("Reading state information"));
       }
+      if(Prog != NULL)
+        Prog->OverallProgress(file_size, file_size, 1,
+                              _("Reading state information"));
    }
 
    return true;
 }
-
-bool pkgDepCache::writeStateFile(OpProgress *prog, bool InstalledOnly)
+                                                                       /*}}}*/
+bool pkgDepCache::writeStateFile(OpProgress *prog, bool InstalledOnly) /*{{{*/
 {
-   if(_config->FindB("Debug::pkgAutoRemove",false))
+   bool debug_autoremove = _config->FindB("Debug::pkgAutoRemove",false);
+   
+   if(debug_autoremove)
       std::clog << "pkgDepCache::writeStateFile()" << std::endl;
 
    FileFd StateFile;
@@ -233,16 +235,30 @@ bool pkgDepCache::writeStateFile(OpProgress *prog, bool InstalledOnly)
    std::set<string> pkgs_seen;
    const char *nullreorderlist[] = {0};
    while(tagfile.Step(section)) {
-        string pkgname = section.FindS("Package");
+        string const 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 newAuto = (PkgState[pkg->ID].Flags & Flag::Auto);
+        StateCache const &P = PkgState[pkg->ID];
+        bool newAuto = (P.Flags & Flag::Auto);
+        // skip not installed or now-removed ones if requested
+        if (InstalledOnly && (
+            (pkg->CurrentVer == 0 && P.Mode != ModeInstall) ||
+            (pkg->CurrentVer != 0 && P.Mode == ModeDelete)))
+        {
+           // The section is obsolete if it contains no other tag
+           unsigned int const count = section.Count();
+           if (count < 2 ||
+               (count == 2 && section.Exists("Auto-Installed")))
+              continue;
+           else
+              newAuto = false;
+        }
         if(_config->FindB("Debug::pkgAutoRemove",false))
-           std::clog << "Update exisiting AutoInstall info: " 
-                     << pkg.Name() << std::endl;
+           std::clog << "Update existing AutoInstall info: " 
+                     << pkgname << std::endl;
         TFRewriteData rewrite[2];
         rewrite[0].Tag = "Auto-Installed";
         rewrite[0].Rewrite = newAuto ? "1" : "0";
@@ -256,16 +272,19 @@ bool pkgDepCache::writeStateFile(OpProgress *prog, bool InstalledOnly)
    // then write the ones we have not seen yet
    std::ostringstream ostr;
    for(pkgCache::PkgIterator pkg=Cache->PkgBegin(); !pkg.end(); pkg++) {
-      if(PkgState[pkg->ID].Flags & Flag::Auto) {
+      StateCache const &P = PkgState[pkg->ID];
+      if(P.Flags & Flag::Auto) {
         if (pkgs_seen.find(pkg.Name()) != pkgs_seen.end()) {
-           if(_config->FindB("Debug::pkgAutoRemove",false))
+           if(debug_autoremove)
               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))
+        // skip not installed ones if requested
+        if (InstalledOnly && (
+            (pkg->CurrentVer == 0 && P.Mode != ModeInstall) ||
+            (pkg->CurrentVer != 0 && P.Mode == ModeDelete)))
+           continue;
+        if(debug_autoremove)
            std::clog << "Writing new AutoInstall: " 
                      << pkg.Name() << std::endl;
         ostr.str(string(""));
@@ -283,7 +302,7 @@ bool pkgDepCache::writeStateFile(OpProgress *prog, bool InstalledOnly)
 
    return true;
 }
-
+                                                                       /*}}}*/
 // DepCache::CheckDep - Checks a single dependency                     /*{{{*/
 // ---------------------------------------------------------------------
 /* This first checks the dependency against the main target package and
@@ -701,9 +720,7 @@ void pkgDepCache::Update(PkgIterator const &Pkg)
           P.end() != true; P++)
         Update(P.ParentPkg().RevDependsList());
 }
-
                                                                        /*}}}*/
-
 // DepCache::MarkKeep - Put the package in the keep state              /*{{{*/
 // ---------------------------------------------------------------------
 /* */
@@ -750,7 +767,7 @@ void pkgDepCache::MarkKeep(PkgIterator const &Pkg, bool Soft, bool FromUser,
 #endif
 
    if (DebugMarker == true)
-      std::clog << OutputInDepth(Depth) << "MarkKeep " << Pkg << std::endl;
+      std::clog << OutputInDepth(Depth) << "MarkKeep " << Pkg << " FU=" << FromUser << std::endl;
 
    RemoveSizes(Pkg);
    RemoveStates(Pkg);
@@ -772,7 +789,7 @@ void pkgDepCache::MarkKeep(PkgIterator const &Pkg, bool Soft, bool FromUser,
 // ---------------------------------------------------------------------
 /* */
 void pkgDepCache::MarkDelete(PkgIterator const &Pkg, bool rPurge,
-                             unsigned long Depth)
+                             unsigned long Depth, bool FromUser)
 {
    // Simplifies other routines.
    if (Pkg.end() == true)
@@ -794,8 +811,12 @@ void pkgDepCache::MarkDelete(PkgIterator const &Pkg, bool rPurge,
    if (Pkg->VersionList == 0)
       return;
 
+   // check if we are allowed to install the package
+   if (IsDeleteOk(Pkg,rPurge,Depth,FromUser) == false)
+      return;
+
    if (DebugMarker == true)
-      std::clog << OutputInDepth(Depth) << "MarkDelete " << Pkg << std::endl;
+      std::clog << OutputInDepth(Depth) << "MarkDelete " << Pkg << " FU=" << FromUser << std::endl;
 
    RemoveSizes(Pkg);
    RemoveStates(Pkg);
@@ -811,6 +832,23 @@ void pkgDepCache::MarkDelete(PkgIterator const &Pkg, bool rPurge,
    AddSizes(Pkg);
 }
                                                                        /*}}}*/
+// DepCache::IsDeleteOk - check if it is ok to remove this package     /*{{{*/
+// ---------------------------------------------------------------------
+/* The default implementation just honors dpkg hold
+   But an application using this library can override this method
+   to control the MarkDelete behaviour */
+bool pkgDepCache::IsDeleteOk(PkgIterator const &Pkg,bool rPurge,
+                             unsigned long Depth, bool FromUser)
+{
+   if (FromUser == false && Pkg->SelectedState == pkgCache::State::Hold && _config->FindB("APT::Ignore-Hold",false) == false)
+   {
+      if (DebugMarker == true)
+        std::clog << OutputInDepth(Depth) << "Hold prevents MarkDelete of " << Pkg << " FU=" << FromUser << std::endl;
+      return false;
+   }
+   return true;
+}
+                                                                       /*}}}*/
 // DepCache::MarkInstall - Put the package in the install state                /*{{{*/
 // ---------------------------------------------------------------------
 /* */
@@ -846,6 +884,11 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
    // We dont even try to install virtual packages..
    if (Pkg->VersionList == 0)
       return;
+
+   // check if we are allowed to install the package
+   if (IsInstallOk(Pkg,AutoInst,Depth,FromUser) == false)
+      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 */
@@ -874,12 +917,12 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
    AddStates(Pkg);
    Update(Pkg);
    AddSizes(Pkg);
-   
+
    if (AutoInst == false)
       return;
 
    if (DebugMarker == true)
-      std::clog << OutputInDepth(Depth) << "MarkInstall " << Pkg << std::endl;
+      std::clog << OutputInDepth(Depth) << "MarkInstall " << Pkg << " FU=" << FromUser << std::endl;
 
    DepIterator Dep = P.InstVerIter(*this).DependsList();
    for (; Dep.end() != true;)
@@ -1004,8 +1047,7 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
            }
         }
         
-        if (InstPkg.end() == false &&
-            AutoInstOk(InstPkg, (*this)[InstPkg].CandidateVerIter(*this), Start))
+        if (InstPkg.end() == false)
         {
            if(DebugAutoInstall == true)
               std::clog << OutputInDepth(Depth) << "Installing " << InstPkg.Name()
@@ -1043,30 +1085,30 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
            PkgIterator Pkg = Ver.ParentPkg();
 
            if (Start->Type != Dep::DpkgBreaks)
-           {
-              if(AutoInstOk(Pkg, VerIterator(*this), Start))
-                 MarkDelete(Pkg);
-           }
-           else
-              if (PkgState[Pkg->ID].CandidateVer != *I &&
-                  AutoInstOk(Pkg, VerIterator(*this, PkgState[Pkg->ID].CandidateVer), Start))
-                 MarkInstall(Pkg,true,Depth + 1, false, ForceImportantDeps);
+              MarkDelete(Pkg,false,Depth + 1, false);
+           else if (PkgState[Pkg->ID].CandidateVer != *I)
+              MarkInstall(Pkg,true,Depth + 1, false, ForceImportantDeps);
         }
         continue;
       }      
    }
 }
-
-// DepCache::AutoInstOk - check if it is to install this package       /*{{{*/
+                                                                       /*}}}*/
+// DepCache::IsInstallOk - check if it is ok to install this package   /*{{{*/
 // ---------------------------------------------------------------------
 /* The default implementation just honors dpkg hold
-   But an application using this  library can override this method
+   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)
+bool pkgDepCache::IsInstallOk(PkgIterator const &Pkg,bool AutoInst,
+                             unsigned long Depth, bool FromUser)
 {
-   return (Pkg->SelectedState != pkgCache::State::Hold);
+   if (FromUser == false && Pkg->SelectedState == pkgCache::State::Hold && _config->FindB("APT::Ignore-Hold",false) == false)
+   {
+      if (DebugMarker == true)
+        std::clog << OutputInDepth(Depth) << "Hold prevents MarkInstall of " << Pkg << " FU=" << FromUser << std::endl;
+      return false;
+   }
+   return true;
 }
                                                                        /*}}}*/
 // DepCache::SetReInstall - Set the reinstallation flag                        /*{{{*/
@@ -1168,7 +1210,6 @@ const char *pkgDepCache::StateCache::StripEpoch(const char *Ver)
    return Ver;
 }
                                                                        /*}}}*/
-
 // Policy::GetCandidateVer - Returns the Candidate install version     /*{{{*/
 // ---------------------------------------------------------------------
 /* The default just returns the highest available version that is not
@@ -1205,7 +1246,6 @@ pkgCache::VerIterator pkgDepCache::Policy::GetCandidateVer(PkgIterator Pkg)
    return Last;
 }
                                                                        /*}}}*/
-
 // Policy::IsImportantDep - True if the dependency is important                /*{{{*/
 // ---------------------------------------------------------------------
 /* */
@@ -1231,8 +1271,7 @@ bool pkgDepCache::Policy::IsImportantDep(DepIterator Dep)
    return false;
 }
                                                                        /*}}}*/
-
-pkgDepCache::DefaultRootSetFunc::DefaultRootSetFunc()
+pkgDepCache::DefaultRootSetFunc::DefaultRootSetFunc()                  /*{{{*/
   : constructedSuccessfully(false)
 {
   Configuration::Item const *Opts;
@@ -1261,8 +1300,8 @@ pkgDepCache::DefaultRootSetFunc::DefaultRootSetFunc()
 
   constructedSuccessfully = true;
 }
-
-pkgDepCache::DefaultRootSetFunc::~DefaultRootSetFunc()
+                                                                       /*}}}*/
+pkgDepCache::DefaultRootSetFunc::~DefaultRootSetFunc()                 /*{{{*/
 {
   for(unsigned int i = 0; i < rootSetRegexp.size(); i++)
     {
@@ -1270,9 +1309,8 @@ pkgDepCache::DefaultRootSetFunc::~DefaultRootSetFunc()
       delete rootSetRegexp[i];
     }
 }
-
-
-bool pkgDepCache::DefaultRootSetFunc::InRootSet(const pkgCache::PkgIterator &pkg)
+                                                                       /*}}}*/
+bool pkgDepCache::DefaultRootSetFunc::InRootSet(const pkgCache::PkgIterator &pkg) /*{{{*/
 {
    for(unsigned int i = 0; i < rootSetRegexp.size(); i++)
       if (regexec(rootSetRegexp[i], pkg.Name(), 0, 0, 0) == 0)
@@ -1280,8 +1318,8 @@ bool pkgDepCache::DefaultRootSetFunc::InRootSet(const pkgCache::PkgIterator &pkg
 
    return false;
 }
-
-pkgDepCache::InRootSetFunc *pkgDepCache::GetRootSetFunc()
+                                                                       /*}}}*/
+pkgDepCache::InRootSetFunc *pkgDepCache::GetRootSetFunc()              /*{{{*/
 {
   DefaultRootSetFunc *f = new DefaultRootSetFunc;
   if(f->wasConstructedSuccessfully())
@@ -1292,7 +1330,7 @@ pkgDepCache::InRootSetFunc *pkgDepCache::GetRootSetFunc()
       return NULL;
     }
 }
-
+                                                                       /*}}}*/
 bool pkgDepCache::MarkFollowsRecommends()
 {
   return _config->FindB("APT::AutoRemove::RecommendsImportant", true);
@@ -1303,11 +1341,12 @@ bool pkgDepCache::MarkFollowsSuggests()
   return _config->FindB("APT::AutoRemove::SuggestsImportant", false);
 }
 
-// the main mark algorithm
+// pkgDepCache::MarkRequired - the main mark algorithm                 /*{{{*/
 bool pkgDepCache::MarkRequired(InRootSetFunc &userFunc)
 {
    bool follow_recommends;
    bool follow_suggests;
+   bool debug_autoremove = _config->FindB("Debug::pkgAutoRemove",false);
 
    // init the states
    for(PkgIterator p = PkgBegin(); !p.end(); ++p)
@@ -1316,8 +1355,7 @@ bool pkgDepCache::MarkRequired(InRootSetFunc &userFunc)
       PkgState[p->ID].Garbage = false;
 
       // debug output
-      if(_config->FindB("Debug::pkgAutoRemove",false) 
-        && PkgState[p->ID].Flags & Flag::Auto)
+      if(debug_autoremove && PkgState[p->ID].Flags & Flag::Auto)
         std::clog << "AutoDep: " << p.Name() << std::endl;
    }
 
@@ -1348,8 +1386,8 @@ bool pkgDepCache::MarkRequired(InRootSetFunc &userFunc)
 
    return true;
 }
-
-// mark a single package in Mark-and-Sweep
+                                                                       /*}}}*/
+// MarkPackage - mark a single package in Mark-and-Sweep               /*{{{*/
 void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
                              const pkgCache::VerIterator &ver,
                              bool follow_recommends,
@@ -1388,7 +1426,9 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
    if(state.Marked)
       return;
 
-   if(_config->FindB("Debug::pkgAutoRemove",false))
+   bool debug_autoremove = _config->FindB("Debug::pkgAutoRemove", false);
+   
+   if(debug_autoremove)
      {
        std::clog << "Marking: " << pkg.Name();
        if(!ver.end())
@@ -1419,7 +1459,7 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
           {
              if(_system->VS->CheckDep(V.VerStr(), d->CompareOp, d.TargetVer()))
              {
-               if(_config->FindB("Debug::pkgAutoRemove",false))
+               if(debug_autoremove)
                  {
                    std::clog << "Following dep: " << d.ParentPkg().Name()
                              << " " << d.ParentVer().VerStr() << " "
@@ -1443,7 +1483,7 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
              if(_system->VS->CheckDep(prv.ProvideVersion(), d->CompareOp, 
                                       d.TargetVer()))
              {
-               if(_config->FindB("Debug::pkgAutoRemove",false))
+               if(debug_autoremove)
                  {
                    std::clog << "Following dep: " << d.ParentPkg().Name()
                              << " " << d.ParentVer().VerStr() << " "
@@ -1468,12 +1508,14 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
      }
    }
 }
-
-bool pkgDepCache::Sweep()
+                                                                       /*}}}*/
+bool pkgDepCache::Sweep()                                              /*{{{*/
 {
+   bool debug_autoremove = _config->FindB("Debug::pkgAutoRemove",false);
+
    // do the sweep
    for(PkgIterator p=PkgBegin(); !p.end(); ++p)
-  {
+   {
      StateCache &state=PkgState[p->ID];
 
      // skip required packages
@@ -1485,10 +1527,11 @@ bool pkgDepCache::Sweep()
      if(!state.Marked && (!p.CurrentVer().end() || state.Install()))
      {
        state.Garbage=true;
-       if(_config->FindB("Debug::pkgAutoRemove",false))
+       if(debug_autoremove)
           std::cout << "Garbage: " << p.Name() << std::endl;
      }
   }   
 
    return true;
 }
+                                                                       /*}}}*/