merged from http://bzr.debian.org/bzr/apt/apt/debian-experimental2
[ntk/apt.git] / apt-pkg / cacheset.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 /* ######################################################################
4
5 Simple wrapper around a std::set to provide a similar interface to
6 a set of cache structures as to the complete set of all structures
7 in the pkgCache. Currently only Package is supported.
8
9 ##################################################################### */
10 /*}}}*/
11 // Include Files /*{{{*/
12 #include <config.h>
13
14 #include <apt-pkg/aptconfiguration.h>
15 #include <apt-pkg/cachefile.h>
16 #include <apt-pkg/cachefilter.h>
17 #include <apt-pkg/cacheset.h>
18 #include <apt-pkg/error.h>
19 #include <apt-pkg/strutl.h>
20 #include <apt-pkg/versionmatch.h>
21 #include <apt-pkg/pkgrecords.h>
22 #include <apt-pkg/policy.h>
23
24 #include <vector>
25
26 #include <regex.h>
27
28 #include <apti18n.h>
29 /*}}}*/
30 namespace APT {
31 // FromTask - Return all packages in the cache from a specific task /*{{{*/
32 PackageSet PackageSet::FromTask(pkgCacheFile &Cache, std::string pattern, CacheSetHelper &helper) {
33 size_t const archfound = pattern.find_last_of(':');
34 std::string arch = "native";
35 if (archfound != std::string::npos) {
36 arch = pattern.substr(archfound+1);
37 pattern.erase(archfound);
38 }
39
40 if (pattern[pattern.length() -1] != '^')
41 return APT::PackageSet(TASK);
42 pattern.erase(pattern.length()-1);
43
44 if (unlikely(Cache.GetPkgCache() == 0 || Cache.GetDepCache() == 0))
45 return APT::PackageSet(TASK);
46
47 PackageSet pkgset(TASK);
48 // get the records
49 pkgRecords Recs(Cache);
50
51 // build regexp for the task
52 regex_t Pattern;
53 char S[300];
54 snprintf(S, sizeof(S), "^Task:.*[, ]%s([, ]|$)", pattern.c_str());
55 if(regcomp(&Pattern,S, REG_EXTENDED | REG_NOSUB | REG_NEWLINE) != 0) {
56 _error->Error("Failed to compile task regexp");
57 return pkgset;
58 }
59
60 for (pkgCache::GrpIterator Grp = Cache->GrpBegin(); Grp.end() == false; ++Grp) {
61 pkgCache::PkgIterator Pkg = Grp.FindPkg(arch);
62 if (Pkg.end() == true)
63 continue;
64 pkgCache::VerIterator ver = Cache[Pkg].CandidateVerIter(Cache);
65 if(ver.end() == true)
66 continue;
67
68 pkgRecords::Parser &parser = Recs.Lookup(ver.FileList());
69 const char *start, *end;
70 parser.GetRec(start,end);
71 unsigned int const length = end - start;
72 char buf[length];
73 strncpy(buf, start, length);
74 buf[length-1] = '\0';
75 if (regexec(&Pattern, buf, 0, 0, 0) != 0)
76 continue;
77
78 pkgset.insert(Pkg);
79 }
80 regfree(&Pattern);
81
82 if (pkgset.empty() == true)
83 return helper.canNotFindTask(Cache, pattern);
84
85 helper.showTaskSelection(pkgset, pattern);
86 return pkgset;
87 }
88 /*}}}*/
89 // FromRegEx - Return all packages in the cache matching a pattern /*{{{*/
90 PackageSet PackageSet::FromRegEx(pkgCacheFile &Cache, std::string pattern, CacheSetHelper &helper) {
91 static const char * const isregex = ".?+*|[^$";
92 if (pattern.find_first_of(isregex) == std::string::npos)
93 return PackageSet(REGEX);
94
95 size_t archfound = pattern.find_last_of(':');
96 std::string arch = "native";
97 if (archfound != std::string::npos) {
98 arch = pattern.substr(archfound+1);
99 if (arch.find_first_of(isregex) == std::string::npos)
100 pattern.erase(archfound);
101 else
102 arch = "native";
103 }
104
105 if (unlikely(Cache.GetPkgCache() == 0))
106 return PackageSet(REGEX);
107
108 APT::CacheFilter::PackageNameMatchesRegEx regexfilter(pattern);
109
110 PackageSet pkgset(REGEX);
111 for (pkgCache::GrpIterator Grp = Cache.GetPkgCache()->GrpBegin(); Grp.end() == false; ++Grp) {
112 if (regexfilter(Grp) == false)
113 continue;
114 pkgCache::PkgIterator Pkg = Grp.FindPkg(arch);
115 if (Pkg.end() == true) {
116 if (archfound == std::string::npos) {
117 std::vector<std::string> archs = APT::Configuration::getArchitectures();
118 for (std::vector<std::string>::const_iterator a = archs.begin();
119 a != archs.end() && Pkg.end() != true; ++a)
120 Pkg = Grp.FindPkg(*a);
121 }
122 if (Pkg.end() == true)
123 continue;
124 }
125
126 pkgset.insert(Pkg);
127 }
128
129 if (pkgset.empty() == true)
130 return helper.canNotFindRegEx(Cache, pattern);
131
132 helper.showRegExSelection(pkgset, pattern);
133 return pkgset;
134 }
135 /*}}}*/
136 // FromName - Returns the package defined by this string /*{{{*/
137 pkgCache::PkgIterator PackageSet::FromName(pkgCacheFile &Cache,
138 std::string const &str, CacheSetHelper &helper) {
139 std::string pkg = str;
140 size_t archfound = pkg.find_last_of(':');
141 std::string arch;
142 if (archfound != std::string::npos) {
143 arch = pkg.substr(archfound+1);
144 pkg.erase(archfound);
145 }
146
147 if (Cache.GetPkgCache() == 0)
148 return pkgCache::PkgIterator(Cache, 0);
149
150 pkgCache::PkgIterator Pkg(Cache, 0);
151 if (arch.empty() == true) {
152 pkgCache::GrpIterator Grp = Cache.GetPkgCache()->FindGrp(pkg);
153 if (Grp.end() == false)
154 Pkg = Grp.FindPreferredPkg();
155 } else
156 Pkg = Cache.GetPkgCache()->FindPkg(pkg, arch);
157
158 if (Pkg.end() == true)
159 return helper.canNotFindPkgName(Cache, str);
160 return Pkg;
161 }
162 /*}}}*/
163 // GroupedFromCommandLine - Return all versions specified on commandline/*{{{*/
164 std::map<unsigned short, PackageSet> PackageSet::GroupedFromCommandLine(
165 pkgCacheFile &Cache, const char **cmdline,
166 std::list<PackageSet::Modifier> const &mods,
167 unsigned short const &fallback, CacheSetHelper &helper) {
168 std::map<unsigned short, PackageSet> pkgsets;
169 for (const char **I = cmdline; *I != 0; ++I) {
170 unsigned short modID = fallback;
171 std::string str = *I;
172 bool modifierPresent = false;
173 for (std::list<PackageSet::Modifier>::const_iterator mod = mods.begin();
174 mod != mods.end(); ++mod) {
175 size_t const alength = strlen(mod->Alias);
176 switch(mod->Pos) {
177 case PackageSet::Modifier::POSTFIX:
178 if (str.compare(str.length() - alength, alength,
179 mod->Alias, 0, alength) != 0)
180 continue;
181 str.erase(str.length() - alength);
182 modID = mod->ID;
183 break;
184 case PackageSet::Modifier::PREFIX:
185 continue;
186 case PackageSet::Modifier::NONE:
187 continue;
188 }
189 modifierPresent = true;
190 break;
191 }
192 if (modifierPresent == true) {
193 bool const errors = helper.showErrors(false);
194 pkgCache::PkgIterator Pkg = FromName(Cache, *I, helper);
195 helper.showErrors(errors);
196 if (Pkg.end() == false) {
197 pkgsets[fallback].insert(Pkg);
198 continue;
199 }
200 }
201 pkgsets[modID].insert(PackageSet::FromString(Cache, str, helper));
202 }
203 return pkgsets;
204 }
205 /*}}}*/
206 // FromCommandLine - Return all packages specified on commandline /*{{{*/
207 PackageSet PackageSet::FromCommandLine(pkgCacheFile &Cache, const char **cmdline, CacheSetHelper &helper) {
208 PackageSet pkgset;
209 for (const char **I = cmdline; *I != 0; ++I) {
210 PackageSet pset = FromString(Cache, *I, helper);
211 pkgset.insert(pset.begin(), pset.end());
212 }
213 return pkgset;
214 }
215 /*}}}*/
216 // FromString - Return all packages matching a specific string /*{{{*/
217 PackageSet PackageSet::FromString(pkgCacheFile &Cache, std::string const &str, CacheSetHelper &helper) {
218 _error->PushToStack();
219
220 PackageSet pkgset;
221 pkgCache::PkgIterator Pkg = FromName(Cache, str, helper);
222 if (Pkg.end() == false)
223 pkgset.insert(Pkg);
224 else {
225 pkgset = FromTask(Cache, str, helper);
226 if (pkgset.empty() == true) {
227 pkgset = FromRegEx(Cache, str, helper);
228 if (pkgset.empty() == true)
229 pkgset = helper.canNotFindPackage(Cache, str);
230 }
231 }
232
233 if (pkgset.empty() == false)
234 _error->RevertToStack();
235 else
236 _error->MergeWithStack();
237 return pkgset;
238 }
239 /*}}}*/
240 // GroupedFromCommandLine - Return all versions specified on commandline/*{{{*/
241 std::map<unsigned short, VersionSet> VersionSet::GroupedFromCommandLine(
242 pkgCacheFile &Cache, const char **cmdline,
243 std::list<VersionSet::Modifier> const &mods,
244 unsigned short const &fallback, CacheSetHelper &helper) {
245 std::map<unsigned short, VersionSet> versets;
246 for (const char **I = cmdline; *I != 0; ++I) {
247 unsigned short modID = fallback;
248 VersionSet::Version select = VersionSet::NEWEST;
249 std::string str = *I;
250 bool modifierPresent = false;
251 for (std::list<VersionSet::Modifier>::const_iterator mod = mods.begin();
252 mod != mods.end(); ++mod) {
253 if (modID == fallback && mod->ID == fallback)
254 select = mod->SelectVersion;
255 size_t const alength = strlen(mod->Alias);
256 switch(mod->Pos) {
257 case VersionSet::Modifier::POSTFIX:
258 if (str.compare(str.length() - alength, alength,
259 mod->Alias, 0, alength) != 0)
260 continue;
261 str.erase(str.length() - alength);
262 modID = mod->ID;
263 select = mod->SelectVersion;
264 break;
265 case VersionSet::Modifier::PREFIX:
266 continue;
267 case VersionSet::Modifier::NONE:
268 continue;
269 }
270 modifierPresent = true;
271 break;
272 }
273
274 if (modifierPresent == true) {
275 bool const errors = helper.showErrors(false);
276 VersionSet const vset = VersionSet::FromString(Cache, std::string(*I), select, helper, true);
277 helper.showErrors(errors);
278 if (vset.empty() == false) {
279 versets[fallback].insert(vset);
280 continue;
281 }
282 }
283 versets[modID].insert(VersionSet::FromString(Cache, str, select , helper));
284 }
285 return versets;
286 }
287 /*}}}*/
288 // FromCommandLine - Return all versions specified on commandline /*{{{*/
289 APT::VersionSet VersionSet::FromCommandLine(pkgCacheFile &Cache, const char **cmdline,
290 APT::VersionSet::Version const &fallback, CacheSetHelper &helper) {
291 VersionSet verset;
292 for (const char **I = cmdline; *I != 0; ++I)
293 verset.insert(VersionSet::FromString(Cache, *I, fallback, helper));
294 return verset;
295 }
296 /*}}}*/
297 // FromString - Returns all versions spedcified by a string /*{{{*/
298 APT::VersionSet VersionSet::FromString(pkgCacheFile &Cache, std::string pkg,
299 APT::VersionSet::Version const &fallback, CacheSetHelper &helper,
300 bool const &onlyFromName) {
301 std::string ver;
302 bool verIsRel = false;
303 size_t const vertag = pkg.find_last_of("/=");
304 if (vertag != std::string::npos) {
305 ver = pkg.substr(vertag+1);
306 verIsRel = (pkg[vertag] == '/');
307 pkg.erase(vertag);
308 }
309 PackageSet pkgset;
310 if (onlyFromName == false)
311 pkgset = PackageSet::FromString(Cache, pkg, helper);
312 else {
313 pkgset.insert(PackageSet::FromName(Cache, pkg, helper));
314 }
315
316 VersionSet verset;
317 bool errors = true;
318 if (pkgset.getConstructor() != PackageSet::UNKNOWN)
319 errors = helper.showErrors(false);
320 for (PackageSet::const_iterator P = pkgset.begin();
321 P != pkgset.end(); ++P) {
322 if (vertag == std::string::npos) {
323 verset.insert(VersionSet::FromPackage(Cache, P, fallback, helper));
324 continue;
325 }
326 pkgCache::VerIterator V;
327 if (ver == "installed")
328 V = getInstalledVer(Cache, P, helper);
329 else if (ver == "candidate")
330 V = getCandidateVer(Cache, P, helper);
331 else if (ver == "newest") {
332 if (P->VersionList != 0)
333 V = P.VersionList();
334 else
335 V = helper.canNotFindNewestVer(Cache, P);
336 } else {
337 pkgVersionMatch Match(ver, (verIsRel == true ? pkgVersionMatch::Release :
338 pkgVersionMatch::Version));
339 V = Match.Find(P);
340 if (V.end() == true) {
341 if (verIsRel == true)
342 _error->Error(_("Release '%s' for '%s' was not found"),
343 ver.c_str(), P.FullName(true).c_str());
344 else
345 _error->Error(_("Version '%s' for '%s' was not found"),
346 ver.c_str(), P.FullName(true).c_str());
347 continue;
348 }
349 }
350 if (V.end() == true)
351 continue;
352 helper.showSelectedVersion(P, V, ver, verIsRel);
353 verset.insert(V);
354 }
355 if (pkgset.getConstructor() != PackageSet::UNKNOWN)
356 helper.showErrors(errors);
357 return verset;
358 }
359 /*}}}*/
360 // FromPackage - versions from package based on fallback /*{{{*/
361 VersionSet VersionSet::FromPackage(pkgCacheFile &Cache, pkgCache::PkgIterator const &P,
362 VersionSet::Version const &fallback, CacheSetHelper &helper) {
363 VersionSet verset;
364 pkgCache::VerIterator V;
365 bool showErrors;
366 switch(fallback) {
367 case VersionSet::ALL:
368 if (P->VersionList != 0)
369 for (V = P.VersionList(); V.end() != true; ++V)
370 verset.insert(V);
371 else
372 verset.insert(helper.canNotFindAllVer(Cache, P));
373 break;
374 case VersionSet::CANDANDINST:
375 verset.insert(getInstalledVer(Cache, P, helper));
376 verset.insert(getCandidateVer(Cache, P, helper));
377 break;
378 case VersionSet::CANDIDATE:
379 verset.insert(getCandidateVer(Cache, P, helper));
380 break;
381 case VersionSet::INSTALLED:
382 verset.insert(getInstalledVer(Cache, P, helper));
383 break;
384 case VersionSet::CANDINST:
385 showErrors = helper.showErrors(false);
386 V = getCandidateVer(Cache, P, helper);
387 if (V.end() == true)
388 V = getInstalledVer(Cache, P, helper);
389 helper.showErrors(showErrors);
390 if (V.end() == false)
391 verset.insert(V);
392 else
393 verset.insert(helper.canNotFindInstCandVer(Cache, P));
394 break;
395 case VersionSet::INSTCAND:
396 showErrors = helper.showErrors(false);
397 V = getInstalledVer(Cache, P, helper);
398 if (V.end() == true)
399 V = getCandidateVer(Cache, P, helper);
400 helper.showErrors(showErrors);
401 if (V.end() == false)
402 verset.insert(V);
403 else
404 verset.insert(helper.canNotFindInstCandVer(Cache, P));
405 break;
406 case VersionSet::NEWEST:
407 if (P->VersionList != 0)
408 verset.insert(P.VersionList());
409 else
410 verset.insert(helper.canNotFindNewestVer(Cache, P));
411 break;
412 }
413 return verset;
414 }
415 /*}}}*/
416 // getCandidateVer - Returns the candidate version of the given package /*{{{*/
417 pkgCache::VerIterator VersionSet::getCandidateVer(pkgCacheFile &Cache,
418 pkgCache::PkgIterator const &Pkg, CacheSetHelper &helper) {
419 pkgCache::VerIterator Cand;
420 if (Cache.IsPolicyBuilt() == true || Cache.IsDepCacheBuilt() == false)
421 {
422 if (unlikely(Cache.GetPolicy() == 0))
423 return pkgCache::VerIterator(Cache);
424 Cand = Cache.GetPolicy()->GetCandidateVer(Pkg);
425 } else {
426 Cand = Cache[Pkg].CandidateVerIter(Cache);
427 }
428 if (Cand.end() == true)
429 return helper.canNotFindCandidateVer(Cache, Pkg);
430 return Cand;
431 }
432 /*}}}*/
433 // getInstalledVer - Returns the installed version of the given package /*{{{*/
434 pkgCache::VerIterator VersionSet::getInstalledVer(pkgCacheFile &Cache,
435 pkgCache::PkgIterator const &Pkg, CacheSetHelper &helper) {
436 if (Pkg->CurrentVer == 0)
437 return helper.canNotFindInstalledVer(Cache, Pkg);
438 return Pkg.CurrentVer();
439 }
440 /*}}}*/
441 // canNotFindPkgName - handle the case no package has this name /*{{{*/
442 pkgCache::PkgIterator CacheSetHelper::canNotFindPkgName(pkgCacheFile &Cache,
443 std::string const &str) {
444 if (ShowError == true)
445 _error->Insert(ErrorType, _("Unable to locate package %s"), str.c_str());
446 return pkgCache::PkgIterator(Cache, 0);
447 }
448 /*}}}*/
449 // canNotFindTask - handle the case no package is found for a task /*{{{*/
450 PackageSet CacheSetHelper::canNotFindTask(pkgCacheFile &Cache, std::string pattern) {
451 if (ShowError == true)
452 _error->Insert(ErrorType, _("Couldn't find task '%s'"), pattern.c_str());
453 return PackageSet();
454 }
455 /*}}}*/
456 // canNotFindRegEx - handle the case no package is found by a regex /*{{{*/
457 PackageSet CacheSetHelper::canNotFindRegEx(pkgCacheFile &Cache, std::string pattern) {
458 if (ShowError == true)
459 _error->Insert(ErrorType, _("Couldn't find any package by regex '%s'"), pattern.c_str());
460 return PackageSet();
461 }
462 /*}}}*/
463 // canNotFindPackage - handle the case no package is found from a string/*{{{*/
464 PackageSet CacheSetHelper::canNotFindPackage(pkgCacheFile &Cache, std::string const &str) {
465 return PackageSet();
466 }
467 /*}}}*/
468 // canNotFindAllVer /*{{{*/
469 VersionSet CacheSetHelper::canNotFindAllVer(pkgCacheFile &Cache,
470 pkgCache::PkgIterator const &Pkg) {
471 if (ShowError == true)
472 _error->Insert(ErrorType, _("Can't select versions from package '%s' as it is purely virtual"), Pkg.FullName(true).c_str());
473 return VersionSet();
474 }
475 /*}}}*/
476 // canNotFindInstCandVer /*{{{*/
477 VersionSet CacheSetHelper::canNotFindInstCandVer(pkgCacheFile &Cache,
478 pkgCache::PkgIterator const &Pkg) {
479 if (ShowError == true)
480 _error->Insert(ErrorType, _("Can't select installed nor candidate version from package '%s' as it has neither of them"), Pkg.FullName(true).c_str());
481 return VersionSet();
482 }
483 /*}}}*/
484 // canNotFindInstCandVer /*{{{*/
485 VersionSet CacheSetHelper::canNotFindCandInstVer(pkgCacheFile &Cache,
486 pkgCache::PkgIterator const &Pkg) {
487 if (ShowError == true)
488 _error->Insert(ErrorType, _("Can't select installed nor candidate version from package '%s' as it has neither of them"), Pkg.FullName(true).c_str());
489 return VersionSet();
490 }
491 /*}}}*/
492 // canNotFindNewestVer /*{{{*/
493 pkgCache::VerIterator CacheSetHelper::canNotFindNewestVer(pkgCacheFile &Cache,
494 pkgCache::PkgIterator const &Pkg) {
495 if (ShowError == true)
496 _error->Insert(ErrorType, _("Can't select newest version from package '%s' as it is purely virtual"), Pkg.FullName(true).c_str());
497 return pkgCache::VerIterator(Cache, 0);
498 }
499 /*}}}*/
500 // canNotFindCandidateVer /*{{{*/
501 pkgCache::VerIterator CacheSetHelper::canNotFindCandidateVer(pkgCacheFile &Cache,
502 pkgCache::PkgIterator const &Pkg) {
503 if (ShowError == true)
504 _error->Insert(ErrorType, _("Can't select candidate version from package %s as it has no candidate"), Pkg.FullName(true).c_str());
505 return pkgCache::VerIterator(Cache, 0);
506 }
507 /*}}}*/
508 // canNotFindInstalledVer /*{{{*/
509 pkgCache::VerIterator CacheSetHelper::canNotFindInstalledVer(pkgCacheFile &Cache,
510 pkgCache::PkgIterator const &Pkg) {
511 if (ShowError == true)
512 _error->Insert(ErrorType, _("Can't select installed version from package %s as it is not installed"), Pkg.FullName(true).c_str());
513 return pkgCache::VerIterator(Cache, 0);
514 }
515 /*}}}*/
516 }