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