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