Split ListParser::NewDepends into two methods to use these new method
authorDavid Kalnischkies <kalnischkies@gmail.com>
Sun, 27 Dec 2009 18:39:47 +0000 (19:39 +0100)
committerDavid Kalnischkies <kalnischkies@gmail.com>
Sun, 27 Dec 2009 18:39:47 +0000 (19:39 +0100)
for creating the dependencies needed for our groups:
For now for all groups only one package can be installed at the same
time which conflicts with each other packages in the group.
The exceptions are architecture all package.

Also, the Multi-Arch field is now parsed, but not used for now.

apt-pkg/cacheiterators.h
apt-pkg/deb/deblistparser.cc
apt-pkg/pkgcache.cc
apt-pkg/pkgcache.h
apt-pkg/pkgcachegen.cc
apt-pkg/pkgcachegen.h

index 35d3aa2..33d2ed6 100644 (file)
@@ -81,13 +81,21 @@ template<typename Str, typename Itr> class pkgCache::Iterator {
    different architectures can be treated as of the "same" package
    (apt internally treat them as totally different packages) */
 class pkgCache::GrpIterator: public Iterator<Group, GrpIterator> {
+       long HashIndex;
+
        protected:
        inline Group* OwnerPointer() const {
                return Owner->GrpP;
        };
 
        public:
-       void operator ++(int) {if (S != Owner->GrpP) S = Owner->GrpP + S->Next;};
+       // This constructor is the 'begin' constructor, never use it.
+       inline GrpIterator(pkgCache &Owner) : Iterator<Group, GrpIterator>(Owner), HashIndex(-1) {
+               S = OwnerPointer();
+               operator ++(0);
+       };
+
+       virtual void operator ++(int);
        virtual void operator ++() {operator ++(0);};
 
        inline const char *Name() const {return S->Name == 0?0:Owner->StrP + S->Name;};
@@ -96,11 +104,11 @@ class pkgCache::GrpIterator: public Iterator<Group, GrpIterator> {
        PkgIterator NextPkg(PkgIterator const &Pkg);
 
        // Constructors
-       inline GrpIterator(pkgCache &Owner, Group *Trg) : Iterator<Group, GrpIterator>(Owner, Trg) {
+       inline GrpIterator(pkgCache &Owner, Group *Trg) : Iterator<Group, GrpIterator>(Owner, Trg), HashIndex(0) {
                if (S == 0)
                        S = OwnerPointer();
        };
-       inline GrpIterator() : Iterator<Group, GrpIterator>() {};
+       inline GrpIterator() : Iterator<Group, GrpIterator>(), HashIndex(0) {};
 
 };
                                                                        /*}}}*/
index b57eca8..f683de4 100644 (file)
@@ -104,6 +104,30 @@ bool debListParser::NewVersion(pkgCache::VerIterator Ver)
    // Parse the architecture
    Ver->Arch = WriteUniqString(Architecture());
 
+   // Parse multi-arch
+   if (Section.FindS("Architecture") == "all")
+      /* Arch all packages can't have a Multi-Arch field,
+         but we need a special treatment for them nonetheless */
+      Ver->MultiArch = pkgCache::Version::All;
+   else
+   {
+      string const MultiArch = Section.FindS("Multi-Arch");
+      if (MultiArch.empty() == true)
+        Ver->MultiArch = pkgCache::Version::None;
+      else if (MultiArch == "same")
+        Ver->MultiArch = pkgCache::Version::Same;
+      else if (MultiArch == "foreign")
+        Ver->MultiArch = pkgCache::Version::Foreign;
+      else if (MultiArch == "allowed")
+        Ver->MultiArch = pkgCache::Version::Allowed;
+      else
+      {
+        _error->Warning("Unknown Multi-Arch type »%s« for package »%s«",
+                       MultiArch.c_str(), Section.FindS("Package").c_str());
+        Ver->MultiArch = pkgCache::Version::None;
+      }
+   }
+
    // Archive Size
    Ver->Size = (unsigned)Section.FindI("Size");
    
index c945c59..1e4c7ed 100644 (file)
@@ -182,6 +182,16 @@ unsigned long pkgCache::sHash(const char *Str) const
 // Cache::FindPkg - Locate a package by name                           /*{{{*/
 // ---------------------------------------------------------------------
 /* Returns 0 on error, pointer to the package otherwise */
+pkgCache::PkgIterator pkgCache::FindPkg(const string &Name) {
+       size_t const found = Name.find(':');
+       if (found == string::npos)
+               return FindPkg(Name, "native");
+       return FindPkg(Name.substr(0, found), Name.substr(found+1, string::npos));
+}
+                                                                       /*}}}*/
+// Cache::FindPkg - Locate a package by name                           /*{{{*/
+// ---------------------------------------------------------------------
+/* Returns 0 on error, pointer to the package otherwise */
 pkgCache::PkgIterator pkgCache::FindPkg(const string &Name, string Arch) {
        /* We make a detour via the GrpIterator here as
           on a multi-arch environment a group is easier to
@@ -322,6 +332,23 @@ pkgCache::PkgIterator pkgCache::GrpIterator::NextPkg(pkgCache::PkgIterator const
        return PkgIterator(*Owner, 0);
 }
                                                                        /*}}}*/
+// GrpIterator::operator ++ - Postfix incr                             /*{{{*/
+// ---------------------------------------------------------------------
+/* This will advance to the next logical group in the hash table. */
+void pkgCache::GrpIterator::operator ++(int) 
+{
+   // Follow the current links
+   if (S != Owner->GrpP)
+      S = Owner->GrpP + S->Next;
+
+   // Follow the hash table
+   while (S == Owner->GrpP && (HashIndex+1) < (signed)_count(Owner->HeaderP->GrpHashTable))
+   {
+      HashIndex++;
+      S = Owner->GrpP + Owner->HeaderP->GrpHashTable[HashIndex];
+   }
+};
+                                                                       /*}}}*/
 // PkgIterator::operator ++ - Postfix incr                             /*{{{*/
 // ---------------------------------------------------------------------
 /* This will advance to the next logical package in the hash table. */
index b3d2752..5f50001 100644 (file)
@@ -125,9 +125,12 @@ class pkgCache                                                             /*{{{*/
    
    // Accessors
    GrpIterator FindGrp(const string &Name);
-   PkgIterator FindPkg(const string &Name, string Arch = "native");
+   PkgIterator FindPkg(const string &Name);
+   PkgIterator FindPkg(const string &Name, string Arch);
 
    Header &Head() {return *HeaderP;};
+   inline GrpIterator GrpBegin();
+   inline GrpIterator GrpEnd();
    inline PkgIterator PkgBegin();
    inline PkgIterator PkgEnd();
    inline PkgFileIterator FileBegin();
@@ -274,7 +277,8 @@ struct pkgCache::Version                                            /*{{{*/
    map_ptrloc VerStr;            // Stringtable
    map_ptrloc Section;           // StringTable (StringItem)
    map_ptrloc Arch;              // StringTable
-   
+   enum {None, All, Foreign, Same, Allowed} MultiArch;
+
    // Lists
    map_ptrloc FileList;          // VerFile
    map_ptrloc NextVer;           // Version
@@ -337,6 +341,10 @@ struct pkgCache::StringItem                                                /*{{{*/
                                                                        /*}}}*/
 #include <apt-pkg/cacheiterators.h>
 
+inline pkgCache::GrpIterator pkgCache::GrpBegin() 
+       {return GrpIterator(*this);};
+inline pkgCache::GrpIterator pkgCache::GrpEnd() 
+       {return GrpIterator(*this,GrpP);};
 inline pkgCache::PkgIterator pkgCache::PkgBegin() 
        {return PkgIterator(*this);};
 inline pkgCache::PkgIterator pkgCache::PkgEnd() 
index c37f6f4..2a4a303 100644 (file)
@@ -18,6 +18,7 @@
 #include <apt-pkg/progress.h>
 #include <apt-pkg/sourcelist.h>
 #include <apt-pkg/configuration.h>
+#include <apt-pkg/aptconfiguration.h>
 #include <apt-pkg/strutl.h>
 #include <apt-pkg/sptr.h>
 #include <apt-pkg/pkgsystem.h>
@@ -38,7 +39,7 @@ typedef vector<pkgIndexFile *>::iterator FileIterator;
 
 // CacheGenerator::pkgCacheGenerator - Constructor                     /*{{{*/
 // ---------------------------------------------------------------------
-/* We set the diry flag and make sure that is written to the disk */
+/* We set the dirty flag and make sure that is written to the disk */
 pkgCacheGenerator::pkgCacheGenerator(DynamicMMap *pMap,OpProgress *Prog) :
                    Map(*pMap), Cache(pMap,false), Progress(Prog),
                    FoundFileDeps(0)
@@ -506,21 +507,58 @@ map_ptrloc pkgCacheGenerator::NewDescription(pkgCache::DescIterator &Desc,
    return Description;
 }
                                                                        /*}}}*/
-// ListParser::NewDepends - Create a dependency element                        /*{{{*/
+// CacheGenerator::FinishCache - do various finish operations          /*{{{*/
+// ---------------------------------------------------------------------
+/* This prepares the Cache for delivery */
+bool pkgCacheGenerator::FinishCache(OpProgress &Progress) {
+       // FIXME: add progress reporting for this operation
+       // Do we have different architectures in your groups ?
+       vector<string> archs = APT::Configuration::getArchitectures();
+       if (archs.size() > 1) {
+               // Create Conflicts in between the group
+               for (pkgCache::GrpIterator G = GetCache().GrpBegin(); G.end() != true; G++) {
+                       string const PkgName = G.Name();
+                       for (pkgCache::PkgIterator P = G.PackageList(); P.end() != true; P = G.NextPkg(P)) {
+                               for (pkgCache::VerIterator V = P.VersionList(); V.end() != true; V++) {
+                                       // Arch all packages are "co-installable"
+                                       if (V->MultiArch == pkgCache::Version::All)
+                                               continue;
+                                       string const Arch = V.Arch();
+                                       map_ptrloc *OldDepLast = NULL;
+                                       for (vector<string>::const_iterator A = archs.begin(); A != archs.end(); ++A) {
+                                               if (*A == Arch)
+                                                       continue;
+                                               /* We allow only one installed arch at the time
+                                                  per group, therefore each group member conflicts
+                                                  with all other group members */
+                                               pkgCache::PkgIterator D = G.FindPkg(*A);
+                                               if (D.end() == true)
+                                                       continue;
+                                               // Conflicts: ${self}:other
+                                               NewDepends(D, V, "",
+                                                       pkgCache::Dep::NoOp, pkgCache::Dep::Conflicts,
+                                                       OldDepLast);
+                                       }
+                               }
+                       }
+               }
+       }
+       return true;
+}
+                                                                       /*}}}*/
+// CacheGenerator::NewDepends - Create a dependency element            /*{{{*/
 // ---------------------------------------------------------------------
 /* This creates a dependency element in the tree. It is linked to the
    version and to the package that it is pointing to. */
-bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver,
-                                              const string &PackageName,
-                                              const string &Arch,
-                                              const string &Version,
-                                              unsigned int Op,
-                                              unsigned int Type)
+bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator &Pkg,
+                                  pkgCache::VerIterator &Ver,
+                                  string const &Version,
+                                  unsigned int const &Op,
+                                  unsigned int const &Type,
+                                  map_ptrloc *OldDepLast)
 {
-   pkgCache &Cache = Owner->Cache;
-   
    // Get a structure
-   unsigned long const Dependency = Owner->Map.Allocate(sizeof(pkgCache::Dependency));
+   unsigned long const Dependency = Map.Allocate(sizeof(pkgCache::Dependency));
    if (unlikely(Dependency == 0))
       return false;
    
@@ -530,17 +568,6 @@ bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver,
    Dep->Type = Type;
    Dep->CompareOp = Op;
    Dep->ID = Cache.HeaderP->DependsCount++;
-   
-   pkgCache::GrpIterator Grp;
-   if (unlikely(Owner->NewGroup(Grp, PackageName) == false))
-      return false;
-
-   // Locate the target package
-   pkgCache::PkgIterator Pkg = Grp.FindPkg(Arch);
-   if (Pkg.end() == true) {
-      if (unlikely(Owner->NewPackage(Pkg, PackageName, Arch) == false))
-        return false;
-   }
 
    // Probe the reverse dependency list for a version string that matches
    if (Version.empty() == false)
@@ -549,29 +576,23 @@ bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver,
         if (I->Version != 0 && I.TargetVer() == Version)
            Dep->Version = I->Version;*/
       if (Dep->Version == 0)
-        if (unlikely((Dep->Version = WriteString(Version)) == 0))
+        if (unlikely((Dep->Version = Map.WriteString(Version)) == 0))
            return false;
    }
-      
+
    // Link it to the package
    Dep->Package = Pkg.Index();
    Dep->NextRevDepends = Pkg->RevDepends;
    Pkg->RevDepends = Dep.Index();
-   
-   /* Link it to the version (at the end of the list)
-      Caching the old end point speeds up generation substantially */
-   if (OldDepVer != Ver)
+
+   // Do we know where to link the Dependency to?
+   if (OldDepLast == NULL)
    {
       OldDepLast = &Ver->DependsList;
       for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; D++)
         OldDepLast = &D->NextDepends;
-      OldDepVer = Ver;
    }
 
-   // Is it a file dependency?
-   if (unlikely(PackageName[0] == '/'))
-      FoundFileDeps = true;
-   
    Dep->NextDepends = *OldDepLast;
    *OldDepLast = Dep.Index();
    OldDepLast = &Dep->NextDepends;
@@ -579,6 +600,41 @@ bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver,
    return true;
 }
                                                                        /*}}}*/
