- initial multilib support (only packages in the same repository are considered)
[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 MultiArch packages.
116    Top = _config->Tree("RPM::MultiArch");
117    for (Top = (Top == 0?0:Top->Child); Top != 0; Top = Top->Next)
118    {
119       regex_t *ptrn = new regex_t;
120       if (regcomp(ptrn,Top->Value.c_str(),REG_EXTENDED|REG_ICASE|REG_NOSUB) != 0)
121       {
122          _error->Warning(_("Bad regular expression '%s' in option RPM::MultiArch."),
123                          Top->Value.c_str());
124          delete ptrn;
125       }
126       else
127           MultiArchPatterns.push_back(ptrn);
128    }
129
130    // Populate fake provides
131    Top = _config->Tree("RPM::Fake-Provides");
132    for (Top = (Top == 0?0:Top->Child); Top != 0; Top = Top->Next)
133    {
134       string Name = "";
135       string Version = "";
136       const char *C = Top->Value.c_str();
137       if (ParseQuoteWord(C,Name) == false)
138       {
139          _error->Warning(_("Bad entry '%s' in option RPM::FakeProvides."),
140                          Top->Value.c_str());
141          continue;
142       }
143       ParseQuoteWord(C,Version);
144
145       if (Version.empty() == true)
146       {
147          delete FakeProvides[Name];
148          FakeProvides[Name] = NULL;
149       }
150       else
151       {
152          if (FakeProvides.find(Name) != FakeProvides.end())
153          {
154             // If it's NULL, it was provided with an empty version
155             if (FakeProvides[Name] != NULL)
156                FakeProvides[Name]->push_back(Version);
157          }
158          else
159          {
160             vector<string> *VerList = new vector<string>;
161             VerList->push_back(Version);
162             FakeProvides[Name] = VerList;
163          }
164       }
165    }
166
167
168    // Populate translations
169    Configuration Cnf;
170    string CnfFile = _config->FindDir("Dir::Etc::translateparts");
171    if (FileExists(CnfFile) == true)
172       if (ReadConfigDir(Cnf,CnfFile,true) == false)
173          return;
174    CnfFile = _config->FindFile("Dir::Etc::translatelist");
175    if (FileExists(CnfFile) == true)
176       if (ReadConfigFile(Cnf,CnfFile,true) == false)
177          return;
178
179    const char *TString[] = {"translate-binary",
180                             "translate-source",
181                             "translate-index"};
182    vector<Translate*> *TList[] = {&BinaryTranslations,
183                                   &SourceTranslations,
184                                   &IndexTranslations};
185    for (int i = 0; i != 3; i++)
186    {
187       Top = Cnf.Tree(TString[i]);
188       for (Top = (Top == 0?0:Top->Child); Top != 0; Top = Top->Next)
189       {
190          Translate *t = new Translate();
191          if (regcomp(&t->Pattern,Top->Tag.c_str(),REG_EXTENDED|REG_ICASE|REG_NOSUB) != 0)
192          {
193             _error->Warning(_("Bad regular expression '%s' in URI translation"),
194                             Top->Tag.c_str());
195             delete t;
196          }
197          else
198          {
199             Configuration Block(Top);
200             t->Template = Block.Find("Template");
201             TList[i]->push_back(t);
202          }
203       }
204    }
205 }
206
207 bool RPMPackageData::HoldPackage(const char *name)
208 {
209    for (vector<regex_t*>::iterator I = HoldPackages.begin();
210         I != HoldPackages.end(); I++)
211       if (regexec(*I,name,0,0,0) == 0)
212          return true;
213    return false;
214 }
215
216 bool RPMPackageData::IgnoreDep(pkgVersioningSystem &VS,
217                                pkgCache::DepIterator &Dep)
218 {
219    const char *name = Dep.TargetPkg().Name();
220    if (FakeProvides.find(name) != FakeProvides.end()) {
221       vector<string> *VerList = FakeProvides[name];
222       if (VerList == NULL)
223          return true;
224       for (vector<string>::iterator I = VerList->begin();
225            I != VerList->end(); I++)
226       {
227          if (VS.CheckDep(I->c_str(),Dep->CompareOp,Dep.TargetVer()) == true)
228             return true;
229       }
230    }
231    return false;
232 }
233
234 static void ParseTemplate(string &Template, map<string,string> &Dict)
235 {
236    string::size_type start(string::npos);
237    string::size_type end(string::npos);
238    string::size_type last_start;
239    while (true)
240    {
241       last_start = start;
242       start = Template.rfind("%(", end);
243       if (start == string::npos)
244          break;
245       end = Template.find(")", start);
246       if (end < last_start)
247       {
248          string Key(Template,start+2,end-(start+2));
249          map<string,string>::const_iterator I = Dict.find(Key);
250          if (I != Dict.end())
251             Template.replace(start, end-start+1, I->second);
252       }
253       if (start == 0)
254          break;
255       end = start-1;
256    }
257 }
258
259 void RPMPackageData::GenericTranslate(vector<Translate*> &TList,
260                                       string &FullURI,
261                                       map<string,string> &Dict)
262 {
263    const char *fulluri = FullURI.c_str();
264    for (vector<Translate*>::iterator I = TList.begin(); I != TList.end(); I++)
265    {
266       if (regexec(&(*I)->Pattern,fulluri,0,0,0) == 0)
267       {
268          FullURI = (*I)->Template;
269          ParseTemplate(FullURI, Dict);
270          break;
271       }
272    }
273 }
274
275 void RPMPackageData::InitMinArchScore()
276 {
277    if (MinArchScore != -1)
278       return;
279    string Arch = _config->Find("RPM::Architecture", "");
280    if (Arch.empty() == false)
281       MinArchScore = rpmMachineScore(RPM_MACHTABLE_INSTARCH, Arch.c_str());
282    else
283       MinArchScore = 0;
284 }
285
286 int RPMPackageData::RpmArchScore(const char *Arch)
287 {
288    int Score = rpmMachineScore(RPM_MACHTABLE_INSTARCH, Arch);
289    if (Score >= MinArchScore)
290       return Score;
291    return 0;
292 }
293
294 bool RPMPackageData::IsDupPackage(const string &Name)
295 {
296    if (DuplicatedPackages.find(Name) != DuplicatedPackages.end())
297       return true;
298    const char *name = Name.c_str();
299    for (vector<regex_t*>::iterator I = DuplicatedPatterns.begin();
300         I != DuplicatedPatterns.end(); I++) {
301       if (regexec(*I,name,0,0,0) == 0) {
302          SetDupPackage(Name);
303          return true;
304       }
305    }
306    return false;
307 }
308
309 bool RPMPackageData::IsMultiArchPackage(const string &Name)
310 {
311    if (MultiArchPackages.find(Name) != MultiArchPackages.end())
312       return true;
313    const char *name = Name.c_str();
314    for (vector<regex_t*>::iterator I = MultiArchPatterns.begin();
315         I != MultiArchPatterns.end(); I++) {
316       if (regexec(*I,name,0,0,0) == 0) {
317          SetMultiArchPackage(Name);
318          return true;
319       }
320    }
321    return false;
322 }
323 RPMPackageData *RPMPackageData::Singleton()
324 {
325    static RPMPackageData *data = NULL;
326    if (!data)
327       data = new RPMPackageData();
328    return data;
329 }
330
331 #endif /* HAVE_RPM */
332 // vim:sw=3:sts=3