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