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