- implement support for filelist and changelog viewing for repomd repositories
authorPanu Matilainen <pmatilai@turre.koti.laiskiainen.org>
Sun, 25 Feb 2007 20:56:44 +0000 (22:56 +0200)
committerPanu Matilainen <pmatilai@turre.koti.laiskiainen.org>
Sun, 25 Feb 2007 20:56:44 +0000 (22:56 +0200)
- searching for files from the full filelists.xml is impossibly slow due
  to various issues in upper levels of libapt-pkg, so we only support
  HasFile() from the "optimized" filelist stored in primary.xml

apt-pkg/rpm/rpmhandler.cc
apt-pkg/rpm/rpmhandler.h
apt-pkg/rpm/rpmindexfile.cc

index 8475ba0..07da21c 100644 (file)
@@ -933,7 +933,10 @@ void RPMDBHandler::Rewind()
 #ifdef APT_WITH_REPOMD
 RPMRepomdHandler::RPMRepomdHandler(string File)
 {
-   PrimaryFile = File;
+   PrimaryPath = File;
+   string DBBase = PrimaryPath.substr(0, File.size() - 11);
+   FilelistPath = DBBase + "filelists.xml";
+   OtherPath = DBBase + "other.xml";
 
    ID = File;
    Root = NULL;
@@ -944,11 +947,11 @@ RPMRepomdHandler::RPMRepomdHandler(string File)
 
    Primary = xmlReadFile(File.c_str(), NULL, XML_PARSE_NONET|XML_PARSE_NOBLANKS);
    if ((Root = xmlDocGetRootElement(Primary)) == NULL) {
-      _error->Error(_("Failed to open package index %s"), PrimaryFile.c_str());
+      _error->Error(_("Failed to open package index %s"), PrimaryPath.c_str());
       goto error;
    }
    if (xmlStrncmp(Root->name, (xmlChar*)"metadata", strlen("metadata")) != 0) {
-      _error->Error(_("Corrupted package index %s"), PrimaryFile.c_str());
+      _error->Error(_("Corrupted package index %s"), PrimaryPath.c_str());
       goto error;
    }
 
@@ -1248,7 +1251,26 @@ bool RPMRepomdHandler::PRCO(unsigned int Type, vector<Dependency*> &Deps)
    return true;
 }
 
