- initial multilib support (only packages in the same repository are considered)
authorpmatilai <pmatilai>
Tue, 17 Jan 2006 00:31:19 +0000 (00:31 +0000)
committerpmatilai <pmatilai>
Tue, 17 Jan 2006 00:31:19 +0000 (00:31 +0000)
apt-pkg/rpm/rpmlistparser.cc
apt-pkg/rpm/rpmlistparser.h
apt-pkg/rpm/rpmpackagedata.cc
apt-pkg/rpm/rpmpackagedata.h
apt-pkg/rpm/rpmsystem.cc

index f353221..d78cd04 100644 (file)
@@ -44,13 +44,20 @@ rpmListParser::rpmListParser(RPMHandler *Handler)
    Handler->Rewind();
    header = NULL;
    if (Handler->IsDatabase() == true)
+   {
 #ifdef WITH_HASH_MAP
       SeenPackages = new SeenPackagesType(517);
+      SeenMultiPackages = new SeenMultiPackagesType(517);
 #else
       SeenPackages = new SeenPackagesType;
+      SeenMultiPackages = new SeenMultiPackagesType;
 #endif
+   }
    else
+   {
       SeenPackages = NULL;
+      SeenMultiPackages = NULL;
+   }
    RpmData = RPMPackageData::Singleton();
 }
                                                                         /*}}}*/
@@ -58,6 +65,7 @@ rpmListParser::rpmListParser(RPMHandler *Handler)
 rpmListParser::~rpmListParser()
 {
    delete SeenPackages;
+   delete SeenMultiPackages;
 }
 
 // ListParser::UniqFindTagWrite - Find the tag and write a unq string  /*{{{*/
@@ -113,7 +121,28 @@ string rpmListParser::Package()
    } 
 
    bool IsDup = false;
+   bool IsMulti = false;
    string Name = str;
+   string BaseArch = _config->Find("APT::Architecture");
+
+   if (RpmData->IsMultiArchPackage(Name) == true)
+      IsMulti = true;
+   else if (SeenMultiPackages != NULL) {
+      if (SeenMultiPackages->find(Name.c_str()) != SeenMultiPackages->end())
+      {
+        RpmData->SetMultiArchPackage(Name);
+        MultiArchPackage(Name);
+        IsMulti = true;
+      }
+   }
+   if (IsMulti == true)
+   {
+      Name += "." + Architecture();     
+      CurrentName = Name;
+      Multilib = true;
+      return Name;
+   }
+
    
    // If this package can have multiple versions installed at
    // the same time, then we make it so that the name of the
