- remove debug junk
[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 // 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("primary"));
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 #ifdef APT_WITH_REPOMD
540 string rpmRepomdIndex::ArchiveURI(string File) const
541 {
542    string Res;
543
544    Res += URI + '/' + Dist + '/' + File;
545    return Res;
546 }
547
548 string rpmRepomdIndex::ArchiveInfo(pkgCache::VerIterator Ver) const
549 {
550    string Res = ::URI::SiteOnly(URI) + ' ';
551    if (Dist[Dist.size() - 1] == '/')
552    {
553       if (Dist != "/")
554          Res += Dist;
555    }
556    else
557       Res += Dist + '/';
558    
559    Res += " ";
560    Res += Ver.ParentPkg().Name();
561    Res += " ";
562    Res += Ver.VerStr();
563    return Res;
564 }
565 pkgCache::PkgFileIterator rpmRepomdIndex::FindInCache(pkgCache &Cache) const
566 {
567    string FileName = IndexPath();
568    pkgCache::PkgFileIterator File = Cache.FileBegin();
569    for (; File.end() == false; File++)
570    {
571       if (FileName != File.FileName())
572          continue;
573       
574       struct stat St;
575       if (stat(File.FileName(),&St) != 0)
576          return pkgCache::PkgFileIterator(Cache);
577
578       if ((unsigned)St.st_size != File->Size || St.st_mtime != File->mtime)
579          return pkgCache::PkgFileIterator(Cache);
580       return File;
581    }
582    
583    return File;
584 }
585 string rpmRepomdIndex::ReleaseURI(string Type) const
586 {
587    string Res = URI + Dist;
588    assert( Res.size() > 0 );
589    if ( Res[Res.size() - 1] != '/' )
590      Res += '/';
591    Res += "repodata/";
592    Res += "repomd.xml";
593    return Res;
594 }
595
596 string rpmRepomdIndex::ReleaseInfo(string Type) const
597 {
598    string Info = ::URI::SiteOnly(URI) + ' ';
599    assert( Dist.size() > 0 );
600    if (Dist[Dist.size() - 1] == '/')
601    {
602       if (Dist != "/")
603          Info += Dist;
604    }
605    else
606       Info += Dist;   
607    Info += " ";
608    Info += Type;
609    return Info;
610 }
611
612 string rpmRepomdIndex::Info(string Type) const 
613 {
614    string Info = ::URI::SiteOnly(URI) + ' ';
615    assert( Dist.size() > 0 );
616    if (Dist[Dist.size() - 1] == '/')
617    {
618       if (Dist != "/")
619          Info += Dist;
620    }
621    else
622       Info += Dist + '/' ;   
623    Info += " ";
624    Info += Type;
625    return Info;
626 }
627
628 string rpmRepomdIndex::IndexURI(string Type) const
629 {
630    string Res = URI + Dist;
631    assert( Dist.size() > 0 );
632    if (Dist[Dist.size() - 1] != '/') {
633          Res += "/";
634    }
635    string TypeURI;
636    if (Repository->FindURI(Type, TypeURI)) {
637       Res += TypeURI;
638    } else {
639       Res = "";
640    }
641    assert(Res.size() > 0);
642    return Res;
643 }
644                                                                         /*}}}*/
645 bool rpmRepomdIndex::GetReleases(pkgAcquire *Owner) const
646 {
647    if (!Repository->Acquire)
648       return true;
649    Repository->Acquire = false;
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
658    new pkgAcqIndex(Owner,Repository,IndexURI("primary"),
659                    Info("primary.xml"), "primary.xml");
660    new pkgAcqIndex(Owner,Repository,IndexURI("filelists"),
661                    Info("filelists.xml"), "filelists.xml");
662    if (_config->FindB("Acquire::ChangeLogs", false)) {
663       new pkgAcqIndex(Owner,Repository,IndexURI("other"),
664                      Info("other.xml"), "other.xml");
665    }
666    string dummy;
667    if (Repository->FindURI("updateinfo", dummy)) {
668       new pkgAcqIndex(Owner,Repository,IndexURI("updateinfo"),
669                      Info("updateinfo.xml"), "updateinfo.xml");
670    }
671    return true;
672 }
673
674 string rpmRepomdIndex::Describe(bool Short) const
675 {
676    char S[300];
677    if (Short == true)
678       snprintf(S,sizeof(S),"%s",Info(MainType()).c_str());
679    else
680       snprintf(S,sizeof(S),"%s (%s)",Info(MainType()).c_str(),
681          IndexFile(MainType()).c_str());
682    return S;
683 }
684
685 string rpmRepomdIndex::IndexFile(string Type) const
686 {
687    return _config->FindDir("Dir::State::lists")+URItoFileName(IndexURI(Type));
688 }
689
690
691 bool rpmRepomdIndex::Exists() const
692 {
693    return FileExists(IndexPath());
694 }
695
696 string rpmRepomdIndex::ReleasePath() const
697 {
698    return _config->FindDir("Dir::State::lists")+URItoFileName(ReleaseURI("repomd.xml"));
699 }
700
701 // This gets called several times per each index during cache generation,
702 // only for progress percentage reporting. A rough estimate would do just
703 // fine but using xmlReader appears to be cheap enough. OTOH creating a new 
704 // handler like is done for rpmPkgDirIndex is hideously expensive.
705 unsigned long rpmRepomdIndex::Size() const
706 {
707    xmlTextReaderPtr Index;
708    unsigned long Res;
709    Index = xmlReaderForFile(IndexPath().c_str(), NULL,
710                           XML_PARSE_NONET|XML_PARSE_NOBLANKS);
711    if (Index == NULL) return 0;
712
713    if (xmlTextReaderRead(Index) == 1) {
714       xmlChar *pkgs = xmlTextReaderGetAttribute(Index, (xmlChar*)"packages");
715       Res = atoi((char*)pkgs);
716       xmlFree(pkgs);
717    } else {
718       Res = 0;
719    }
720    xmlFreeTextReader(Index);
721    return Res;
722 }
723
724 bool rpmRepomdIndex::Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const
725 {
726    string PackageFile = IndexPath();
727    RPMHandler *Handler = CreateHandler();
728
729    Prog.SubProgress(0,Info("primary"));
730    ::URI Tmp(URI);
731    if (Gen.SelectFile(PackageFile,Tmp.Host,*this) == false)
732    {
733       delete Handler;
734       return _error->Error(_("Problem with SelectFile %s"),PackageFile.c_str());
735    }
736
737    // Store the IMS information
738    pkgCache::PkgFileIterator File = Gen.GetCurFile();
739    struct stat St;
740    if (stat(PackageFile.c_str(),&St) != 0) 
741    {
742       delete Handler;
743       return _error->Errno("stat",_("Failed to stat %s"), PackageFile.c_str());
744    }
745    File->Size = St.st_size;
746    File->mtime = St.st_mtime;
747    
748    rpmRepomdParser Parser(Handler);
749    if (_error->PendingError() == true) 
750    {
751       delete Handler;
752       return _error->Error(_("Problem opening %s"),PackageFile.c_str());
753    }
754    
755    if (Gen.MergeList(Parser) == false)
756    {
757       delete Handler;
758       return _error->Error(_("Problem with MergeList %s"),PackageFile.c_str());
759    }
760    
761    delete Handler;
762
763    // Check the release file
764    string RelFile = ReleasePath();
765    if (FileExists(RelFile) == true)
766    {
767       Parser.LoadReleaseInfo(File,RelFile,Dist);
768    }
769
770    return true;
771 }
772
773 bool rpmRepomdIndex::MergeFileProvides(pkgCacheGenerator &Gen,
774                                         OpProgress &Prog) const
775 {
776    string PackageFile = IndexPath();
777    RPMHandler *Handler = new RPMRepomdFLHandler(IndexPath());
778    rpmListParser Parser(Handler);
779    if (_error->PendingError() == true) {
780       delete Handler;
781       return _error->Error(_("Problem opening %s"),PackageFile.c_str());
782    }
783    // We call SubProgress with Size(), since we won't call SelectFile() here.
784    Prog.SubProgress(Size(),Info("pkglist"));
785    if (Gen.MergeFileProvides(Parser) == false)
786       return _error->Error(_("Problem with MergeFileProvides %s"),
787                            PackageFile.c_str());
788    delete Handler;
789    return true;
790 }
791
792 rpmRepomdIndex::rpmRepomdIndex(string URI,string Dist,string Section, 
793                                pkgRepository *Repository):
794                                URI(URI), Dist(Dist), Section(Section),
795                                Repository(Repository)   
796 {
797    if (FileExists(ReleasePath())) {
798       Repository->ParseRelease(ReleasePath());
799    }
800 }
801
802 pkgSrcRecords::Parser *rpmRepomdIndex::CreateSrcParser() const
803 {
804    return new rpmSrcRecordParser(IndexPath(), this);
805 }
806
807 string rpmRepomdSrcIndex::SourceInfo(pkgSrcRecords::Parser const &Record,
808                                      pkgSrcRecords::File const &File) const
809 {
810    string Res;
811    Res = ::URI::SiteOnly(URI) + ' ';
812    if (Dist[Dist.size() - 1] == '/')
813    {
814       if (Dist != "/")
815          Res += Dist;
816    }      
817    else
818       Res += Dist + '/' + Section;
819    
820    Res += " ";
821    Res += Record.Package();
822    Res += " ";
823    Res += Record.Version();
824    if (File.Type.empty() == false)
825       Res += " (" + File.Type + ")";
826    return Res;
827 }
828 #endif /* APT_WITH_REPOMD */
829
830 // DatabaseIndex::rpmDatabaseIndex - Constructor                        /*{{{*/
831 // ---------------------------------------------------------------------
832 /* */
833 rpmDatabaseIndex::rpmDatabaseIndex()
834 {
835 }
836                                                                         /*}}}*/
837 // DatabaseIndex::Size - Return the size of the index                   /*{{{*/
838 // ---------------------------------------------------------------------
839 /* */
840 unsigned long rpmDatabaseIndex::Size() const
841 {
842    return rpmSys.GetDBHandler()->Size();
843 }
844                                                                         /*}}}*/
845 // DatabaseIndex::CreateHandler - Create a RPMHandler for this file     /*{{{*/
846 // ---------------------------------------------------------------------
847 RPMHandler *rpmDatabaseIndex::CreateHandler() const
848 {
849    return rpmSys.GetDBHandler();
850 }
851                                                                         /*}}}*/
852 // DatabaseIndex::Merge - Load the index file into a cache              /*{{{*/
853 // ---------------------------------------------------------------------
854 /* */
855 bool rpmDatabaseIndex::Merge(pkgCacheGenerator &Gen,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    
862    Prog.SubProgress(0,"RPM Database");
863    if (Gen.SelectFile(Handler->DataPath(false),string(),*this,pkgCache::Flag::NotSource) == false)
864       return _error->Error(_("Problem with SelectFile RPM Database"));
865
866    // Store the IMS information
867    pkgCache::PkgFileIterator CFile = Gen.GetCurFile();
868    struct stat St;
869    if (stat(Handler->DataPath(false).c_str(),&St) != 0)
870       return _error->Errno("fstat",_("Failed to stat %s"), Handler->DataPath(false).c_str());
871    CFile->Size = St.st_size;
872    CFile->mtime = Handler->Mtime();
873    
874    if (Gen.MergeList(Parser) == false)
875       return _error->Error(_("Problem with MergeList %s"),
876                            Handler->DataPath(false).c_str());
877    return true;
878 }
879                                                                         /*}}}*/
880 // DatabaseIndex::MergeFileProvides - Process file dependencies if any  /*{{{*/
881 // ---------------------------------------------------------------------
882 /* */
883 bool rpmDatabaseIndex::MergeFileProvides(pkgCacheGenerator &Gen,
884                                          OpProgress &Prog) const
885 {
886    RPMDBHandler *Handler = rpmSys.GetDBHandler();
887    rpmListParser Parser(Handler);
888    if (_error->PendingError() == true)
889       return _error->Error(_("Problem opening RPM database"));
890    // We call SubProgress with Size(), since we won't call SelectFile() here.
891    Prog.SubProgress(Size(),"RPM Database");
892    if (Gen.MergeFileProvides(Parser) == false)
893       return _error->Error(_("Problem with MergeFileProvides %s"),
894                            Handler->DataPath(false).c_str());
895    return true;
896 }
897                                                                         /*}}}*/
898 // DatabaseIndex::FindInCache - Find this index                         /*{{{*/
899 // ---------------------------------------------------------------------
900 /* */
901 pkgCache::PkgFileIterator rpmDatabaseIndex::FindInCache(pkgCache &Cache) const
902 {
903    pkgCache::PkgFileIterator File = Cache.FileBegin();
904    for (; File.end() == false; File++)
905    {
906       if (rpmSys.GetDBHandler()->DataPath(false) != File.FileName())
907          continue;
908       struct stat St;
909       if (stat(File.FileName(),&St) != 0)
910          return pkgCache::PkgFileIterator(Cache);
911       if ((unsigned)St.st_size != File->Size || St.st_mtime != File->mtime)
912          return pkgCache::PkgFileIterator(Cache);
913       return File;
914    }   
915    return File;
916 }
917                                                                         /*}}}*/
918
919 // Source List types for rpm                                            /*{{{*/
920
921 class rpmSLTypeGen : public pkgSourceList::Type
922 {
923    public:
924
925    rpmSLTypeGen()
926    {
927       Name = "rpm";
928       Label = "Standard RPM source tree";
929    }   
930
931    pkgRepository *FindRepository(string URI,string Dist,
932                                  const pkgSourceList::Vendor *Vendor) const
933    {
934       for (vector<pkgRepository *>::const_iterator iter = RepList.begin();
935            iter != RepList.end(); iter++) 
936       {
937          if ((*iter)->URI == URI && (*iter)->Dist == Dist) 
938          {       
939             if (Vendor != NULL)
940                (*iter)->FingerPrint = Vendor->FingerPrint;
941             return *iter;
942          }
943       }
944       return NULL;
945    }
946
947    pkgRepository *GetRepository(string URI,string Dist,
948                                 const pkgSourceList::Vendor *Vendor) const
949    {
950       pkgRepository *Rep = FindRepository(URI,Dist,Vendor);
951       if (Rep != NULL)
952          return Rep;
953
954       string BaseURI;
955       if (Dist[Dist.size() - 1] == '/')
956       {
957          if (Dist != "/")
958             BaseURI = URI + Dist;
959          else 
960             BaseURI = URI + '/';
961       }
962       else
963          BaseURI = URI + Dist + '/';
964
965       Rep = new pkgRepository(URI,Dist,Vendor,BaseURI);
966       RepList.push_back(Rep);
967       return Rep;
968    }
969 };
970
971
972 class rpmSLTypeRpm : public rpmSLTypeGen
973 {
974    public:
975
976    bool CreateItem(vector<pkgIndexFile *> &List,
977                    string URI, string Dist, string Section,
978                    pkgSourceList::Vendor const *Vendor) const 
979    {
980       pkgRepository *Rep = GetRepository(URI,Dist,Vendor);
981       List.push_back(new rpmPkgListIndex(URI,Dist,Section,Rep));
982       return true;
983    };
984
985    rpmSLTypeRpm()
986    {
987       Name = "rpm";
988       Label = "Standard RPM binary tree";
989    }   
990 };
991
992 class rpmSLTypeSrpm : public rpmSLTypeGen
993 {
994    public:
995
996    bool CreateItem(vector<pkgIndexFile *> &List,
997                    string URI, string Dist, string Section,
998                    pkgSourceList::Vendor const *Vendor) const 
999    {
1000       pkgRepository *Rep = GetRepository(URI,Dist,Vendor);
1001       List.push_back(new rpmSrcListIndex(URI,Dist,Section,Rep));
1002       return true;
1003    };  
1004    
1005    rpmSLTypeSrpm()
1006    {
1007       Name = "rpm-src";
1008       Label = "Standard RPM source tree";
1009    }   
1010 };
1011
1012 class rpmSLTypeRpmDir : public rpmSLTypeGen
1013 {
1014    public:
1015
1016    bool CreateItem(vector<pkgIndexFile *> &List,
1017                    string URI, string Dist, string Section,
1018                    pkgSourceList::Vendor const *Vendor) const 
1019    {
1020       pkgRepository *Rep = GetRepository(URI,Dist,Vendor);
1021       List.push_back(new rpmPkgDirIndex(URI,Dist,Section,Rep));
1022       return true;
1023    };
1024
1025    rpmSLTypeRpmDir()
1026    {
1027       Name = "rpm-dir";
1028       Label = "Local RPM directory tree";
1029    }   
1030 };
1031
1032 class rpmSLTypeSrpmDir : public rpmSLTypeGen
1033 {
1034    public:
1035
1036    bool CreateItem(vector<pkgIndexFile *> &List,
1037                    string URI, string Dist, string Section,
1038                    pkgSourceList::Vendor const *Vendor) const 
1039    {
1040       pkgRepository *Rep = GetRepository(URI,Dist,Vendor);
1041       List.push_back(new rpmSrcDirIndex(URI,Dist,Section,Rep));
1042       return true;
1043    };
1044
1045    rpmSLTypeSrpmDir()
1046    {
1047       Name = "rpm-src-dir";
1048       Label = "Local SRPM directory tree";
1049    }   
1050 };
1051
1052 #ifdef APT_WITH_REPOMD
1053 class rpmSLTypeRepomd : public rpmSLTypeGen
1054 {
1055    public:
1056
1057    pkgRepository *GetRepository(string URI,string Dist,
1058                                 const pkgSourceList::Vendor *Vendor) const
1059    {
1060       pkgRepository *Rep = FindRepository(URI,Dist,Vendor);
1061       if (Rep != NULL)
1062          return Rep;
1063
1064       string BaseURI;
1065       if (Dist[Dist.size() - 1] == '/')
1066       {
1067          if (Dist != "/")
1068             BaseURI = URI + Dist;
1069          else 
1070             BaseURI = URI + '/';
1071       }
1072       else
1073          BaseURI = URI + Dist + '/';
1074
1075       Rep = new repomdRepository(URI,Dist,Vendor,BaseURI);
1076       RepList.push_back(Rep);
1077       return Rep;
1078    }
1079
1080    bool CreateItem(vector<pkgIndexFile *> &List,
1081                    string URI, string Dist, string Section,
1082                    pkgSourceList::Vendor const *Vendor) const 
1083    {
1084       pkgRepository *Rep = GetRepository(URI,Dist,Vendor);
1085       List.push_back(new rpmRepomdPkgIndex(URI,Dist,Section,Rep));
1086       return true;
1087    };
1088
1089    bool ParseLine(vector<pkgIndexFile *> &List,
1090                   pkgSourceList::Vendor const *Vendor,
1091                   const char *Buffer,
1092                   unsigned long CurLine,string File) const
1093    {
1094       string URI;
1095       string Dist;
1096       if (ParseQuoteWord(Buffer,URI) == false)
1097          return _error->Error(_("Malformed line %lu in source list %s (URI)"),CurLine,File.c_str());
1098       if (ParseQuoteWord(Buffer,Dist) == false)
1099          return _error->Error(_("Malformed line %lu in source list %s (dist)"),CurLine,File.c_str());
1100
1101       if (FixupURI(URI) == false)
1102          return _error->Error(_("Malformed line %lu in source list %s (URI parse)"),CurLine,File.c_str());
1103       
1104       Dist = SubstVar(Dist,"$(ARCH)",_config->Find("APT::Architecture"));
1105       Dist = SubstVar(Dist,"$(VERSION)",_config->Find("APT::DistroVersion"));
1106
1107       if (CreateItem(List,URI,Dist,"",Vendor) == false)
1108          return false;
1109
1110       return true;
1111    };
1112
1113
1114    rpmSLTypeRepomd()
1115    {
1116       Name = "repomd";
1117       Label = "RepoMD tree";
1118    }   
1119 };
1120 class rpmSLTypeRepomdSrc : public rpmSLTypeRepomd
1121 {
1122    public:
1123
1124    bool CreateItem(vector<pkgIndexFile *> &List,
1125                    string URI, string Dist, string Section,
1126                    pkgSourceList::Vendor const *Vendor) const 
1127    {
1128       pkgRepository *Rep = GetRepository(URI,Dist,Vendor);
1129       List.push_back(new rpmRepomdSrcIndex(URI,Dist,Section,Rep));
1130       return true;
1131    };
1132
1133    rpmSLTypeRepomdSrc()
1134    {
1135       Name = "repomd-src";
1136       Label = "RepoMD src tree";
1137    }   
1138 };
1139 #endif /* APT_WITH_REPOMD */
1140
1141 rpmSLTypeRpm _apt_rpmType;
1142 rpmSLTypeSrpm _apt_rpmSrcType;
1143 rpmSLTypeRpmDir _apt_rpmDirType;
1144 rpmSLTypeSrpmDir _apt_rpmSrcDirType;
1145 #ifdef APT_WITH_REPOMD
1146 rpmSLTypeRepomd _apt_repomdType;
1147 rpmSLTypeRepomdSrc _apt_repomdSrcType;
1148 #endif
1149                                                                         /*}}}*/
1150 // Index File types for rpm                                             /*{{{*/
1151 class rpmIFTypeSrc : public pkgIndexFile::Type
1152 {
1153    public:
1154    
1155    rpmIFTypeSrc() {Label = "RPM Source Index";};
1156 };
1157 class rpmIFTypePkg : public pkgIndexFile::Type
1158 {
1159    public:
1160    
1161    virtual pkgRecords::Parser *CreatePkgParser(pkgCache::PkgFileIterator File) const
1162    {
1163       return new rpmRecordParser(File.FileName(),*File.Cache());
1164    };
1165    rpmIFTypePkg() {Label = "RPM Package Index";};
1166 };
1167 class rpmIFTypeDatabase : public pkgIndexFile::Type
1168 {
1169    public:
1170    
1171    virtual pkgRecords::Parser *CreatePkgParser(pkgCache::PkgFileIterator File) const
1172    {
1173       return new rpmRecordParser(File.FileName(),*File.Cache());
1174    };
1175    rpmIFTypeDatabase() {Label = "RPM Database";};
1176 };
1177 static rpmIFTypeSrc _apt_Src;
1178 static rpmIFTypePkg _apt_Pkg;
1179 static rpmIFTypeDatabase _apt_DB;
1180
1181 const pkgIndexFile::Type *rpmSrcListIndex::GetType() const
1182 {
1183    return &_apt_Src;
1184 }
1185 const pkgIndexFile::Type *rpmPkgListIndex::GetType() const
1186 {
1187    return &_apt_Pkg;
1188 }
1189 const pkgIndexFile::Type *rpmSrcDirIndex::GetType() const
1190 {
1191    return &_apt_Src;
1192 }
1193 const pkgIndexFile::Type *rpmPkgDirIndex::GetType() const
1194 {
1195    return &_apt_Pkg;
1196 }
1197 const pkgIndexFile::Type *rpmSinglePkgIndex::GetType() const
1198 {
1199    return &_apt_Pkg;
1200 }
1201 const pkgIndexFile::Type *rpmSingleSrcIndex::GetType() const
1202 {
1203    return &_apt_Src;
1204 }
1205 const pkgIndexFile::Type *rpmDatabaseIndex::GetType() const
1206 {
1207    return &_apt_DB;
1208 }
1209 #ifdef APT_WITH_REPOMD
1210 const pkgIndexFile::Type *rpmRepomdPkgIndex::GetType() const
1211 {
1212    return &_apt_Pkg;
1213 }
1214 const pkgIndexFile::Type *rpmRepomdSrcIndex::GetType() const
1215 {
1216    return &_apt_Src;
1217 }
1218 #endif
1219
1220                                                                         /*}}}*/
1221 #endif /* HAVE_RPM */
1222
1223 // vim:sts=3:sw=3