939332a580c123a51b6a1ac8223274c419286eb9
[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    cout << "packagefile " << PackageFile << endl;
728    RPMHandler *Handler = CreateHandler();
729
730    Prog.SubProgress(0,Info("primary"));
731    ::URI Tmp(URI);
732    if (Gen.SelectFile(PackageFile,Tmp.Host,*this) == false)
733    {
734       delete Handler;
735       return _error->Error(_("Problem with SelectFile %s"),PackageFile.c_str());
736    }
737
738    // Store the IMS information
739    pkgCache::PkgFileIterator File = Gen.GetCurFile();
740    struct stat St;
741    if (stat(PackageFile.c_str(),&St) != 0) 
742    {
743       delete Handler;
744       return _error->Errno("stat",_("Failed to stat %s"), PackageFile.c_str());
745    }
746    File->Size = St.st_size;
747    File->mtime = St.st_mtime;
748    
749    rpmRepomdParser Parser(Handler);
750    if (_error->PendingError() == true) 
751    {
752       delete Handler;
753       return _error->Error(_("Problem opening %s"),PackageFile.c_str());
754    }
755    
756    if (Gen.MergeList(Parser) == false)
757    {
758       delete Handler;
759       return _error->Error(_("Problem with MergeList %s"),PackageFile.c_str());
760    }
761    
762    delete Handler;
763
764    // Check the release file
765    string RelFile = ReleasePath();
766    if (FileExists(RelFile) == true)
767    {
768       Parser.LoadReleaseInfo(File,RelFile,Dist);
769    }
770
771    return true;
772 }
773
774 bool rpmRepomdIndex::MergeFileProvides(pkgCacheGenerator &Gen,
775                                         OpProgress &Prog) const
776 {
777    string PackageFile = IndexPath();
778    RPMHandler *Handler = new RPMRepomdFLHandler(IndexPath());
779    rpmListParser Parser(Handler);
780    if (_error->PendingError() == true) {
781       delete Handler;
782       return _error->Error(_("Problem opening %s"),PackageFile.c_str());
783    }
784    // We call SubProgress with Size(), since we won't call SelectFile() here.
785    Prog.SubProgress(Size(),Info("pkglist"));
786    if (Gen.MergeFileProvides(Parser) == false)
787       return _error->Error(_("Problem with MergeFileProvides %s"),
788                            PackageFile.c_str());
789    delete Handler;
790    return true;
791 }
792
793 rpmRepomdIndex::rpmRepomdIndex(string URI,string Dist,string Section, 
794                                pkgRepository *Repository):
795                                URI(URI), Dist(Dist), Section(Section),
796                                Repository(Repository)   
797 {
798    if (FileExists(ReleasePath())) {
799       Repository->ParseRelease(ReleasePath());
800    }
801 }
802
803 pkgSrcRecords::Parser *rpmRepomdIndex::CreateSrcParser() const
804 {
805    return new rpmSrcRecordParser(IndexPath(), this);
806 }
807
808 string rpmRepomdSrcIndex::SourceInfo(pkgSrcRecords::Parser const &Record,
809                                      pkgSrcRecords::File const &File) const
810 {
811    string Res;
812    Res = ::URI::SiteOnly(URI) + ' ';
813    if (Dist[Dist.size() - 1] == '/')
814    {
815       if (Dist != "/")
816          Res += Dist;
817    }      
818    else
819       Res += Dist + '/' + Section;
820    
821    Res += " ";
822    Res += Record.Package();
823    Res += " ";
824    Res += Record.Version();
825    if (File.Type.empty() == false)
826       Res += " (" + File.Type + ")";
827    return Res;
828 }
829 #endif /* APT_WITH_REPOMD */
830
831 // DatabaseIndex::rpmDatabaseIndex - Constructor                        /*{{{*/
832 // ---------------------------------------------------------------------
833 /* */
834 rpmDatabaseIndex::rpmDatabaseIndex()
835 {
836 }
837                                                                         /*}}}*/
838 // DatabaseIndex::Size - Return the size of the index                   /*{{{*/
839 // ---------------------------------------------------------------------
840 /* */
841 unsigned long rpmDatabaseIndex::Size() const
842 {
843    return rpmSys.GetDBHandler()->Size();
844 }
845                                                                         /*}}}*/
846 // DatabaseIndex::CreateHandler - Create a RPMHandler for this file     /*{{{*/
847 // ---------------------------------------------------------------------
848 RPMHandler *rpmDatabaseIndex::CreateHandler() const
849 {
850    return rpmSys.GetDBHandler();
851 }
852                                                                         /*}}}*/
853 // DatabaseIndex::Merge - Load the index file into a cache              /*{{{*/
854 // ---------------------------------------------------------------------
855 /* */
856 bool rpmDatabaseIndex::Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const
857 {
858    RPMDBHandler *Handler = rpmSys.GetDBHandler();
859    rpmListParser Parser(Handler);
860    if (_error->PendingError() == true)
861       return _error->Error(_("Problem opening RPM database"));
862    
863    Prog.SubProgress(0,"RPM Database");
864    if (Gen.SelectFile(Handler->DataPath(false),string(),*this,pkgCache::Flag::NotSource) == false)
865       return _error->Error(_("Problem with SelectFile RPM Database"));
866
867    // Store the IMS information
868    pkgCache::PkgFileIterator CFile = Gen.GetCurFile();
869    struct stat St;
870    if (stat(Handler->DataPath(false).c_str(),&St) != 0)
871       return _error->Errno("fstat",_("Failed to stat %s"), Handler->DataPath(false).c_str());
872    CFile->Size = St.st_size;
873    CFile->mtime = Handler->Mtime();
874    
875    if (Gen.MergeList(Parser) == false)
876       return _error->Error(_("Problem with MergeList %s"),
877                            Handler->DataPath(false).c_str());
878    return true;
879 }
880                                                                         /*}}}*/
881 // DatabaseIndex::MergeFileProvides - Process file dependencies if any  /*{{{*/
882 // ---------------------------------------------------------------------
883 /* */
884 bool rpmDatabaseIndex::MergeFileProvides(pkgCacheGenerator &Gen,
885                                          OpProgress &Prog) const
886 {
887    RPMDBHandler *Handler = rpmSys.GetDBHandler();
888    rpmListParser Parser(Handler);
889    if (_error->PendingError() == true)
890       return _error->Error(_("Problem opening RPM database"));
891    // We call SubProgress with Size(), since we won't call SelectFile() here.
892    Prog.SubProgress(Size(),"RPM Database");
893    if (Gen.MergeFileProvides(Parser) == false)
894       return _error->Error(_("Problem with MergeFileProvides %s"),
895                            Handler->DataPath(false).c_str());
896    return true;
897 }
898                                                                         /*}}}*/
899 // DatabaseIndex::FindInCache - Find this index                         /*{{{*/
900 // ---------------------------------------------------------------------
901 /* */
902 pkgCache::PkgFileIterator rpmDatabaseIndex::FindInCache(pkgCache &Cache) const
903 {
904    pkgCache::PkgFileIterator File = Cache.FileBegin();
905    for (; File.end() == false; File++)
906    {
907       if (rpmSys.GetDBHandler()->DataPath(false) != File.FileName())
908          continue;
909       struct stat St;
910       if (stat(File.FileName(),&St) != 0)
911          return pkgCache::PkgFileIterator(Cache);
912       if ((unsigned)St.st_size != File->Size || St.st_mtime != File->mtime)
913          return pkgCache::PkgFileIterator(Cache);
914       return File;
915    }   
916    return File;
917 }
918                                                                         /*}}}*/
919
920 // Source List types for rpm                                            /*{{{*/
921
922 class rpmSLTypeGen : public pkgSourceList::Type
923 {
924    public:
925
926    rpmSLTypeGen()
927    {
928       Name = "rpm";
929       Label = "Standard RPM source tree";
930    }   
931
932    pkgRepository *FindRepository(string URI,string Dist,
933                                  const pkgSourceList::Vendor *Vendor) const
934    {
935       for (vector<pkgRepository *>::const_iterator iter = RepList.begin();
936            iter != RepList.end(); iter++) 
937       {
938          if ((*iter)->URI == URI && (*iter)->Dist == Dist) 
939          {       
940             if (Vendor != NULL)
941                (*iter)->FingerPrint = Vendor->FingerPrint;
942             return *iter;
943          }
944       }
945       return NULL;
946    }
947
948    pkgRepository *GetRepository(string URI,string Dist,
949                                 const pkgSourceList::Vendor *Vendor) const
950    {
951       pkgRepository *Rep = FindRepository(URI,Dist,Vendor);
952       if (Rep != NULL)
953          return Rep;
954
955       string BaseURI;
956       if (Dist[Dist.size() - 1] == '/')
957       {
958          if (Dist != "/")
959             BaseURI = URI + Dist;
960          else 
961             BaseURI = URI + '/';
962       }
963       else
964          BaseURI = URI + Dist + '/';
965
966       Rep = new pkgRepository(URI,Dist,Vendor,BaseURI);
967       RepList.push_back(Rep);
968       return Rep;
969    }
970 };
971
972
973 class rpmSLTypeRpm : public rpmSLTypeGen
974 {
975    public:
976
977    bool CreateItem(vector<pkgIndexFile *> &List,
978                    string URI, string Dist, string Section,
979                    pkgSourceList::Vendor const *Vendor) const 
980    {
981       pkgRepository *Rep = GetRepository(URI,Dist,Vendor);
982       List.push_back(new rpmPkgListIndex(URI,Dist,Section,Rep));
983       return true;
984    };
985
986    rpmSLTypeRpm()
987    {
988       Name = "rpm";
989       Label = "Standard RPM binary tree";
990    }   
991 };
992
993 class rpmSLTypeSrpm : public rpmSLTypeGen
994 {
995    public:
996
997    bool CreateItem(vector<pkgIndexFile *> &List,
998                    string URI, string Dist, string Section,
999                    pkgSourceList::Vendor const *Vendor) const 
1000    {
1001       pkgRepository *Rep = GetRepository(URI,Dist,Vendor);
1002       List.push_back(new rpmSrcListIndex(URI,Dist,Section,Rep));
1003       return true;
1004    };  
1005    
1006    rpmSLTypeSrpm()
1007    {
1008       Name = "rpm-src";
1009       Label = "Standard RPM source tree";
1010    }   
1011 };
1012
1013 class rpmSLTypeRpmDir : public rpmSLTypeGen
1014 {
1015    public:
1016
1017    bool CreateItem(vector<pkgIndexFile *> &List,
1018                    string URI, string Dist, string Section,
1019                    pkgSourceList::Vendor const *Vendor) const 
1020    {
1021       pkgRepository *Rep = GetRepository(URI,Dist,Vendor);
1022       List.push_back(new rpmPkgDirIndex(URI,Dist,Section,Rep));
1023       return true;
1024    };
1025
1026    rpmSLTypeRpmDir()
1027    {
1028       Name = "rpm-dir";
1029       Label = "Local RPM directory tree";
1030    }   
1031 };
1032
1033 class rpmSLTypeSrpmDir : public rpmSLTypeGen
1034 {
1035    public:
1036
1037    bool CreateItem(vector<pkgIndexFile *> &List,
1038                    string URI, string Dist, string Section,
1039                    pkgSourceList::Vendor const *Vendor) const 
1040    {
1041       pkgRepository *Rep = GetRepository(URI,Dist,Vendor);
1042       List.push_back(new rpmSrcDirIndex(URI,Dist,Section,Rep));
1043       return true;
1044    };
1045
1046    rpmSLTypeSrpmDir()
1047    {
1048       Name = "rpm-src-dir";
1049       Label = "Local SRPM directory tree";
1050    }   
1051 };
1052
1053 #ifdef APT_WITH_REPOMD
1054 class rpmSLTypeRepomd : public rpmSLTypeGen
1055 {
1056    public:
1057
1058    pkgRepository *GetRepository(string URI,string Dist,
1059                                 const pkgSourceList::Vendor *Vendor) const
1060    {
1061       pkgRepository *Rep = FindRepository(URI,Dist,Vendor);
1062       if (Rep != NULL)
1063          return Rep;
1064
1065       string BaseURI;
1066       if (Dist[Dist.size() - 1] == '/')
1067       {
1068          if (Dist != "/")
1069             BaseURI = URI + Dist;
1070          else 
1071             BaseURI = URI + '/';
1072       }
1073       else
1074          BaseURI = URI + Dist + '/';
1075
1076       Rep = new repomdRepository(URI,Dist,Vendor,BaseURI);
1077       RepList.push_back(Rep);
1078       return Rep;
1079    }
1080
1081    bool CreateItem(vector<pkgIndexFile *> &List,
1082                    string URI, string Dist, string Section,
1083                    pkgSourceList::Vendor const *Vendor) const 
1084    {
1085       pkgRepository *Rep = GetRepository(URI,Dist,Vendor);
1086       List.push_back(new rpmRepomdPkgIndex(URI,Dist,Section,Rep));
1087       return true;
1088    };
1089
1090    bool ParseLine(vector<pkgIndexFile *> &List,
1091                   pkgSourceList::Vendor const *Vendor,
1092                   const char *Buffer,
1093                   unsigned long CurLine,string File) const
1094    {
1095       string URI;
1096       string Dist;
1097       if (ParseQuoteWord(Buffer,URI) == false)
1098          return _error->Error(_("Malformed line %lu in source list %s (URI)"),CurLine,File.c_str());
1099       if (ParseQuoteWord(Buffer,Dist) == false)
1100          return _error->Error(_("Malformed line %lu in source list %s (dist)"),CurLine,File.c_str());
1101
1102       if (FixupURI(URI) == false)
1103          return _error->Error(_("Malformed line %lu in source list %s (URI parse)"),CurLine,File.c_str());
1104       
1105       Dist = SubstVar(Dist,"$(ARCH)",_config->Find("APT::Architecture"));
1106       Dist = SubstVar(Dist,"$(VERSION)",_config->Find("APT::DistroVersion"));
1107
1108       if (CreateItem(List,URI,Dist,"",Vendor) == false)
1109          return false;
1110
1111       return true;
1112    };
1113
1114
1115    rpmSLTypeRepomd()
1116    {
1117       Name = "repomd";
1118       Label = "RepoMD tree";
1119    }   
1120 };
1121 class rpmSLTypeRepomdSrc : public rpmSLTypeRepomd
1122 {
1123    public:
1124
1125    bool CreateItem(vector<pkgIndexFile *> &List,
1126                    string URI, string Dist, string Section,
1127                    pkgSourceList::Vendor const *Vendor) const 
1128    {
1129       pkgRepository *Rep = GetRepository(URI,Dist,Vendor);
1130       List.push_back(new rpmRepomdSrcIndex(URI,Dist,Section,Rep));
1131       return true;
1132    };
1133
1134    rpmSLTypeRepomdSrc()
1135    {
1136       Name = "repomd-src";
1137       Label = "RepoMD src tree";
1138    }   
1139 };
1140 #endif /* APT_WITH_REPOMD */
1141
1142 rpmSLTypeRpm _apt_rpmType;
1143 rpmSLTypeSrpm _apt_rpmSrcType;
1144 rpmSLTypeRpmDir _apt_rpmDirType;
1145 rpmSLTypeSrpmDir _apt_rpmSrcDirType;
1146 #ifdef APT_WITH_REPOMD
1147 rpmSLTypeRepomd _apt_repomdType;
1148 rpmSLTypeRepomdSrc _apt_repomdSrcType;
1149 #endif
1150                                                                         /*}}}*/
1151 // Index File types for rpm                                             /*{{{*/
1152 class rpmIFTypeSrc : public pkgIndexFile::Type
1153 {
1154    public:
1155    
1156    rpmIFTypeSrc() {Label = "RPM Source Index";};
1157 };
1158 class rpmIFTypePkg : public pkgIndexFile::Type
1159 {
1160    public:
1161    
1162    virtual pkgRecords::Parser *CreatePkgParser(pkgCache::PkgFileIterator File) const
1163    {
1164       return new rpmRecordParser(File.FileName(),*File.Cache());
1165    };
1166    rpmIFTypePkg() {Label = "RPM Package Index";};
1167 };
1168 class rpmIFTypeDatabase : public pkgIndexFile::Type
1169 {
1170    public:
1171    
1172    virtual pkgRecords::Parser *CreatePkgParser(pkgCache::PkgFileIterator File) const
1173    {
1174       return new rpmRecordParser(File.FileName(),*File.Cache());
1175    };
1176    rpmIFTypeDatabase() {Label = "RPM Database";};
1177 };
1178 static rpmIFTypeSrc _apt_Src;
1179 static rpmIFTypePkg _apt_Pkg;
1180 static rpmIFTypeDatabase _apt_DB;
1181
1182 const pkgIndexFile::Type *rpmSrcListIndex::GetType() const
1183 {
1184    return &_apt_Src;
1185 }
1186 const pkgIndexFile::Type *rpmPkgListIndex::GetType() const
1187 {
1188    return &_apt_Pkg;
1189 }
1190 const pkgIndexFile::Type *rpmSrcDirIndex::GetType() const
1191 {
1192    return &_apt_Src;
1193 }
1194 const pkgIndexFile::Type *rpmPkgDirIndex::GetType() const
1195 {
1196    return &_apt_Pkg;
1197 }
1198 const pkgIndexFile::Type *rpmSinglePkgIndex::GetType() const
1199 {
1200    return &_apt_Pkg;
1201 }
1202 const pkgIndexFile::Type *rpmSingleSrcIndex::GetType() const
1203 {
1204    return &_apt_Src;
1205 }
1206 const pkgIndexFile::Type *rpmDatabaseIndex::GetType() const
1207 {
1208    return &_apt_DB;
1209 }
1210 #ifdef APT_WITH_REPOMD
1211 const pkgIndexFile::Type *rpmRepomdPkgIndex::GetType() const
1212 {
1213    return &_apt_Pkg;
1214 }
1215 const pkgIndexFile::Type *rpmRepomdSrcIndex::GetType() const
1216 {
1217    return &_apt_Src;
1218 }
1219 #endif
1220
1221                                                                         /*}}}*/
1222 #endif /* HAVE_RPM */
1223
1224 // vim:sts=3:sw=3