@@ -267,6 +296,8 @@ bool rpmListParser::UsePackage(pkgCache::PkgIterator Pkg,
 {
    if (SeenPackages != NULL)
       (*SeenPackages)[Pkg.Name()] = true;
+   if (SeenMultiPackages != NULL)
+      (*SeenMultiPackages)[Pkg.Name()] = true;
    if (Pkg->Section == 0)
       Pkg->Section = UniqFindTagWrite(RPMTAG_GROUP);
    if (_error->PendingError()) 
@@ -674,6 +705,9 @@ bool rpmListParser::Step()
 #endif
       
       string RealName = Package();
+
+      if (Multilib == true)
+        RealName = RealName.substr(0,RealName.find('.'));
       if (Duplicated == true)
         RealName = RealName.substr(0,RealName.find('#'));
       if (RpmData->IgnorePackage(RealName) == true)
@@ -815,6 +849,75 @@ void rpmListParser::VirtualizePackage(string Name)
    FromPkgI->CurrentState = 0;
 }
 
+void rpmListParser::MultiArchPackage(string Name)
+{
+   pkgCache::PkgIterator FromPkgI = Owner->GetCache().FindPkg(Name);
+
+   // Should always be false
+   if (FromPkgI.end() == true)
+      return;
+
+   pkgCache::VerIterator FromVerI = FromPkgI.VersionList();
+   while (FromVerI.end() == false) {
+      string MangledName = Name+"."+string(FromVerI.Arch());
+
+      // Get the new package.
+      pkgCache::PkgIterator ToPkgI = Owner->GetCache().FindPkg(MangledName);
+      if (ToPkgI.end() == true) {
+        // Theoretically, all packages virtualized should pass here at least
+        // once for each new version in the list, since either the package was
+        // already setup as Allow-Duplicated (and this method would never be
+        // called), or the package doesn't exist before getting here. If
+        // we discover that this assumption is false, then we must do
+        // something to order the version list correctly, since the package
+        // could already have some other version there.
+        Owner->NewPackage(ToPkgI, MangledName);
+
+        // Should it get the flags from the original package? Probably not,
+        // or automatic Allow-Duplicated would work differently than
+        // hardcoded ones.
+        ToPkgI->Flags |= RpmData->PkgFlags(MangledName);
+        ToPkgI->Section = FromPkgI->Section;
+      }
+      
+      // Move the version to the new package.
+      FromVerI->ParentPkg = ToPkgI.Index();
+
+      // Put it at the end of the version list (about ordering,
+      // read the comment above).
+      map_ptrloc *ToVerLast = &ToPkgI->VersionList;
+      for (pkgCache::VerIterator ToVerLastI = ToPkgI.VersionList();
+          ToVerLastI.end() == false; ToVerLastI++)
+          ToVerLast = &ToVerLastI->NextVer;
+
+      *ToVerLast = FromVerI.Index();
+
+      // Provide the real package name with the current version.
+      NewProvides(FromVerI, Name, FromVerI.VerStr());
+
+      // Is this the current version of the old package? If yes, set it
+      // as the current version of the new package as well.
+      if (FromVerI == FromPkgI.CurrentVer()) {
+        ToPkgI->CurrentVer = FromVerI.Index();
+        ToPkgI->SelectedState = pkgCache::State::Install;
+        ToPkgI->InstState = pkgCache::State::Ok;
+        ToPkgI->CurrentState = pkgCache::State::Installed;
+      }
+
+      // Move the iterator before reseting the NextVer.
+      pkgCache::Version *FromVer = (pkgCache::Version*)FromVerI;
+      FromVerI++;
+      FromVer->NextVer = 0;
+   }
+
+   // Reset original package data.
+   FromPkgI->CurrentVer = 0;
+   FromPkgI->VersionList = 0;
+   FromPkgI->Section = 0;
+   FromPkgI->SelectedState = 0;
+   FromPkgI->InstState = 0;
+   FromPkgI->CurrentState = 0;
+}
 #endif /* HAVE_RPM */
 
 // vim:sts=3:sw=3
index 7ed147c..09c3492 100644 (file)
@@ -38,12 +38,17 @@ class rpmListParser : public pkgCacheGenerator::ListParser
 #ifdef WITH_HASH_MAP
    typedef hash_map<const char*,bool,
                    hash<const char*>,cstr_eq_pred> SeenPackagesType;
+   typedef hash_map<const char*,bool,
+                   hash<const char*>,cstr_eq_pred> SeenMultiPackagesType;
 #else
    typedef map<const char*,bool,cstr_lt_pred> SeenPackagesType;
+   typedef map<const char*,bool,cstr_lt_pred> SeenMultiPackagesType;
 #endif
    SeenPackagesType *SeenPackages;
+   SeenMultiPackagesType *SeenMultiPackages;
    
    bool Duplicated;
+   bool Multilib;
    
    unsigned long UniqFindTagWrite(int Tag);
    bool ParseStatus(pkgCache::PkgIterator Pkg,pkgCache::VerIterator Ver);
@@ -84,6 +89,7 @@ class rpmListParser : public pkgCacheGenerator::ListParser
    bool LoadReleaseInfo(pkgCache::PkgFileIterator FileI,FileFd &File);
 
    void VirtualizePackage(string Name);
+   void MultiArchPackage(string Name);
    
    rpmListParser(RPMHandler *Handler);
    ~rpmListParser();
index 489bd96..3c400bf 100644 (file)
@@ -112,6 +112,21 @@ RPMPackageData::RPMPackageData()
          DuplicatedPatterns.push_back(ptrn);
    }
 
