- resurrect source operations for repomd repositories
[apt.git] / apt-pkg / rpm / rpmindexfile.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description                                                          /*{{{*/
3 // $Id: rpmindexfile.cc,v 1.4 2002/11/27 16:22:40 niemeyer Exp $
4 /* ######################################################################
5
6    RPM Specific sources.list types and the three sorts of RPM
7    index files.
8    
9    ##################################################################### */
10                                                                         /*}}}*/
11 // Include Files                                                        /*{{{*/
12 #ifdef __GNUG__
13 #pragma implementation "apt-pkg/rpmindexfile.h"
14 #endif
15
16 #include <config.h>
17
18 #ifdef HAVE_RPM
19
20 #include <apt-pkg/rpmindexfile.h>
21 #include <apt-pkg/rpmsrcrecords.h>
22 #include <apt-pkg/rpmlistparser.h>
23 #include <apt-pkg/rpmrecords.h>
24 #include <apt-pkg/rpmsystem.h>
25 #include <apt-pkg/rpmhandler.h>
26 #include <apt-pkg/rpmpackagedata.h>
27 #include <apt-pkg/sourcelist.h>
28 #include <apt-pkg/configuration.h>
29 #include <apt-pkg/progress.h>
30 #include <apt-pkg/error.h>
31 #include <apt-pkg/strutl.h>
32 #include <apt-pkg/acquire-item.h>
33 #include <apt-pkg/repomd.h>
34
35 #include <apti18n.h>
36
37 #include <sys/stat.h>
38                                                                         /*}}}*/
39 vector<pkgRepository *> RepList;
40
41 // rpmListIndex::Release* - Return the URI to the release file          /*{{{*/
42 // ---------------------------------------------------------------------
43 /* */
44 inline string rpmListIndex::ReleaseFile(string Type) const
45 {
46    return URItoFileName(ReleaseURI(Type));
47 }
48
49 string rpmListIndex::ReleaseURI(string Type) const
50 {
51    RPMPackageData *rpmdata = RPMPackageData::Singleton();
52    string Res;
53    if (Dist[Dist.size() - 1] == '/')
54    {
55       if (Dist != "/")
56          Res = URI + Dist;
57       else
58          Res = URI;
59    }
60    else
61       Res = URI + Dist + "/base/";
62
63    Res += Type;
64    
65    if (rpmdata->HasIndexTranslation() == true)
66    {
67       map<string,string> Dict;
68       Dict["uri"] = URI;
69       Dict["dist"] = Dist;
70       Dict["sect"] = "";
71       Dict["type"] = Type;
72       rpmdata->TranslateIndex(Res, Dict);
73    }
74
75    return Res;
76 }
77                                                                         /*}}}*/
78 // rpmListIndex::ReleaseInfo - One liner describing the index URI       /*{{{*/
79 // ---------------------------------------------------------------------
80 /* */
81 string rpmListIndex::ReleaseInfo(string Type) const 
82 {
83    string Info = ::URI::SiteOnly(URI) + ' ';
84    if (Dist[Dist.size() - 1] == '/')
85    {
86       if (Dist != "/")
87          Info += Dist;
88    }
89    else
90       Info += Dist;   
91    Info += " ";
92    Info += Type;
93    return Info;
94 }
95                                                                         /*}}}*/
96 // rpmListIndex::GetReleases - Fetch the index files                    /*{{{*/
97 // ---------------------------------------------------------------------
98 /* */
99 bool rpmListIndex::GetReleases(pkgAcquire *Owner) const
100 {
101    if (!Repository->Acquire)
102       return true;
103    Repository->Acquire = false;
104    new pkgAcqIndexRel(Owner,Repository,ReleaseURI("release"),
105                       ReleaseInfo("release"), "release", true);
106    return true;
107 }
108                                                                         /*}}}*/
109 // rpmListIndex::Info - One liner describing the index URI              /*{{{*/
110 // ---------------------------------------------------------------------
111 /* */
112 string rpmListIndex::Info(string Type) const 
113 {
114    string Info = ::URI::SiteOnly(URI) + ' ';
115    if (Dist[Dist.size() - 1] == '/')
116    {
117       if (Dist != "/")
118          Info += Dist;
119    }
120    else
121       Info += Dist + '/' + Section;   
122    Info += " ";
123    Info += Type;
124    return Info;
125 }
126                                                                         /*}}}*/
127 // rpmListIndex::Index* - Return the URI to the index files             /*{{{*/
128 // ---------------------------------------------------------------------
129 /* */
130 inline string rpmListIndex::IndexFile(string Type) const
131 {
132    return _config->FindDir("Dir::State::lists")+URItoFileName(IndexURI(Type));
133 }
134
135
136 string rpmListIndex::IndexURI(string Type) const
137 {
138    RPMPackageData *rpmdata = RPMPackageData::Singleton();
139    string Res;
140    if (Dist[Dist.size() - 1] == '/')
141    {
142       if (Dist != "/")
143          Res = URI + Dist;
144       else 
145          Res = URI;
146    }
147    else
148       Res = URI + Dist + "/base/";
149    
150    Res += Type + '.' + Section;
151
152    if (rpmdata->HasIndexTranslation() == true)
153    {
154       map<string,string> Dict;
155       Dict["uri"] = URI;
156       Dict["dist"] = Dist; 
157       Dict["sect"] = Section;
158       Dict["type"] = Type;
159       rpmdata->TranslateIndex(Res, Dict);
160    }
161
162    return Res;
163 }
164                                                                         /*}}}*/
165 // rpmListIndex::Exists - Check if the index is available               /*{{{*/
166 // ---------------------------------------------------------------------
167 /* */
168 bool rpmListIndex::Exists() const
169 {
170    return FileExists(IndexPath());
171 }
172                                                                         /*}}}*/
173 // rpmListIndex::Size - Return the size of the index                    /*{{{*/
174 // ---------------------------------------------------------------------
175 /* */
176 unsigned long rpmListIndex::Size() const
177 {
178    struct stat S;
179    if (stat(IndexPath().c_str(),&S) != 0)
180       return 0;
181    return S.st_size;
182 }
183                                                                         /*}}}*/
184 // rpmListIndex::Describe - Give a descriptive path to the index        /*{{{*/
185 // ---------------------------------------------------------------------
186 /* */
187 string rpmListIndex::Describe(bool Short) const
188 {
189    char S[300];
190    if (Short == true)
191       snprintf(S,sizeof(S),"%s",Info(MainType()).c_str());
192    else
193       snprintf(S,sizeof(S),"%s (%s)",Info(MainType()).c_str(),
194          IndexFile(MainType()).c_str());
195    return S;
196 }
197                                                                         /*}}}*/
198
199 // SrcListIndex::SourceInfo - Short 1 liner describing a source         /*{{{*/
200 // ---------------------------------------------------------------------
201 string rpmSrcListIndex::SourceInfo(pkgSrcRecords::Parser const &Record,
202                                    pkgSrcRecords::File const &File) const
203 {
204    string Res;
205    Res = ::URI::SiteOnly(URI) + ' ';
206    if (Dist[Dist.size() - 1] == '/')
207    {
208       if (Dist != "/")
209          Res += Dist;
210    }      
211    else
212       Res += Dist + '/' + Section;
213    
214    Res += " ";
215    Res += Record.Package();
216    Res += " ";
217    Res += Record.Version();
218    if (File.Type.empty() == false)
219       Res += " (" + File.Type + ")";
220    return Res;
221 }
222                                                                         /*}}}*/
223 // SrcListIndex::ArchiveURI - URI for the archive                       /*{{{*/
224 // ---------------------------------------------------------------------
225 string rpmSrcListIndex::ArchiveURI(string File) const
226 {
227    RPMPackageData *rpmdata = RPMPackageData::Singleton();
228    string Res;
229    
230    if (Dist[Dist.size() - 1] == '/')
231    {
232       if (Dist != "/")
233          Res = URI + Dist;
234       else
235          Res = URI;
236    }
237    else
238       Res = URI + Dist;
239    
240    if (File.find("/") != string::npos)
241       Res += '/' + File;
242    else
243       Res += "/SRPMS."+Section + '/' + File;
244
245    if (rpmdata->HasSourceTranslation() == true)
246    {
247       map<string,string> Dict;
248       Dict["uri"] = URI;
249       Dict["dist"] = Dist; 
250       Dict["sect"] = Section;
251       string::size_type pos = File.rfind("/");
252       if (pos != string::npos)
253          Dict["file"] = string(File, pos+1);
254       else
255          Dict["file"] = File;
256       
257       rpmdata->TranslateSource(Res, Dict);
258    }
259          
260    return Res;
261 }
262                                                                         /*}}}*/
263 // SrcListIndex::CreateSrcParser - Get a parser for the source files    /*{{{*/
264 // ---------------------------------------------------------------------
265 /* */
266 pkgSrcRecords::Parser *rpmSrcListIndex::CreateSrcParser() const
267 {
268    return new rpmSrcRecordParser(IndexPath(), this);
269 }
270                                                                         /*}}}*/
271 // SrcListIndex::GetIndexes - Fetch the index files                     /*{{{*/
272 // ---------------------------------------------------------------------
273 /* */
274 bool rpmSrcListIndex::GetIndexes(pkgAcquire *Owner) const
275 {
276    // Ignore indexes for repositories that could not be authenticated
277    if (Repository->IsAuthenticated() == true && 
278        Repository->HasRelease() == false)
279       return true;
280    new pkgAcqIndex(Owner,Repository,IndexURI("srclist"),Info("srclist"),
281                    "srclist");
282    return true;
283 }
284                                                                         /*}}}*/
285
286 // PkgListIndex::ArchiveInfo - Short version of the archive url         /*{{{*/
287 // ---------------------------------------------------------------------
288 /* This is a shorter version that is designed to be < 60 chars or so */
289 string rpmPkgListIndex::ArchiveInfo(pkgCache::VerIterator Ver) const
290 {
291    string Res = ::URI::SiteOnly(URI) + ' ';
292    if (Dist[Dist.size() - 1] == '/')
293    {
294       if (Dist != "/")
295          Res += Dist;
296    }
297    else
298       Res += Dist + '/' + Section;
299    
300    Res += " ";
301    Res += Ver.ParentPkg().Name();
302    Res += " ";
303    Res += Ver.VerStr();
304    return Res;
305 }
306                                                                         /*}}}*/
307 // PkgListIndex::ArchiveURI - URI for the archive                       /*{{{*/
308 // ---------------------------------------------------------------------
309 string rpmPkgListIndex::ArchiveURI(string File) const
310 {
311    RPMPackageData *rpmdata = RPMPackageData::Singleton();
312    string Res;
313    if (Dist[Dist.size() - 1] == '/')
314    {
315       if (Dist != "/")
316          Res = URI + Dist;
317       else
318          Res = URI;
319    }
320    else
321       Res = URI + Dist;
322
323    if (File.find("/") != string::npos)
324       Res += '/' + File;
325    else
326       Res += "/RPMS." + Section + '/' + File;
327
328    if (rpmdata->HasBinaryTranslation() == true)
329    {
330       map<string,string> Dict;
331       Dict["uri"] = URI;
332       Dict["dist"] = Dist; 
333       Dict["sect"] = Section;
334       string::size_type pos = File.rfind("/");
335       if (pos != string::npos)
336          Dict["file"] = string(File, pos+1);
337       else
338          Dict["file"] = File;
339       rpmdata->TranslateBinary(Res, Dict);
340    }
341          
342    return Res;
343 }
344                                                                         /*}}}*/
345 // PkgListIndex::GetIndexes - Fetch the index files                     /*{{{*/
346 // ---------------------------------------------------------------------
347 /* */
348 bool rpmPkgListIndex::GetIndexes(pkgAcquire *Owner) const
349 {
350    // Ignore indexes for repositories that could not be authenticated
351    if (Repository->IsAuthenticated() == true && 
352        Repository->HasRelease() == false)
353       return true;
354    new pkgAcqIndex(Owner,Repository,IndexURI("pkglist"),Info("pkglist"),
355                    "pkglist");
356    new pkgAcqIndexRel(Owner,Repository,IndexURI("release"),Info("release"),
357                       "release");
358    return true;
359 }
360                                                                         /*}}}*/
361 // PkgListIndex::Merge - Load the index file into a cache               /*{{{*/
362 // ---------------------------------------------------------------------
363 /* */
364 bool rpmPkgListIndex::Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const
365 {
366    string PackageFile = IndexPath();
367    RPMHandler *Handler = CreateHandler();
368
369    Prog.SubProgress(0,Info(MainType()));
370    ::URI Tmp(URI);
371    if (Gen.SelectFile(PackageFile,Tmp.Host,*this) == false)
372    {
373       delete Handler;
374       return _error->Error(_("Problem with SelectFile %s"),PackageFile.c_str());
375    }
376
377    // Store the IMS information
378    pkgCache::PkgFileIterator File = Gen.GetCurFile();
379    struct stat St;
380    if (stat(PackageFile.c_str(),&St) != 0) 
381    {
382       delete Handler;
383       return _error->Errno("stat",_("Failed to stat %s"), PackageFile.c_str());
384    }
385    File->Size = St.st_size;
386    File->mtime = St.st_mtime;
387    
388    rpmListParser Parser(Handler);
389    if (_error->PendingError() == true) 
390    {
391       delete Handler;
392       return _error->Error(_("Problem opening %s"),PackageFile.c_str());
393    }
394    
395    if (Gen.MergeList(Parser) == false)
396    {
397       delete Handler;
398       return _error->Error(_("Problem with MergeList %s"),PackageFile.c_str());
399    }
400    
401    delete Handler;
402
403    // Check the release file
404    string RelFile = ReleasePath();
405    if (FileExists(RelFile) == true)
406    {
407       FileFd Rel(RelFile,FileFd::ReadOnly);
408       if (_error->PendingError() == true)
409          return false;
410       Parser.LoadReleaseInfo(File,Rel);
411       Rel.Seek(0);
412    }
413
414    return true;
415 }
416                                                                         /*}}}*/
417 // PkgListIndex::MergeFileProvides - Process file dependencies if any   /*{{{*/
418 // ---------------------------------------------------------------------
419 /* */
420 bool rpmPkgListIndex::MergeFileProvides(pkgCacheGenerator &Gen,
421                                         OpProgress &Prog) const
422 {
423    string PackageFile = IndexPath();
424    RPMHandler *Handler = CreateHandler();
425    rpmListParser Parser(Handler);
426    if (_error->PendingError() == true) {
427       delete Handler;
428       return _error->Error(_("Problem opening %s"),PackageFile.c_str());
429    }
430    // We call SubProgress with Size(), since we won't call SelectFile() here.
431    Prog.SubProgress(Size(),Info("pkglist"));
432    if (Gen.MergeFileProvides(Parser) == false)
433       return _error->Error(_("Problem with MergeFileProvides %s"),
434                            PackageFile.c_str());
435    delete Handler;
436    return true;
437 }
438                                                                         /*}}}*/
439 // PkgListIndex::FindInCache - Find this index                          /*{{{*/
440 // ---------------------------------------------------------------------
441 /* */
442 pkgCache::PkgFileIterator rpmPkgListIndex::FindInCache(pkgCache &Cache) const
443 {
444    string FileName = IndexPath();
445    pkgCache::PkgFileIterator File = Cache.FileBegin();
446    for (; File.end() == false; File++)
447    {
448       if (FileName != File.FileName())
449          continue;
450       
451       struct stat St;
452       if (stat(File.FileName(),&St) != 0)
453          return pkgCache::PkgFileIterator(Cache);
454
455       if ((unsigned)St.st_size != File->Size || St.st_mtime != File->mtime)
456          return pkgCache::PkgFileIterator(Cache);
457       return File;
458    }
459    
460    return File;
461 }
462                                                                         /*}}}*/
463
464 // PkgDirIndex::Index* - Return the URI to the index files              /*{{{*/
465 // ---------------------------------------------------------------------
466 /* */
467 string rpmPkgDirIndex::IndexPath() const
468 {
469    return ::URI(ArchiveURI("")).Path;
470 }
471                                                                         /*}}}*/
472 // PkgDirIndex::Release* - Return the URI to the index files            /*{{{*/
473 // ---------------------------------------------------------------------
474 /* */
475 string rpmPkgDirIndex::ReleasePath() const
476 {
477    return ::URI(IndexURI("release")).Path;
478 }
479                                                                         /*}}}*/
480 // PkgDirIndex::Size - Return the size of the index                     /*{{{*/
481 // ---------------------------------------------------------------------
482 /* This is really only used for progress reporting. */
483 unsigned long rpmPkgDirIndex::Size() const
484 {
485    // XXX: Must optimize this somehow.
486    RPMHandler *Handler = CreateHandler();
487    unsigned long Res = Handler->Size();
488    delete Handler;
489    return Res;
490 }
491                                                                         /*}}}*/
492
493 // SrcDirIndex::Index* - Return the URI to the index files              /*{{{*/
494 // ---------------------------------------------------------------------
495 /* */
496 string rpmSrcDirIndex::IndexPath() const
497 {
498    return ::URI(ArchiveURI("")).Path;
499 }
500                                                                         /*}}}*/
501 // SrcDirIndex::Size - Return the size of the index                     /*{{{*/
502 // ---------------------------------------------------------------------
503 /* This is really only used for progress reporting. */
504 unsigned long rpmSrcDirIndex::Size() const
505 {
506    // XXX: Must optimize this somehow.
507    RPMHandler *Handler = CreateHandler();
508    unsigned long Res = Handler->Size();
509    delete Handler;
510    return Res;
511 }
512
513 // SinglePkgIndex::ArchiveURI - URI for the archive                     /*{{{*/
514 // ---------------------------------------------------------------------
515 string rpmSinglePkgIndex::ArchiveURI(string File) const
516 {
517    char *cwd = getcwd(NULL,0);
518    if (File[0] == '.' && File[1] == '/')
519       File = string(File, 2);
520    string URI = "file://"+flCombine(cwd, File);
521    free(cwd);
522    return URI;
523 }
524                                                                         /*}}}*/
525 // SinglePkgIndex::ArchiveURI - URI for the archive                     /*{{{*/
526 // ---------------------------------------------------------------------
527 string rpmSingleSrcIndex::ArchiveURI(string File) const
528 {
529    char *cwd = getcwd(NULL,0);
530    if (File[0] == '.' && File[1] == '/')
531       File = string(File, 2);
532    string URI = "file://"+flCombine(cwd, File);
533    free(cwd);
534    return URI;
535 }
536
537 string rpmRepomdIndex::ArchiveURI(string File) const
538 {
539    string Res;
540
541    //cout << Dist << File << endl;
542
543    Res += URI + '/' + Dist + '/' + File;
544    //cout << "repomd archiveuri " << " " << Res << endl;
545
546    return Res;
547 }
548
549 string rpmRepomdIndex::ArchiveInfo(pkgCache::VerIterator Ver) const
550 {
551    string Res = ::URI::SiteOnly(URI) + ' ';
552    if (Dist[Dist.size() - 1] == '/')
553    {
554       if (Dist != "/")
555          Res += Dist;
556    }
557    else
558       Res += Dist + '/';
559    
560    Res += " ";
561    Res += Ver.ParentPkg().Name();
562    Res += " ";
563    Res += Ver.VerStr();
564    return Res;
565 }
566 pkgCache::PkgFileIterator rpmRepomdIndex::FindInCache(pkgCache &Cache) const
567 {
568    string FileName = IndexPath();
569    pkgCache::PkgFileIterator File = Cache.FileBegin();
570    for (; File.end() == false; File++)
571    {
572       if (FileName != File.FileName())
573          continue;
574       
575       struct stat St;
576       if (stat(File.FileName(),&St) != 0)
577          return pkgCache::PkgFileIterator(Cache);
578
579       if ((unsigned)St.st_size != File->Size || St.st_mtime != File->mtime)
580          return pkgCache::PkgFileIterator(Cache);
581       return File;
582    }
583    
584    return File;
585 }
586 string rpmRepomdIndex::ReleaseURI(string Type) const
587 {
588    string Res;
589    Res = URI + Dist + "/repodata/" + "repomd.xml";
590
591    //cout << "XXXXX repomd releaseuri " << Res << endl;
592    
593    return Res;
594 }
595
596 string rpmRepomdIndex::ReleaseInfo(string Type) const
597 {
598    string Info = ::URI::SiteOnly(URI) + ' ';
599    if (Dist[Dist.size() - 1] == '/')
600    {
601       if (Dist != "/")
602          Info += Dist;
603    }
604    else
605       Info += Dist;   
606    Info += " ";
607    Info += Type;
608    //cout << "repomd releaseinfo " << Info << endl;
609    return Info;
610 };
611
612 string rpmRepomdIndex::Info(string Type) const 
613 {
614    string Info = ::URI::SiteOnly(URI) + ' ';
615    if (Dist[Dist.size() - 1] == '/')
616    {
617       if (Dist != "/")
618          Info += Dist;
619    }
620    else
621       Info += Dist + '/' ;   
622    Info += " ";
623    Info += Type;
624    //cout << "repomd info " << Info << endl;
625    return Info;
626 }
627
628 string rpmRepomdIndex::IndexURI(string Type) const
629 {
630    string Res = URI + Dist;
631    if (Dist[Dist.size() - 1] != '/') {
632          Res += "/";
633    }
634    // When called with the main type it's primary.xml we want, at other
635    // times it could be eg filelists.xml
636    if (Type == "repomd" || Type == "repomd-src")
637       Res += "repodata/primary.xml";
638    else
639       Res += "repodata/" + Type;
640    return Res;
641 }
642                                                                         /*}}}*/
643 bool rpmRepomdIndex::GetReleases(pkgAcquire *Owner) const
644 {
645    if (!Repository->Acquire)
646       return true;
647    Repository->Acquire = false;
648    // ignore for now - we need to parse the file for checksum and 
649    // optimally for location of other xml files as well
650    new pkgAcqIndexRel(Owner,Repository,ReleaseURI("repomd.xml"),
651                       ReleaseInfo("repomd.xml"), "repomd.xml", true);
652    return true;
653 }
654
655 bool rpmRepomdIndex::GetIndexes(pkgAcquire *Owner) const
656 {
657    new pkgAcqIndex(Owner,Repository,IndexURI("primary.xml"),
658                    Info("primary.xml"), "primary.xml");
659    new pkgAcqIndex(Owner,Repository,IndexURI("filelists.xml"),
660                    Info("filelists.xml"), "filelists.xml");
661 #if 0
662    new pkgAcqIndex(Owner,Repository,IndexURI("other.xml"),
663                    Info("other.xml"), "other.xml");
664 #endif
665    return true;
666 }
667
668 string rpmRepomdIndex::Describe(bool Short) const
669 {
670    char S[300];
671    if (Short == true)
672       snprintf(S,sizeof(S),"%s",Info(MainType()).c_str());
673    else
674       snprintf(S,sizeof(S),"%s (%s)",Info(MainType()).c_str(),
675          IndexFile(MainType()).c_str());
676    return S;
677 }
678
679 string rpmRepomdIndex::IndexFile(string Type) const
680 {
681    return _config->FindDir("Dir::State::lists")+URItoFileName(IndexURI(Type));
682 };
683
684
685 bool rpmRepomdIndex::Exists() const
686 {
687    return FileExists(IndexPath());
688 }
689
690 string rpmRepomdIndex::ReleasePath() const
691 {
692    return _config->FindDir("Dir::State::lists")+URItoFileName(ReleaseURI("release.xml"));
693 }
694
695 unsigned long rpmRepomdIndex::Size() const
696 {
697    // ugh.. all this just to get the package count ;(
698    RPMHandler *Handler = CreateHandler();
699    unsigned long Res = Handler->Size();
700    delete Handler;
701    return Res;
702 }
703
704 bool rpmRepomdIndex::Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const
705 {
706    //cout << "repomd MERGE" << endl;
707    string PackageFile = IndexPath();
708    RPMHandler *Handler = CreateHandler();
709
710    Prog.SubProgress(0,Info(MainType()));
711    ::URI Tmp(URI);
712    if (Gen.SelectFile(PackageFile,Tmp.Host,*this) == false)
713    {
714       delete Handler;
715       return _error->Error(_("Problem with SelectFile %s"),PackageFile.c_str());
716    }
717
718    // Store the IMS information
719    pkgCache::PkgFileIterator File = Gen.GetCurFile();
720    //cout << "merge pkgfile " << PackageFile << endl;
721    struct stat St;
722    if (stat(PackageFile.c_str(),&St) != 0) 
723    {
724       delete Handler;
725       return _error->Errno("stat",_("Failed to stat %s"), PackageFile.c_str());
726    }
727    File->Size = St.st_size;
728    File->mtime = St.st_mtime;
729    
730    rpmRepomdParser Parser(Handler);
731    if (_error->PendingError() == true) 
732    {
733       delete Handler;
734       return _error->Error(_("Problem opening %s"),PackageFile.c_str());
735    }
736    
737    if (Gen.MergeList(Parser) == false)
738    {
739       delete Handler;
740       return _error->Error(_("Problem with MergeList %s"),PackageFile.c_str());
741    }
742    
743    delete Handler;
744
745    // Check the release file
746    string RelFile = ReleasePath();
747    if (FileExists(RelFile) == true)
748    {
749       Parser.LoadReleaseInfo(File,RelFile);
750    }
751
752    return true;
753 }
754
755 bool rpmRepomdIndex::MergeFileProvides(pkgCacheGenerator &Gen,
756                                         OpProgress &Prog) const
757 {
758    string PackageFile = IndexPath();
759    RPMHandler *Handler = CreateHandler();
760    rpmListParser Parser(Handler);
761    if (_error->PendingError() == true) {
762       delete Handler;
763       return _error->Error(_("Problem opening %s"),PackageFile.c_str());
764    }
765    // We call SubProgress with Size(), since we won't call SelectFile() here.
766    Prog.SubProgress(Size(),Info("pkglist"));
767    if (Gen.MergeFileProvides(Parser) == false)
768       return _error->Error(_("Problem with MergeFileProvides %s"),
769                            PackageFile.c_str());
770    delete Handler;
771    return true;
772 }
773
774 pkgSrcRecords::Parser *rpmRepomdSrcIndex::CreateSrcParser() const
775 {
776    return new rpmSrcRecordParser(IndexPath(), this);
777 }
778
779 string rpmRepomdSrcIndex::SourceInfo(pkgSrcRecords::Parser const &Record,
780                                      pkgSrcRecords::File const &File) const
781 {
782    string Res;
783    Res = ::URI::SiteOnly(URI) + ' ';
784    if (Dist[Dist.size() - 1] == '/')
785    {
786       if (Dist != "/")
787          Res += Dist;
788    }      
789    else
790       Res += Dist + '/' + Section;
791    
792    Res += " ";
793    Res += Record.Package();
794    Res += " ";
795    Res += Record.Version();
796    if (File.Type.empty() == false)
797       Res += " (" + File.Type + ")";
798    return Res;
799 }
800
801 // DatabaseIndex::rpmDatabaseIndex - Constructor                        /*{{{*/
802 // ---------------------------------------------------------------------
803 /* */
804 rpmDatabaseIndex::rpmDatabaseIndex()
805 {
806 }
807                                                                         /*}}}*/
808 // DatabaseIndex::Size - Return the size of the index                   /*{{{*/
809 // ---------------------------------------------------------------------
810 /* */
811 unsigned long rpmDatabaseIndex::Size() const
812 {
813    return rpmSys.GetDBHandler()->Size();
814 }
815                                                                         /*}}}*/
816 // DatabaseIndex::CreateHandler - Create a RPMHandler for this file     /*{{{*/
817 // ---------------------------------------------------------------------
818 RPMHandler *rpmDatabaseIndex::CreateHandler() const
819 {
820    return rpmSys.GetDBHandler();
821 }
822                                                                         /*}}}*/
823 // DatabaseIndex::Merge - Load the index file into a cache              /*{{{*/
824 // ---------------------------------------------------------------------
825 /* */
826 bool rpmDatabaseIndex::Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const
827 {
828    RPMDBHandler *Handler = rpmSys.GetDBHandler();
829    rpmListParser Parser(Handler);
830    if (_error->PendingError() == true)
831       return _error->Error(_("Problem opening RPM database"));
832    
833    Prog.SubProgress(0,"RPM Database");
834    if (Gen.SelectFile(Handler->DataPath(false),string(),*this,pkgCache::Flag::NotSource) == false)
835       return _error->Error(_("Problem with SelectFile RPM Database"));
836
837    // Store the IMS information
838    pkgCache::PkgFileIterator CFile = Gen.GetCurFile();
839    struct stat St;
840    if (stat(Handler->DataPath(false).c_str(),&St) != 0)
841       return _error->Errno("fstat",_("Failed to stat %s"), Handler->DataPath(false).c_str());
842    CFile->Size = St.st_size;
843    CFile->mtime = Handler->Mtime();
844    
845    if (Gen.MergeList(Parser) == false)
846       return _error->Error(_("Problem with MergeList %s"),
847                            Handler->DataPath(false).c_str());
848    return true;
849 }
850                                                                         /*}}}*/
851 // DatabaseIndex::MergeFileProvides - Process file dependencies if any  /*{{{*/
852 // ---------------------------------------------------------------------
853 /* */
854 bool rpmDatabaseIndex::MergeFileProvides(pkgCacheGenerator &Gen,
855                                          OpProgress &Prog) const
856 {
857    RPMDBHandler *Handler = rpmSys.GetDBHandler();
858    rpmListParser Parser(Handler);
859    if (_error->PendingError() == true)
860       return _error->Error(_("Problem opening RPM database"));
861    // We call SubProgress with Size(), since we won't call SelectFile() here.
862    Prog.SubProgress(Size(),"RPM Database");
863    if (Gen.MergeFileProvides(Parser) == false)
864       return _error->Error(_("Problem with MergeFileProvides %s"),
865                            Handler->DataPath(false).c_str());
866    return true;
867 }
868                                                                         /*}}}*/
869 // DatabaseIndex::FindInCache - Find this index                         /*{{{*/
870 // ---------------------------------------------------------------------
871 /* */
872 pkgCache::PkgFileIterator rpmDatabaseIndex::FindInCache(pkgCache &Cache) const
873 {
874    pkgCache::PkgFileIterator File = Cache.FileBegin();
875    for (; File.end() == false; File++)
876    {
877       if (rpmSys.GetDBHandler()->DataPath(false) != File.FileName())
878          continue;
879       struct stat St;
880       if (stat(File.FileName(),&St) != 0)
881          return pkgCache::PkgFileIterator(Cache);
882       if ((unsigned)St.st_size != File->Size || St.st_mtime != File->mtime)
883          return pkgCache::PkgFileIterator(Cache);
884       return File;
885    }   
886    return File;
887 }
888                                                                         /*}}}*/
889
890 // Source List types for rpm                                            /*{{{*/
891
892 class rpmSLTypeGen : public pkgSourceList::Type
893 {
894    public:
895
896    rpmSLTypeGen()
897    {
898       Name = "rpm";
899       Label = "Standard RPM source tree";
900    }   
901
902    pkgRepository *FindRepository(string URI,string Dist,
903                                  const pkgSourceList::Vendor *Vendor) const
904    {
905       for (vector<pkgRepository *>::const_iterator iter = RepList.begin();
906            iter != RepList.end(); iter++) 
907       {
908          if ((*iter)->URI == URI && (*iter)->Dist == Dist) 
909          {       
910             if (Vendor != NULL)
911                (*iter)->FingerPrint = Vendor->FingerPrint;
912             return *iter;
913          }
914       }
915       return NULL;
916    }
917
918    pkgRepository *GetRepository(string URI,string Dist,
919                                 const pkgSourceList::Vendor *Vendor) const
920    {
921       pkgRepository *Rep = FindRepository(URI,Dist,Vendor);
922       if (Rep != NULL)
923          return Rep;
924
925       string BaseURI;
926       if (Dist[Dist.size() - 1] == '/')
927       {
928          if (Dist != "/")
929             BaseURI = URI + Dist;
930          else 
931             BaseURI = URI + '/';
932       }
933       else
934          BaseURI = URI + Dist + '/';
935
936       Rep = new pkgRepository(URI,Dist,Vendor,BaseURI);
937       RepList.push_back(Rep);
938       return Rep;
939    }
940 };
941
942
943 class rpmSLTypeRpm : public rpmSLTypeGen
944 {
945    public:
946
947    bool CreateItem(vector<pkgIndexFile *> &List,
948                    string URI, string Dist, string Section,
949                    pkgSourceList::Vendor const *Vendor) const 
950    {
951       pkgRepository *Rep = GetRepository(URI,Dist,Vendor);
952       List.push_back(new rpmPkgListIndex(URI,Dist,Section,Rep));
953       return true;
954    };
955
956    rpmSLTypeRpm()
957    {
958       Name = "rpm";
959       Label = "Standard RPM binary tree";
960    }   
961 };
962
963 class rpmSLTypeSrpm : public rpmSLTypeGen
964 {
965    public:
966
967    bool CreateItem(vector<pkgIndexFile *> &List,
968                    string URI, string Dist, string Section,
969                    pkgSourceList::Vendor const *Vendor) const 
970    {
971       pkgRepository *Rep = GetRepository(URI,Dist,Vendor);
972       List.push_back(new rpmSrcListIndex(URI,Dist,Section,Rep));
973       return true;
974    };  
975    
976    rpmSLTypeSrpm()
977    {
978       Name = "rpm-src";
979       Label = "Standard RPM source tree";
980    }   
981 };
982
983 class rpmSLTypeRpmDir : public rpmSLTypeGen
984 {
985    public:
986
987    bool CreateItem(vector<pkgIndexFile *> &List,
988                    string URI, string Dist, string Section,
989                    pkgSourceList::Vendor const *Vendor) const 
990    {
991       pkgRepository *Rep = GetRepository(URI,Dist,Vendor);
992       List.push_back(new rpmPkgDirIndex(URI,Dist,Section,Rep));
993       return true;
994    };
995
996    rpmSLTypeRpmDir()
997    {
998       Name = "rpm-dir";
999       Label = "Local RPM directory tree";
1000    }   
1001 };
1002
1003 class rpmSLTypeSrpmDir : public rpmSLTypeGen
1004 {
1005    public:
1006
1007    bool CreateItem(vector<pkgIndexFile *> &List,
1008                    string URI, string Dist, string Section,
1009                    pkgSourceList::Vendor const *Vendor) const 
1010    {
1011       pkgRepository *Rep = GetRepository(URI,Dist,Vendor);
1012       List.push_back(new rpmSrcDirIndex(URI,Dist,Section,Rep));
1013       return true;
1014    };
1015
1016    rpmSLTypeSrpmDir()
1017    {
1018       Name = "rpm-src-dir";
1019       Label = "Local SRPM directory tree";
1020    }   
1021 };
1022
1023 class rpmSLTypeRepomd : public rpmSLTypeGen
1024 {
1025    public:
1026
1027    pkgRepository *GetRepository(string URI,string Dist,
1028                                 const pkgSourceList::Vendor *Vendor) const
1029    {
1030       pkgRepository *Rep = FindRepository(URI,Dist,Vendor);
1031       if (Rep != NULL)
1032          return Rep;
1033
1034       string BaseURI;
1035       if (Dist[Dist.size() - 1] == '/')
1036       {
1037          if (Dist != "/")
1038             BaseURI = URI + Dist;
1039          else 
1040             BaseURI = URI + '/';
1041       }
1042       else
1043          BaseURI = URI + Dist + '/';
1044
1045       Rep = new repomdRepository(URI,Dist,Vendor,BaseURI);
1046       RepList.push_back(Rep);
1047       return Rep;
1048    }
1049
1050    bool CreateItem(vector<pkgIndexFile *> &List,
1051                    string URI, string Dist, string Section,
1052                    pkgSourceList::Vendor const *Vendor) const 
1053    {
1054       pkgRepository *Rep = GetRepository(URI,Dist,Vendor);
1055       List.push_back(new rpmRepomdPkgIndex(URI,Dist,Section,Rep));
1056       return true;
1057    };
1058
1059    bool ParseLine(vector<pkgIndexFile *> &List,
1060                   pkgSourceList::Vendor const *Vendor,
1061                   const char *Buffer,
1062                   unsigned long CurLine,string File) const
1063    {
1064       string URI;
1065       string Dist;
1066       if (ParseQuoteWord(Buffer,URI) == false)
1067          return _error->Error(_("Malformed line %lu in source list %s (URI)"),CurLine,File.c_str());
1068       if (ParseQuoteWord(Buffer,Dist) == false)
1069          return _error->Error(_("Malformed line %lu in source list %s (dist)"),CurLine,File.c_str());
1070
1071       if (FixupURI(URI) == false)
1072          return _error->Error(_("Malformed line %lu in source list %s (URI parse)"),CurLine,File.c_str());
1073       
1074       Dist = SubstVar(Dist,"$(ARCH)",_config->Find("APT::Architecture"));
1075       Dist = SubstVar(Dist,"$(VERSION)",_config->Find("APT::DistroVersion"));
1076
1077       if (CreateItem(List,URI,Dist,"",Vendor) == false)
1078          return false;
1079
1080       return true;
1081    };
1082
1083
1084    rpmSLTypeRepomd()
1085    {
1086       Name = "repomd";
1087       Label = "RepoMD tree";
1088    }   
1089 };
1090 class rpmSLTypeRepomdSrc : public rpmSLTypeRepomd
1091 {
1092    public:
1093
1094    bool CreateItem(vector<pkgIndexFile *> &List,
1095                    string URI, string Dist, string Section,
1096                    pkgSourceList::Vendor const *Vendor) const 
1097    {
1098       pkgRepository *Rep = GetRepository(URI,Dist,Vendor);
1099       List.push_back(new rpmRepomdSrcIndex(URI,Dist,Section,Rep));
1100       return true;
1101    };
1102
1103    rpmSLTypeRepomdSrc()
1104    {
1105       Name = "repomd-src";
1106       Label = "RepoMD src tree";
1107    }   
1108 };
1109
1110 rpmSLTypeRpm _apt_rpmType;
1111 rpmSLTypeSrpm _apt_rpmSrcType;
1112 rpmSLTypeRpmDir _apt_rpmDirType;
1113 rpmSLTypeSrpmDir _apt_rpmSrcDirType;
1114 rpmSLTypeRepomd _apt_repomdType;
1115 rpmSLTypeRepomdSrc _apt_repomdSrcType;
1116                                                                         /*}}}*/
1117 // Index File types for rpm                                             /*{{{*/
1118 class rpmIFTypeSrc : public pkgIndexFile::Type
1119 {
1120    public:
1121    
1122    rpmIFTypeSrc() {Label = "RPM Source Index";};
1123 };
1124 class rpmIFTypePkg : public pkgIndexFile::Type
1125 {
1126    public:
1127    
1128    virtual pkgRecords::Parser *CreatePkgParser(pkgCache::PkgFileIterator File) const
1129    {
1130       return new rpmRecordParser(File.FileName(),*File.Cache());
1131    };
1132    rpmIFTypePkg() {Label = "RPM Package Index";};
1133 };
1134 class rpmIFTypeDatabase : public pkgIndexFile::Type
1135 {
1136    public:
1137    
1138    virtual pkgRecords::Parser *CreatePkgParser(pkgCache::PkgFileIterator File) const
1139    {
1140       return new rpmRecordParser(File.FileName(),*File.Cache());
1141    };
1142    rpmIFTypeDatabase() {Label = "RPM Database";};
1143 };
1144 static rpmIFTypeSrc _apt_Src;
1145 static rpmIFTypePkg _apt_Pkg;
1146 static rpmIFTypeDatabase _apt_DB;
1147
1148 const pkgIndexFile::Type *rpmSrcListIndex::GetType() const
1149 {
1150    return &_apt_Src;
1151 }
1152 const pkgIndexFile::Type *rpmPkgListIndex::GetType() const
1153 {
1154    return &_apt_Pkg;
1155 }
1156 const pkgIndexFile::Type *rpmSrcDirIndex::GetType() const
1157 {
1158    return &_apt_Src;
1159 }
1160 const pkgIndexFile::Type *rpmPkgDirIndex::GetType() const
1161 {
1162    return &_apt_Pkg;
1163 }
1164 const pkgIndexFile::Type *rpmSinglePkgIndex::GetType() const
1165 {
1166    return &_apt_Pkg;
1167 }
1168 const pkgIndexFile::Type *rpmSingleSrcIndex::GetType() const
1169 {
1170    return &_apt_Src;
1171 }
1172 const pkgIndexFile::Type *rpmDatabaseIndex::GetType() const
1173 {
1174    return &_apt_DB;
1175 }
1176 const pkgIndexFile::Type *rpmRepomdPkgIndex::GetType() const
1177 {
1178    return &_apt_Pkg;
1179 }
1180 const pkgIndexFile::Type *rpmRepomdSrcIndex::GetType() const
1181 {
1182    return &_apt_Src;
1183 }
1184
1185                                                                         /*}}}*/
1186 #endif /* HAVE_RPM */
1187
1188 // vim:sts=3:sw=3