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