1 // -*- mode: cpp; mode: fold -*-
3 /* ######################################################################
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.
9 ##################################################################### */
11 // Include Files /*{{{*/
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>
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
);
40 if (pattern
[pattern
.length() -1] != '^')
41 return APT::PackageSet(TASK
);
42 pattern
.erase(pattern
.length()-1);
44 if (unlikely(Cache
.GetPkgCache() == 0 || Cache
.GetDepCache() == 0))
45 return APT::PackageSet(TASK
);
47 PackageSet
pkgset(TASK
);
49 pkgRecords
Recs(Cache
);
51 // build regexp for the task
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");
60 for (pkgCache::GrpIterator Grp
= Cache
->GrpBegin(); Grp
.end() == false; ++Grp
) {
61 pkgCache::PkgIterator Pkg
= Grp
.FindPkg(arch
);
62 if (Pkg
.end() == true)
64 pkgCache::VerIterator ver
= Cache
[Pkg
].CandidateVerIter(Cache
);
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
;
73 strncpy(buf
, start
, length
);
75 if (regexec(&Pattern
, buf
, 0, 0, 0) != 0)
82 if (pkgset
.empty() == true)
83 return helper
.canNotFindTask(Cache
, pattern
);
85 helper
.showTaskSelection(pkgset
, pattern
);
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
);
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
);
105 if (unlikely(Cache
.GetPkgCache() == 0))
106 return PackageSet(REGEX
);
108 APT::CacheFilter::PackageNameMatchesRegEx
regexfilter(pattern
);
110 PackageSet
pkgset(REGEX
);
111 for (pkgCache::GrpIterator Grp
= Cache
.GetPkgCache()->GrpBegin(); Grp
.end() == false; ++Grp
) {
112 if (regexfilter(Grp
) == false)
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
);
122 if (Pkg
.end() == true)
129 if (pkgset
.empty() == true)
130 return helper
.canNotFindRegEx(Cache
, pattern
);
132 helper
.showRegExSelection(pkgset
, pattern
);
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(':');
142 if (archfound
!= std::string::npos
) {
143 arch
= pkg
.substr(archfound
+1);
144 pkg
.erase(archfound
);
147 if (Cache
.GetPkgCache() == 0)
148 return pkgCache::PkgIterator(Cache
, 0);
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();
156 Pkg
= Cache
.GetPkgCache()->FindPkg(pkg
, arch
);
158 if (Pkg
.end() == true)
159 return helper
.canNotFindPkgName(Cache
, str
);
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
);
177 case PackageSet::Modifier::POSTFIX
:
178 if (str
.compare(str
.length() - alength
, alength
,
179 mod
->Alias
, 0, alength
) != 0)
181 str
.erase(str
.length() - alength
);
184 case PackageSet::Modifier::PREFIX
:
186 case PackageSet::Modifier::NONE
:
189 modifierPresent
= true;
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
);
201 pkgsets
[modID
].insert(PackageSet::FromString(Cache
, str
, helper
));
206 // FromCommandLine - Return all packages specified on commandline /*{{{*/
207 PackageSet
PackageSet::FromCommandLine(pkgCacheFile
&Cache
, const char **cmdline
, CacheSetHelper
&helper
) {
209 for (const char **I
= cmdline
; *I
!= 0; ++I
) {
210 PackageSet pset
= FromString(Cache
, *I
, helper
);
211 pkgset
.insert(pset
.begin(), pset
.end());
216 // FromString - Return all packages matching a specific string /*{{{*/
217 PackageSet
PackageSet::FromString(pkgCacheFile
&Cache
, std::string
const &str
, CacheSetHelper
&helper
) {
218 _error
->PushToStack();
221 pkgCache::PkgIterator Pkg
= FromName(Cache
, str
, helper
);
222 if (Pkg
.end() == false)
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
);
233 if (pkgset
.empty() == false)
234 _error
->RevertToStack();
236 _error
->MergeWithStack();
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
);
257 case VersionSet::Modifier::POSTFIX
:
258 if (str
.compare(str
.length() - alength
, alength
,
259 mod
->Alias
, 0, alength
) != 0)
261 str
.erase(str
.length() - alength
);
263 select
= mod
->SelectVersion
;
265 case VersionSet::Modifier::PREFIX
:
267 case VersionSet::Modifier::NONE
:
270 modifierPresent
= true;
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
);
283 versets
[modID
].insert(VersionSet::FromString(Cache
, str
, select
, helper
));
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
) {
292 for (const char **I
= cmdline
; *I
!= 0; ++I
)
293 verset
.insert(VersionSet::FromString(Cache
, *I
, fallback
, helper
));
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
) {
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
] == '/');
310 if (onlyFromName
== false)
311 pkgset
= PackageSet::FromString(Cache
, pkg
, helper
);
313 pkgset
.insert(PackageSet::FromName(Cache
, pkg
, helper
));
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
));
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)
335 V
= helper
.canNotFindNewestVer(Cache
, P
);
337 pkgVersionMatch
Match(ver
, (verIsRel
== true ? pkgVersionMatch::Release
:
338 pkgVersionMatch::Version
));
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());
345 _error
->Error(_("Version '%s' for '%s' was not found"),
346 ver
.c_str(), P
.FullName(true).c_str());
352 helper
.showSelectedVersion(P
, V
, ver
, verIsRel
);
355 if (pkgset
.getConstructor() != PackageSet::UNKNOWN
)
356 helper
.showErrors(errors
);
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
) {
364 pkgCache::VerIterator V
;
367 case VersionSet::ALL
:
368 if (P
->VersionList
!= 0)
369 for (V
= P
.VersionList(); V
.end() != true; ++V
)
372 verset
.insert(helper
.canNotFindAllVer(Cache
, P
));
374 case VersionSet::CANDANDINST
:
375 verset
.insert(getInstalledVer(Cache
, P
, helper
));
376 verset
.insert(getCandidateVer(Cache
, P
, helper
));
378 case VersionSet::CANDIDATE
:
379 verset
.insert(getCandidateVer(Cache
, P
, helper
));
381 case VersionSet::INSTALLED
:
382 verset
.insert(getInstalledVer(Cache
, P
, helper
));
384 case VersionSet::CANDINST
:
385 showErrors
= helper
.showErrors(false);
386 V
= getCandidateVer(Cache
, P
, helper
);
388 V
= getInstalledVer(Cache
, P
, helper
);
389 helper
.showErrors(showErrors
);
390 if (V
.end() == false)
393 verset
.insert(helper
.canNotFindInstCandVer(Cache
, P
));
395 case VersionSet::INSTCAND
:
396 showErrors
= helper
.showErrors(false);
397 V
= getInstalledVer(Cache
, P
, helper
);
399 V
= getCandidateVer(Cache
, P
, helper
);
400 helper
.showErrors(showErrors
);
401 if (V
.end() == false)
404 verset
.insert(helper
.canNotFindInstCandVer(Cache
, P
));
406 case VersionSet::NEWEST
:
407 if (P
->VersionList
!= 0)
408 verset
.insert(P
.VersionList());
410 verset
.insert(helper
.canNotFindNewestVer(Cache
, P
));
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)
422 if (unlikely(Cache
.GetPolicy() == 0))
423 return pkgCache::VerIterator(Cache
);
424 Cand
= Cache
.GetPolicy()->GetCandidateVer(Pkg
);
426 Cand
= Cache
[Pkg
].CandidateVerIter(Cache
);
428 if (Cand
.end() == true)
429 return helper
.canNotFindCandidateVer(Cache
, Pkg
);
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();
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);
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());
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());
463 // canNotFindPackage - handle the case no package is found from a string/*{{{*/
464 PackageSet
CacheSetHelper::canNotFindPackage(pkgCacheFile
&Cache
, std::string
const &str
) {
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());
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());
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());
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);
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);
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);