- initial import of revision 374 from cnc
[apt.git] / apt-pkg / rpm / rpmpackagedata.cc
1
2 #include <config.h>
3
4 #ifdef HAVE_RPM
5
6 #include <apt-pkg/error.h>
7 #include <apt-pkg/rpmpackagedata.h>
8 #include <apt-pkg/fileutl.h>
9 #include <apt-pkg/strutl.h>
10 #include <apt-pkg/configuration.h>
11 #include <apt-pkg/version.h>
12
13 #include <apti18n.h>
14
15 #include <rpm/rpmlib.h>
16
17 RPMPackageData::RPMPackageData()
18    : MinArchScore(-1)
19 #ifdef WITH_HASH_MAP
20    , ArchScores(31), VerMap(517)
21 #endif
22 {
23    // Populate priorities
24    string FileName = _config->FindFile("Dir::Etc::rpmpriorities");
25    FileFd F(FileName, FileFd::ReadOnly);
26    if (_error->PendingError()) 
27    {
28       _error->Error(_("could not open package priority file %s"),
29                     FileName.c_str());
30       return;
31    }
32    pkgTagFile Tags(&F);
33    pkgTagSection Section;
34
35    if (!Tags.Step(Section)) 
36    {
37       _error->Error(_("no data in %s"), FileName.c_str());
38        return;
39    }
40    
41    for (int i = 0; i != 6; i++) 
42    {
43       const char *priorities[] = 
44       {
45          "Essential", "Important", "Required", "Standard", "Optional", "Extra"
46       };
47       pkgCache::State::VerPriority states[] = {
48              pkgCache::State::Important,
49              pkgCache::State::Important,
50              pkgCache::State::Required,
51              pkgCache::State::Standard,
52              pkgCache::State::Optional,
53              pkgCache::State::Extra
54       };
55       pkgCache::Flag::PkgFlags flags[] = {
56              pkgCache::Flag::Essential,
57              pkgCache::Flag::Important,
58              pkgCache::Flag::Important,
59              (pkgCache::Flag::PkgFlags)0,
60              (pkgCache::Flag::PkgFlags)0,
61              (pkgCache::Flag::PkgFlags)0
62       };
63
64       string Packages = Section.FindS(priorities[i]);
65       if (Packages.empty()) 
66          continue;
67
68       const char *C = Packages.c_str();
69       while (*C != 0)
70       {
71          string pkg;
72          if (ParseQuoteWord(C,pkg))
73          {
74             Priorities[pkg] = states[i];
75             Flags[pkg] = flags[i];
76          }
77       }
78    }
79
80    // Populate holding packages
81    const Configuration::Item *Top = _config->Tree("RPM::Hold");
82    for (Top = (Top == 0?0:Top->Child); Top != 0; Top = Top->Next)
83    {
84       regex_t *ptrn = new regex_t;
85       if (regcomp(ptrn,Top->Value.c_str(),REG_EXTENDED|REG_ICASE|REG_NOSUB) != 0)
86       {
87          _error->Warning(_("Bad regular expression '%s' in option RPM::Hold."),
88                          Top->Value.c_str());
89          delete ptrn;
90       }
91       else
92           HoldPackages.push_back(ptrn);
93    }
94
95    // Populate ignored packages
96    Top = _config->Tree("RPM::Ignore");
97    for (Top = (Top == 0?0:Top->Child); Top != 0; Top = Top->Next)
98       IgnorePackages[Top->Value] = 1;
99
100    // Populate Allow-Duplicated packages.
101    Top = _config->Tree("RPM::Allow-Duplicated");
102    for (Top = (Top == 0?0:Top->Child); Top != 0; Top = Top->Next)
103    {
104       regex_t *ptrn = new regex_t;
105       if (regcomp(ptrn,Top->Value.c_str(),REG_EXTENDED|REG_ICASE|REG_NOSUB) != 0)
106       {
107          _error->Warning(_("Bad regular expression '%s' in option RPM::Allow-Duplicated."),
108                          Top->Value.c_str());
109          delete ptrn;
110       }
111       else
112           DuplicatedPatterns.push_back(ptrn);
113    }
114
115    // Populate fake provides
116    Top = _config->Tree("RPM::Fake-Provides");
117    for (Top = (Top == 0?0:Top->Child); Top != 0; Top = Top->Next)
118    {
119       string Name = "";
120       string Version = "";
121       const char *C = Top->Value.c_str();
122       if (ParseQuoteWord(C,Name) == false)
123       {
124          _error->Warning(_("Bad entry '%s' in option RPM::FakeProvides."),
125                          Top->Value.c_str());
126          continue;
127       }
128       ParseQuoteWord(C,Version);
129
130       if (Version.empty() == true)
131       {
132          delete FakeProvides[Name];
133          FakeProvides[Name] = NULL;
134       }
135       else
136       {
137          if (FakeProvides.find(Name) != FakeProvides.end())
138          {
139             // If it's NULL, it was provided with an empty version
140             if (FakeProvides[Name] != NULL)
141                FakeProvides[Name]->push_back(Version);
142          }
143          else
144          {
145             vector<string> *VerList = new vector<string>;
146             VerList->push_back(Version);
147             FakeProvides[Name] = VerList;
148          }
149       }
150    }
151
152
153    // Populate translations
154    Configuration Cnf;
155    string CnfFile = _config->FindDir("Dir::Etc::translateparts");
156    if (FileExists(CnfFile) == true)
157       if (ReadConfigDir(Cnf,CnfFile,true) == false)
158          return;
159    CnfFile = _config->FindFile("Dir::Etc::translatelist");
160    if (FileExists(CnfFile) == true)
161       if (ReadConfigFile(Cnf,CnfFile,true) == false)
162          return;
163
164    const char *TString[] = {"translate-binary",
165                             "translate-source",
166                             "translate-index"};
167    vector<Translate*> *TList[] = {&BinaryTranslations,
168                                   &SourceTranslations,
169                                   &IndexTranslations};
170    for (int i = 0; i != 3; i++)
171    {
172       Top = Cnf.Tree(TString[i]);
173       for (Top = (Top == 0?0:Top->Child); Top != 0; Top = Top->Next)
174       {
175          Translate *t = new Translate();
176          if (regcomp(&t->Pattern,Top->Tag.c_str(),REG_EXTENDED|REG_ICASE|REG_NOSUB) != 0)
177          {
178             _error->Warning(_("Bad regular expression '%s' in URI translation"),
179                             Top->Tag.c_str());
180             delete t;
181          }
182          else
183          {
184             Configuration Block(Top);
185             t->Template = Block.Find("Template");
186             TList[i]->push_back(t);
187          }
188       }
189    }
190 }
191
192 bool RPMPackageData::HoldPackage(const char *name)
193 {
194    for (vector<regex_t*>::iterator I = HoldPackages.begin();
195         I != HoldPackages.end(); I++)
196       if (regexec(*I,name,0,0,0) == 0)
197          return true;
198    return false;
199 }
200
201 bool RPMPackageData::IgnoreDep(pkgVersioningSystem &VS,
202                                pkgCache::DepIterator &Dep)
203 {
204    const char *name = Dep.TargetPkg().Name();
205    if (FakeProvides.find(name) != FakeProvides.end()) {
206       vector<string> *VerList = FakeProvides[name];
207       if (VerList == NULL)
208          return true;
209       for (vector<string>::iterator I = VerList->begin();
210            I != VerList->end(); I++)
211       {
212          if (VS.CheckDep(I->c_str(),Dep->CompareOp,Dep.TargetVer()) == true)
213             return true;
214       }
215    }
216    return false;
217 }
218
219 static void ParseTemplate(string &Template, map<string,string> &Dict)
220 {
221    string::size_type start(string::npos);
222    string::size_type end(string::npos);
223    string::size_type last_start;
224    while (true)
225    {
226       last_start = start;
227       start = Template.rfind("%(", end);
228       if (start == string::npos)
229          break;
230       end = Template.find(")", start);
231       if (end < last_start)
232       {
233          string Key(Template,start+2,end-(start+2));
234          map<string,string>::const_iterator I = Dict.find(Key);
235          if (I != Dict.end())
236             Template.replace(start, end-start+1, I->second);
237       }
238       if (start == 0)
239          break;
240       end = start-1;
241    }
242 }
243
244 void RPMPackageData::GenericTranslate(vector<Translate*> &TList,
245                                       string &FullURI,
246                                       map<string,string> &Dict)
247 {
248    const char *fulluri = FullURI.c_str();
249    for (vector<Translate*>::iterator I = TList.begin(); I != TList.end(); I++)
250    {
251       if (regexec(&(*I)->Pattern,fulluri,0,0,0) == 0)
252       {
253          FullURI = (*I)->Template;
254          ParseTemplate(FullURI, Dict);
255          break;
256       }
257    }
258 }
259
260 void RPMPackageData::InitMinArchScore()
261 {
262    if (MinArchScore != -1)
263       return;
264    string Arch = _config->Find("RPM::Architecture", "");
265    if (Arch.empty() == false)
266       MinArchScore = rpmMachineScore(RPM_MACHTABLE_INSTARCH, Arch.c_str());
267    else
268       MinArchScore = 0;
269 }
270
271 int RPMPackageData::RpmArchScore(const char *Arch)
272 {
273    int Score = rpmMachineScore(RPM_MACHTABLE_INSTARCH, Arch);
274    if (Score >= MinArchScore)
275       return Score;
276    return 0;
277 }
278
279 bool RPMPackageData::IsDupPackage(const string &Name)
280 {
281    if (DuplicatedPackages.find(Name) != DuplicatedPackages.end())
282       return true;
283    const char *name = Name.c_str();
284    for (vector<regex_t*>::iterator I = DuplicatedPatterns.begin();
285         I != DuplicatedPatterns.end(); I++) {
286       if (regexec(*I,name,0,0,0) == 0) {
287          SetDupPackage(Name);
288          return true;
289       }
290    }
291    return false;
292 }
293
294 RPMPackageData *RPMPackageData::Singleton()
295 {
296    static RPMPackageData *data = NULL;
297    if (!data)
298       data = new RPMPackageData();
299    return data;
300 }
301
302 #endif /* HAVE_RPM */
303 // vim:sw=3:sts=3