]> git.saurik.com Git - apt.git/commitdiff
criss-cross merge with my sid branch
authorDavid Kalnischkies <kalnischkies@gmail.com>
Wed, 17 Feb 2010 23:48:02 +0000 (00:48 +0100)
committerDavid Kalnischkies <kalnischkies@gmail.com>
Wed, 17 Feb 2010 23:48:02 +0000 (00:48 +0100)
31 files changed:
README.MultiArch [new file with mode: 0644]
apt-pkg/algorithms.cc
apt-pkg/aptconfiguration.cc
apt-pkg/aptconfiguration.h
apt-pkg/cacheiterators.h
apt-pkg/cdrom.cc
apt-pkg/clean.cc
apt-pkg/contrib/macros.h
apt-pkg/deb/debindexfile.cc
apt-pkg/deb/debindexfile.h
apt-pkg/deb/deblistparser.cc
apt-pkg/deb/deblistparser.h
apt-pkg/deb/debmetaindex.cc
apt-pkg/deb/debmetaindex.h
apt-pkg/depcache.cc
apt-pkg/depcache.h
apt-pkg/metaindex.h
apt-pkg/orderlist.cc
apt-pkg/packagemanager.cc
apt-pkg/pkgcache.cc
apt-pkg/pkgcache.h
apt-pkg/pkgcachegen.cc
apt-pkg/pkgcachegen.h
apt-pkg/sourcelist.cc
apt-pkg/sourcelist.h
apt-pkg/versionmatch.cc
apt-pkg/versionmatch.h
cmdline/apt-cache.cc
cmdline/apt-get.cc
debian/apt-doc.docs
debian/changelog