+   // Populate MultiArch packages.
+   Top = _config->Tree("RPM::MultiArch");
+   for (Top = (Top == 0?0:Top->Child); Top != 0; Top = Top->Next)
+   {
+      regex_t *ptrn = new regex_t;
+      if (regcomp(ptrn,Top->Value.c_str(),REG_EXTENDED|REG_ICASE|REG_NOSUB) != 0)
+      {
+        _error->Warning(_("Bad regular expression '%s' in option RPM::MultiArch."),
+                        Top->Value.c_str());
+        delete ptrn;
+      }
+      else
+         MultiArchPatterns.push_back(ptrn);
+   }
+
    // Populate fake provides
    Top = _config->Tree("RPM::Fake-Provides");
    for (Top = (Top == 0?0:Top->Child); Top != 0; Top = Top->Next)
@@ -291,6 +306,20 @@ bool RPMPackageData::IsDupPackage(const string &Name)
    return false;
 }
 
+bool RPMPackageData::IsMultiArchPackage(const string &Name)
+{
+   if (MultiArchPackages.find(Name) != MultiArchPackages.end())
+      return true;
+   const char *name = Name.c_str();
+   for (vector<regex_t*>::iterator I = MultiArchPatterns.begin();
+       I != MultiArchPatterns.end(); I++) {
+      if (regexec(*I,name,0,0,0) == 0) {
+        SetMultiArchPackage(Name);
+        return true;
+      }
+   }
+   return false;
+}
 RPMPackageData *RPMPackageData::Singleton()
 {
    static RPMPackageData *data = NULL;
index 106ecf8..cb68dbc 100644 (file)
@@ -27,6 +27,7 @@ class RPMPackageData
    hash_map<string,vector<string>*,hash_string> FakeProvides;
    hash_map<string,int,hash_string> IgnorePackages;
    hash_map<string,int,hash_string> DuplicatedPackages;
+   hash_map<string,int,hash_string> MultiArchPackages;
    typedef map<string,pkgCache::VerIterator> VerMapValueType;
    typedef hash_map<unsigned long,VerMapValueType> VerMapType;
    typedef hash_map<const char*,int,
@@ -37,6 +38,7 @@ class RPMPackageData
    map<string,vector<string>*> FakeProvides;
    map<string,int> IgnorePackages;
    map<string,int> DuplicatedPackages;
+   map<string,int> MultiArchPackages;
    typedef map<string,pkgCache::VerIterator> VerMapValueType;
    typedef map<unsigned long,VerMapValueType> VerMapType;
    typedef map<const char*,int,cstr_lt_pred> ArchScoresType;
@@ -44,6 +46,7 @@ class RPMPackageData
 
    vector<regex_t*> HoldPackages;   
    vector<regex_t*> DuplicatedPatterns;
+   vector<regex_t*> MultiArchPatterns;
 
    struct Translate {
           regex_t Pattern;
@@ -110,6 +113,9 @@ class RPMPackageData
    void SetDupPackage(const string &Name)
        {DuplicatedPackages[Name] = 1;};
    bool IsDupPackage(const string &Name);
+   void SetMultiArchPackage(const string &Name)
+        {MultiArchPackages[Name] = 1;};
+   bool IsMultiArchPackage(const string &Name);
 
    static RPMPackageData *Singleton();
 
index 8308aab..dc6e695 100644 (file)
@@ -538,6 +538,7 @@ unsigned long rpmSystem::OptionsHash() const
    unsigned long Hash = 0;
    HashOption(Hash, "RPM::Architecture");
    HashOptionTree(Hash, "RPM::Allow-Duplicated");
+   HashOptionTree(Hash, "RPM::MultiArch");
    HashOptionTree(Hash, "RPM::Ignore");
    HashOptionFile(Hash, "Dir::Etc::rpmpriorities");
    HashEnv(Hash, "LANG");