-bool RPMRepomdHandler::FileList(vector<string> &FileList)
+// XXX HasFile() usage with repomd with full filelists is slower than
+// having the user manually look it up, literally. So we only support the 
+// more common files which are stored in primary.xml which supports fast
+// random access.
+bool RPMRepomdHandler::HasFile(const char *File)
+{
+   if (*File == '\0')
+      return false;
+   
+   vector<string> Files;
+   ShortFileList(Files);
+   for (vector<string>::iterator I = Files.begin(); I != Files.end(); I++) {
+      if (string(File) == (*I)) {
+        return true;
+      }
+   }
+   return false;
+}
+
+bool RPMRepomdHandler::ShortFileList(vector<string> &FileList)
 {
    xmlNode *format = FindNode("format");
    for (xmlNode *n = format->children; n; n = n->next) {
@@ -1260,89 +1282,107 @@ bool RPMRepomdHandler::FileList(vector<string> &FileList)
    return true;
 }
 
+bool RPMRepomdHandler::FileList(vector<string> &FileList)
+{
+   RPMRepomdFLHandler *FL = new RPMRepomdFLHandler(FilelistPath);
+   bool res = FL->Jump(iOffset);
+   res &= FL->FileList(FileList);
+   delete FL;
+   return res; 
+}
+
+bool RPMRepomdHandler::ChangeLog(vector<ChangeLogEntry* > &ChangeLogs)
+{
+   RPMRepomdOtherHandler *OL = new RPMRepomdOtherHandler(OtherPath);
+   bool res = OL->Jump(iOffset);
+   res &= OL->ChangeLog(ChangeLogs);
+   delete OL;
+   return res; 
+}
+
 RPMRepomdHandler::~RPMRepomdHandler()
 {
    xmlFreeDoc(Primary);
 }
 
-RPMRepomdFLHandler::RPMRepomdFLHandler(string File) : RPMHandler()
+RPMRepomdReaderHandler::RPMRepomdReaderHandler(string File) : RPMHandler()
 {
-   FilelistFile = File.substr(0, File.size() - 11) + "filelists.xml";
-
+   XmlPath = File;
    ID = File;
-   Filelist = NULL;
+   XmlFile = NULL;
    NodeP = NULL;
    iOffset = -1;
 
-   if (FileExists(FilelistFile)) {
-      Filelist = xmlReaderForFile(FilelistFile.c_str(), NULL,
+   if (FileExists(XmlPath)) {
+      XmlFile = xmlReaderForFile(XmlPath.c_str(), NULL,
                                   XML_PARSE_NONET|XML_PARSE_NOBLANKS);
-      if (Filelist == NULL) {
-        xmlFreeTextReader(Filelist);
-        _error->Error(_("Failed to open filelist index %s"), FilelistFile.c_str());
+      if (XmlFile == NULL) {
+        xmlFreeTextReader(XmlFile);
+        _error->Error(_("Failed to open filelist index %s"), XmlPath.c_str());
         goto error;
       }
 
-      // seek into first package in filelists.xml
-      int ret = xmlTextReaderRead(Filelist);
+      // seek into first package in xml
+      int ret = xmlTextReaderRead(XmlFile);
       if (ret == 1) {
-        xmlChar *pkgs = xmlTextReaderGetAttribute(Filelist, (xmlChar*)"packages");
+        xmlChar *pkgs = xmlTextReaderGetAttribute(XmlFile, (xmlChar*)"packages");
         iSize = atoi((char*)pkgs);
         xmlFree(pkgs);
       }
       while (ret == 1) {
-        if (xmlStrcmp(xmlTextReaderConstName(Filelist),
+        if (xmlStrcmp(xmlTextReaderConstName(XmlFile),
                      (xmlChar*)"package") == 0) {
            break;
         }
-        ret = xmlTextReaderRead(Filelist);
+        ret = xmlTextReaderRead(XmlFile);
       }
    }
    return;
 
 error:
-   if (Filelist) {
-       xmlFreeTextReader(Filelist);
+   if (XmlFile) {
+       xmlFreeTextReader(XmlFile);
    }
 }
 
-bool RPMRepomdFLHandler::Jump(off_t Offset)
+bool RPMRepomdReaderHandler::Jump(off_t Offset)
 {
-   //cerr << "RepomdFLHandler::Jump() called but not implemented!" << endl;
-   return false;
+   bool res = false;
+   while (iOffset != Offset) {
+      res = Skip();
+      if (res == false)
+        break;
+   }
+      
+   return res;
 }
 
-void RPMRepomdFLHandler::Rewind()
+void RPMRepomdReaderHandler::Rewind()
 {
-   //cerr << "RepomdFLHandler::Rewind() called but not implemented!" << endl;
+   // XXX Ignore rewinds when already at start, any other cases we can't
+   // handle at the moment. Other cases shouldn't be needed due to usage
+   // patterns but just in case...
+   if (iOffset != -1) {
+      _error->Error(_("Unable to handle xmlReader rewind from offset %d!"), 
+                     iOffset);
+   }
 }
 
-bool RPMRepomdFLHandler::Skip()
+bool RPMRepomdReaderHandler::Skip()
 {
    if (iOffset +1 >= iSize) {
       return false;
    }
    if (iOffset >= 0) {
-      xmlTextReaderNext(Filelist);
+      xmlTextReaderNext(XmlFile);
    }
-   NodeP = xmlTextReaderExpand(Filelist);
+   NodeP = xmlTextReaderExpand(XmlFile);
    iOffset++;
 
    return true;
 }
 
-bool RPMRepomdFLHandler::FileList(vector<string> &FileList)
-{
-   for (xmlNode *n = NodeP->children; n; n = n->next) {
-      if (xmlStrcmp(n->name, (xmlChar*)"file") != 0)  continue;
-      xmlChar *Filename = xmlNodeGetContent(n);
-      FileList.push_back(string((char*)Filename));
-      xmlFree(Filename);
-   }
-   return true;
-}
-
-string RPMRepomdFLHandler::FindTag(char *Tag)
+string RPMRepomdReaderHandler::FindTag(char *Tag)
 {
      string str = "";
      if (NodeP) {
@@ -1355,9 +1395,44 @@ string RPMRepomdFLHandler::FindTag(char *Tag)
      return str;
 }
 
-RPMRepomdFLHandler::~RPMRepomdFLHandler()
+RPMRepomdReaderHandler::~RPMRepomdReaderHandler()
+{
+   xmlFreeTextReader(XmlFile);
+}
+
+bool RPMRepomdFLHandler::FileList(vector<string> &FileList)
+{
+   for (xmlNode *n = NodeP->children; n; n = n->next) {
+      if (xmlStrcmp(n->name, (xmlChar*)"file") != 0)  continue;
+      xmlChar *Filename = xmlNodeGetContent(n);
+      FileList.push_back(string((char*)Filename));
+      xmlFree(Filename);
+   }
+   return true;
+}
+
+bool RPMRepomdOtherHandler::ChangeLog(vector<ChangeLogEntry* > &ChangeLogs)
 {
-   xmlFreeTextReader(Filelist);
+   // Changelogs aren't necessarily available at all
+   if (! XmlFile) {
+      return false;
+   }
+
+   for (xmlNode *n = NodeP->children; n; n = n->next) {
+      if (xmlStrcmp(n->name, (xmlChar*)"changelog") != 0)  continue;
+      ChangeLogEntry *Entry = new ChangeLogEntry;
+      xmlChar *Text = xmlNodeGetContent(n);
+      xmlChar *Time = xmlGetProp(n, (xmlChar*)"date");
+      xmlChar *Author = xmlGetProp(n, (xmlChar*)"author");
+      Entry->Text = string((char*)Text);
+      Entry->Time = atoi((char*)Time);
+      Entry->Author = string((char*)Author);
+      ChangeLogs.push_back(Entry);
+      xmlFree(Text);
+      xmlFree(Time);
+      xmlFree(Author);
+   }
+   return true;
 }
 
 RPMSqliteHandler::RPMSqliteHandler(string File) : 
index d02510a..f373950 100644 (file)
@@ -276,7 +276,9 @@ class RPMRepomdHandler : public RPMHandler
    vector<xmlNode *> Pkgs;
    vector<xmlNode *>::iterator PkgIter;
 
-   string PrimaryFile;
+   string PrimaryPath;
+   string FilelistPath;
+   string OtherPath;
 
    xmlNode *FindNode(const string Name);
    xmlNode *FindNode(xmlNode *Node, const string Name);
@@ -312,18 +314,22 @@ class RPMRepomdHandler : public RPMHandler
    virtual string Description() {return FindTag(NodeP, "description");};
    virtual string SourceRpm();
 
+   virtual bool HasFile(const char *File);
+   virtual bool ShortFileList(vector<string> &FileList);
+
    virtual bool PRCO(unsigned int Type, vector<Dependency*> &Deps);
    virtual bool FileList(vector<string> &FileList);
+   virtual bool ChangeLog(vector<ChangeLogEntry* > &ChangeLogs);
 
    RPMRepomdHandler(string File);
    virtual ~RPMRepomdHandler();
 };
 
-class RPMRepomdFLHandler : public RPMHandler
+class RPMRepomdReaderHandler : public RPMHandler
 {
    protected:
-   xmlTextReaderPtr Filelist;
-   string FilelistFile;
+   xmlTextReaderPtr XmlFile;
+   string XmlPath;
    xmlNode *NodeP;
 
    string FindTag(char *Tag);
@@ -334,7 +340,7 @@ class RPMRepomdFLHandler : public RPMHandler
    virtual void Rewind();
    virtual bool IsDatabase() {return false;};
 
-   virtual string FileName() {return FilelistFile;};
+   virtual string FileName() {return XmlPath;};
    virtual string Directory() {return "";};
    virtual unsigned long FileSize() {return 0;};
    virtual unsigned long InstalledSize() {return 0;};
@@ -356,9 +362,25 @@ class RPMRepomdFLHandler : public RPMHandler
    virtual bool PRCO(unsigned int Type, vector<Dependency*> &Deps)
        {return true;};
 
+   virtual bool FileList(vector<string> &FileList) {return true;};
+   RPMRepomdReaderHandler(string File);
+   virtual ~RPMRepomdReaderHandler();
+};
+
+class RPMRepomdFLHandler : public RPMRepomdReaderHandler
+{
+   public:
    virtual bool FileList(vector<string> &FileList);
-   RPMRepomdFLHandler(string File);
-   virtual ~RPMRepomdFLHandler();
+   RPMRepomdFLHandler(string File) : RPMRepomdReaderHandler(File) {};
+   virtual ~RPMRepomdFLHandler() {};
+};
+
+class RPMRepomdOtherHandler : public RPMRepomdReaderHandler
+{
+   public:
+   virtual bool ChangeLog(vector<ChangeLogEntry* > &ChangeLogs);
+   RPMRepomdOtherHandler(string File) : RPMRepomdReaderHandler(File) {};
+   virtual ~RPMRepomdOtherHandler() {};
 };
 
 class RPMSqliteHandler : public RPMHandler
index 2565f96..68d62d8 100644 (file)
@@ -659,6 +659,10 @@ bool rpmRepomdIndex::GetIndexes(pkgAcquire *Owner) const
                   Info("primary.xml"), "primary.xml");
    new pkgAcqIndex(Owner,Repository,IndexURI("filelists"),
                   Info("filelists.xml"), "filelists.xml");
+   if (_config->FindB("Acquire::ChangeLogs", false)) {
+      new pkgAcqIndex(Owner,Repository,IndexURI("other"),
+                    Info("other.xml"), "other.xml");
+   }
    return true;
 }
 
@@ -765,7 +769,7 @@ bool rpmRepomdIndex::MergeFileProvides(pkgCacheGenerator &Gen,
                                        OpProgress &Prog) const
 {
    string PackageFile = IndexPath();
-   RPMHandler *Handler = new RPMRepomdFLHandler(IndexPath());
+   RPMHandler *Handler = new RPMRepomdFLHandler(IndexFile("filelists"));
    rpmListParser Parser(Handler);
    if (_error->PendingError() == true) {
       delete Handler;