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