+// ListParser::NewDepends - Create the environment for a new dependency        /*{{{*/
+// ---------------------------------------------------------------------
+/* This creates a Group and the Package to link this dependency to if
+   needed and handles also the caching of the old endpoint */
+bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver,
+                                              const string &PackageName,
+                                              const string &Arch,
+                                              const string &Version,
+                                              unsigned int Op,
+                                              unsigned int Type)
+{
+   pkgCache::GrpIterator Grp;
+   if (unlikely(Owner->NewGroup(Grp, PackageName) == false))
+      return false;
+
+   // Locate the target package
+   pkgCache::PkgIterator Pkg = Grp.FindPkg(Arch);
+   if (Pkg.end() == true) {
+      if (unlikely(Owner->NewPackage(Pkg, PackageName, Arch) == false))
+        return false;
+   }
+
+   // Is it a file dependency?
+   if (unlikely(PackageName[0] == '/'))
+      FoundFileDeps = true;
+
+   /* Caching the old end point speeds up generation substantially */
+   if (OldDepVer != Ver) {
+      OldDepLast = NULL;
+      OldDepVer = Ver;
+   }
+
+   return Owner->NewDepends(Pkg, Ver, Version, Op, Type, OldDepLast);
+}
+                                                                       /*}}}*/
 // ListParser::NewProvides - Create a Provides element                 /*{{{*/
 // ---------------------------------------------------------------------
 /* */
