]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/depcache.h
* add hook for MarkInstall and MarkDelete (closes: #470035)
[apt.git] / apt-pkg / depcache.h
index 042abb5cc1619b675b7b8cd6a1b48d5d9c334673..44a7f8c02c98ee81221c5f1f7836e20638a3c9ec 100644 (file)
@@ -1,4 +1,4 @@
-// -*- mode: cpp; mode: fold -*-
+// -*- mode: c++; mode: fold -*-
 // Description                                                         /*{{{*/
 // $Id: depcache.h,v 1.14 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
 #ifndef PKGLIB_DEPCACHE_H
 #define PKGLIB_DEPCACHE_H
 
-#ifdef __GNUG__
-#pragma interface "apt-pkg/depcache.h"
-#endif
 
 #include <apt-pkg/pkgcache.h>
 #include <apt-pkg/progress.h>
 
+#include <regex.h>
+
+#include <vector>
+#include <memory>
+
 class pkgDepCache : protected pkgCache::Namespace
 {
    public:
+
+   /** \brief An arbitrary predicate on packages. */
+   class InRootSetFunc
+   {
+   public:
+     virtual bool InRootSet(const pkgCache::PkgIterator &pkg) {return false;};
+     virtual ~InRootSetFunc() {};
+   };
+
+   private:
+   /** \brief Mark a single package and all its unmarked important
+    *  dependencies during mark-and-sweep.
+    *
+    *  Recursively invokes itself to mark all dependencies of the
+    *  package.
+    *
+    *  \param pkg The package to mark.
+    *
+    *  \param ver The version of the package that is to be marked.
+    *
+    *  \param follow_recommends If \b true, recommendations of the
+    *  package will be recursively marked.
+    *
+    *  \param follow_suggests If \b true, suggestions of the package
+    *  will be recursively marked.
+    */
+   void MarkPackage(const pkgCache::PkgIterator &pkg,
+                   const pkgCache::VerIterator &ver,
+                   bool follow_recommends,
+                   bool follow_suggests);
+
+   /** \brief Update the Marked field of all packages.
+    *
+    *  Each package's StateCache::Marked field will be set to \b true
+    *  if and only if it can be reached from the root set.  By
+    *  default, the root set consists of the set of manually installed
+    *  or essential packages, but it can be extended using the
+    *  parameter #rootFunc.
+    *
+    *  \param rootFunc A callback that can be used to add extra
+    *  packages to the root set.
+    *
+    *  \return \b false if an error occurred.
+    */
+   bool MarkRequired(InRootSetFunc &rootFunc);
+
+   /** \brief Set the StateCache::Garbage flag on all packages that
+    *  should be removed.
+    *
+    *  Packages that were not marked by the last call to #MarkRequired
+    *  are tested to see whether they are actually garbage.  If so,
+    *  they are marked as such.
+    *
+    *  \return \b false if an error occurred.
+    */
+   bool Sweep();
+
+   public:
    
    // These flags are used in DepState
    enum DepFlags {DepNow = (1 << 0),DepInstall = (1 << 1),DepCVer = (1 << 2),
@@ -63,6 +123,84 @@ class pkgDepCache : protected pkgCache::Namespace
       
    enum VersionTypes {NowVersion, InstallVersion, CandidateVersion};
    enum ModeList {ModeDelete = 0, ModeKeep = 1, ModeInstall = 2};
+
+   /** \brief Represents an active action group.
+    *
+    *  An action group is a group of actions that are currently being
+    *  performed.  While an active group is active, certain routine
+    *  clean-up actions that would normally be performed after every
+    *  cache operation are delayed until the action group is
+    *  completed.  This is necessary primarily to avoid inefficiencies
+    *  when modifying a large number of packages at once.
+    *
+    *  This class represents an active action group.  Creating an
+    *  instance will create an action group; destroying one will
+    *  destroy the corresponding action group.
+    *
+    *  The following operations are suppressed by this class:
+    *
+    *    - Keeping the Marked and Garbage flags up to date.
+    *
+    *  \note This can be used in the future to easily accumulate
+    *  atomic actions for undo or to display "what apt did anyway";
+    *  e.g., change the counter of how many action groups are active
+    *  to a std::set of pointers to them and use those to store
+    *  information about what happened in a group in the group.
+    */
+   class ActionGroup
+   {
+       pkgDepCache &cache;
+
+       bool released;
+
+       /** Action groups are noncopyable. */
+       ActionGroup(const ActionGroup &other);
+   public:
+       /** \brief Create a new ActionGroup.
+       *
+       *  \param cache The cache that this ActionGroup should
+       *  manipulate.
+       *
+       *  As long as this object exists, no automatic cleanup
+       *  operations will be undertaken.
+       */
+       ActionGroup(pkgDepCache &cache);
+
+       /** \brief Clean up the action group before it is destroyed.
+        *
+        *  If it is destroyed later, no second cleanup wil be run.
+       */
+       void release();
+
+       /** \brief Destroy the action group.
+       *
+       *  If this is the last action group, the automatic cache
+       *  cleanup operations will be undertaken.
+       */
+       ~ActionGroup();
+   };
+
+   /** \brief Returns \b true for packages matching a regular
+    *  expression in APT::NeverAutoRemove.
+    */
+   class DefaultRootSetFunc : public InRootSetFunc
+   {
+     std::vector<regex_t *> rootSetRegexp;
+     bool constructedSuccessfully;
+
+   public:
+     DefaultRootSetFunc();
+     ~DefaultRootSetFunc();
+
+     /** \return \b true if the class initialized successfully, \b
+      *  false otherwise.  Used to avoid throwing an exception, since
+      *  APT classes generally don't.
+      */
+     bool wasConstructedSuccessfully() const { return constructedSuccessfully; }
+
+     bool InRootSet(const pkgCache::PkgIterator &pkg);
+   };
+
    struct StateCache
    {
       // Epoch stripped text versions of the two version fields
@@ -79,6 +217,17 @@ class pkgDepCache : protected pkgCache::Namespace
       unsigned short Flags;
       unsigned short iFlags;           // Internal flags
 
+      /** \brief \b true if this package can be reached from the root set. */
+      bool Marked;
+
+      /** \brief \b true if this package is unused and should be removed.
+       *
+       *  This differs from !#Marked, because it is possible that some
+       *  unreachable packages will be protected from becoming
+       *  garbage.
+       */
+      bool Garbage;
+
       // Various tree indicators
       signed char Status;              // -1,0,1,2
       unsigned char Mode;              // ModeList
@@ -121,6 +270,14 @@ class pkgDepCache : protected pkgCache::Namespace
       
       virtual ~Policy() {};
    };
+
+   private:
+   /** The number of open "action groups"; certain post-action
+    *  operations are suppressed if this number is > 0.
+    */
+   int group_level;
+
+   friend class ActionGroup;
      
    protected:
 
@@ -137,7 +294,10 @@ class pkgDepCache : protected pkgCache::Namespace
    unsigned long iBrokenCount;
    unsigned long iPolicyBrokenCount;
    unsigned long iBadCount;
-   
+
+   bool DebugMarker;
+   bool DebugAutoInstall;
+
    Policy *delLocalPolicy;           // For memory clean up..
    Policy *LocalPolicy;
    
@@ -185,16 +345,93 @@ class pkgDepCache : protected pkgCache::Namespace
    inline StateCache &operator [](PkgIterator const &I) {return PkgState[I->ID];};
    inline unsigned char &operator [](DepIterator const &I) {return DepState[I->ID];};
 
-   // Manipulators
-   void MarkKeep(PkgIterator const &Pkg,bool Soft = false);
-   void MarkDelete(PkgIterator const &Pkg,bool Purge = false);
+   /** \return A function identifying packages in the root set other
+    *  than manually installed packages and essential packages, or \b
+    *  NULL if an error occurs.
+    *
+    *  \todo Is this the best place for this function?  Perhaps the
+    *  settings for mark-and-sweep should be stored in a single
+    *  external class?
+    */
+   virtual InRootSetFunc *GetRootSetFunc();
+
+   /** \return \b true if the garbage collector should follow recommendations.
+    */
+   virtual bool MarkFollowsRecommends();
+
+   /** \return \b true if the garbage collector should follow suggestions.
+    */
+   virtual bool MarkFollowsSuggests();
+
+   /** \brief Update the Marked and Garbage fields of all packages.
+    *
+    *  This routine is implicitly invoked after all state manipulators
+    *  and when an ActionGroup is destroyed.  It invokes #MarkRequired
+    *  and #Sweep to do its dirty work.
+    *
+    *  \param rootFunc A predicate that returns \b true for packages
+    *  that should be added to the root set.
+    */
+   bool MarkAndSweep(InRootSetFunc &rootFunc)
+   {
+     return MarkRequired(rootFunc) && Sweep();
+   }
+
+   bool MarkAndSweep()
+   {
+     std::auto_ptr<InRootSetFunc> f(GetRootSetFunc());
+     if(f.get() != NULL)
+       return MarkAndSweep(*f.get());
+     else
+       return false;
+   }
+
+   /** \name State Manipulators
+    */
+   // @{
+   void MarkKeep(PkgIterator const &Pkg, bool Soft = false,
+                bool FromUser = true, unsigned long Depth = 0);
+   void MarkDelete(PkgIterator const &Pkg, bool Purge = false,
+                   unsigned long Depth = 0, bool FromUser = true);
    void MarkInstall(PkgIterator const &Pkg,bool AutoInst = true,
-                   unsigned long Depth = 0, bool ForceImportantDeps = false);
+                   unsigned long Depth = 0, bool FromUser = true,
+                   bool ForceImportantDeps = false);
+
    void SetReInstall(PkgIterator const &Pkg,bool To);
    void SetCandidateVersion(VerIterator TargetVer);
-   
+
+   /** Set the "is automatically installed" flag of Pkg. */
+   void MarkAuto(const PkgIterator &Pkg, bool Auto);
+   // @}
+
+   /** \return \b true if it's OK for MarkInstall to install
+    *  the given package.
+    *
+    *  \param Pkg       the package that MarkInstall wants to install.
+    *  \param AutoInst  needs a previous MarkInstall this package?
+    *  \param Depth     recursive deep of this Marker call
+    *  \param FromUser  was the install requested by the user?
+    */
+   virtual bool IsInstallOk(const PkgIterator &Pkg,bool AutoInst = true,
+                           unsigned long Depth = 0, bool FromUser = true);
+
+   /** \return \b true if it's OK for MarkDelete to remove
+    *  the given package.
+    *
+    *  \param Pkg       the package that MarkDelete wants to remove.
+    *  \param Purge     should we purge instead of "only" remove?
+    *  \param Depth     recursive deep of this Marker call
+    *  \param FromUser  was the remove requested by the user?
+    */
+   virtual bool IsDeleteOk(const PkgIterator &Pkg,bool Purge = false,
+                           unsigned long Depth = 0, bool FromUser = true);
+
    // This is for debuging
    void Update(OpProgress *Prog = 0);
+
+   // read persistent states
+   bool readStateFile(OpProgress *prog);
+   bool writeStateFile(OpProgress *prog, bool InstalledOnly=false);
    
    // Size queries
    inline double UsrSize() {return iUsrSize;};