diff --git a/README.MultiArch b/README.MultiArch
new file mode 100644 (file)
index 0000000..b2964ac
--- /dev/null
@@ -0,0 +1,113 @@
+Before we start with this topic: Note that MultiArch is not yet ready for
+prime time and/or for the casual user. The implementation is so far widely
+untested and only useful for developers of packagemanagment tools which
+use APT and his friends and maintainers of (upcoming) MultiArch packages.
+This README is especially NOT written for the casual user and is NOT a
+usage guide - you have been warned. It is assumed that the reader has
+at least a bit of knowledge about APT internals, dependency relations
+and the MultiArch spec [0].
+
+Note also that the toolchain isn't ready yet, e.g. while you can simulate
+the installation of MultiArch packages they will more sooner than later
+cause enormous problems if really installed as dpkg can't handle MultiArch
+yet (no, --force-{overwrite,architecture} aren't good options here).
+Other parts of the big picture are missing and/or untested too.
+You have been warned!
+
+
+The implementation is focused on NOT breaking existing singleArch-only
+applications and/or systems as this is the current status-quo for all
+systems. Also, many systems don't need (or can't make use of) MultiArch,
+so APT will proceed in thinking SingleArch as long as it is not explicitly
+told to handle MultiArch:
+To activate MultiArch handling you need to specify architectures you
+want to be considered by APT with the config list APT::Architectures
+(Insert architectures in order of preference).
+APT will download Packages files for all these architectures in the
+update step. Exception: In the sourcelist is the optionfield used:
+deb [ arch=amd64,i386 ] http://example.org/ experimental main
+(This optionfield is a NOP in previous apt versions)
+
+Internally in APT a package is represented as a PkgIterator -
+before MultiArch this PkgIterator was architecture unaware,
+only VerIterators include the architecture they came from.
+This is/was a big problem as all versions in a package are
+considered for dependency resolution, so pinning will not work in all cases.
+
+The problem is solved by a conceptional change:
+A PkgIterator is now architecture aware, so the packages
+of foobar for amd64 and for i386 are now for apt internal totally
+different packages. That is a good thing for e.g. pinning, but
+sometimes you need the information that such packages are belonging together:
+All these foobar packages therefore form a Group accessible with GrpIterators.
+Note that the GrpIterator has the same name as all the packages in this group,
+so e.g. apt-cache pkgnames iterates over GrpIterator to get the package names:
+This is compatible to SingleArch as a Group consists only of a single package
+and also to MultiArch as a Group consists of possible many packages which
+all have the same name and are therefore out of interest for pkgnames.
+
+
+Caused by the paragraph "Dependencies involving Architecture: all packages"
+in the MultiArch spec we have a second major conceptional change
+which could even break existing applications, but we hope for the best…
+An Architecture: all package is internally split into pseudo packages
+for all MultiArch Architectures and additional a package with the
+architecture "all" with no dependencies which is a dependency of all
+these architecture depending packages. While the architecture depending
+packages are mainly used for dependency resolution (a package of arch A which
+depends on an arch all package assumes that the dependencies of this package
+are also from arch A. Packages also sometimes change from any to all or v.v.)
+the arch "all" package is used for scheduling download/installation of the
+underlying "real" package. Note that the architecture depending packages can
+be detected with Pseudo() while the "all" package reports exactly this arch
+as package architecture and as pseudo architecture of the versions of this pkg.
+Beware: All versions of a "real" architecture all package will be report "all"
+as their architecture if asked with Arch() regardless if they are the "all" or
+the architecture depending packages. If you want to know the architecture this
+pseudo package was created for call Arch(true). Also, while the spec say that
+arch:all packages are not allowed to have a MultiArch flag APT assigns a
+special value to them: MultiArch: all.
+
+
+As you might guess this arch:all handling has a few problems (but we think so
+far that the problems are minor compared to the problems we would have with
+other implementations.)
+APT doesn't know which pseudo packages of such an arch all package are
+"installed" (to satisfy dependencies), so APT will generate a Cache in which
+all these pseudo packages are installed (e.g. apt-cache policy will display
+them all as installed). Later in the DepCache step it will "remove"
+all pseudo packages whose dependencies are not satisfied.
+The expense is that if the package state is broken APT could come to the
+conclusion to "remove" too many pseudo packages, but in a stable environment
+APT should never end up in a broken system state…
+
+
+Given all these internal changes it is quite interesting that the actual
+implementation of MultiArch is trivial: Some implicit dependencies and a few
+more provides are all changes needed to get it working. Especially noteworthy
+is that it wasn't needed to change the resolver in any way and other parts only
+need to be told about ignoring pseudo packages or using GrpIterator instead of
+PkgIterator, so chances are good that libapt-applications will proceed to work
+without or at least only require minor changes, but your mileage may vary…
+
+
+Known Issues and/or noteworthy stuff:
+* The implementation is mostly untested, so it is very likely that APT will
+  eat your kids if you aren't as lucky as the author of these patches.
+* the (install)size of a pseudo package is always NULL - if you want to know
+  the (install)size you need to get the info from the arch "all" package.
+* It is maybe confusing, but the arch "all" package does have the same versions
+  and in general roughly the same information with one subtil difference:
+  It doesn't have any dependency, regardless of the type. The pseudo packages
+  depend on this package.
+* apt-cache policy foobar on installed architecture all package foobar will
+  report all architecture depending packages as installed. Displaying here the
+  correct information would require to build the complete DepCache…
+* [BUG] An installed package which changes the architecture from any to all
+  (and v.v.) shows up in the NEW packages section instead of UPGRADE.
+* [TODO] Investigate the DepCache pseudo-package killer heuristic:
+  e.g. add more safety guards…
+* [FIXME] a few corner cases/missing features marked as FIXME in the code
+
+
+[0] https://wiki.ubuntu.com/MultiarchSpec
index 34da745dea5ac67a2b25c1e83d7478e96f0a7a27..c905cffa9ca0a763dc8f9868ad93c204c2c9a4e6 100644 (file)
@@ -83,13 +83,28 @@ void pkgSimulate::Describe(PkgIterator Pkg,ostream &out,bool Current,bool Candid
 bool pkgSimulate::Install(PkgIterator iPkg,string /*File*/)
 {
    // Adapt the iterator
-   PkgIterator Pkg = Sim.FindPkg(iPkg.Name());
+   PkgIterator Pkg = Sim.FindPkg(iPkg.Name(), iPkg.Arch());
    Flags[Pkg->ID] = 1;
    
    cout << "Inst ";
    Describe(Pkg,cout,true,true);
    Sim.MarkInstall(Pkg,false);
-   
+
+   if (strcmp(Pkg.Arch(),"all") == 0)
+   {
+      pkgCache::GrpIterator G = Pkg.Group();
+      pkgCache::GrpIterator iG = iPkg.Group();
+      for (pkgCache::PkgIterator P = G.FindPkg("any"); P.end() != true; P = G.NextPkg(P))
+      {
+        if (strcmp(P.Arch(), "all") == 0)
+           continue;
+        if (iG.FindPkg(P.Arch())->CurrentVer == 0)
+           continue;
+        Flags[P->ID] = 1;
+        Sim.MarkInstall(P, false);
+      }
+   }
+
    // Look for broken conflicts+predepends.
    for (PkgIterator I = Sim.PkgBegin(); I.end() == false; I++)
    {
@@ -131,9 +146,22 @@ bool pkgSimulate::Install(PkgIterator iPkg,string /*File*/)
 bool pkgSimulate::Configure(PkgIterator iPkg)
 {
    // Adapt the iterator
-   PkgIterator Pkg = Sim.FindPkg(iPkg.Name());
+   PkgIterator Pkg = Sim.FindPkg(iPkg.Name(), iPkg.Arch());
    
    Flags[Pkg->ID] = 2;
+
+   if (strcmp(Pkg.Arch(),"all") == 0)
+   {
+      pkgCache::GrpIterator G = Pkg.Group();
+      for (pkgCache::PkgIterator P = G.FindPkg("any"); P.end() != true; P = G.NextPkg(P))
+      {
+        if (strcmp(P.Arch(), "all") == 0)
+           continue;
+        if (Flags[P->ID] == 1)
+           Flags[P->ID] = 2;
+      }
+   }
+
 //   Sim.MarkInstall(Pkg,false);
    if (Sim[Pkg].InstBroken() == true)
    {
@@ -181,10 +209,26 @@ bool pkgSimulate::Configure(PkgIterator iPkg)
 bool pkgSimulate::Remove(PkgIterator iPkg,bool Purge)
 {
    // Adapt the iterator
-   PkgIterator Pkg = Sim.FindPkg(iPkg.Name());
+   PkgIterator Pkg = Sim.FindPkg(iPkg.Name(), iPkg.Arch());
 
    Flags[Pkg->ID] = 3;
    Sim.MarkDelete(Pkg);
+
+   if (strcmp(Pkg.Arch(),"all") == 0)
+   {
+      pkgCache::GrpIterator G = Pkg.Group();
+      pkgCache::GrpIterator iG = iPkg.Group();
+      for (pkgCache::PkgIterator P = G.FindPkg("any"); P.end() != true; P = G.NextPkg(P))
+      {
+        if (strcmp(P.Arch(), "all") == 0)
+           continue;
+        if (iG.FindPkg(P.Arch())->CurrentVer == 0)
+           continue;
+        Flags[P->ID] = 3;
+        Sim.MarkDelete(P);
+      }
+   }
+
    if (Purge == true)
       cout << "Purg ";
    else
index b5f29472d556460ad55464f882d21f72ac0d4dcc..429219cbd73d1a4f273506023c78a3165a415354 100644 (file)
@@ -317,4 +317,28 @@ std::vector<std::string> const Configuration::getLanguages(bool const &All,
                return codes;
 }
                                                                        /*}}}*/
+// getArchitectures - Return Vector of prefered Architectures          /*{{{*/
+std::vector<std::string> const Configuration::getArchitectures(bool const &Cached) {
+       using std::string;
+
+       std::vector<string> static archs;
+       if (likely(Cached == true) && archs.empty() == false)
+               return archs;
+
+       string const arch = _config->Find("APT::Architecture");
+       archs = _config->FindVector("APT::Architectures");
+       if (archs.empty() == true ||
+           std::find(archs.begin(), archs.end(), arch) == archs.end())
+               archs.push_back(arch);
+       return archs;
+}
+                                                                       /*}}}*/
+// checkArchitecture - are we interested in the given Architecture?    /*{{{*/
+bool const Configuration::checkArchitecture(std::string const &Arch) {
+       if (Arch == "all")
+               return true;
+       std::vector<std::string> const archs = getArchitectures(true);
+       return (std::find(archs.begin(), archs.end(), Arch) != archs.end());
+}
+                                                                       /*}}}*/
 }
index 2ba1b38256699d8e9b76a811c9270d0c28e30580..dd339d841434ab22b483481dc4bb0d30b3aca7c4 100644 (file)
@@ -66,6 +66,22 @@ public:                                                                      /*{{{*/
        std::vector<std::string> static const getLanguages(bool const &All = false,
                        bool const &Cached = true, char const ** const Locale = 0);
 
+       /** \brief Returns a vector of Architectures we support
+        *
+        *  \param Cached saves the result so we need to calculated it only once
+        *                this parameter should ony be used for testing purposes.
+        *
+        *  \return a vector of Architectures in prefered order
+        */
+       std::vector<std::string> static const getArchitectures(bool const &Cached = true);
+
+       /** \brief Are we interested in the given Architecture?
+        *
+        *  \param Arch we want to check
+        *  \return true if we are interested, false otherwise
+        */
+       bool static const checkArchitecture(std::string const &Arch);
+
                                                                        /*}}}*/
 };
                                                                        /*}}}*/
index 28466cd406aae39c5c08eed2c735229a3fef40cd..43cbe1377ba033fd16e989774693ff3d411f5933 100644 (file)
@@ -1,6 +1,5 @@
 // -*- mode: cpp; mode: fold -*-
 // Description                                                         /*{{{*/
-// $Id: cacheiterators.h,v 1.18.2.1 2004/05/08 22:44:27 mdz Exp $
 /* ######################################################################
    
    Cache Iterators - Iterators for navigating the cache structure
                                                                        /*}}}*/
 #ifndef PKGLIB_CACHEITERATORS_H
 #define PKGLIB_CACHEITERATORS_H
+// abstract Iterator template                                          /*{{{*/
+/* This template provides the very basic iterator methods we
+   need to have for doing some walk-over-the-cache magic */
+template<typename Str, typename Itr> class pkgCache::Iterator {
+       protected:
+       Str *S;
+       pkgCache *Owner;
+
+       /** \brief Returns the Pointer for this struct in the owner
+        *  The implementation of this method should be pretty short
+        *  as it will only return the Pointer into the mmap stored
+        *  in the owner but the name of this pointer is different for
+        *  each stucture and we want to abstract here at least for the
+        *  basic methods from the actual structure.
+        *  \return Pointer to the first structure of this type
+        */
+       virtual Str* OwnerPointer() const = 0;
+
+       public:
+       // Iteration
+       virtual void operator ++(int) = 0;
+       virtual void operator ++() = 0; // Should be {operator ++(0);};
+       inline bool end() const {return Owner == 0 || S == OwnerPointer();};
+
+       // Comparison
+       inline bool operator ==(const Itr &B) const {return S == B.S;};
+       inline bool operator !=(const Itr &B) const {return S != B.S;};
+
+       // Accessors
+       inline Str *operator ->() {return S;};
+       inline Str const *operator ->() const {return S;};
+       inline operator Str *() {return S == OwnerPointer() ? 0 : S;};
+       inline operator Str const *() const {return S == OwnerPointer() ? 0 : S;};
+       inline Str const &operator *() const {return *S;};
+       inline pkgCache *Cache() {return Owner;};
+
+       // Mixed stuff
+       inline void operator =(const Itr &B) {S = B.S; Owner = B.Owner;};
+       inline bool IsGood() const { return S && Owner && ! end();};
+       inline unsigned long Index() const {return S - OwnerPointer();};
+
+       // Constructors - look out for the variable assigning
+       inline Iterator() : S(0), Owner(0) {};
+       inline Iterator(pkgCache &Owner,Str *T = 0) : S(T), Owner(&Owner) {};
+};
+                                                                       /*}}}*/
+// Group Iterator                                                      /*{{{*/
+/* Packages with the same name are collected in a Group so someone only
+   interest in package names can iterate easily over the names, so the
+   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:
+       // 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;};
+       inline PkgIterator PackageList() const;
+       PkgIterator FindPkg(string Arch = "any");
+       PkgIterator NextPkg(PkgIterator const &Pkg);
+
+       // Constructors
+       inline GrpIterator(pkgCache &Owner, Group *Trg) : Iterator<Group, GrpIterator>(Owner, Trg), HashIndex(0) {
+               if (S == 0)
+                       S = OwnerPointer();
+       };
+       inline GrpIterator() : Iterator<Group, GrpIterator>(), HashIndex(0) {};
 
-
+};
+                                                                       /*}}}*/
 // Package Iterator                                                    /*{{{*/
-class pkgCache::PkgIterator
-{
-   friend class pkgCache;
-   Package *Pkg;
-   pkgCache *Owner;
-   long HashIndex;
-
-   protected:
-   
-   // This constructor is the 'begin' constructor, never use it.
-   inline PkgIterator(pkgCache &Owner) : Owner(&Owner), HashIndex(-1)
-   {
-      Pkg = Owner.PkgP;
-      operator ++(0);
-   };
-   
-   public:
-
-   enum OkState {NeedsNothing,NeedsUnpack,NeedsConfigure};
-      
-   // Iteration
-   void operator ++(int);
-   inline void operator ++() {operator ++(0);};
-   inline bool end() const {return Owner == 0 || Pkg == Owner->PkgP?true:false;};
-
-   // Comparison
-   inline bool operator ==(const PkgIterator &B) const {return Pkg == B.Pkg;};
-   inline bool operator !=(const PkgIterator &B) const {return Pkg != B.Pkg;};
-                          
-   // Accessors
-   inline Package *operator ->() {return Pkg;};
-   inline Package const *operator ->() const {return Pkg;};
-   inline Package const &operator *() const {return *Pkg;};
-   inline operator Package *() {return Pkg == Owner->PkgP?0:Pkg;};
-   inline operator Package const *() const {return Pkg == Owner->PkgP?0:Pkg;};
-   inline pkgCache *Cache() {return Owner;};
-   
-   inline const char *Name() const {return Pkg->Name == 0?0:Owner->StrP + Pkg->Name;};
-   inline const char *Section() const {return Pkg->Section == 0?0:Owner->StrP + Pkg->Section;};
-   inline bool Purge() const {return Pkg->CurrentState == pkgCache::State::Purge ||
-        (Pkg->CurrentVer == 0 && Pkg->CurrentState == pkgCache::State::NotInstalled);};
-   inline VerIterator VersionList() const;
-   inline VerIterator CurrentVer() const;
-   inline DepIterator RevDependsList() const;
-   inline PrvIterator ProvidesList() const;
-   inline unsigned long Index() const {return Pkg - Owner->PkgP;};
-   OkState State() const;
-
-   //Nice printable representation
-   friend std::ostream& operator<<(std::ostream& out, pkgCache::PkgIterator Pkg);
-
-   const char *CandVersion() const;
-   const char *CurVersion() const;
-
-   // Constructors
-   inline PkgIterator(pkgCache &Owner,Package *Trg) : Pkg(Trg), Owner(&Owner),
-          HashIndex(0) 
-   { 
-      if (Pkg == 0)
-        Pkg = Owner.PkgP;
-   };
-   inline PkgIterator() : Pkg(0), Owner(0), HashIndex(0) {};
+class pkgCache::PkgIterator: public Iterator<Package, PkgIterator> {
+       long HashIndex;
+
+       protected:
+       inline Package* OwnerPointer() const {
+               return Owner->PkgP;
+       };
+
+       public:
+       // This constructor is the 'begin' constructor, never use it.
+       inline PkgIterator(pkgCache &Owner) : Iterator<Package, PkgIterator>(Owner), HashIndex(-1) {
+               S = OwnerPointer();
+               operator ++(0);
+       };
+
+       virtual void operator ++(int);
+       virtual void operator ++() {operator ++(0);};
+
+       enum OkState {NeedsNothing,NeedsUnpack,NeedsConfigure};
+
+       // Accessors
+       inline const char *Name() const {return S->Name == 0?0:Owner->StrP + S->Name;};
+       inline const char *Section() const {return S->Section == 0?0:Owner->StrP + S->Section;};
+       inline bool Purge() const {return S->CurrentState == pkgCache::State::Purge ||
+               (S->CurrentVer == 0 && S->CurrentState == pkgCache::State::NotInstalled);};
+       inline const char *Arch() const {return S->Arch == 0?0:Owner->StrP + S->Arch;};
+       inline GrpIterator Group() const { return GrpIterator(*Owner, Owner->GrpP + S->Group);};
+
+       inline VerIterator VersionList() const;
+       inline VerIterator CurrentVer() const;
+       inline DepIterator RevDependsList() const;
+       inline PrvIterator ProvidesList() const;
+       OkState State() const;
+       const char *CandVersion() const;
+       const char *CurVersion() const;
+
+       //Nice printable representation
+       friend std::ostream& operator <<(std::ostream& out, PkgIterator i);
+
+       // Constructors
+       inline PkgIterator(pkgCache &Owner,Package *Trg) : Iterator<Package, PkgIterator>(Owner, Trg), HashIndex(0) {
+               if (S == 0)
+                       S = OwnerPointer();
+       };
+       inline PkgIterator() : Iterator<Package, PkgIterator>(), HashIndex(0) {};
 };
                                                                        /*}}}*/
 // Version Iterator                                                    /*{{{*/
-class pkgCache::VerIterator
-{
-   Version *Ver;
-   pkgCache *Owner;
-
-   void _dummy();
-   
-   public:
-
-   // Iteration
-   void operator ++(int) {if (Ver != Owner->VerP) Ver = Owner->VerP + Ver->NextVer;};
-   inline void operator ++() {operator ++(0);};
-   inline bool end() const {return Owner == 0 || (Ver == Owner->VerP?true:false);};
-   inline void operator =(const VerIterator &B) {Ver = B.Ver; Owner = B.Owner;};
-   
-   // Comparison
-   inline bool operator ==(const VerIterator &B) const {return Ver == B.Ver;};
-   inline bool operator !=(const VerIterator &B) const {return Ver != B.Ver;};
-   int CompareVer(const VerIterator &B) const;
-
-   // Testing
-   inline bool IsGood() const { return Ver && Owner && ! end();};
-
-   // Accessors
-   inline Version *operator ->() {return Ver;};
-   inline Version const *operator ->() const {return Ver;};
-   inline Version &operator *() {return *Ver;};
-   inline Version const &operator *() const {return *Ver;};
-   inline operator Version *() {return Ver == Owner->VerP?0:Ver;};
-   inline operator Version const *() const {return Ver == Owner->VerP?0:Ver;};
-   inline pkgCache *Cache() {return Owner;};
-      
-   inline const char *VerStr() const {return Ver->VerStr == 0?0:Owner->StrP + Ver->VerStr;};
-   inline const char *Section() const {return Ver->Section == 0?0:Owner->StrP + Ver->Section;};
-   inline const char *Arch() const {return Ver->Arch == 0?0:Owner->StrP + Ver->Arch;};
-   inline PkgIterator ParentPkg() const {return PkgIterator(*Owner,Owner->PkgP + Ver->ParentPkg);};
-   inline DescIterator DescriptionList() const;
-   DescIterator TranslatedDescription() const;
-   inline DepIterator DependsList() const;
-   inline PrvIterator ProvidesList() const;
-   inline VerFileIterator FileList() const;
-   inline unsigned long Index() const {return Ver - Owner->VerP;};
-   bool Downloadable() const;
-   inline const char *PriorityType() {return Owner->Priority(Ver->Priority);};
-   string RelStr();
-   
-   bool Automatic() const;
-   VerFileIterator NewestFile() const;
-
-   inline VerIterator() : Ver(0), Owner(0) {};   
-   inline VerIterator(pkgCache &Owner,Version *Trg = 0) : Ver(Trg), 
-              Owner(&Owner) 
-   { 
-      if (Ver == 0)
-        Ver = Owner.VerP;
-   };
+class pkgCache::VerIterator : public Iterator<Version, VerIterator> {
+       protected:
+       inline Version* OwnerPointer() const {
+               return Owner->VerP;
+       };
+
+       public:
+       // Iteration
+       void operator ++(int) {if (S != Owner->VerP) S = Owner->VerP + S->NextVer;};
+       inline void operator ++() {operator ++(0);};
+
+       // Comparison
+       int CompareVer(const VerIterator &B) const;
+
+       // Accessors
+       inline const char *VerStr() const {return S->VerStr == 0?0:Owner->StrP + S->VerStr;};
+       inline const char *Section() const {return S->Section == 0?0:Owner->StrP + S->Section;};
+       inline const char *Arch() const {
+               if(S->MultiArch == pkgCache::Version::All)
+                       return "all";
+               return S->ParentPkg == 0?0:Owner->StrP + ParentPkg()->Arch;
+       };
+       inline const char *Arch(bool const pseudo) const {
+               if(pseudo == false)
+                       return Arch();
+               return S->ParentPkg == 0?0:Owner->StrP + ParentPkg()->Arch;
+       };
+       inline PkgIterator ParentPkg() const {return PkgIterator(*Owner,Owner->PkgP + S->ParentPkg);};
+
+       inline DescIterator DescriptionList() const;
+       DescIterator TranslatedDescription() const;
+       inline DepIterator DependsList() const;
+       inline PrvIterator ProvidesList() const;
+       inline VerFileIterator FileList() const;
+       bool Downloadable() const;
+       inline const char *PriorityType() {return Owner->Priority(S->Priority);};
+       string RelStr();
+
+       bool Automatic() const;
+       bool Pseudo() const;
+       VerFileIterator NewestFile() const;
+
+       inline VerIterator(pkgCache &Owner,Version *Trg = 0) : Iterator<Version, VerIterator>(Owner, Trg) {
+               if (S == 0)
+                       S = OwnerPointer();
+       };
+       inline VerIterator() : Iterator<Version, VerIterator>() {};
 };
                                                                        /*}}}*/
 // Description Iterator                                                        /*{{{*/
-class pkgCache::DescIterator
-{
-   Description *Desc;
-   pkgCache *Owner;
-   
-   void _dummy();
-   
-   public:
-
-   // Iteration
-   void operator ++(int) {if (Desc != Owner->DescP) Desc = Owner->DescP + Desc->NextDesc;};
-   inline void operator ++() {operator ++(0);};
-   inline bool end() const {return Owner == 0 || Desc == Owner->DescP?true:false;};
-   inline void operator =(const DescIterator &B) {Desc = B.Desc; Owner = B.Owner;};
-   
-   // Comparison
-   inline bool operator ==(const DescIterator &B) const {return Desc == B.Desc;};
-   inline bool operator !=(const DescIterator &B) const {return Desc != B.Desc;};
-   int CompareDesc(const DescIterator &B) const;
-   
-   // Accessors
-   inline Description *operator ->() {return Desc;};
-   inline Description const *operator ->() const {return Desc;};
-   inline Description &operator *() {return *Desc;};
-   inline Description const &operator *() const {return *Desc;};
-   inline operator Description *() {return Desc == Owner->DescP?0:Desc;};
-   inline operator Description const *() const {return Desc == Owner->DescP?0:Desc;};
-   inline pkgCache *Cache() {return Owner;};
-      
-   inline const char *LanguageCode() const {return Owner->StrP + Desc->language_code;};
-   inline const char *md5() const {return Owner->StrP + Desc->md5sum;};
-   inline DescFileIterator FileList() const;
-   inline unsigned long Index() const {return Desc - Owner->DescP;};
-
-   inline DescIterator() : Desc(0), Owner(0) {};   
-   inline DescIterator(pkgCache &Owner,Description *Trg = 0) : Desc(Trg), 
-              Owner(&Owner) 
-   { 
-      if (Desc == 0)
-        Desc = Owner.DescP;
-   };
+class pkgCache::DescIterator : public Iterator<Description, DescIterator> {
+       protected:
+       inline Description* OwnerPointer() const {
+               return Owner->DescP;
+       };
+
+       public:
+       // Iteration
+       void operator ++(int) {if (S != Owner->DescP) S = Owner->DescP + S->NextDesc;};
+       inline void operator ++() {operator ++(0);};
+
+       // Comparison
+       int CompareDesc(const DescIterator &B) const;
+
+       // Accessors
+       inline const char *LanguageCode() const {return Owner->StrP + S->language_code;};
+       inline const char *md5() const {return Owner->StrP + S->md5sum;};
+       inline DescFileIterator FileList() const;
+
+       inline DescIterator() : Iterator<Description, DescIterator>() {};
+       inline DescIterator(pkgCache &Owner,Description *Trg = 0) : Iterator<Description, DescIterator>(Owner, Trg) {
+               if (S == 0)
+                       S = Owner.DescP;
+       };
 };
                                                                        /*}}}*/
 // Dependency iterator                                                 /*{{{*/
-class pkgCache::DepIterator
-{
-   Dependency *Dep;
-   enum {DepVer, DepRev} Type;
-   pkgCache *Owner;
-   
-   void _dummy();
-   
-   public:
-
-   // Iteration
-   void operator ++(int) {if (Dep != Owner->DepP) Dep = Owner->DepP +
-       (Type == DepVer?Dep->NextDepends:Dep->NextRevDepends);};
-   inline void operator ++() {operator ++(0);};
-   inline bool end() const {return Owner == 0 || Dep == Owner->DepP?true:false;};
-   
-   // Comparison
-   inline bool operator ==(const DepIterator &B) const {return Dep == B.Dep;};
-   inline bool operator !=(const DepIterator &B) const {return Dep != B.Dep;};
-
-   // Accessors
-   inline Dependency *operator ->() {return Dep;};
-   inline Dependency const *operator ->() const {return Dep;};
-   inline Dependency &operator *() {return *Dep;};
-   inline Dependency const &operator *() const {return *Dep;};
-   inline operator Dependency *() {return Dep == Owner->DepP?0:Dep;};
-   inline operator Dependency const *() const {return Dep == Owner->DepP?0:Dep;};
-   inline pkgCache *Cache() {return Owner;};
-   
-   inline const char *TargetVer() const {return Dep->Version == 0?0:Owner->StrP + Dep->Version;};
-   inline PkgIterator TargetPkg() {return PkgIterator(*Owner,Owner->PkgP + Dep->Package);};
-   inline PkgIterator SmartTargetPkg() {PkgIterator R(*Owner,0);SmartTargetPkg(R);return R;};
-   inline VerIterator ParentVer() {return VerIterator(*Owner,Owner->VerP + Dep->ParentVer);};
-   inline PkgIterator ParentPkg() {return PkgIterator(*Owner,Owner->PkgP + Owner->VerP[Dep->ParentVer].ParentPkg);};
-   inline bool Reverse() {return Type == DepRev;};
-   inline unsigned long Index() const {return Dep - Owner->DepP;};
-   bool IsCritical();
-   void GlobOr(DepIterator &Start,DepIterator &End);
-   Version **AllTargets();   
-   bool SmartTargetPkg(PkgIterator &Result);
-   inline const char *CompType() {return Owner->CompType(Dep->CompareOp);};
-   inline const char *DepType() {return Owner->DepType(Dep->Type);};
-   
-   inline DepIterator(pkgCache &Owner,Dependency *Trg,Version * = 0) :
-          Dep(Trg), Type(DepVer), Owner(&Owner) 
-   {
-      if (Dep == 0)
-        Dep = Owner.DepP;
-   };
-   inline DepIterator(pkgCache &Owner,Dependency *Trg,Package *) :
-          Dep(Trg), Type(DepRev), Owner(&Owner)
-   {
-      if (Dep == 0)
-        Dep = Owner.DepP;
-   };
-   inline DepIterator() : Dep(0), Type(DepVer), Owner(0) {};
+class pkgCache::DepIterator : public Iterator<Dependency, DepIterator> {
+       enum {DepVer, DepRev} Type;
+
+       protected:
+       inline Dependency* OwnerPointer() const {
+               return Owner->DepP;
+       };
+
+       public:
+       // Iteration
+       void operator ++(int) {if (S != Owner->DepP) S = Owner->DepP +
+               (Type == DepVer ? S->NextDepends : S->NextRevDepends);};
+       inline void operator ++() {operator ++(0);};
+
+       // Accessors
+       inline const char *TargetVer() const {return S->Version == 0?0:Owner->StrP + S->Version;};
+       inline PkgIterator TargetPkg() {return PkgIterator(*Owner,Owner->PkgP + S->Package);};
+       inline PkgIterator SmartTargetPkg() {PkgIterator R(*Owner,0);SmartTargetPkg(R);return R;};
+       inline VerIterator ParentVer() {return VerIterator(*Owner,Owner->VerP + S->ParentVer);};
+       inline PkgIterator ParentPkg() {return PkgIterator(*Owner,Owner->PkgP + Owner->VerP[S->ParentVer].ParentPkg);};
+       inline bool Reverse() {return Type == DepRev;};
+       bool IsCritical();
+       void GlobOr(DepIterator &Start,DepIterator &End);
+       Version **AllTargets();
+       bool SmartTargetPkg(PkgIterator &Result);
+       inline const char *CompType() {return Owner->CompType(S->CompareOp);};
+       inline const char *DepType() {return Owner->DepType(S->Type);};
+
+       inline DepIterator(pkgCache &Owner, Dependency *Trg, Version* = 0) :
+               Iterator<Dependency, DepIterator>(Owner, Trg), Type(DepVer) {
+               if (S == 0)
+                       S = Owner.DepP;
+       };
+       inline DepIterator(pkgCache &Owner, Dependency *Trg, Package*) :
+               Iterator<Dependency, DepIterator>(Owner, Trg), Type(DepRev) {
+               if (S == 0)
+                       S = Owner.DepP;
+       };
+       inline DepIterator() : Iterator<Dependency, DepIterator>(), Type(DepVer) {};
 };
                                                                        /*}}}*/
 // Provides iterator                                                   /*{{{*/
-class pkgCache::PrvIterator
-{
-   Provides *Prv;
-   enum {PrvVer, PrvPkg} Type;
-   pkgCache *Owner;
-   
-   void _dummy();
-   
-   public:
-
-   // Iteration
-   void operator ++(int) {if (Prv != Owner->ProvideP) Prv = Owner->ProvideP +
-       (Type == PrvVer?Prv->NextPkgProv:Prv->NextProvides);};
-   inline void operator ++() {operator ++(0);};
-   inline bool end() const {return Owner == 0 || Prv == Owner->ProvideP?true:false;};
-   
-   // Comparison
-   inline bool operator ==(const PrvIterator &B) const {return Prv == B.Prv;};
-   inline bool operator !=(const PrvIterator &B) const {return Prv != B.Prv;};
-
-   // Accessors
-   inline Provides *operator ->() {return Prv;};
-   inline Provides const *operator ->() const {return Prv;};
-   inline Provides &operator *() {return *Prv;};
-   inline Provides const &operator *() const {return *Prv;};
-   inline operator Provides *() {return Prv == Owner->ProvideP?0:Prv;};
-   inline operator Provides const *() const {return Prv == Owner->ProvideP?0:Prv;};
-   inline pkgCache *Cache() {return Owner;};
-
-   inline const char *Name() const {return Owner->StrP + Owner->PkgP[Prv->ParentPkg].Name;};
-   inline const char *ProvideVersion() const {return Prv->ProvideVersion == 0?0:Owner->StrP + Prv->ProvideVersion;};
-   inline PkgIterator ParentPkg() {return PkgIterator(*Owner,Owner->PkgP + Prv->ParentPkg);};
-   inline VerIterator OwnerVer() {return VerIterator(*Owner,Owner->VerP + Prv->Version);};
-   inline PkgIterator OwnerPkg() {return PkgIterator(*Owner,Owner->PkgP + Owner->VerP[Prv->Version].ParentPkg);};
-   inline unsigned long Index() const {return Prv - Owner->ProvideP;};
-
-   inline PrvIterator() : Prv(0), Type(PrvVer), Owner(0)  {};
-
-   inline PrvIterator(pkgCache &Owner,Provides *Trg,Version *) :
-          Prv(Trg), Type(PrvVer), Owner(&Owner) 
-   {
-      if (Prv == 0)
-        Prv = Owner.ProvideP;
-   };
-   inline PrvIterator(pkgCache &Owner,Provides *Trg,Package *) : 
-          Prv(Trg), Type(PrvPkg), Owner(&Owner)
-   {
-      if (Prv == 0)
-        Prv = Owner.ProvideP;
-   };
+class pkgCache::PrvIterator : public Iterator<Provides, PrvIterator> {
+       enum {PrvVer, PrvPkg} Type;
+
+       protected:
+       inline Provides* OwnerPointer() const {
+               return Owner->ProvideP;
+       };
+
+       public:
+       // Iteration
+       void operator ++(int) {if (S != Owner->ProvideP) S = Owner->ProvideP +
+               (Type == PrvVer?S->NextPkgProv:S->NextProvides);};
+       inline void operator ++() {operator ++(0);};
+
+       // Accessors
+       inline const char *Name() const {return Owner->StrP + Owner->PkgP[S->ParentPkg].Name;};
+       inline const char *ProvideVersion() const {return S->ProvideVersion == 0?0:Owner->StrP + S->ProvideVersion;};
+       inline PkgIterator ParentPkg() {return PkgIterator(*Owner,Owner->PkgP + S->ParentPkg);};
+       inline VerIterator OwnerVer() {return VerIterator(*Owner,Owner->VerP + S->Version);};
+       inline PkgIterator OwnerPkg() {return PkgIterator(*Owner,Owner->PkgP + Owner->VerP[S->Version].ParentPkg);};
+
+       inline PrvIterator() : Iterator<Provides, PrvIterator>(), Type(PrvVer) {};
+
+       inline PrvIterator(pkgCache &Owner, Provides *Trg, Version*) :
+               Iterator<Provides, PrvIterator>(Owner, Trg), Type(PrvVer) {
+               if (S == 0)
+                       S = Owner.ProvideP;
+       };
+       inline PrvIterator(pkgCache &Owner, Provides *Trg, Package*) :
+               Iterator<Provides, PrvIterator>(Owner, Trg), Type(PrvPkg) {
+               if (S == 0)
+                       S = Owner.ProvideP;
+       };
 };
                                                                        /*}}}*/
 // Package file                                                                /*{{{*/
-class pkgCache::PkgFileIterator
-{
-   pkgCache *Owner;
-   PackageFile *File;
-
-   public:
-
-   // Iteration
-   void operator ++(int) {if (File!= Owner->PkgFileP) File = Owner->PkgFileP + File->NextFile;};
-   inline void operator ++() {operator ++(0);};
-   inline bool end() const {return Owner == 0 || File == Owner->PkgFileP?true:false;};
-
-   // Comparison
-   inline bool operator ==(const PkgFileIterator &B) const {return File == B.File;};
-   inline bool operator !=(const PkgFileIterator &B) const {return File != B.File;};
-                          
-   // Accessors
-   inline PackageFile *operator ->() {return File;};
-   inline PackageFile const *operator ->() const {return File;};
-   inline PackageFile const &operator *() const {return *File;};
-   inline operator PackageFile *() {return File == Owner->PkgFileP?0:File;};
-   inline operator PackageFile const *() const {return File == Owner->PkgFileP?0:File;};
-   inline pkgCache *Cache() {return Owner;};
-
-   inline const char *FileName() const {return File->FileName == 0?0:Owner->StrP + File->FileName;};
-   inline const char *Archive() const {return File->Archive == 0?0:Owner->StrP + File->Archive;};
-   inline const char *Component() const {return File->Component == 0?0:Owner->StrP + File->Component;};
-   inline const char *Version() const {return File->Version == 0?0:Owner->StrP + File->Version;};
-   inline const char *Origin() const {return File->Origin == 0?0:Owner->StrP + File->Origin;};
-   inline const char *Codename() const {return File->Codename ==0?0:Owner->StrP + File->Codename;};
-   inline const char *Label() const {return File->Label == 0?0:Owner->StrP + File->Label;};
-   inline const char *Site() const {return File->Site == 0?0:Owner->StrP + File->Site;};
-   inline const char *Architecture() const {return File->Architecture == 0?0:Owner->StrP + File->Architecture;};
-   inline const char *IndexType() const {return File->IndexType == 0?0:Owner->StrP + File->IndexType;};
-
-   inline unsigned long Index() const {return File - Owner->PkgFileP;};
-
-   bool IsOk();
-   string RelStr();
-   
-   // Constructors
-   inline PkgFileIterator() : Owner(0), File(0) {};
-   inline PkgFileIterator(pkgCache &Owner) : Owner(&Owner), File(Owner.PkgFileP) {};
-   inline PkgFileIterator(pkgCache &Owner,PackageFile *Trg) : Owner(&Owner), File(Trg) {};
+class pkgCache::PkgFileIterator : public Iterator<PackageFile, PkgFileIterator> {
+       protected:
+       inline PackageFile* OwnerPointer() const {
+               return Owner->PkgFileP;
+       };
+
+       public:
+       // Iteration
+       void operator ++(int) {if (S != Owner->PkgFileP) S = Owner->PkgFileP + S->NextFile;};
+       inline void operator ++() {operator ++(0);};
+
+       // Accessors
+       inline const char *FileName() const {return S->FileName == 0?0:Owner->StrP + S->FileName;};
+       inline const char *Archive() const {return S->Archive == 0?0:Owner->StrP + S->Archive;};
+       inline const char *Component() const {return S->Component == 0?0:Owner->StrP + S->Component;};
+       inline const char *Version() const {return S->Version == 0?0:Owner->StrP + S->Version;};
+       inline const char *Origin() const {return S->Origin == 0?0:Owner->StrP + S->Origin;};
+       inline const char *Codename() const {return S->Codename ==0?0:Owner->StrP + S->Codename;};
+       inline const char *Label() const {return S->Label == 0?0:Owner->StrP + S->Label;};
+       inline const char *Site() const {return S->Site == 0?0:Owner->StrP + S->Site;};
+       inline const char *Architecture() const {return S->Architecture == 0?0:Owner->StrP + S->Architecture;};
+       inline const char *IndexType() const {return S->IndexType == 0?0:Owner->StrP + S->IndexType;};
+
+       bool IsOk();
+       string RelStr();
+
+       // Constructors
+       inline PkgFileIterator() : Iterator<PackageFile, PkgFileIterator>() {};
+       inline PkgFileIterator(pkgCache &Owner,PackageFile *Trg = 0) : Iterator<PackageFile, PkgFileIterator>(Owner, Trg) {};
 };
                                                                        /*}}}*/
 // Version File                                                                /*{{{*/
-class pkgCache::VerFileIterator
-{
-   pkgCache *Owner;
-   VerFile *FileP;
-
-   public:
-
-   // Iteration
-   void operator ++(int) {if (FileP != Owner->VerFileP) FileP = Owner->VerFileP + FileP->NextFile;};
-   inline void operator ++() {operator ++(0);};
-   inline bool end() const {return Owner == 0 || FileP == Owner->VerFileP?true:false;};
-
-   // Comparison
-   inline bool operator ==(const VerFileIterator &B) const {return FileP == B.FileP;};
-   inline bool operator !=(const VerFileIterator &B) const {return FileP != B.FileP;};
-                          
-   // Accessors
-   inline VerFile *operator ->() {return FileP;};
-   inline VerFile const *operator ->() const {return FileP;};
-   inline VerFile const &operator *() const {return *FileP;};
-   inline operator VerFile *() {return FileP == Owner->VerFileP?0:FileP;};
-   inline operator VerFile const *() const {return FileP == Owner->VerFileP?0:FileP;};
-   inline pkgCache *Cache() {return Owner;};
-  
-   inline PkgFileIterator File() const {return PkgFileIterator(*Owner,FileP->File + Owner->PkgFileP);};
-   inline unsigned long Index() const {return FileP - Owner->VerFileP;};
-      
-   inline VerFileIterator() : Owner(0), FileP(0) {};
-   inline VerFileIterator(pkgCache &Owner,VerFile *Trg) : Owner(&Owner), FileP(Trg) {};
+class pkgCache::VerFileIterator : public pkgCache::Iterator<VerFile, VerFileIterator> {
+       protected:
+       inline VerFile* OwnerPointer() const {
+               return Owner->VerFileP;
+       };
+
+       public:
+       // Iteration
+       void operator ++(int) {if (S != Owner->VerFileP) S = Owner->VerFileP + S->NextFile;};
+       inline void operator ++() {operator ++(0);};
+
+       // Accessors
+       inline PkgFileIterator File() const {return PkgFileIterator(*Owner,S->File + Owner->PkgFileP);};
+
+       inline VerFileIterator() : Iterator<VerFile, VerFileIterator>() {};
+       inline VerFileIterator(pkgCache &Owner,VerFile *Trg) : Iterator<VerFile, VerFileIterator>(Owner, Trg) {};
 };
                                                                        /*}}}*/
 // Description File                                                    /*{{{*/
-class pkgCache::DescFileIterator
-{
-   pkgCache *Owner;
-   DescFile *FileP;
-
-   public:
-
-   // Iteration
-   void operator ++(int) {if (FileP != Owner->DescFileP) FileP = Owner->DescFileP + FileP->NextFile;};
-   inline void operator ++() {operator ++(0);};
-   inline bool end() const {return Owner == 0 ||  FileP == Owner->DescFileP?true:false;};
-
-   // Comparison
-   inline bool operator ==(const DescFileIterator &B) const {return FileP == B.FileP;};
-   inline bool operator !=(const DescFileIterator &B) const {return FileP != B.FileP;};
-                          
-   // Accessors
-   inline DescFile *operator ->() {return FileP;};
-   inline DescFile const *operator ->() const {return FileP;};
-   inline DescFile const &operator *() const {return *FileP;};
-   inline operator DescFile *() {return FileP == Owner->DescFileP?0:FileP;};
-   inline operator DescFile const *() const {return FileP == Owner->DescFileP?0:FileP;};
-   inline pkgCache *Cache() {return Owner;};
-  
-   inline PkgFileIterator File() const {return PkgFileIterator(*Owner,FileP->File + Owner->PkgFileP);};
-   inline unsigned long Index() const {return FileP - Owner->DescFileP;};
-      
-   inline DescFileIterator() : Owner(0), FileP(0) {};
-   inline DescFileIterator(pkgCache &Owner,DescFile *Trg) : Owner(&Owner), FileP(Trg) {};
+class pkgCache::DescFileIterator : public Iterator<DescFile, DescFileIterator> {
+       protected:
+       inline DescFile* OwnerPointer() const {
+               return Owner->DescFileP;
+       };
+
+       public:
+       // Iteration
+       void operator ++(int) {if (S != Owner->DescFileP) S = Owner->DescFileP + S->NextFile;};
+       inline void operator ++() {operator ++(0);};
+
+       // Accessors
+       inline PkgFileIterator File() const {return PkgFileIterator(*Owner,S->File + Owner->PkgFileP);};
+
+       inline DescFileIterator() : Iterator<DescFile, DescFileIterator>() {};
+       inline DescFileIterator(pkgCache &Owner,DescFile *Trg) : Iterator<DescFile, DescFileIterator>(Owner, Trg) {};
 };
                                                                        /*}}}*/
 // Inlined Begin functions cant be in the class because of order problems /*{{{*/
+inline pkgCache::PkgIterator pkgCache::GrpIterator::PackageList() const
+       {return PkgIterator(*Owner,Owner->PkgP + S->FirstPackage);};
 inline pkgCache::VerIterator pkgCache::PkgIterator::VersionList() const
-       {return VerIterator(*Owner,Owner->VerP + Pkg->VersionList);};
+       {return VerIterator(*Owner,Owner->VerP + S->VersionList);};
 inline pkgCache::VerIterator pkgCache::PkgIterator::CurrentVer() const
-       {return VerIterator(*Owner,Owner->VerP + Pkg->CurrentVer);};
+       {return VerIterator(*Owner,Owner->VerP + S->CurrentVer);};
 inline pkgCache::DepIterator pkgCache::PkgIterator::RevDependsList() const
-       {return DepIterator(*Owner,Owner->DepP + Pkg->RevDepends,Pkg);};
+       {return DepIterator(*Owner,Owner->DepP + S->RevDepends,S);};
 inline pkgCache::PrvIterator pkgCache::PkgIterator::ProvidesList() const
-       {return PrvIterator(*Owner,Owner->ProvideP + Pkg->ProvidesList,Pkg);};
+       {return PrvIterator(*Owner,Owner->ProvideP + S->ProvidesList,S);};
 inline pkgCache::DescIterator pkgCache::VerIterator::DescriptionList() const
-       {return DescIterator(*Owner,Owner->DescP + Ver->DescriptionList);};
+       {return DescIterator(*Owner,Owner->DescP + S->DescriptionList);};
 inline pkgCache::PrvIterator pkgCache::VerIterator::ProvidesList() const
-       {return PrvIterator(*Owner,Owner->ProvideP + Ver->ProvidesList,Ver);};
+       {return PrvIterator(*Owner,Owner->ProvideP + S->ProvidesList,S);};
 inline pkgCache::DepIterator pkgCache::VerIterator::DependsList() const
-       {return DepIterator(*Owner,Owner->DepP + Ver->DependsList,Ver);};
+       {return DepIterator(*Owner,Owner->DepP + S->DependsList,S);};
 inline pkgCache::VerFileIterator pkgCache::VerIterator::FileList() const
-       {return VerFileIterator(*Owner,Owner->VerFileP + Ver->FileList);};
+       {return VerFileIterator(*Owner,Owner->VerFileP + S->FileList);};
 inline pkgCache::DescFileIterator pkgCache::DescIterator::FileList() const
-       {return DescFileIterator(*Owner,Owner->DescFileP + Desc->FileList);};
+       {return DescFileIterator(*Owner,Owner->DescFileP + S->FileList);};
                                                                        /*}}}*/
 #endif
index 96d4e9c91c2f95ef56a3a851e68a9dd7a1e51347..83165c6c012966646188793c4abd7a1d14d3e1b1 100644 (file)
@@ -6,6 +6,8 @@
 #include<apt-pkg/cdromutl.h>
 #include<apt-pkg/strutl.h>
 #include<apt-pkg/cdrom.h>
+#include<apt-pkg/aptconfiguration.h>
+
 #include<sstream>
 #include<fstream>
 #include<config.h>
@@ -216,33 +218,23 @@ int pkgCdrom::Score(string Path)
 /* Here we drop everything that is not this machines arch */
 bool pkgCdrom::DropBinaryArch(vector<string> &List)
 {
-   char S[300];
-   snprintf(S,sizeof(S),"/binary-%s/",
-           _config->Find("Apt::Architecture").c_str());
-   
+
    for (unsigned int I = 0; I < List.size(); I++)
    {
       const char *Str = List[I].c_str();
-      
-      const char *Res;
-      if ((Res = strstr(Str,"/binary-")) == 0)
+      const char *Start, *End;
+      if ((Start = strstr(Str,"/binary-")) == 0)
         continue;
 
-      // Weird, remove it.
-      if (strlen(Res) < strlen(S))
-      {
-        List.erase(List.begin() + I);
-        I--;
-        continue;
-      }
-         
-      // See if it is our arch
-      if (stringcmp(Res,Res + strlen(S),S) == 0)
-        continue;
-      
-      // Erase it
+      // Between Start and End is the architecture
+      Start += 8;
+      if ((End = strstr(Start,"/")) != 0 && Start != End &&
+          APT::Configuration::checkArchitecture(string(Start, --End)) == true)
+        continue; // okay, architecture is accepted
+
+      // not accepted -> Erase it
       List.erase(List.begin() + I);
-      I--;
+      --I; // the next entry is at the same index after the erase
    }
    
    return true;
index 0d1dfbf74276a0373624327f92beb8da133a5a37..629afd7cf2a7849e4b8ff2798a39698e5a0c7019 100644 (file)
@@ -12,6 +12,7 @@
 #include <apt-pkg/strutl.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/configuration.h>
+#include <apt-pkg/aptconfiguration.h>
 
 #include <apti18n.h>    
 
@@ -26,7 +27,6 @@
 bool pkgArchiveCleaner::Go(string Dir,pkgCache &Cache)
 {
    bool CleanInstalled = _config->FindB("APT::Clean-Installed",true);
-   string MyArch = _config->Find("APT::Architecture");
       
    DIR *D = opendir(Dir.c_str());
    if (D == 0)
@@ -75,9 +75,9 @@ bool pkgArchiveCleaner::Go(string Dir,pkgCache &Cache)
       for (I = Start; *I != 0 && *I != '.' ;I++);
       if (*I != '.')
         continue;
-      string Arch = DeQuoteString(string(Start,I-Start));
+      string const Arch = DeQuoteString(string(Start,I-Start));
       
-      if (Arch != "all" && Arch != MyArch)
+      if (APT::Configuration::checkArchitecture(Arch) == false)
         continue;
       
       // Lookup the package
index 9aeb77b8180aa232d32362e338512843ecece104..c39caf198dfe12a8875fc5bd7558978dd7d073e1 100644 (file)
 
 // some nice optional GNUC features
 #if __GNUC__ >= 3
-        #define __must_check    __attribute__ ((warn_unused_result))
-        #define __deprecated    __attribute__ ((deprecated))
-        /* likely() and unlikely() can be used to mark boolean expressions
-           as (not) likely true which will help the compiler to optimise */
-        #define likely(x)       __builtin_expect (!!(x), 1)
-        #define unlikely(x)     __builtin_expect (!!(x), 0)
+       #define __must_check    __attribute__ ((warn_unused_result))
+       #define __deprecated    __attribute__ ((deprecated))
+       /* likely() and unlikely() can be used to mark boolean expressions
+          as (not) likely true which will help the compiler to optimise */
+       #define likely(x)       __builtin_expect (!!(x), 1)
+       #define unlikely(x)     __builtin_expect (!!(x), 0)
 #else
-        #define __must_check    /* no warn_unused_result */
-        #define __deprecated    /* no deprecated */
-        #define likely(x)       (x)
-        #define unlikely(x)     (x)
+       #define __must_check    /* no warn_unused_result */
+       #define __deprecated    /* no deprecated */
+       #define likely(x)       (x)
+       #define unlikely(x)     (x)
 #endif
 
 // cold functions are unlikely() to be called
 #if (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) || __GNUC__ > 4
-        #define __cold  __attribute__ ((__cold__))
+       #define __cold  __attribute__ ((__cold__))
 #else
-        #define __cold  /* no cold marker */
+       #define __cold  /* no cold marker */
 #endif
 
 #ifdef __GNUG__
 // Methods have a hidden this parameter that is visible to this attribute
-       #define __like_printf_1 __attribute__ ((format (printf, 2, 3)))
-       #define __like_printf_2 __attribute__ ((format (printf, 3, 4)))
+       #define __like_printf_1 __attribute__ ((format (printf, 2, 3)))
+       #define __like_printf_2 __attribute__ ((format (printf, 3, 4)))
 #else
-       #define __like_printf_1
-       #define __like_printf_2
+       #define __like_printf_1 /* no like-printf */
+       #define __like_printf_2 /* no like-printf */
 #endif
 
 #endif
index 201fd7fdf754bf59967ee2bb77683c9c80d31c66..bb8fae7cb94ffde23a19e85ae1f2fc925e4bbce3 100644 (file)
@@ -149,9 +149,12 @@ unsigned long debSourcesIndex::Size() const
 // PackagesIndex::debPackagesIndex - Contructor                                /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-debPackagesIndex::debPackagesIndex(string URI,string Dist,string Section,bool Trusted) : 
-                  pkgIndexFile(Trusted), URI(URI), Dist(Dist), Section(Section)
+debPackagesIndex::debPackagesIndex(string const &URI, string const &Dist, string const &Section,
+                                       bool const &Trusted, string const &Arch) :
+                  pkgIndexFile(Trusted), URI(URI), Dist(Dist), Section(Section), Architecture(Arch)
 {
+       if (Architecture == "native")
+               Architecture = _config->Find("APT::Architecture");
 }
                                                                        /*}}}*/
 // PackagesIndex::ArchiveInfo - Short version of the archive url       /*{{{*/
@@ -171,6 +174,8 @@ string debPackagesIndex::ArchiveInfo(pkgCache::VerIterator Ver) const
    Res += " ";
    Res += Ver.ParentPkg().Name();
    Res += " ";
+   Res += Ver.Arch();
+   Res += " ";
    Res += Ver.VerStr();
    return Res;
 }
@@ -204,6 +209,8 @@ string debPackagesIndex::Info(const char *Type) const
    else
       Info += Dist + '/' + Section;   
    Info += " ";
+   Info += Architecture;
+   Info += " ";
    Info += Type;
    return Info;
 }
@@ -227,7 +234,7 @@ string debPackagesIndex::IndexURI(const char *Type) const
    }
    else
       Res = URI + "dists/" + Dist + '/' + Section +
-      "/binary-" + _config->Find("APT::Architecture") + '/';
+      "/binary-" + Architecture + '/';
    
    Res += Type;
    return Res;
@@ -259,7 +266,7 @@ bool debPackagesIndex::Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const
 {
    string PackageFile = IndexFile("Packages");
    FileFd Pkg(PackageFile,FileFd::ReadOnly);
-   debListParser Parser(&Pkg);
+   debListParser Parser(&Pkg, Architecture);
    if (_error->PendingError() == true)
       return _error->Error("Problem opening %s",PackageFile.c_str());
    
index c0e8d7d8eed52d909b5fbf414c7093fbb984a516..766e8b214b55aca3010c00b90e350316bea5093a 100644 (file)
@@ -46,6 +46,7 @@ class debPackagesIndex : public pkgIndexFile
    string URI;
    string Dist;
    string Section;
+   string Architecture;
 
    string Info(const char *Type) const;
    string IndexFile(const char *Type) const;
@@ -69,7 +70,8 @@ class debPackagesIndex : public pkgIndexFile
    virtual bool Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const;
    virtual pkgCache::PkgFileIterator FindInCache(pkgCache &Cache) const;
 
-   debPackagesIndex(string URI,string Dist,string Section,bool Trusted);
+   debPackagesIndex(string const &URI, string const &Dist, string const &Section,
+                       bool const &Trusted, string const &Arch = "native");
 };
 
 class debTranslationsIndex : public pkgIndexFile
index 66108d8220e96be3c0c76d9bc16baf217135b1bf..84eab44a7f16b8201b09264944367cfea6659d8d 100644 (file)
@@ -31,10 +31,13 @@ static debListParser::WordList PrioList[] = {{"important",pkgCache::State::Impor
 
 // ListParser::debListParser - Constructor                             /*{{{*/
 // ---------------------------------------------------------------------
-/* */
-debListParser::debListParser(FileFd *File) : Tags(File)
-{
-   Arch = _config->Find("APT::architecture");
+/* Provide an architecture and only this one and "all" will be accepted
+   in Step(), if no Architecture is given we will accept every arch
+   we would accept in general with checkArchitecture() */
+debListParser::debListParser(FileFd *File, string const &Arch) : Tags(File),
+                               Arch(Arch) {
+       if (Arch == "native")
+               this->Arch = _config->Find("APT::Architecture");
 }
                                                                        /*}}}*/
 // ListParser::UniqFindTagWrite - Find the tag and write a unq string  /*{{{*/
@@ -52,12 +55,38 @@ unsigned long debListParser::UniqFindTagWrite(const char *Tag)
 // ListParser::Package - Return the package name                       /*{{{*/
 // ---------------------------------------------------------------------
 /* This is to return the name of the package this section describes */
-string debListParser::Package()
-{
-   string Result = Section.FindS("Package");
-   if (Result.empty() == true)
-      _error->Error("Encountered a section with no Package: header");
-   return Result;
+string debListParser::Package() {
+       string const Result = Section.FindS("Package");
+       if(unlikely(Result.empty() == true))
+               _error->Error("Encountered a section with no Package: header");
+       return Result;
+}
+                                                                       /*}}}*/
+// ListParser::Architecture - Return the package arch                  /*{{{*/
+// ---------------------------------------------------------------------
+/* This will return the Architecture of the package this section describes
+   Note that architecture "all" packages will get the architecture of the
+   Packages file parsed here. */
+string debListParser::Architecture() {
+       string const Result = Section.FindS("Architecture");
+       if (Result.empty() == true || Result == "all") {
+               if (Arch.empty() == true)
+                       /* FIXME: this is a problem for installed arch all
+                          packages as we don't know from which arch this
+                          package was installed - and therefore which
+                          dependency this package resolves. */
+                       return _config->Find("APT::Architecture");
+               else
+                       return Arch;
+       }
+       return Result;
+}
+                                                                       /*}}}*/
+// ListParser::ArchitectureAll                                         /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool debListParser::ArchitectureAll() {
+       return Section.FindS("Architecture") == "all";
 }
                                                                        /*}}}*/
 // ListParser::Version - Return the version string                     /*{{{*/
@@ -77,8 +106,31 @@ bool debListParser::NewVersion(pkgCache::VerIterator Ver)
 {
    // Parse the section
    Ver->Section = UniqFindTagWrite("Section");
-   Ver->Arch = UniqFindTagWrite("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");
    
@@ -95,6 +147,25 @@ bool debListParser::NewVersion(pkgCache::VerIterator Ver)
         Ver->Priority = pkgCache::State::Extra;
    }
 
+   if (Ver->MultiArch == pkgCache::Version::All)
+   {
+      /* We maintain a "pseudo" arch=all package for architecture all versions
+        on which these versions can depend on. This pseudo package is many used
+        for downloading/installing: The other pseudo-packages will degenerate
+        to a NOP in the download/install step - this package will ensure that
+        it is downloaded only one time and installed only one time -- even if
+        the architecture bound versions coming in and out on regular basis. */
+      bool const static multiArch = APT::Configuration::getArchitectures().size() > 1;
+      if (strcmp(Ver.Arch(true),"all") == 0)
+        return true;
+      else if (multiArch == true)
+      {
+        // our pseudo packages have no size to not confuse the fetcher
+        Ver->Size = 0;
+        Ver->InstalledSize = 0;
+      }
+   }
+
    if (ParseDepends(Ver,"Depends",pkgCache::Dep::Depends) == false)
       return false;
    if (ParseDepends(Ver,"Pre-Depends",pkgCache::Dep::PreDepends) == false)
@@ -183,8 +254,12 @@ bool debListParser::UsePackage(pkgCache::PkgIterator Pkg,
 {
    if (Pkg->Section == 0)
       Pkg->Section = UniqFindTagWrite("Section");
-   if (Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
-      return false;
+
+   // Packages which are not from "our" arch doesn't get the essential flag
+   string const static myArch = _config->Find("APT::Architecture");
+   if (Pkg->Arch != 0 && myArch == Pkg.Arch())
+      if (Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
+        return false;
    if (Section.FindFlag("Important",Pkg->Flags,pkgCache::Flag::Important) == false)
       return false;
 
@@ -536,6 +611,7 @@ bool debListParser::ParseDepends(pkgCache::VerIterator Ver,
       return true;
    
    string Package;
+   string const pkgArch = Ver.Arch(true);
    string Version;
    unsigned int Op;
 
@@ -545,7 +621,7 @@ bool debListParser::ParseDepends(pkgCache::VerIterator Ver,
       if (Start == 0)
         return _error->Error("Problem parsing dependency %s",Tag);
       
-      if (NewDepends(Ver,Package,Version,Op,Type) == false)
+      if (NewDepends(Ver,Package,pkgArch,Version,Op,Type) == false)
         return false;
       if (Start == Stop)
         break;
@@ -560,29 +636,52 @@ bool debListParser::ParseProvides(pkgCache::VerIterator Ver)
 {
    const char *Start;
    const char *Stop;
-   if (Section.Find("Provides",Start,Stop) == false)
-      return true;
-   
-   string Package;
-   string Version;
-   unsigned int Op;
-
-   while (1)
+   if (Section.Find("Provides",Start,Stop) == true)
    {
-      Start = ParseDepends(Start,Stop,Package,Version,Op);
-      if (Start == 0)
-        return _error->Error("Problem parsing Provides line");
-      if (Op != pkgCache::Dep::NoOp) {
-        _error->Warning("Ignoring Provides line with DepCompareOp for package %s", Package.c_str());
-      } else {
-        if (NewProvides(Ver,Package,Version) == false)
-           return false;
+      string Package;
+      string Version;
+      string const Arch = Ver.Arch(true);
+      unsigned int Op;
+
+      while (1)
+      {
+        Start = ParseDepends(Start,Stop,Package,Version,Op);
+        if (Start == 0)
+           return _error->Error("Problem parsing Provides line");
+        if (Op != pkgCache::Dep::NoOp) {
+           _error->Warning("Ignoring Provides line with DepCompareOp for package %s", Package.c_str());
+        } else {
+           if (NewProvides(Ver, Package, Arch, Version) == false)
+              return false;
+        }
+
+        if (Start == Stop)
+           break;
       }
+   }
 
-      if (Start == Stop)
-        break;
+   if (Ver->MultiArch == pkgCache::Version::Allowed)
+   {
+      string const Package = string(Ver.ParentPkg().Name()).append(":").append("any");
+      NewProvides(Ver, Package, "any", Ver.VerStr());
    }
-   
+
+   if (Ver->MultiArch != pkgCache::Version::Foreign)
+      return true;
+
+   std::vector<string> const archs = APT::Configuration::getArchitectures();
+   if (archs.size() <= 1)
+      return true;
+
+   string const Package = Ver.ParentPkg().Name();
+   string const Version = Ver.VerStr();
+   for (std::vector<string>::const_iterator a = archs.begin();
+       a != archs.end(); ++a)
+   {
+      if (NewProvides(Ver, Package, *a, Version) == false)
+        return false;
+   }
+
    return true;
 }
                                                                        /*}}}*/
@@ -613,16 +712,23 @@ bool debListParser::Step()
       /* See if this is the correct Architecture, if it isn't then we
          drop the whole section. A missing arch tag only happens (in theory)
          inside the Status file, so that is a positive return */
-      const char *Start;
-      const char *Stop;
-      if (Section.Find("Architecture",Start,Stop) == false)
+      string const Architecture = Section.FindS("Architecture");
+      if (Architecture.empty() == true)
         return true;
 
-      if (stringcmp(Arch,Start,Stop) == 0)
-        return true;
+      if (Arch.empty() == true)
+      {
+        if (APT::Configuration::checkArchitecture(Architecture) == true)
+           return true;
+      }
+      else
+      {
+        if (Architecture == Arch)
+           return true;
 
-      if (stringcmp(Start,Stop,"all") == 0)
-        return true;
+        if (Architecture == "all")
+           return true;
+      }
 
       iOffset = Tags.Offset();
    }   
@@ -640,8 +746,9 @@ bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI,
    if (Tags.Step(Section) == false)
       return false;
 
-   //mvo: I don't think we need to fill that in (it's unused since apt-0.6)
-   //FileI->Architecture = WriteUniqString(Arch);
+   // FIXME: Do we need it now for multi-arch?
+   // mvo: I don't think we need to fill that in (it's unused since apt-0.6)
+//    FileI->Architecture = WriteUniqString(Arch);
    
    // apt-secure does no longer download individual (per-section) Release
    // file. to provide Component pinning we use the section name now
index 1c709229faa5b713d5a5d30f84a101a7ae86d4bb..8da051530fd06cf9b60e5a25e318a90ee733c64d 100644 (file)
@@ -46,6 +46,8 @@ class debListParser : public pkgCacheGenerator::ListParser
       
    // These all operate against the current section
    virtual string Package();
+   virtual string Architecture();
+   virtual bool ArchitectureAll();
    virtual string Version();
    virtual bool NewVersion(pkgCache::VerIterator Ver);
    virtual string Description();
@@ -68,7 +70,7 @@ class debListParser : public pkgCacheGenerator::ListParser
                            bool const &StripMultiArch = false);
    static const char *ConvertRelation(const char *I,unsigned int &Op);
 
-   debListParser(FileFd *File);
+   debListParser(FileFd *File, string const &Arch = "");
 };
 
 #endif
index 520e94a807a0d80cb187ed0bab9bea062b2ca843..0e4e6df9e02c7ff42cf3f2ccc0045e0a65e9f670 100644 (file)
@@ -8,9 +8,11 @@
 #include <apt-pkg/aptconfiguration.h>
 #include <apt-pkg/error.h>
 
+#include <set>
+
 using namespace std;
 
-string debReleaseIndex::Info(const char *Type, const string Section) const
+string debReleaseIndex::Info(const char *Type, string const &Section, string const &Arch) const
 {
    string Info = ::URI::SiteOnly(URI) + ' ';
    if (Dist[Dist.size() - 1] == '/')
@@ -19,7 +21,11 @@ string debReleaseIndex::Info(const char *Type, const string Section) const
          Info += Dist;
    }
    else
-      Info += Dist + '/' + Section;   
+   {
+      Info += Dist + '/' + Section;
+      if (Arch.empty() == true)
+        Info += " " + Arch;
+   }
    Info += " ";
    Info += Type;
    return Info;
@@ -61,16 +67,21 @@ string debReleaseIndex::MetaIndexURI(const char *Type) const
    return Res;
 }
 
-string debReleaseIndex::IndexURISuffix(const char *Type, const string Section) const
+string debReleaseIndex::IndexURISuffix(const char *Type, string const &Section, string const &Arch) const
 {
    string Res ="";
    if (Dist[Dist.size() - 1] != '/')
-      Res += Section + "/binary-" + _config->Find("APT::Architecture") + '/';
+   {
+      if (Arch == "native")
+        Res += Section + "/binary-" + _config->Find("APT::Architecture") + '/';
+      else
+        Res += Section + "/binary-" + Arch + '/';
+   }
    return Res + Type;
 }
    
 
-string debReleaseIndex::IndexURI(const char *Type, const string Section) const
+string debReleaseIndex::IndexURI(const char *Type, string const &Section, string const &Arch) const
 {
    if (Dist[Dist.size() - 1] == '/')
    {
@@ -82,10 +93,10 @@ string debReleaseIndex::IndexURI(const char *Type, const string Section) const
       return Res + Type;
    }
    else
-      return URI + "dists/" + Dist + '/' + IndexURISuffix(Type, Section);
+      return URI + "dists/" + Dist + '/' + IndexURISuffix(Type, Section, Arch);
  }
 
-string debReleaseIndex::SourceIndexURISuffix(const char *Type, const string Section) const
+string debReleaseIndex::SourceIndexURISuffix(const char *Type, const string &Section) const
 {
    string Res ="";
    if (Dist[Dist.size() - 1] != '/')
@@ -93,7 +104,7 @@ string debReleaseIndex::SourceIndexURISuffix(const char *Type, const string Sect
    return Res + Type;
 }
 
-string debReleaseIndex::SourceIndexURI(const char *Type, const string Section) const
+string debReleaseIndex::SourceIndexURI(const char *Type, const string &Section) const
 {
    string Res;
    if (Dist[Dist.size() - 1] == '/')
@@ -108,44 +119,61 @@ string debReleaseIndex::SourceIndexURI(const char *Type, const string Section) c
       return URI + "dists/" + Dist + "/" + SourceIndexURISuffix(Type, Section);
 }
 
-debReleaseIndex::debReleaseIndex(string URI,string Dist)
-{
-   this->URI = URI;
-   this->Dist = Dist;
-   this->Indexes = NULL;
-   this->Type = "deb";
+debReleaseIndex::debReleaseIndex(string const &URI, string const &Dist) {
+       this->URI = URI;
+       this->Dist = Dist;
+       this->Indexes = NULL;
+       this->Type = "deb";
 }
 
-debReleaseIndex::~debReleaseIndex()
-{
-   for (vector<const debSectionEntry *>::const_iterator I = SectionEntries.begin();
-       I != SectionEntries.end(); I++)
-      delete *I;
+debReleaseIndex::~debReleaseIndex() {
+       for (map<string, vector<debSectionEntry const*> >::const_iterator A = ArchEntries.begin();
+            A != ArchEntries.end(); ++A)
+               for (vector<const debSectionEntry *>::const_iterator S = A->second.begin();
+                    S != A->second.end(); ++S)
+                       delete *S;
 }
 
-vector <struct IndexTarget *>* debReleaseIndex::ComputeIndexTargets() const
-{
-   vector <struct IndexTarget *>* IndexTargets = new vector <IndexTarget *>;
-   for (vector <const debSectionEntry *>::const_iterator I = SectionEntries.begin();
-       I != SectionEntries.end();
-       I++)
-   {
-      IndexTarget * Target = new IndexTarget();
-      Target->ShortDesc = (*I)->IsSrc ? "Sources" : "Packages";
-      Target->MetaKey
-       = (*I)->IsSrc ? SourceIndexURISuffix(Target->ShortDesc.c_str(), (*I)->Section)
-                     : IndexURISuffix(Target->ShortDesc.c_str(), (*I)->Section);
-      Target->URI 
-       = (*I)->IsSrc ? SourceIndexURI(Target->ShortDesc.c_str(), (*I)->Section)
-                     : IndexURI(Target->ShortDesc.c_str(), (*I)->Section);
-      
-      Target->Description = Info (Target->ShortDesc.c_str(), (*I)->Section);
-      IndexTargets->push_back (Target);
-   }
-   return IndexTargets;
+vector <struct IndexTarget *>* debReleaseIndex::ComputeIndexTargets() const {
+       vector <struct IndexTarget *>* IndexTargets = new vector <IndexTarget *>;
+
+       map<string, vector<debSectionEntry const*> >::const_iterator const src = ArchEntries.find("source");
+       if (src != ArchEntries.end()) {
+               vector<debSectionEntry const*> const SectionEntries = src->second;
+               for (vector<debSectionEntry const*>::const_iterator I = SectionEntries.begin();
+                    I != SectionEntries.end(); ++I) {
+                       IndexTarget * Target = new IndexTarget();
+                       Target->ShortDesc = "Sources";
+                       Target->MetaKey = SourceIndexURISuffix(Target->ShortDesc.c_str(), (*I)->Section);
+                       Target->URI = SourceIndexURI(Target->ShortDesc.c_str(), (*I)->Section);
+                       Target->Description = Info (Target->ShortDesc.c_str(), (*I)->Section);
+                       IndexTargets->push_back (Target);
+               }
+       }
+
+       // Only source release
+       if (IndexTargets->empty() == false && ArchEntries.size() == 1)
+               return IndexTargets;
+
+       for (map<string, vector<debSectionEntry const*> >::const_iterator a = ArchEntries.begin();
+            a != ArchEntries.end(); ++a) {
+               if (a->first == "source")
+                       continue;
+               for (vector <const debSectionEntry *>::const_iterator I = a->second.begin();
+                    I != a->second.end(); ++I) {
+                       IndexTarget * Target = new IndexTarget();
+                       Target->ShortDesc = "Packages";
+                       Target->MetaKey = IndexURISuffix(Target->ShortDesc.c_str(), (*I)->Section, a->first);
+                       Target->URI = IndexURI(Target->ShortDesc.c_str(), (*I)->Section, a->first);
+                       Target->Description = Info (Target->ShortDesc.c_str(), (*I)->Section, a->first);
+                       IndexTargets->push_back (Target);
+               }
+       }
+
+       return IndexTargets;
 }
                                                                        /*}}}*/
-bool debReleaseIndex::GetIndexes(pkgAcquire *Owner, bool GetAll) const
+bool debReleaseIndex::GetIndexes(pkgAcquire *Owner, bool const &GetAll) const
 {
    // special case for --print-uris
    if (GetAll) {
@@ -170,24 +198,28 @@ bool debReleaseIndex::GetIndexes(pkgAcquire *Owner, bool GetAll) const
                     ComputeIndexTargets(),
                     new indexRecords (Dist));
 
-   // Queue the translations
-   std::vector<std::string> const lang = APT::Configuration::getLanguages(true);
-   for (vector<const debSectionEntry *>::const_iterator I = SectionEntries.begin(); 
-       I != SectionEntries.end(); I++) {
-
-      if((*I)->IsSrc)
-        continue;
-
-      for (vector<string>::const_iterator l = lang.begin();
-               l != lang.end(); l++)
-      {
-       if (*l == "none") continue;
-       debTranslationsIndex i = debTranslationsIndex(URI,Dist,(*I)->Section,(*l).c_str());
-       i.GetIndexes(Owner);
-      }
-   }
-
-   return true;
+       // Queue the translations
+       std::vector<std::string> const lang = APT::Configuration::getLanguages(true);
+       map<string, set<string> > sections;
+       for (map<string, vector<debSectionEntry const*> >::const_iterator a = ArchEntries.begin();
+            a != ArchEntries.end(); ++a) {
+               if (a->first == "source")
+                       continue;
+               for (vector<debSectionEntry const*>::const_iterator I = a->second.begin();
+                    I != a->second.end(); I++)
+                       sections[(*I)->Section].insert(lang.begin(), lang.end());
+       }
+
+       for (map<string, set<string> >::const_iterator s = sections.begin();
+            s != sections.end(); ++s)
+               for (set<string>::const_iterator l = s->second.begin();
+                    l != s->second.end(); l++) {
+                       if (*l == "none") continue;
+                       debTranslationsIndex i = debTranslationsIndex(URI,Dist,s->first,(*l).c_str());
+                       i.GetIndexes(Owner);
+               }
+
+       return true;
 }
 
 bool debReleaseIndex::IsTrusted() const
@@ -204,73 +236,113 @@ bool debReleaseIndex::IsTrusted() const
    return false;
 }
 
-vector <pkgIndexFile *> *debReleaseIndex::GetIndexFiles()
-{
-   if (Indexes != NULL)
-      return Indexes;
-
-   Indexes = new vector <pkgIndexFile*>;
-   std::vector<std::string> const lang = APT::Configuration::getLanguages(true);
-   for (vector<const debSectionEntry *>::const_iterator I = SectionEntries.begin(); 
-       I != SectionEntries.end(); I++) {
-      if ((*I)->IsSrc)
-         Indexes->push_back(new debSourcesIndex (URI, Dist, (*I)->Section, IsTrusted()));
-      else 
-      {
-         Indexes->push_back(new debPackagesIndex (URI, Dist, (*I)->Section, IsTrusted()));
-
-        for (vector<string>::const_iterator l = lang.begin();
-               l != lang.end(); l++) {
-           if (*l == "none") continue;
-           Indexes->push_back(new debTranslationsIndex(URI,Dist,(*I)->Section,(*l).c_str()));
-        }
-      }
-   }
+vector <pkgIndexFile *> *debReleaseIndex::GetIndexFiles() {
+       if (Indexes != NULL)
+               return Indexes;
+
+       Indexes = new vector <pkgIndexFile*>;
+       map<string, vector<debSectionEntry const*> >::const_iterator const src = ArchEntries.find("source");
+       if (src != ArchEntries.end()) {
+               vector<debSectionEntry const*> const SectionEntries = src->second;
+               for (vector<debSectionEntry const*>::const_iterator I = SectionEntries.begin();
+                    I != SectionEntries.end(); I++)
+                       Indexes->push_back(new debSourcesIndex (URI, Dist, (*I)->Section, IsTrusted()));
+       }
+
+       // Only source release
+       if (Indexes->empty() == false && ArchEntries.size() == 1)
+               return Indexes;
+
+       std::vector<std::string> const lang = APT::Configuration::getLanguages(true);
+       map<string, set<string> > sections;
+       for (map<string, vector<debSectionEntry const*> >::const_iterator a = ArchEntries.begin();
+            a != ArchEntries.end(); ++a) {
+               if (a->first == "source")
+                       continue;
+               for (vector<debSectionEntry const*>::const_iterator I = a->second.begin();
+                    I != a->second.end(); I++) {
+                       Indexes->push_back(new debPackagesIndex (URI, Dist, (*I)->Section, IsTrusted(), a->first));
+                       sections[(*I)->Section].insert(lang.begin(), lang.end());
+               }
+       }
+
+       for (map<string, set<string> >::const_iterator s = sections.begin();
+            s != sections.end(); ++s)
+               for (set<string>::const_iterator l = s->second.begin();
+                    l != s->second.end(); l++) {
+                       if (*l == "none") continue;
+                       Indexes->push_back(new debTranslationsIndex(URI,Dist,s->first,(*l).c_str()));
+               }
+
+       return Indexes;
+}
 
-   return Indexes;
+void debReleaseIndex::PushSectionEntry(vector<string> const &Archs, const debSectionEntry *Entry) {
+       for (vector<string>::const_iterator a = Archs.begin();
+            a != Archs.end(); ++a)
+               ArchEntries[*a].push_back(new debSectionEntry(Entry->Section, Entry->IsSrc));
+       delete Entry;
 }
 
-void debReleaseIndex::PushSectionEntry(const debSectionEntry *Entry)
-{
-   SectionEntries.push_back(Entry);
+void debReleaseIndex::PushSectionEntry(string const &Arch, const debSectionEntry *Entry) {
+       ArchEntries[Arch].push_back(Entry);
 }
 
-debReleaseIndex::debSectionEntry::debSectionEntry (string Section, bool IsSrc): Section(Section)
-{
-   this->IsSrc = IsSrc;
+void debReleaseIndex::PushSectionEntry(const debSectionEntry *Entry) {
+       if (Entry->IsSrc == true)
+               PushSectionEntry("source", Entry);
+       else {
+               for (map<string, vector<const debSectionEntry *> >::iterator a = ArchEntries.begin();
+                    a != ArchEntries.end(); ++a) {
+                       a->second.push_back(Entry);
+               }
+       }
 }
 
+debReleaseIndex::debSectionEntry::debSectionEntry (string const &Section,
+               bool const &IsSrc): Section(Section), IsSrc(IsSrc)
+{}
+
 class debSLTypeDebian : public pkgSourceList::Type
 {
    protected:
 
-   bool CreateItemInternal(vector<metaIndex *> &List,string URI,
-                          string Dist,string Section,
-                          bool IsSrc) const
+   bool CreateItemInternal(vector<metaIndex *> &List, string const &URI,
+                          string const &Dist, string const &Section,
+                          bool const &IsSrc, map<string, string> const &Options) const
    {
-      for (vector<metaIndex *>::const_iterator I = List.begin(); 
+      map<string, string>::const_iterator const arch = Options.find("arch");
+      vector<string> const Archs =
+               (arch != Options.end()) ? ExplodeString(arch->second) :
+                               APT::Configuration::getArchitectures();
+
+      for (vector<metaIndex *>::const_iterator I = List.begin();
           I != List.end(); I++)
       {
-        // This check insures that there will be only one Release file
-        // queued for all the Packages files and Sources files it
-        // corresponds to.
-               if (strcmp((*I)->GetType(), "deb") == 0)
+        // We only worry about debian entries here
+        if (strcmp((*I)->GetType(), "deb") != 0)
+           continue;
+
+        debReleaseIndex *Deb = (debReleaseIndex *) (*I);
+        /* This check insures that there will be only one Release file
+           queued for all the Packages files and Sources files it
+           corresponds to. */
+        if (Deb->GetURI() == URI && Deb->GetDist() == Dist)
         {
-           debReleaseIndex *Deb = (debReleaseIndex *) (*I);
-           // This check insures that there will be only one Release file
-           // queued for all the Packages files and Sources files it
-           // corresponds to.
-           if (Deb->GetURI() == URI && Deb->GetDist() == Dist)
-           {
-              Deb->PushSectionEntry(new debReleaseIndex::debSectionEntry(Section, IsSrc));
-              return true;
-           }
+           if (IsSrc == true)
+              Deb->PushSectionEntry("source", new debReleaseIndex::debSectionEntry(Section, IsSrc));
+           else
+              Deb->PushSectionEntry(Archs, new debReleaseIndex::debSectionEntry(Section, IsSrc));
+           return true;
         }
       }
       // No currently created Release file indexes this entry, so we create a new one.
       // XXX determine whether this release is trusted or not
-      debReleaseIndex *Deb = new debReleaseIndex(URI,Dist);
-      Deb->PushSectionEntry (new debReleaseIndex::debSectionEntry(Section, IsSrc));
+      debReleaseIndex *Deb = new debReleaseIndex(URI, Dist);
+      if (IsSrc == true)
+        Deb->PushSectionEntry ("source", new debReleaseIndex::debSectionEntry(Section, IsSrc));
+      else
+        Deb->PushSectionEntry (Archs, new debReleaseIndex::debSectionEntry(Section, IsSrc));
       List.push_back(Deb);
       return true;
    }
@@ -280,10 +352,11 @@ class debSLTypeDeb : public debSLTypeDebian
 {
    public:
 
-   bool CreateItem(vector<metaIndex *> &List,string URI,
-                  string Dist,string Section) const
+   bool CreateItem(vector<metaIndex *> &List, string const &URI,
+                  string const &Dist, string const &Section,
+                  std::map<string, string> const &Options) const
    {
-      return CreateItemInternal(List, URI, Dist, Section, false);
+      return CreateItemInternal(List, URI, Dist, Section, false, Options);
    }
 
    debSLTypeDeb()
@@ -297,10 +370,11 @@ class debSLTypeDebSrc : public debSLTypeDebian
 {
    public:
 
-   bool CreateItem(vector<metaIndex *> &List,string URI,
-                  string Dist,string Section) const 
+   bool CreateItem(vector<metaIndex *> &List, string const &URI,
+                  string const &Dist, string const &Section,
+                  std::map<string, string> const &Options) const
    {
-      return CreateItemInternal(List, URI, Dist, Section, true);
+      return CreateItemInternal(List, URI, Dist, Section, true, Options);
    }
    
    debSLTypeDebSrc()
index 8e6a1463bdd40e51b8176eba0de63ef551cf5c2d..360fa5419a73a6ecf1075369c9f74f244dd8d232 100644 (file)
@@ -5,40 +5,44 @@
 #include <apt-pkg/metaindex.h>
 #include <apt-pkg/sourcelist.h>
 
+#include <map>
+
 class debReleaseIndex : public metaIndex {
    public:
 
    class debSectionEntry
    {
       public:
-      debSectionEntry (string Section, bool IsSrc);
-      bool IsSrc;
-      string Section;
+      debSectionEntry (string const &Section, bool const &IsSrc);
+      string const Section;
+      bool const IsSrc;
    };
 
    private:
-   vector <const debSectionEntry *> SectionEntries;
+   std::map<string, vector<debSectionEntry const*> > ArchEntries;
 
    public:
 
-   debReleaseIndex(string URI, string Dist);
+   debReleaseIndex(string const &URI, string const &Dist);
    ~debReleaseIndex();
 
-   virtual string ArchiveURI(string File) const {return URI + File;};
-   virtual bool GetIndexes(pkgAcquire *Owner, bool GetAll=false) const;
+   virtual string ArchiveURI(string const &File) const {return URI + File;};
+   virtual bool GetIndexes(pkgAcquire *Owner, bool const &GetAll=false) const;
    vector <struct IndexTarget *>* ComputeIndexTargets() const;
-   string Info(const char *Type, const string Section) const;
+   string Info(const char *Type, string const &Section, string const &Arch="") const;
    string MetaIndexInfo(const char *Type) const;
    string MetaIndexFile(const char *Types) const;
    string MetaIndexURI(const char *Type) const;
-   string IndexURI(const char *Type, const string Section) const;
-   string IndexURISuffix(const char *Type, const string Section) const;
-   string SourceIndexURI(const char *Type, const string Section) const;
-   string SourceIndexURISuffix(const char *Type, const string Section) const;
+   string IndexURI(const char *Type, string const &Section, string const &Arch="native") const;
+   string IndexURISuffix(const char *Type, string const &Section, string const &Arch="native") const;
+   string SourceIndexURI(const char *Type, const string &Section) const;
+   string SourceIndexURISuffix(const char *Type, const string &Section) const;
    virtual vector <pkgIndexFile *> *GetIndexFiles();
 
    virtual bool IsTrusted() const;
 
+   void PushSectionEntry(vector<string> const &Archs, const debSectionEntry *Entry);
+   void PushSectionEntry(string const &Arch, const debSectionEntry *Entry);
    void PushSectionEntry(const debSectionEntry *Entry);
 };
 
index 5943d858a2fb6d5373bc4a2004f50ba93cddfff1..eeb74a434eb6846304d1199fcf334c5c69046d6d 100644 (file)
@@ -17,6 +17,7 @@
 #include <apt-pkg/fileutl.h>
 #include <apt-pkg/strutl.h>
 #include <apt-pkg/configuration.h>
+#include <apt-pkg/aptconfiguration.h>
 #include <apt-pkg/pkgsystem.h>
 #include <apt-pkg/tagfile.h>
 
@@ -596,6 +597,57 @@ void pkgDepCache::UpdateVerState(PkgIterator Pkg)
    }
 }
                                                                        /*}}}*/
+// DepCache::RemovePseudoInstalledPkg - MultiArch helper for Update()  /*{{{*/
+// ---------------------------------------------------------------------
+/* We "install" arch all packages for all archs if it is installed. Many
+   of these will be broken. This method will look at these broken Pkg and
+   "remove" it. */
+bool pkgDepCache::RemovePseudoInstalledPkg(PkgIterator &Pkg, std::set<unsigned long> &recheck) {
+   if (unlikely(Pkg->CurrentVer == 0))
+      return false;
+
+   VerIterator V = Pkg.CurrentVer();
+   if (V->MultiArch != Version::All)
+      return false;
+
+   unsigned char const DepState = VersionState(V.DependsList(),DepInstall,DepInstMin,DepInstPolicy);
+   if ((DepState & DepInstMin) == DepInstMin)
+      return false;
+
+   // Dependencies for this arch all are not statisfied
+   // so we installed it only for our convenience: get right of it now.
+   RemoveSizes(Pkg);
+   RemoveStates(Pkg);
+
+   Pkg->CurrentVer = 0;
+   PkgState[Pkg->ID].InstallVer = 0;
+
+   AddStates(Pkg);
+   Update(Pkg);
+   AddSizes(Pkg);
+
+   // After the remove previously satisfied pseudo pkg could be now
+   // no longer satisfied, so we need to recheck the reverse dependencies
+   for (DepIterator d = Pkg.RevDependsList(); d.end() != true; ++d)
+   {
+      PkgIterator const P = d.ParentPkg();
+      if (P->CurrentVer != 0)
+        recheck.insert(P.Index());
+   }
+
+   if (V.end() != true)
+      for (PrvIterator Prv = V.ProvidesList(); Prv.end() != true; Prv++)
+        for (DepIterator d = Prv.ParentPkg().RevDependsList();
+             d.end() != true; ++d)
+        {
+           PkgIterator const P = d.ParentPkg();
+           if (P->CurrentVer != 0)
+              recheck.insert(P.Index());
+        }
+
+   return true;
+}
+                                                                       /*}}}*/
 // DepCache::Update - Figure out all the state information             /*{{{*/
 // ---------------------------------------------------------------------
 /* This will figure out the state of all the packages and all the 
@@ -609,9 +661,13 @@ void pkgDepCache::Update(OpProgress *Prog)
    iKeepCount = 0;
    iBrokenCount = 0;
    iBadCount = 0;
-   
+
+   std::set<unsigned long> recheck;
+
    // Perform the depends pass
    int Done = 0;
+   bool const checkMultiArch = APT::Configuration::getArchitectures().size() > 1;
+   unsigned long killed = 0;
    for (PkgIterator I = PkgBegin(); I.end() != true; I++,Done++)
    {
       if (Prog != 0 && Done%20 == 0)
@@ -619,7 +675,7 @@ void pkgDepCache::Update(OpProgress *Prog)
       for (VerIterator V = I.VersionList(); V.end() != true; V++)
       {
         unsigned char Group = 0;
-        
+
         for (DepIterator D = V.DependsList(); D.end() != true; D++)
         {
            // Build the dependency state.
@@ -637,16 +693,43 @@ void pkgDepCache::Update(OpProgress *Prog)
                D->Type == Dep::DpkgBreaks ||
                D->Type == Dep::Obsoletes)
               State = ~State;
-        }       
+        }
       }
 
-      // Compute the pacakge dependency state and size additions
+      // Compute the package dependency state and size additions
       AddSizes(I);
       UpdateVerState(I);
       AddStates(I);
+
+      if (checkMultiArch != true || I->CurrentVer == 0)
+        continue;
+
+      VerIterator const V = I.CurrentVer();
+      if (V->MultiArch != Version::All)
+        continue;
+
+      recheck.insert(I.Index());
+      --Done; // no progress if we need to recheck the package
+   }
+
+   if (checkMultiArch == true) {
+      /* FIXME: recheck breaks proper progress reporting as we don't know
+               how many packages we need to recheck. To lower the effect
+               a bit we increase with a kill, but we should do something more clever… */
+      for(std::set<unsigned long>::const_iterator p = recheck.begin();
+         p != recheck.end(); ++p) {
+        if (Prog != 0 && Done%20 == 0)
+           Prog->Progress(Done);
+        PkgIterator P = PkgIterator(*Cache, Cache->PkgP + *p);
+        if (RemovePseudoInstalledPkg(P, recheck) == true) {
+           ++killed;
+           ++Done;
+        }
+        recheck.erase(p);
+      }
    }
 
-   if (Prog != 0)      
+   if (Prog != 0)
       Prog->Progress(Done);
 
    readStateFile(Prog);
@@ -813,6 +896,10 @@ void pkgDepCache::MarkDelete(PkgIterator const &Pkg, bool rPurge,
    AddStates(Pkg);   
    Update(Pkg);
    AddSizes(Pkg);
+
+   // if we remove the pseudo package, we also need to remove the "real"
+   if (Pkg->CurrentVer != 0 && Pkg.CurrentVer().Pseudo() == true)
+      MarkDelete(Pkg.Group().FindPkg("all"), rPurge, Depth+1, FromUser);
 }
                                                                        /*}}}*/
 // DepCache::IsDeleteOk - check if it is ok to remove this package     /*{{{*/
index 0306861a1b4ea0399a09c008ce08e847a560ef88..ab1021a4424859b558cc3a04c52d7ec0e235e541 100644 (file)
@@ -46,6 +46,7 @@
 
 #include <vector>
 #include <memory>
+#include <set>
 
 class pkgDepCache : protected pkgCache::Namespace
 {
@@ -332,6 +333,7 @@ class pkgDepCache : protected pkgCache::Namespace
    inline Header &Head() {return *Cache->HeaderP;};
    inline PkgIterator PkgBegin() {return Cache->PkgBegin();};
    inline PkgIterator FindPkg(string const &Name) {return Cache->FindPkg(Name);};
+   inline PkgIterator FindPkg(string const &Name, string const &Arch) {return Cache->FindPkg(Name, Arch);};
 
    inline pkgCache &GetCache() {return *Cache;};
    inline pkgVersioningSystem &VS() {return *Cache->VS;};
@@ -442,9 +444,6 @@ class pkgDepCache : protected pkgCache::Namespace
    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);
@@ -460,9 +459,15 @@ class pkgDepCache : protected pkgCache::Namespace
    inline unsigned long BadCount() {return iBadCount;};
 
    bool Init(OpProgress *Prog);
-   
+   // Generate all state information
+   void Update(OpProgress *Prog = 0);
+
    pkgDepCache(pkgCache *Cache,Policy *Plcy = 0);
    virtual ~pkgDepCache();
+
+   private:
+   // Helper for Update(OpProgress) to remove pseudoinstalled arch all packages
+   bool RemovePseudoInstalledPkg(PkgIterator &Pkg, std::set<unsigned long> &recheck);
 };
 
 #endif
index 779b6ab141e8cc8fdb3faff8f73c6917ff3977e5..1d2140799ba792b9b9c980c9a7f5576ba965e729 100644 (file)
@@ -33,8 +33,8 @@ class metaIndex
    virtual const char* GetType() const {return Type;}
 
    // Interface for acquire
-   virtual string ArchiveURI(string /*File*/) const = 0;
-   virtual bool GetIndexes(pkgAcquire *Owner, bool GetAll=false) const = 0;
+   virtual string ArchiveURI(string const& /*File*/) const = 0;
+   virtual bool GetIndexes(pkgAcquire *Owner, bool const &GetAll=false) const = 0;
    
    virtual vector<pkgIndexFile *> *GetIndexFiles() = 0; 
    virtual bool IsTrusted() const = 0;
index 0ee2e2bc8bfccea7de8e1a5e645020c8ba663e4b..2e7618b5582f0d2f7e9c2ed564f33a7b1edcb913 100644 (file)
@@ -126,6 +126,10 @@ bool pkgOrderList::IsMissing(PkgIterator Pkg)
    
    if (FileList[Pkg->ID].empty() == false)
       return false;
+
+   if (pkgCache::VerIterator(Cache, Cache[Pkg].CandidateVer).Pseudo() == true)
+      return false;
+
    return true;
 }
                                                                        /*}}}*/
index 491bff110b8938dd55d80427b673ac4848f32b8d..db882721e800f2d00c7db0da928bf82b15937dc3 100644 (file)
@@ -80,7 +80,10 @@ bool pkgPackageManager::GetArchives(pkgAcquire *Owner,pkgSourceList *Sources,
       // Skip already processed packages
       if (List->IsNow(Pkg) == false)
         continue;
-        
+
+      if (pkgCache::VerIterator(Cache, Cache[Pkg].CandidateVer).Pseudo() == true)
+        continue;
+
       new pkgAcqArchive(Owner,Sources,Recs,Cache[Pkg].InstVerIter(Cache),
                        FileNames[Pkg->ID]);
    }
@@ -277,8 +280,10 @@ bool pkgPackageManager::ConfigureAll()
    for (pkgOrderList::iterator I = OList.begin(); I != OList.end(); I++)
    {
       PkgIterator Pkg(Cache,*I);
-      
-      if (ConfigurePkgs == true && Configure(Pkg) == false)
+
+      if (ConfigurePkgs == true &&
+         pkgCache::VerIterator(Cache, Cache[Pkg].CandidateVer).Pseudo() == false &&
+         Configure(Pkg) == false)
         return false;
       
       List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States);
@@ -313,7 +318,9 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg)
    {
       PkgIterator Pkg(Cache,*I);
       
-      if (ConfigurePkgs == true && Configure(Pkg) == false)
+      if (ConfigurePkgs == true &&
+         pkgCache::VerIterator(Cache, Cache[Pkg].CandidateVer).Pseudo() == false &&
+         Configure(Pkg) == false)
         return false;
       
       List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States);
@@ -460,7 +467,10 @@ bool pkgPackageManager::SmartRemove(PkgIterator Pkg)
       return true;
 
    List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States);
-   return Remove(Pkg,(Cache[Pkg].iFlags & pkgDepCache::Purge) == pkgDepCache::Purge);
+
+   if (pkgCache::VerIterator(Cache, Cache[Pkg].CandidateVer).Pseudo() == false)
+      return Remove(Pkg,(Cache[Pkg].iFlags & pkgDepCache::Purge) == pkgDepCache::Purge);
+   return true;
 }
                                                                        /*}}}*/
 // PM::SmartUnPack - Install helper                                    /*{{{*/
@@ -575,7 +585,8 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg)
        P.end() == false; P++)
       CheckRConflicts(Pkg,P.ParentPkg().RevDependsList(),P.ProvideVersion());
    
-   if (Install(Pkg,FileNames[Pkg->ID]) == false)
+   if (pkgCache::VerIterator(Cache, Cache[Pkg].CandidateVer).Pseudo() == false &&
+       Install(Pkg,FileNames[Pkg->ID]) == false)
       return false;
    
    List->Flag(Pkg,pkgOrderList::UnPacked,pkgOrderList::States);
index 038bd7ec4a7986706e1ae24b11fcdece6e26c8d7..29c27b58eb1497c3a9a01ad4bb11fce5742bb458 100644 (file)
@@ -79,7 +79,8 @@ pkgCache::Header::Header()
    StringList = 0;
    VerSysName = 0;
    Architecture = 0;
-   memset(HashTable,0,sizeof(HashTable));
+   memset(PkgHashTable,0,sizeof(PkgHashTable));
+   memset(GrpHashTable,0,sizeof(GrpHashTable));
    memset(Pools,0,sizeof(Pools));
 }
                                                                        /*}}}*/
@@ -118,6 +119,7 @@ bool pkgCache::ReMap()
 {
    // Apply the typecasts.
    HeaderP = (Header *)Map.Data();
+   GrpP = (Group *)Map.Data();
    PkgP = (Package *)Map.Data();
    VerFileP = (VerFile *)Map.Data();
    DescFileP = (DescFile *)Map.Data();
@@ -165,7 +167,7 @@ unsigned long pkgCache::sHash(const string &Str) const
    unsigned long Hash = 0;
    for (string::const_iterator I = Str.begin(); I != Str.end(); I++)
       Hash = 5*Hash + tolower_ascii(*I);
-   return Hash % _count(HeaderP->HashTable);
+   return Hash % _count(HeaderP->PkgHashTable);
 }
 
 unsigned long pkgCache::sHash(const char *Str) const
@@ -173,24 +175,53 @@ unsigned long pkgCache::sHash(const char *Str) const
    unsigned long Hash = 0;
    for (const char *I = Str; *I != 0; I++)
       Hash = 5*Hash + tolower_ascii(*I);
-   return Hash % _count(HeaderP->HashTable);
+   return Hash % _count(HeaderP->PkgHashTable);
 }
 
                                                                        /*}}}*/
 // Cache::FindPkg - Locate a package by name                           /*{{{*/
 // ---------------------------------------------------------------------
 /* Returns 0 on error, pointer to the package otherwise */
-pkgCache::PkgIterator pkgCache::FindPkg(const string &Name)
-{
-   // Look at the hash bucket
-   Package *Pkg = PkgP + HeaderP->HashTable[Hash(Name)];
-   for (; Pkg != PkgP; Pkg = PkgP + Pkg->NextPackage)
-   {
-      if (Pkg->Name != 0 && StrP[Pkg->Name] == Name[0] &&
-         stringcasecmp(Name,StrP + Pkg->Name) == 0)
-        return PkgIterator(*this,Pkg);
-   }
-   return PkgIterator(*this,0);
+pkgCache::PkgIterator pkgCache::FindPkg(const string &Name) {
+       size_t const found = Name.find(':');
+       if (found == string::npos)
+               return FindPkg(Name, "native");
+       string const Arch = Name.substr(found+1);
+       if (Arch == "any")
+               return FindPkg(Name, "any");
+       return FindPkg(Name.substr(0, found), Arch);
+}
+                                                                       /*}}}*/
+// 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
+          find than a package (less entries in the buckets) */
+       pkgCache::GrpIterator Grp = FindGrp(Name);
+       if (Grp.end() == true)
+               return PkgIterator(*this,0);
+
+       return Grp.FindPkg(Arch);
+}
+                                                                       /*}}}*/
+// Cache::FindGrp - Locate a group by name                             /*{{{*/
+// ---------------------------------------------------------------------
+/* Returns End-Pointer on error, pointer to the group otherwise */
+pkgCache::GrpIterator pkgCache::FindGrp(const string &Name) {
+       if (unlikely(Name.empty() == true))
+               return GrpIterator(*this,0);
+
+       // Look at the hash bucket for the group
+       Group *Grp = GrpP + HeaderP->GrpHashTable[sHash(Name)];
+       for (; Grp != GrpP; Grp = GrpP + Grp->Next) {
+               if (Grp->Name != 0 && StrP[Grp->Name] == Name[0] &&
+                   stringcasecmp(Name, StrP + Grp->Name) == 0)
+                       return GrpIterator(*this, Grp);
+       }
+
+       return GrpIterator(*this,0);
 }
                                                                        /*}}}*/
 // Cache::CompTypeDeb - Return a string describing the compare type    /*{{{*/
@@ -242,11 +273,84 @@ const char *pkgCache::Priority(unsigned char Prio)
    return 0;
 }
                                                                        /*}}}*/
-// Bases for iterator classes                                          /*{{{*/
-void pkgCache::VerIterator::_dummy() {}
-void pkgCache::DepIterator::_dummy() {}
-void pkgCache::PrvIterator::_dummy() {}
-void pkgCache::DescIterator::_dummy() {}
+// GrpIterator::FindPkg - Locate a package by arch                     /*{{{*/
+// ---------------------------------------------------------------------
+/* Returns an End-Pointer on error, pointer to the package otherwise */
+pkgCache::PkgIterator pkgCache::GrpIterator::FindPkg(string Arch) {
+       if (unlikely(IsGood() == false || S->FirstPackage == 0))
+               return PkgIterator(*Owner, 0);
+
+       static string const myArch = _config->Find("APT::Architecture");
+       /* Most of the time the package for our native architecture is
+          the one we add at first to the cache, but this would be the
+          last one we check, so we do it now. */
+       if (Arch == "native" || Arch == myArch) {
+               Arch = myArch;
+               pkgCache::Package *Pkg = Owner->PkgP + S->LastPackage;
+               if (stringcasecmp(Arch, Owner->StrP + Pkg->Arch) == 0)
+                       return PkgIterator(*Owner, Pkg);
+       }
+
+       /* If we accept any package we simply return the "first"
+          package in this group (the last one added). */
+       if (Arch == "any")
+               return PkgIterator(*Owner, Owner->PkgP + S->FirstPackage);
+
+       /* Iterate over the list to find the matching arch
+          unfortunately this list includes "package noise"
+          (= different packages with same calculated hash),
+          so we need to check the name also */
+       for (pkgCache::Package *Pkg = PackageList(); Pkg != Owner->PkgP;
+            Pkg = Owner->PkgP + Pkg->NextPackage) {
+               if (S->Name == Pkg->Name &&
+                   stringcasecmp(Arch, Owner->StrP + Pkg->Arch) == 0)
+                       return PkgIterator(*Owner, Pkg);
+               if ((Owner->PkgP + S->LastPackage) == Pkg)
+                       break;
+       }
+
+       return PkgIterator(*Owner, 0);
+}
+                                                                       /*}}}*/
+// GrpIterator::NextPkg - Locate the next package in the group         /*{{{*/
+// ---------------------------------------------------------------------
+/* Returns an End-Pointer on error, pointer to the package otherwise.
+   We can't simply ++ to the next as the list of packages includes
+   "package noise" (= packages with the same hash value but different name) */
+pkgCache::PkgIterator pkgCache::GrpIterator::NextPkg(pkgCache::PkgIterator const &LastPkg) {
+       if (unlikely(IsGood() == false || S->FirstPackage == 0 ||
+           LastPkg.end() == true))
+               return PkgIterator(*Owner, 0);
+
+       // Iterate over the list to find the next package
+       pkgCache::Package *Pkg = Owner->PkgP + LastPkg.Index();
+       Pkg = Owner->PkgP + Pkg->NextPackage;
+       for (; Pkg != Owner->PkgP; Pkg = Owner->PkgP + Pkg->NextPackage) {
+               if (S->Name == Pkg->Name)
+                       return PkgIterator(*Owner, Pkg);
+               if ((Owner->PkgP + S->LastPackage) == Pkg)
+                       break;
+       }
+
+       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                             /*{{{*/
 // ---------------------------------------------------------------------
@@ -254,14 +358,14 @@ void pkgCache::DescIterator::_dummy() {}
 void pkgCache::PkgIterator::operator ++(int) 
 {
    // Follow the current links
-   if (Pkg != Owner->PkgP)
-      Pkg = Owner->PkgP + Pkg->NextPackage;
+   if (S != Owner->PkgP)
+      S = Owner->PkgP + S->NextPackage;
 
    // Follow the hash table
-   while (Pkg == Owner->PkgP && (HashIndex+1) < (signed)_count(Owner->HeaderP->HashTable))
+   while (S == Owner->PkgP && (HashIndex+1) < (signed)_count(Owner->HeaderP->PkgHashTable))
    {
       HashIndex++;
-      Pkg = Owner->PkgP + Owner->HeaderP->HashTable[HashIndex];
+      S = Owner->PkgP + Owner->HeaderP->PkgHashTable[HashIndex];
    }
 };
                                                                        /*}}}*/
@@ -270,12 +374,12 @@ void pkgCache::PkgIterator::operator ++(int)
 /* By this we mean if it is either cleanly installed or cleanly removed. */
 pkgCache::PkgIterator::OkState pkgCache::PkgIterator::State() const
 {  
-   if (Pkg->InstState == pkgCache::State::ReInstReq ||
-       Pkg->InstState == pkgCache::State::HoldReInstReq)
+   if (S->InstState == pkgCache::State::ReInstReq ||
+       S->InstState == pkgCache::State::HoldReInstReq)
       return NeedsUnpack;
    
-   if (Pkg->CurrentState == pkgCache::State::UnPacked ||
-       Pkg->CurrentState == pkgCache::State::HalfConfigured)
+   if (S->CurrentState == pkgCache::State::UnPacked ||
+       S->CurrentState == pkgCache::State::HalfConfigured)
       // we leave triggers alone complettely. dpkg deals with
       // them in a hard-to-predict manner and if they get 
       // resolved by dpkg before apt run dpkg --configure on 
@@ -284,8 +388,8 @@ pkgCache::PkgIterator::OkState pkgCache::PkgIterator::State() const
       //Pkg->CurrentState == pkgCache::State::TriggersPending)
       return NeedsConfigure;
    
-   if (Pkg->CurrentState == pkgCache::State::HalfInstalled ||
-       Pkg->InstState != pkgCache::State::Ok)
+   if (S->CurrentState == pkgCache::State::HalfInstalled ||
+       S->InstState != pkgCache::State::Ok)
       return NeedsUnpack;
       
    return NeedsNothing;
@@ -332,7 +436,7 @@ operator<<(ostream& out, pkgCache::PkgIterator Pkg)
    string candidate = string(Pkg.CandVersion() == 0 ? "none" : Pkg.CandVersion());
    string newest = string(Pkg.VersionList().end() ? "none" : Pkg.VersionList().VerStr());
 
-   out << Pkg.Name() << " < " << current;
+   out << Pkg.Name() << " [ " << Pkg.Arch() << " ] < " << current;
    if (current != candidate)
       out << " -> " << candidate;
    if ( newest != "none" && candidate != newest)
@@ -347,11 +451,11 @@ operator<<(ostream& out, pkgCache::PkgIterator Pkg)
    conflicts (including dpkg's Breaks fields). */
 bool pkgCache::DepIterator::IsCritical()
 {
-   if (Dep->Type == pkgCache::Dep::Conflicts ||
-       Dep->Type == pkgCache::Dep::DpkgBreaks ||
-       Dep->Type == pkgCache::Dep::Obsoletes ||
-       Dep->Type == pkgCache::Dep::Depends ||
-       Dep->Type == pkgCache::Dep::PreDepends)
+   if (S->Type == pkgCache::Dep::Conflicts ||
+       S->Type == pkgCache::Dep::DpkgBreaks ||
+       S->Type == pkgCache::Dep::Obsoletes ||
+       S->Type == pkgCache::Dep::Depends ||
+       S->Type == pkgCache::Dep::PreDepends)
       return true;
    return false;
 }
@@ -430,12 +534,12 @@ pkgCache::Version **pkgCache::DepIterator::AllTargets()
       // Walk along the actual package providing versions
       for (VerIterator I = DPkg.VersionList(); I.end() == false; I++)
       {
-        if (Owner->VS->CheckDep(I.VerStr(),Dep->CompareOp,TargetVer()) == false)
+        if (Owner->VS->CheckDep(I.VerStr(),S->CompareOp,TargetVer()) == false)
            continue;
 
-        if ((Dep->Type == pkgCache::Dep::Conflicts ||
-             Dep->Type == pkgCache::Dep::DpkgBreaks ||
-             Dep->Type == pkgCache::Dep::Obsoletes) &&
+        if ((S->Type == pkgCache::Dep::Conflicts ||
+             S->Type == pkgCache::Dep::DpkgBreaks ||
+             S->Type == pkgCache::Dep::Obsoletes) &&
             ParentPkg() == I.ParentPkg())
            continue;
         
@@ -447,12 +551,12 @@ pkgCache::Version **pkgCache::DepIterator::AllTargets()
       // Follow all provides
       for (PrvIterator I = DPkg.ProvidesList(); I.end() == false; I++)
       {
-        if (Owner->VS->CheckDep(I.ProvideVersion(),Dep->CompareOp,TargetVer()) == false)
+        if (Owner->VS->CheckDep(I.ProvideVersion(),S->CompareOp,TargetVer()) == false)
            continue;
         
-        if ((Dep->Type == pkgCache::Dep::Conflicts ||
-             Dep->Type == pkgCache::Dep::DpkgBreaks ||
-             Dep->Type == pkgCache::Dep::Obsoletes) &&
+        if ((S->Type == pkgCache::Dep::Conflicts ||
+             S->Type == pkgCache::Dep::DpkgBreaks ||
+             S->Type == pkgCache::Dep::Obsoletes) &&
             ParentPkg() == I.OwnerPkg())
            continue;
         
@@ -490,7 +594,7 @@ void pkgCache::DepIterator::GlobOr(DepIterator &Start,DepIterator &End)
    End = *this;
    for (bool LastOR = true; end() == false && LastOR == true;)
    {
-      LastOR = (Dep->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or;
+      LastOR = (S->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or;
       (*this)++;
       if (LastOR == true)
         End = (*this);
@@ -545,6 +649,23 @@ bool pkgCache::VerIterator::Automatic() const
    return false;
 }
                                                                        /*}}}*/
+// VerIterator::Pseudo - Check if this version is a pseudo one         /*{{{*/
+// ---------------------------------------------------------------------
+/* Sometimes you have the need to express dependencies with versions
+   which doesn't really exist or exist multiply times for "different"
+   packages. We need these versions for dependency resolution but they
+   are a problem everytime we need to download/install something. */
+bool pkgCache::VerIterator::Pseudo() const
+{
+   if (S->MultiArch == pkgCache::Version::All &&
+          strcmp(Arch(true),"all") != 0)
+   {
+          GrpIterator const Grp = ParentPkg().Group();
+          return (Grp->LastPackage != Grp->FirstPackage);
+   }
+   return false;
+}
+                                                                       /*}}}*/
 // VerIterator::NewestFile - Return the newest file version relation   /*{{{*/
 // ---------------------------------------------------------------------
 /* This looks at the version numbers associated with all of the sources
@@ -625,7 +746,9 @@ string pkgCache::VerIterator::RelStr()
         else
            Res += File.Site();
       }      
-   }   
+   }
+   if (S->ParentPkg != 0)
+      Res.append(" [").append(Arch()).append("]");
    return Res;
 }
                                                                        /*}}}*/
@@ -640,7 +763,7 @@ bool pkgCache::PkgFileIterator::IsOk()
    if (stat(FileName(),&Buf) != 0)
       return false;
 
-   if (Buf.st_size != (signed)File->Size || Buf.st_mtime != File->mtime)
+   if (Buf.st_size != (signed)S->Size || Buf.st_mtime != S->mtime)
       return false;
 
    return true;
@@ -664,6 +787,8 @@ string pkgCache::PkgFileIterator::RelStr()
       Res = Res + (Res.empty() == true?"l=":",l=")  + Label();
    if (Component() != 0)
       Res = Res + (Res.empty() == true?"c=":",c=")  + Component();
+   if (Architecture() != 0)
+      Res = Res + (Res.empty() == true?"b=":",b=")  + Architecture();
    return Res;
 }
                                                                        /*}}}*/
index e8a3e10645561bc03130ae0b39b924575f7640bd..012caac76c5a0e5cdd14f7077cd365ff546b0ec3 100644 (file)
@@ -32,6 +32,7 @@ class pkgCache                                                                /*{{{*/
    public:
    // Cache element predeclarations
    struct Header;
+   struct Group;
    struct Package;
    struct PackageFile;
    struct Version;
@@ -43,6 +44,8 @@ class pkgCache                                                                /*{{{*/
    struct DescFile;
    
    // Iterators
+   template<typename Str, typename Itr> class Iterator;
+   class GrpIterator;
    class PkgIterator;
    class VerIterator;
    class DescIterator;
@@ -51,14 +54,6 @@ class pkgCache                                                               /*{{{*/
    class PkgFileIterator;
    class VerFileIterator;
    class DescFileIterator;
-   friend class PkgIterator;
-   friend class VerIterator;
-   friend class DescInterator;
-   friend class DepIterator;
-   friend class PrvIterator;
-   friend class PkgFileIterator;
-   friend class VerFileIterator;
-   friend class DescFileIterator;
    
    class Namespace;
    
@@ -104,6 +99,7 @@ class pkgCache                                                               /*{{{*/
    
    // Pointers to the arrays of items
    Header *HeaderP;
+   Group *GrpP;
    Package *PkgP;
    VerFile *VerFileP;
    DescFile *DescFileP;
@@ -128,8 +124,13 @@ class pkgCache                                                             /*{{{*/
    const char *Priority(unsigned char Priority);
    
    // Accessors
+   GrpIterator FindGrp(const string &Name);
    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();
@@ -168,6 +169,7 @@ struct pkgCache::Header
    unsigned short DescFileSz;
    
    // Structure counts
+   unsigned long GroupCount;
    unsigned long PackageCount;
    unsigned long VersionCount;
    unsigned long DescriptionCount;
@@ -187,22 +189,36 @@ struct pkgCache::Header
 
    /* Allocation pools, there should be one of these for each structure
       excluding the header */
-   DynamicMMap::Pool Pools[8];
+   DynamicMMap::Pool Pools[9];
    
-   // Rapid package name lookup
-   map_ptrloc HashTable[2*1048];
+   // Rapid package and group name lookup
+   // Notice: Increase only both table sizes as the
+   // hashmethod assume the size of the Pkg one
+   map_ptrloc PkgHashTable[2*1048];
+   map_ptrloc GrpHashTable[2*1048];
 
    bool CheckSizes(Header &Against) const;
    Header();
 };
                                                                        /*}}}*/
+struct pkgCache::Group {                                               /*{{{*/
+       map_ptrloc Name;        // Stringtable
+
+       // Linked List
+       map_ptrloc FirstPackage;// Package
+       map_ptrloc LastPackage; // Package
+       map_ptrloc Next;        // Group
+};
+                                                                       /*}}}*/
 struct pkgCache::Package                                               /*{{{*/
 {
    // Pointers
    map_ptrloc Name;              // Stringtable
+   map_ptrloc Arch;              // StringTable (StringItem)
    map_ptrloc VersionList;       // Version
    map_ptrloc CurrentVer;        // Version
    map_ptrloc Section;           // StringTable (StringItem)
+   map_ptrloc Group;             // Group the Package belongs to
       
    // Linked list 
    map_ptrloc NextPackage;       // Package
@@ -260,8 +276,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
@@ -324,6 +340,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() 
@@ -337,7 +357,7 @@ inline pkgCache::PkgFileIterator pkgCache::FileEnd()
 class pkgCache::Namespace                                              /*{{{*/
 {   
    public:
-
+   typedef pkgCache::GrpIterator GrpIterator;
    typedef pkgCache::PkgIterator PkgIterator;
    typedef pkgCache::VerIterator VerIterator;
    typedef pkgCache::DescIterator DescIterator;
index 3eeb18cae69c2ee85ea1242a7481f1d7a917876b..3d1a654d1af65ca3071919bcead5ad1517588a42 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)
@@ -107,13 +108,26 @@ bool pkgCacheGenerator::MergeList(ListParser &List,
    unsigned int Counter = 0;
    while (List.Step() == true)
    {
-      // Get a pointer to the package structure
-      string PackageName = List.Package();
+      string const PackageName = List.Package();
       if (PackageName.empty() == true)
         return false;
-      
+
+      /* As we handle Arch all packages as architecture bounded
+         we add all information to every (simulated) arch package */
+      std::vector<string> genArch;
+      if (List.ArchitectureAll() == true) {
+        genArch = APT::Configuration::getArchitectures();
+        if (genArch.size() != 1)
+           genArch.push_back("all");
+      } else
+        genArch.push_back(List.Architecture());
+
+      for (std::vector<string>::const_iterator arch = genArch.begin();
+          arch != genArch.end(); ++arch)
+      {
+      // Get a pointer to the package structure
       pkgCache::PkgIterator Pkg;
-      if (NewPackage(Pkg,PackageName) == false)
+      if (NewPackage(Pkg, PackageName, *arch) == false)
         return _error->Error(_("Error occurred while processing %s (NewPackage)"),PackageName.c_str());
       Counter++;
       if (Counter % 100 == 0 && Progress != 0)
@@ -256,6 +270,7 @@ bool pkgCacheGenerator::MergeList(ListParser &List,
 
       if ((*LastDesc == 0 && _error->PendingError()) || NewFileDesc(Desc,List) == false)
         return _error->Error(_("Error occurred while processing %s (NewFileDesc2)"),PackageName.c_str());
+      }
    }
 
    FoundFileDeps |= List.HasFileDeps();
@@ -323,33 +338,71 @@ bool pkgCacheGenerator::MergeFileProvides(ListParser &List)
    return true;
 }
                                                                        /*}}}*/
+// CacheGenerator::NewGroup - Add a new group                          /*{{{*/
+// ---------------------------------------------------------------------
+/* This creates a new group structure and adds it to the hash table */
+bool pkgCacheGenerator::NewGroup(pkgCache::GrpIterator &Grp, const string &Name) {
+       Grp = Cache.FindGrp(Name);
+       if (Grp.end() == false)
+               return true;
+
+       // Get a structure
+       unsigned long const Group = Map.Allocate(sizeof(pkgCache::Group));
+       if (unlikely(Group == 0))
+               return false;
+
+       Grp = pkgCache::GrpIterator(Cache, Cache.GrpP + Group);
+       Grp->Name = Map.WriteString(Name);
+       if (unlikely(Grp->Name == 0))
+               return false;
+
+       // Insert it into the hash table
+       unsigned long const Hash = Cache.Hash(Name);
+       Grp->Next = Cache.HeaderP->GrpHashTable[Hash];
+       Cache.HeaderP->GrpHashTable[Hash] = Group;
+
+       Cache.HeaderP->GroupCount++;
+
+       return true;
+}
+                                                                       /*}}}*/
 // CacheGenerator::NewPackage - Add a new package                      /*{{{*/
 // ---------------------------------------------------------------------
 /* This creates a new package structure and adds it to the hash table */
-bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg,const string &Name)
-{
-   Pkg = Cache.FindPkg(Name);
-   if (Pkg.end() == false)
-      return true;
+bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg,const string &Name,
+                                       const string &Arch) {
+   pkgCache::GrpIterator Grp;
+   if (unlikely(NewGroup(Grp, Name) == false))
+      return false;
+
+   Pkg = Grp.FindPkg(Arch);
+      if (Pkg.end() == false)
+        return true;
 
    // Get a structure
-   unsigned long Package = Map.Allocate(sizeof(pkgCache::Package));
-   if (Package == 0)
+   unsigned long const Package = Map.Allocate(sizeof(pkgCache::Package));
+   if (unlikely(Package == 0))
       return false;
-   
    Pkg = pkgCache::PkgIterator(Cache,Cache.PkgP + Package);
-   
+
    // Insert it into the hash table
-   unsigned long Hash = Cache.Hash(Name);
-   Pkg->NextPackage = Cache.HeaderP->HashTable[Hash];
-   Cache.HeaderP->HashTable[Hash] = Package;
-   
-   // Set the name and the ID
-   Pkg->Name = Map.WriteString(Name);
-   if (Pkg->Name == 0)
+   unsigned long const Hash = Cache.Hash(Name);
+   Pkg->NextPackage = Cache.HeaderP->PkgHashTable[Hash];
+   Cache.HeaderP->PkgHashTable[Hash] = Package;
+
+   // remember the packages in the group
+   Grp->FirstPackage = Package;
+   if (Grp->LastPackage == 0)
+      Grp->LastPackage = Package;
+
+   // Set the name, arch and the ID
+   Pkg->Name = Grp->Name;
+   Pkg->Group = Grp.Index();
+   Pkg->Arch = WriteUniqString(Arch.c_str());
+   if (unlikely(Pkg->Arch == 0))
       return false;
    Pkg->ID = Cache.HeaderP->PackageCount++;
-   
+
    return true;
 }
                                                                        /*}}}*/
@@ -468,21 +521,87 @@ 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)) {
+                               if (strcmp(P.Arch(),"all") == 0)
+                                       continue;
+                               pkgCache::PkgIterator allPkg;
+                               for (pkgCache::VerIterator V = P.VersionList(); V.end() != true; V++) {
+                                       string const Arch = V.Arch(true);
+                                       map_ptrloc *OldDepLast = NULL;
+                                       /* MultiArch handling introduces a lot of implicit Dependencies:
+                                          - MultiArch: same → Co-Installable if they have the same version
+                                          - Architecture: all → Need to be Co-Installable for internal reasons
+                                          - All others conflict with all other group members */
+                                       bool const coInstall = (V->MultiArch == pkgCache::Version::All ||
+                                                               V->MultiArch == pkgCache::Version::Same);
+                                       if (V->MultiArch == pkgCache::Version::All && allPkg.end() == true)
+                                               allPkg = G.FindPkg("all");
+                                       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;
+                                               if (coInstall == true) {
+                                                       // Replaces: ${self}:other ( << ${binary:Version})
+                                                       NewDepends(D, V, V.VerStr(),
+                                                                  pkgCache::Dep::Less, pkgCache::Dep::Replaces,
+                                                                  OldDepLast);
+                                                       // Breaks: ${self}:other (!= ${binary:Version})
+                                                       NewDepends(D, V, V.VerStr(),
+                                                                  pkgCache::Dep::Less, pkgCache::Dep::DpkgBreaks,
+                                                                  OldDepLast);
+                                                       NewDepends(D, V, V.VerStr(),
+                                                                  pkgCache::Dep::Greater, pkgCache::Dep::DpkgBreaks,
+                                                                  OldDepLast);
+                                                       if (V->MultiArch == pkgCache::Version::All) {
+                                                               // Depend on ${self}:all which does depend on nothing
+                                                               NewDepends(allPkg, V, V.VerStr(),
+                                                                          pkgCache::Dep::Equals, pkgCache::Dep::Depends,
+                                                                          OldDepLast);
+                                                       }
+                                               } else {
+                                                       // 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 &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 Dependency = Owner->Map.Allocate(sizeof(pkgCache::Dependency));
-   if (Dependency == 0)
+   unsigned long const Dependency = Map.Allocate(sizeof(pkgCache::Dependency));
+   if (unlikely(Dependency == 0))
       return false;
    
    // Fill it in
@@ -491,12 +610,7 @@ bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver,
    Dep->Type = Type;
    Dep->CompareOp = Op;
    Dep->ID = Cache.HeaderP->DependsCount++;
-   
-   // Locate the target package
-   pkgCache::PkgIterator Pkg;
-   if (Owner->NewPackage(Pkg,PackageName) == false)
-      return false;
-   
+
    // Probe the reverse dependency list for a version string that matches
    if (Version.empty() == false)
    {
@@ -504,29 +618,23 @@ bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver,
         if (I->Version != 0 && I.TargetVer() == Version)
            Dep->Version = I->Version;*/
       if (Dep->Version == 0)
-        if ((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 (PackageName[0] == '/')
-      FoundFileDeps = true;
-   
    Dep->NextDepends = *OldDepLast;
    *OldDepLast = Dep.Index();
    OldDepLast = &Dep->NextDepends;
@@ -534,22 +642,58 @@ 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                 /*{{{*/
 // ---------------------------------------------------------------------
 /* */
 bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver,
-                                               const string &PackageName,
+                                               const string &PkgName,
+                                               const string &PkgArch,
                                                const string &Version)
 {
    pkgCache &Cache = Owner->Cache;
 
    // We do not add self referencing provides
-   if (Ver.ParentPkg().Name() == PackageName)
+   if (Ver.ParentPkg().Name() == PkgName && PkgArch == Ver.Arch(true))
       return true;
    
    // Get a structure
-   unsigned long Provides = Owner->Map.Allocate(sizeof(pkgCache::Provides));
-   if (Provides == 0)
+   unsigned long const Provides = Owner->Map.Allocate(sizeof(pkgCache::Provides));
+   if (unlikely(Provides == 0))
       return false;
    Cache.HeaderP->ProvidesCount++;
    
@@ -558,12 +702,12 @@ bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver,
    Prv->Version = Ver.Index();
    Prv->NextPkgProv = Ver->ProvidesList;
    Ver->ProvidesList = Prv.Index();
-   if (Version.empty() == false && (Prv->ProvideVersion = WriteString(Version)) == 0)
+   if (Version.empty() == false && unlikely((Prv->ProvideVersion = WriteString(Version)) == 0))
       return false;
    
    // Locate the target package
    pkgCache::PkgIterator Pkg;
-   if (Owner->NewPackage(Pkg,PackageName) == false)
+   if (unlikely(Owner->NewPackage(Pkg,PkgName, PkgArch) == false))
       return false;
    
    // Link it to the package
@@ -923,6 +1067,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 +1112,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 (Debug == true)
       std::clog << "Caches are ready for shipping" << std::endl;
@@ -1012,7 +1162,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 108b34207a1cbab0cecb18b73e4692f6ea7fc894..46d0cd893ef9e25fe343105b87dc6c9a23d78fbc 100644 (file)
@@ -51,9 +51,13 @@ class pkgCacheGenerator                                                      /*{{{*/
    // Flag file dependencies
    bool FoundFileDeps;
    
-   bool NewPackage(pkgCache::PkgIterator &Pkg,const string &PkgName);
+   bool NewGroup(pkgCache::GrpIterator &Grp,const string &Name);
+   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);
 
@@ -72,7 +76,8 @@ class pkgCacheGenerator                                                       /*{{{*/
 
    bool HasFileDeps() {return FoundFileDeps;};
    bool MergeFileProvides(ListParser &List);
-      
+   bool FinishCache(OpProgress &Progress);
+
    pkgCacheGenerator(DynamicMMap *Map,OpProgress *Progress);
    ~pkgCacheGenerator();
 };
@@ -96,16 +101,18 @@ class pkgCacheGenerator::ListParser
    inline unsigned long WriteUniqString(const char *S,unsigned int Size) {return Owner->WriteUniqString(S,Size);};
    inline unsigned long WriteString(const string &S) {return Owner->Map.WriteString(S);};
    inline unsigned long WriteString(const char *S,unsigned int Size) {return Owner->Map.WriteString(S,Size);};
-   bool NewDepends(pkgCache::VerIterator Ver,const string &Package,
+   bool NewDepends(pkgCache::VerIterator Ver,const string &Package, const string &Arch,
                   const string &Version,unsigned int Op,
                   unsigned int Type);
-   bool NewProvides(pkgCache::VerIterator Ver,const string &Package,
-                   const string &Version);
+   bool NewProvides(pkgCache::VerIterator Ver,const string &PkgName,
+                   const string &PkgArch, const string &Version);
    
    public:
    
    // These all operate against the current section
    virtual string Package() = 0;
+   virtual string Architecture() = 0;
+   virtual bool ArchitectureAll() = 0;
    virtual string Version() = 0;
    virtual bool NewVersion(pkgCache::VerIterator Ver) = 0;
    virtual string Description() = 0;
index 929259961e966a74b5cb404ecfca57ff67d39c3c..a860c7eac51e2e53ef44a933cb7857d5c52406b0 100644 (file)
@@ -72,13 +72,51 @@ bool pkgSourceList::Type::FixupURI(string &URI) const
    Weird types may override this. */
 bool pkgSourceList::Type::ParseLine(vector<metaIndex *> &List,
                                    const char *Buffer,
-                                   unsigned long CurLine,
-                                   string File) const
+                                   unsigned long const &CurLine,
+                                   string const &File) const
 {
+   for (;Buffer != 0 && isspace(*Buffer); ++Buffer); // Skip whitespaces
+
+   // Parse option field if it exists
+   // e.g.: [ option1=value1 option2=value2 ]
+   map<string, string> Options;
+   if (Buffer != 0 && Buffer[0] == '[')
+   {
+      ++Buffer; // ignore the [
+      for (;Buffer != 0 && isspace(*Buffer); ++Buffer); // Skip whitespaces
+      while (*Buffer != ']')
+      {
+        // get one option, e.g. option1=value1
+        string option;
+        if (ParseQuoteWord(Buffer,option) == false)
+           return _error->Error(_("Malformed line %lu in source list %s ([option] unparseable)"),CurLine,File.c_str());
+
+        if (option.length() < 3)
+           return _error->Error(_("Malformed line %lu in source list %s ([option] too short)"),CurLine,File.c_str());
+
+        size_t const needle = option.find('=');
+        if (needle == string::npos)
+           return _error->Error(_("Malformed line %lu in source list %s ([%s] is not an assignment)"),CurLine,File.c_str(), option.c_str());
+
+        string const key = string(option, 0, needle);
+        string const value = string(option, needle + 1, option.length());
+
+        if (key.empty() == true)
+           return _error->Error(_("Malformed line %lu in source list %s ([%s] has no key)"),CurLine,File.c_str(), option.c_str());
+
+        if (value.empty() == true)
+           return _error->Error(_("Malformed line %lu in source list %s ([%s] key %s has no value)"),CurLine,File.c_str(),option.c_str(),key.c_str());
+
+        Options[key] = value;
+      }
+      ++Buffer; // ignore the ]
+      for (;Buffer != 0 && isspace(*Buffer); ++Buffer); // Skip whitespaces
+   }
+
    string URI;
    string Dist;
-   string Section;   
-   
+   string Section;
+
    if (ParseQuoteWord(Buffer,URI) == false)
       return _error->Error(_("Malformed line %lu in source list %s (URI)"),CurLine,File.c_str());
    if (ParseQuoteWord(Buffer,Dist) == false)
@@ -93,7 +131,7 @@ bool pkgSourceList::Type::ParseLine(vector<metaIndex *> &List,
       if (ParseQuoteWord(Buffer,Section) == true)
         return _error->Error(_("Malformed line %lu in source list %s (absolute dist)"),CurLine,File.c_str());
       Dist = SubstVar(Dist,"$(ARCH)",_config->Find("APT::Architecture"));
-      return CreateItem(List,URI,Dist,Section);
+      return CreateItem(List, URI, Dist, Section, Options);
    }
    
    // Grab the rest of the dists
@@ -102,7 +140,7 @@ bool pkgSourceList::Type::ParseLine(vector<metaIndex *> &List,
    
    do
    {
-      if (CreateItem(List,URI,Dist,Section) == false)
+      if (CreateItem(List, URI, Dist, Section, Options) == false)
         return false;
    }
    while (ParseQuoteWord(Buffer,Section) == true);
@@ -239,36 +277,7 @@ bool pkgSourceList::ReadAppend(string File)
       if (Parse == 0)
         return _error->Error(_("Type '%s' is not known on line %u in source list %s"),LineType.c_str(),CurLine,File.c_str());
       
-      // Vendor name specified
-      if (C[0] == '[')
-      {
-        string VendorID;
-        
-        if (ParseQuoteWord(C,VendorID) == false)
-            return _error->Error(_("Malformed line %u in source list %s (vendor id)"),CurLine,File.c_str());
-
-        if (VendorID.length() < 2 || VendorID.end()[-1] != ']')
-            return _error->Error(_("Malformed line %u in source list %s (vendor id)"),CurLine,File.c_str());
-        VendorID = string(VendorID,1,VendorID.size()-2);
-        
-//      for (vector<const Vendor *>::const_iterator iter = VendorList.begin();
-//           iter != VendorList.end(); iter++) 
-//      {
-//         if ((*iter)->GetVendorID() == VendorID)
-//         {
-//           if (_config->FindB("Debug::sourceList", false)) 
-//             std::cerr << "Comparing VendorID \"" << VendorID << "\" with \"" << (*iter)->GetVendorID() << '"' << std::endl;
-//            Verifier = *iter;
-//            break;
-//         }
-//      }
-
-//      if (Verifier == 0)
-//         return _error->Error(_("Unknown vendor ID '%s' in line %u of source list %s"),
-//                              VendorID.c_str(),CurLine,File.c_str());
-      }
-
-      if (Parse->ParseLine(SrcList,C,CurLine,File) == false)
+      if (Parse->ParseLine(SrcList, C, CurLine, File) == false)
         return false;
    }
    return true;
index b9e4389ed1ee89e087b3de1347f7bf6f68a6c1ee..e15314a5e796fbd87a7eb1ded8101e6790bbdc8e 100644 (file)
@@ -29,6 +29,7 @@
 
 #include <string>
 #include <vector>
+#include <map>
 #include <apt-pkg/pkgcache.h>
 #include <apt-pkg/metaindex.h>
 
@@ -57,9 +58,10 @@ class pkgSourceList
       bool FixupURI(string &URI) const;
       virtual bool ParseLine(vector<metaIndex *> &List,
                             const char *Buffer,
-                            unsigned long CurLine,string File) const;
-      virtual bool CreateItem(vector<metaIndex *> &List,string URI,
-                             string Dist,string Section) const = 0;
+                            unsigned long const &CurLine,string const &File) const;
+      virtual bool CreateItem(vector<metaIndex *> &List,string const &URI,
+                             string const &Dist,string const &Section,
+                             std::map<string, string> const &Options) const = 0;
       Type();
       virtual ~Type() {};
    };
index b4d1d4696ed58b983256efff47f910c2d20b70d1..e5f0fafd29ce0773922e2bfca71f65470b17bd8a 100644 (file)
@@ -100,6 +100,8 @@ pkgVersionMatch::pkgVersionMatch(string Data,MatchType Type) : Type(Type)
            RelLabel = Fragments[J]+2;
         else if (stringcasecmp(Fragments[J],Fragments[J]+2,"c=") == 0)
            RelComponent = Fragments[J]+2;
+        else if (stringcasecmp(Fragments[J],Fragments[J]+2,"b=") == 0)
+           RelArchitecture = Fragments[J]+2;
       }
 
       if (RelVerStr.end()[-1] == '*')
@@ -178,7 +180,7 @@ bool pkgVersionMatch::FileMatch(pkgCache::PkgFileIterator File)
       if (RelVerStr.empty() == true && RelOrigin.empty() == true &&
          RelArchive.empty() == true && RelLabel.empty() == true &&
          RelRelease.empty() == true && RelCodename.empty() == true &&
-         RelComponent.empty() == true)
+         RelComponent.empty() == true && RelArchitecture.empty() == true)
         return false;
 
       if (RelVerStr.empty() == false)
@@ -211,6 +213,10 @@ bool pkgVersionMatch::FileMatch(pkgCache::PkgFileIterator File)
         if (File->Component == 0 ||
             stringcasecmp(RelComponent,File.Component()) != 0)
            return false;
+      if (RelArchitecture.empty() == false)
+        if (File->Architecture == 0 ||
+            stringcasecmp(RelArchitecture,File.Architecture()) != 0)
+           return false;
       return true;
    }
 
index a8f3c84ac9a8ab92fcb3fdb289510a3ea208c035..a8da072ae078e039ce8dafd9004ec8183eca9fb7 100644 (file)
@@ -23,6 +23,7 @@
       Codename (n=) e.g. etch, lenny, squeeze, sid
       Label (l=)
       Component (c=)
+      Binary Architecture (b=)
    If there are no equals signs in the string then it is scanned in short
    form - if it starts with a number it is Version otherwise it is an
    Archive or a Codename.
@@ -55,6 +56,7 @@ class pkgVersionMatch
    string RelArchive;
    string RelLabel;
    string RelComponent;
+   string RelArchitecture;
    bool MatchAll;
    
    // Origin Matching
index 286f306cdbc79f2a94e802a5e5eb6779c63f1726..8323a740ee3da7c735daf0619d27660b38d5e17e 100644 (file)
@@ -1417,11 +1417,15 @@ bool ShowPackage(CommandLine &CmdL)
    
    for (const char **I = CmdL.FileList + 1; *I != 0; I++)
    {
+      // FIXME: Handle the case in which pkgname name:arch is not found
       pkgCache::PkgIterator Pkg = Cache.FindPkg(*I);
       if (Pkg.end() == true)
       {
-        _error->Warning(_("Unable to locate package %s"),*I);
-        continue;
+        Pkg = Cache.FindPkg(*I, "any");
+        if (Pkg.end() == true) {
+               _error->Warning(_("Unable to locate package %s"),*I);
+               continue;
+        }
       }
 
       ++found;
@@ -1457,16 +1461,17 @@ bool ShowPackage(CommandLine &CmdL)
 bool ShowPkgNames(CommandLine &CmdL)
 {
    pkgCache &Cache = *GCache;
-   pkgCache::PkgIterator I = Cache.PkgBegin();
-   bool All = _config->FindB("APT::Cache::AllNames","false");
-   
+   pkgCache::GrpIterator I = Cache.GrpBegin();
+   bool const All = _config->FindB("APT::Cache::AllNames","false");
+
    if (CmdL.FileList[1] != 0)
    {
       for (;I.end() != true; I++)
       {
-        if (All == false && I->VersionList == 0)
+        if (All == false && I->FirstPackage == 0)
+           continue;
+        if (I.FindPkg("any")->VersionList == 0)
            continue;
-        
         if (strncmp(I.Name(),CmdL.FileList[1],strlen(CmdL.FileList[1])) == 0)
            cout << I.Name() << endl;
       }
@@ -1477,7 +1482,9 @@ bool ShowPkgNames(CommandLine &CmdL)
    // Show all pkgs
    for (;I.end() != true; I++)
    {
-      if (All == false && I->VersionList == 0)
+      if (All == false && I->FirstPackage == 0)
+        continue;
+      if (I.FindPkg("any")->VersionList == 0)
         continue;
       cout << I.Name() << endl;
    }
@@ -1565,19 +1572,29 @@ bool Policy(CommandLine &CmdL)
       
       return true;
    }
-   
+
+   string const myArch = _config->Find("APT::Architecture");
+
    // Print out detailed information for each package
    for (const char **I = CmdL.FileList + 1; *I != 0; I++)
    {
-      pkgCache::PkgIterator Pkg = Cache.FindPkg(*I);
+      pkgCache::GrpIterator Grp = Cache.FindGrp(*I);
+      pkgCache::PkgIterator Pkg = Grp.FindPkg("any");
       if (Pkg.end() == true)
       {
         _error->Warning(_("Unable to locate package %s"),*I);
         continue;
       }
-      
-      cout << Pkg.Name() << ":" << endl;
-      
+
+      for (; Pkg.end() != true; Pkg = Grp.NextPkg(Pkg)) {
+      if (strcmp(Pkg.Arch(),"all") == 0)
+        continue;
+
+      if (myArch == Pkg.Arch())
+        cout << Pkg.Name() << ":" << endl;
+      else
+        cout << Pkg.Name() << ": [" << Pkg.Arch() << "]" << endl;
+
       // Installed version
       cout << _("  Installed: ");
       if (Pkg->CurrentVer == 0)
@@ -1622,8 +1639,9 @@ bool Policy(CommandLine &CmdL)
               return _error->Error(_("Cache is out of sync, can't x-ref a package file"));
            printf("       %4i %s\n",Plcy.GetPriority(VF.File()),
                   Indx->Describe(true).c_str());
-        }       
-      }      
+        }
+      }
+      }
    }
    
    return true;
index 5a814e255e4971f0a42c863244500d9afcbb50cb..c8c733716774923a92cf8730f247b865f1f7dfe4 100644 (file)
@@ -227,6 +227,17 @@ bool ShowList(ostream &out,string Title,string List,string VersionsList)
    return false;
 }
                                                                        /*}}}*/
+// ShowPkg - display a package name                                    /*{{{*/
+// ---------------------------------------------------------------------
+/* Displays the package name and maybe also the architecture
+   if it is not the main architecture */
+string ShowPkg(pkgCache::PkgIterator const Pkg) {
+       string p = Pkg.Name();
+       if (strcmp(Pkg.Arch(),"all") != 0 && _config->Find("APT::Architecture") != Pkg.Arch())
+               p.append(":").append(Pkg.Arch());
+       return p;
+}
+                                                                       /*}}}*/
 // ShowBroken - Debugging aide                                         /*{{{*/
 // ---------------------------------------------------------------------
 /* This prints out the names of all the packages that are broken along
@@ -258,8 +269,8 @@ void ShowBroken(ostream &out,CacheFile &Cache,bool Now)
       }
       
       // Print out each package and the failed dependencies
-      out <<"  " <<  I.Name() << ":";
-      unsigned Indent = strlen(I.Name()) + 3;
+      out << " " << ShowPkg(I) << " :";
+      unsigned const Indent = ShowPkg(I).size() + 3;
       bool First = true;
       pkgCache::VerIterator Ver;
       
@@ -312,7 +323,7 @@ void ShowBroken(ostream &out,CacheFile &Cache,bool Now)
               out << ' ' << End.DepType() << ": ";
            FirstOr = false;
            
-           out << Start.TargetPkg().Name();
+           out << ShowPkg(Start.TargetPkg());
         
            // Show a quick summary of the version requirements
            if (Start.TargetVer() != 0)
@@ -374,7 +385,9 @@ void ShowNew(ostream &out,CacheFile &Cache)
    {
       pkgCache::PkgIterator I(Cache,Cache.List[J]);
       if (Cache[I].NewInstall() == true) {
-         List += string(I.Name()) + " ";
+        if (Cache[I].CandidateVerIter(Cache).Pseudo() == true)
+           continue;
+         List += ShowPkg(I) + " ";
          VersionsList += string(Cache[I].CandVersion) + "\n";
       }
    }
@@ -396,10 +409,12 @@ void ShowDel(ostream &out,CacheFile &Cache)
       pkgCache::PkgIterator I(Cache,Cache.List[J]);
       if (Cache[I].Delete() == true)
       {
+        if (Cache[I].CandidateVerIter(Cache).Pseudo() == true)
+           continue;
         if ((Cache[I].iFlags & pkgDepCache::Purge) == pkgDepCache::Purge)
-           List += string(I.Name()) + "* ";
+           List += ShowPkg(I) + "* ";
         else
-           List += string(I.Name()) + " ";
+           List += ShowPkg(I) + " ";
      
      VersionsList += string(Cache[I].CandVersion)+ "\n";
       }
@@ -424,7 +439,7 @@ void ShowKept(ostream &out,CacheFile &Cache)
          I->CurrentVer == 0 || Cache[I].Delete() == true)
         continue;
       
-      List += string(I.Name()) + " ";
+      List += ShowPkg(I) + " ";
       VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n";
    }
    ShowList(out,_("The following packages have been kept back:"),List,VersionsList);
@@ -444,8 +459,10 @@ void ShowUpgraded(ostream &out,CacheFile &Cache)
       // Not interesting
       if (Cache[I].Upgrade() == false || Cache[I].NewInstall() == true)
         continue;
-      
-      List += string(I.Name()) + " ";
+      if (Cache[I].CandidateVerIter(Cache).Pseudo() == true)
+        continue;
+
+      List += ShowPkg(I) + " ";
       VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n";
    }
    ShowList(out,_("The following packages will be upgraded:"),List,VersionsList);
@@ -465,8 +482,10 @@ bool ShowDowngraded(ostream &out,CacheFile &Cache)
       // Not interesting
       if (Cache[I].Downgrade() == false || Cache[I].NewInstall() == true)
         continue;
-      
-      List += string(I.Name()) + " ";
+      if (Cache[I].CandidateVerIter(Cache).Pseudo() == true)
+        continue;
+
+      List += ShowPkg(I) + " ";
       VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n";
    }
    return ShowList(out,_("The following packages will be DOWNGRADED:"),List,VersionsList);
@@ -484,7 +503,7 @@ bool ShowHold(ostream &out,CacheFile &Cache)
       pkgCache::PkgIterator I(Cache,Cache.List[J]);
       if (Cache[I].InstallVer != (pkgCache::Version *)I.CurrentVer() &&
           I->SelectedState == pkgCache::State::Hold) {
-         List += string(I.Name()) + " ";
+         List += ShowPkg(I) + " ";
                 VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n";
       }
    }
@@ -518,7 +537,7 @@ bool ShowEssential(ostream &out,CacheFile &Cache)
         if (Added[I->ID] == false)
         {
            Added[I->ID] = true;
-           List += string(I.Name()) + " ";
+           List += ShowPkg(I) + " ";
         //VersionsList += string(Cache[I].CurVersion) + "\n"; ???
         }
       }
@@ -566,6 +585,9 @@ void Stats(ostream &out,pkgDepCache &Dep)
    unsigned long ReInstall = 0;
    for (pkgCache::PkgIterator I = Dep.PkgBegin(); I.end() == false; I++)
    {
+      if (pkgCache::VerIterator(Dep, Dep[I].CandidateVer).Pseudo() == true)
+        continue;
+
       if (Dep[I].NewInstall() == true)
         Install++;
       else
@@ -2438,7 +2460,7 @@ bool DoBuildDep(CommandLine &CmdL)
             
       // Process the build-dependencies
       vector<pkgSrcRecords::Parser::BuildDepRec> BuildDeps;
-      if (Last->BuildDepends(BuildDeps, _config->FindB("APT::Get::Arch-Only",false)) == false)
+      if (Last->BuildDepends(BuildDeps, _config->FindB("APT::Get::Arch-Only",true)) == false)
        return _error->Error(_("Unable to get build-dependency information for %s"),Src.c_str());
    
       // Also ensure that build-essential packages are present
index a7507f4e7ba4246b0d4d88b2bf43d11b5c9790a2..86aa69cebe9d1951df090a02cd1fd52c0d893b6f 100644 (file)
@@ -1 +1,2 @@
-README.progress-reporting
\ No newline at end of file
+README.progress-reporting
+README.MultiArch
index f0ab5025b108d037b4d971bdd334df0663e779d3..8a4e2ac20be045dc125d42ee1c5381f7c1644cf3 100644 (file)
@@ -4,10 +4,14 @@ apt (0.7.26) UNRELEASED; urgency=low
   * [BREAK] add possibility to download and use multiply
     Translation files, configurable with Acquire::Translation
     (Closes: #444222, #448216, #550564)
+  * [BREAK] merge MultiArch-ABI. We don't support MultiArch,
+    but we support the usage of the new ABI so libapt users
+    can start to prepare for MultiArch (Closes: #536029)
   * Ignore :qualifiers after package name in build dependencies
-    for now as long we don't understand them (Closes: #558103)
+    in the library by default, but try to honour them in apt-get
+    as we have some sort of MultiArch support ready (Closes: #558103)
   * apt-pkg/contrib/mmap.{cc,h}:
-    - extend it to have a growable flag - unused now but maybe...
+    - extend it to have a growable flag - unused now but maybe
   * apt-pkg/pkgcache.h:
     - use long instead of short for {Ver,Desc}File size,
       patch from Víctor Manuel Jáquez Leal, thanks! (Closes: #538917)