@@ -925,6 +981,9 @@ bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress,
       if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
                     Files.begin()+EndOfSource,Files.end()) == false)
         return false;
+
+      // FIXME: move me to a better place
+      Gen.FinishCache(Progress);
    }
    else
    {
@@ -965,6 +1024,9 @@ bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress,
       if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
                     Files.begin()+EndOfSource,Files.end()) == false)
         return false;
+
+      // FIXME: move me to a better place
+      Gen.FinishCache(Progress);
    }
 
    if (_error->PendingError() == true)
@@ -1010,7 +1072,10 @@ bool pkgMakeOnlyStatusCache(OpProgress &Progress,DynamicMMap **OutMap)
    if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
                  Files.begin()+EndOfSource,Files.end()) == false)
       return false;
-   
+
+   // FIXME: move me to a better place
+   Gen.FinishCache(Progress);
+
    if (_error->PendingError() == true)
       return false;
    *OutMap = Map.UnGuard();
index 4a2419b..53f09b9 100644 (file)
@@ -55,6 +55,9 @@ class pkgCacheGenerator                                                       /*{{{*/
    bool NewPackage(pkgCache::PkgIterator &Pkg,const string &Name, const string &Arch);
    bool NewFileVer(pkgCache::VerIterator &Ver,ListParser &List);
    bool NewFileDesc(pkgCache::DescIterator &Desc,ListParser &List);
+   bool NewDepends(pkgCache::PkgIterator &Pkg, pkgCache::VerIterator &Ver,
+                  string const &Version, unsigned int const &Op,
+                  unsigned int const &Type, map_ptrloc *OldDepLast);
    unsigned long NewVersion(pkgCache::VerIterator &Ver,const string &VerStr,unsigned long Next);
    map_ptrloc NewDescription(pkgCache::DescIterator &Desc,const string &Lang,const MD5SumValue &md5sum,map_ptrloc Next);
 
@@ -73,7 +76,8 @@ class pkgCacheGenerator                                                       /*{{{*/
 
    bool HasFileDeps() {return FoundFileDeps;};
    bool MergeFileProvides(ListParser &List);
-      
+   bool FinishCache(OpProgress &Progress);
+
    pkgCacheGenerator(DynamicMMap *Map,OpProgress *Progress);
    ~pkgCacheGenerator();
 };