get packages by task^ with FromTask()
[ntk/apt.git] / cmdline / 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 <apt-pkg/aptconfiguration.h>
13 #include <apt-pkg/error.h>
14 #include <apt-pkg/strutl.h>
15 #include <apt-pkg/versionmatch.h>
16
17 #include <apti18n.h>
18
19 #include "cacheset.h"
20
21 #include <vector>
22
23 #include <regex.h>
24 /*}}}*/
25 namespace APT {
26 // FromTask - Return all packages in the cache from a specific task /*{{{*/
27 PackageSet PackageSet::FromTask(pkgCacheFile &Cache, std::string pattern, std::ostream &out) {
28 PackageSet pkgset;
29 if (Cache.BuildCaches() == false || Cache.BuildDepCache() == false)
30 return pkgset;
31
32 size_t archfound = pattern.find_last_of(':');
33 std::string arch = "native";
34 if (archfound != std::string::npos) {
35 arch = pattern.substr(archfound+1);
36 pattern.erase(archfound);
37 }
38
39 if (pattern[pattern.length() -1] != '^')
40 return pkgset;
41 pattern.erase(pattern.length()-1);
42
43 // get the records
44 pkgRecords Recs(Cache);
45
46 // build regexp for the task
47 regex_t Pattern;
48 char S[300];
49 snprintf(S, sizeof(S), "^Task:.*[, ]%s([, ]|$)", pattern.c_str());
50 if(regcomp(&Pattern,S, REG_EXTENDED | REG_NOSUB | REG_NEWLINE) != 0) {
51 _error->Error("Failed to compile task regexp");
52 return pkgset;
53 }
54
55 for (pkgCache::GrpIterator Grp = Cache->GrpBegin(); Grp.end() == false; ++Grp) {
56 pkgCache::PkgIterator Pkg = Grp.FindPkg(arch);
57 if (Pkg.end() == true)
58 continue;
59 pkgCache::VerIterator ver = Cache[Pkg].CandidateVerIter(Cache);
60 if(ver.end() == true)
61 continue;
62
63 pkgRecords::Parser &parser = Recs.Lookup(ver.FileList());
64 const char *start, *end;
65 parser.GetRec(start,end);
66 unsigned int const length = end - start;
67 char buf[length];
68 strncpy(buf, start, length);
69 buf[length-1] = '\0';
70 if (regexec(&Pattern, buf, 0, 0, 0) == 0)
71 pkgset.insert(Pkg);
72 }
73
74 if (pkgset.empty() == true)
75 _error->Error(_("Couldn't find task %s"), pattern.c_str());
76
77 regfree(&Pattern);
78 return pkgset;
79 }
80 /*}}}*/
81 // FromRegEx - Return all packages in the cache matching a pattern /*{{{*/
82 PackageSet PackageSet::FromRegEx(pkgCacheFile &Cache, std::string pattern, std::ostream &out) {
83 PackageSet pkgset;
84 static const char * const isregex = ".?+*|[^$";
85
86 if (pattern.find_first_of(isregex) == std::string::npos)
87 return pkgset;
88
89 size_t archfound = pattern.find_last_of(':');
90 std::string arch = "native";
91 if (archfound != std::string::npos) {
92 arch = pattern.substr(archfound+1);
93 if (arch.find_first_of(isregex) == std::string::npos)
94 pattern.erase(archfound);
95 else
96 arch = "native";
97 }
98
99 regex_t Pattern;
100 int Res;
101 if ((Res = regcomp(&Pattern, pattern.c_str() , REG_EXTENDED | REG_ICASE | REG_NOSUB)) != 0) {
102 char Error[300];
103 regerror(Res, &Pattern, Error, sizeof(Error));
104 _error->Error(_("Regex compilation error - %s"), Error);
105 return pkgset;
106 }
107
108 for (pkgCache::GrpIterator Grp = Cache.GetPkgCache()->GrpBegin(); Grp.end() == false; ++Grp)
109 {
110 if (regexec(&Pattern, Grp.Name(), 0, 0, 0) != 0)
111 continue;
112 pkgCache::PkgIterator Pkg = Grp.FindPkg(arch);
113 if (Pkg.end() == true) {
114 if (archfound == std::string::npos) {
115 std::vector<std::string> archs = APT::Configuration::getArchitectures();
116 for (std::vector<std::string>::const_iterator a = archs.begin();
117 a != archs.end() && Pkg.end() != true; ++a)
118 Pkg = Grp.FindPkg(*a);
119 }
120 if (Pkg.end() == true)
121 continue;
122 }
123
124 ioprintf(out, _("Note, selecting %s for regex '%s'\n"),
125 Pkg.FullName(true).c_str(), pattern.c_str());
126
127 pkgset.insert(Pkg);
128 }
129
130 regfree(&Pattern);
131
132 return pkgset;
133 }
134 /*}}}*/
135 // GroupedFromCommandLine - Return all versions specified on commandline/*{{{*/
136 std::map<unsigned short, PackageSet> PackageSet::GroupedFromCommandLine(
137 pkgCacheFile &Cache, const char **cmdline,
138 std::list<PackageSet::Modifier> const &mods,
139 unsigned short const &fallback, std::ostream &out) {
140 std::map<unsigned short, PackageSet> pkgsets;
141 for (const char **I = cmdline; *I != 0; ++I) {
142 unsigned short modID = fallback;
143 std::string str = *I;
144 for (std::list<PackageSet::Modifier>::const_iterator mod = mods.begin();
145 mod != mods.end(); ++mod) {
146 size_t const alength = strlen(mod->Alias);
147 switch(mod->Pos) {
148 case PackageSet::Modifier::POSTFIX:
149 if (str.compare(str.length() - alength, alength,
150 mod->Alias, 0, alength) != 0)
151 continue;
152 str.erase(str.length() - alength);
153 modID = mod->ID;
154 break;
155 case PackageSet::Modifier::PREFIX:
156 continue;
157 case PackageSet::Modifier::NONE:
158 continue;
159 }
160 break;
161 }
162 PackageSet pset = PackageSet::FromString(Cache, str, out);
163 pkgsets[modID].insert(pset.begin(), pset.end());
164 }
165 return pkgsets;
166 }
167 /*}}}*/
168 // FromCommandLine - Return all packages specified on commandline /*{{{*/
169 PackageSet PackageSet::FromCommandLine(pkgCacheFile &Cache, const char **cmdline, std::ostream &out) {
170 PackageSet pkgset;
171 for (const char **I = cmdline; *I != 0; ++I) {
172 PackageSet pset = FromString(Cache, *I, out);
173 pkgset.insert(pset.begin(), pset.end());
174 }
175 return pkgset;
176 }
177 /*}}}*/
178 // FromString - Return all packages matching a specific string /*{{{*/
179 PackageSet PackageSet::FromString(pkgCacheFile &Cache, std::string const &str, std::ostream &out) {
180 std::string pkg = str;
181 size_t archfound = pkg.find_last_of(':');
182 std::string arch;
183 if (archfound != std::string::npos) {
184 arch = pkg.substr(archfound+1);
185 pkg.erase(archfound);
186 }
187
188 pkgCache::PkgIterator Pkg;
189 if (arch.empty() == true) {
190 pkgCache::GrpIterator Grp = Cache.GetPkgCache()->FindGrp(pkg);
191 if (Grp.end() == false)
192 Pkg = Grp.FindPreferredPkg();
193 } else
194 Pkg = Cache.GetPkgCache()->FindPkg(pkg, arch);
195
196 if (Pkg.end() == false) {
197 PackageSet pkgset;
198 pkgset.insert(Pkg);
199 return pkgset;
200 }
201 PackageSet pset = FromTask(Cache, str, out);
202 if (pset.empty() == false)
203 return pset;
204
205 pset = FromRegEx(Cache, str, out);
206 if (pset.empty() == false)
207 return pset;
208
209 _error->Warning(_("Unable to locate package %s"), str.c_str());
210 return pset;
211 }
212 /*}}}*/
213 // GroupedFromCommandLine - Return all versions specified on commandline/*{{{*/
214 std::map<unsigned short, VersionSet> VersionSet::GroupedFromCommandLine(
215 pkgCacheFile &Cache, const char **cmdline,
216 std::list<VersionSet::Modifier> const &mods,
217 unsigned short const &fallback, std::ostream &out) {
218 std::map<unsigned short, VersionSet> versets;
219 for (const char **I = cmdline; *I != 0; ++I) {
220 unsigned short modID = fallback;
221 VersionSet::Version select = VersionSet::NEWEST;
222 std::string str = *I;
223 for (std::list<VersionSet::Modifier>::const_iterator mod = mods.begin();
224 mod != mods.end(); ++mod) {
225 if (modID == fallback && mod->ID == fallback)
226 select = mod->SelectVersion;
227 size_t const alength = strlen(mod->Alias);
228 switch(mod->Pos) {
229 case VersionSet::Modifier::POSTFIX:
230 if (str.compare(str.length() - alength, alength,
231 mod->Alias, 0, alength) != 0)
232 continue;
233 str.erase(str.length() - alength);
234 modID = mod->ID;
235 select = mod->SelectVersion;
236 break;
237 case VersionSet::Modifier::PREFIX:
238 continue;
239 case VersionSet::Modifier::NONE:
240 continue;
241 }
242 break;
243 }
244 VersionSet vset = VersionSet::FromString(Cache, str, select , out);
245 versets[modID].insert(vset.begin(), vset.end());
246 }
247 return versets;
248 }
249 /*}}}*/
250 // FromCommandLine - Return all versions specified on commandline /*{{{*/
251 APT::VersionSet VersionSet::FromCommandLine(pkgCacheFile &Cache, const char **cmdline,
252 APT::VersionSet::Version const &fallback, std::ostream &out) {
253 VersionSet verset;
254 for (const char **I = cmdline; *I != 0; ++I) {
255 VersionSet vset = VersionSet::FromString(Cache, *I, fallback, out);
256 verset.insert(vset.begin(), vset.end());
257 }
258 return verset;
259 }
260 /*}}}*/
261 // FromString - Returns all versions spedcified by a string /*{{{*/
262 APT::VersionSet VersionSet::FromString(pkgCacheFile &Cache, std::string pkg,
263 APT::VersionSet::Version const &fallback, std::ostream &out) {
264 std::string ver;
265 bool verIsRel = false;
266 size_t const vertag = pkg.find_last_of("/=");
267 if (vertag != string::npos) {
268 ver = pkg.substr(vertag+1);
269 verIsRel = (pkg[vertag] == '/');
270 pkg.erase(vertag);
271 }
272 PackageSet pkgset = PackageSet::FromString(Cache, pkg.c_str(), out);
273 VersionSet verset;
274 for (PackageSet::const_iterator P = pkgset.begin();
275 P != pkgset.end(); ++P) {
276 if (vertag == string::npos) {
277 AddSelectedVersion(Cache, verset, P, fallback);
278 continue;
279 }
280 pkgCache::VerIterator V;
281 if (ver == "installed")
282 V = getInstalledVer(Cache, P);
283 else if (ver == "candidate")
284 V = getCandidateVer(Cache, P);
285 else {
286 pkgVersionMatch Match(ver, (verIsRel == true ? pkgVersionMatch::Release :
287 pkgVersionMatch::Version));
288 V = Match.Find(P);
289 if (V.end() == true) {
290 if (verIsRel == true)
291 _error->Error(_("Release '%s' for '%s' was not found"),
292 ver.c_str(), P.FullName(true).c_str());
293 else
294 _error->Error(_("Version '%s' for '%s' was not found"),
295 ver.c_str(), P.FullName(true).c_str());
296 continue;
297 }
298 }
299 if (V.end() == true)
300 continue;
301 if (ver != V.VerStr())
302 ioprintf(out, _("Selected version '%s' (%s) for '%s'\n"),
303 V.VerStr(), V.RelStr().c_str(), P.FullName(true).c_str());
304 verset.insert(V);
305 }
306 return verset;
307 }
308 /*}}}*/
309 // AddSelectedVersion - add version from package based on fallback /*{{{*/
310 bool VersionSet::AddSelectedVersion(pkgCacheFile &Cache, VersionSet &verset,
311 pkgCache::PkgIterator const &P, VersionSet::Version const &fallback,
312 bool const &AllowError) {
313 pkgCache::VerIterator V;
314 switch(fallback) {
315 case VersionSet::ALL:
316 if (P->VersionList != 0)
317 for (V = P.VersionList(); V.end() != true; ++V)
318 verset.insert(V);
319 else if (AllowError == false)
320 return _error->Error(_("Can't select versions from package '%s' as it purely virtual"), P.FullName(true).c_str());
321 else
322 return false;
323 break;
324 case VersionSet::CANDANDINST:
325 verset.insert(getInstalledVer(Cache, P, AllowError));
326 verset.insert(getCandidateVer(Cache, P, AllowError));
327 break;
328 case VersionSet::CANDIDATE:
329 verset.insert(getCandidateVer(Cache, P, AllowError));
330 break;
331 case VersionSet::INSTALLED:
332 verset.insert(getInstalledVer(Cache, P, AllowError));
333 break;
334 case VersionSet::CANDINST:
335 V = getCandidateVer(Cache, P, true);
336 if (V.end() == true)
337 V = getInstalledVer(Cache, P, true);
338 if (V.end() == false)
339 verset.insert(V);
340 else if (AllowError == false)
341 return _error->Error(_("Can't select installed nor candidate version from package '%s' as it has neither of them"), P.FullName(true).c_str());
342 else
343 return false;
344 break;
345 case VersionSet::INSTCAND:
346 V = getInstalledVer(Cache, P, true);
347 if (V.end() == true)
348 V = getCandidateVer(Cache, P, true);
349 if (V.end() == false)
350 verset.insert(V);
351 else if (AllowError == false)
352 return _error->Error(_("Can't select installed nor candidate version from package '%s' as it has neither of them"), P.FullName(true).c_str());
353 else
354 return false;
355 break;
356 case VersionSet::NEWEST:
357 if (P->VersionList != 0)
358 verset.insert(P.VersionList());
359 else if (AllowError == false)
360 return _error->Error(_("Can't select newest version from package '%s' as it is purely virtual"), P.FullName(true).c_str());
361 else
362 return false;
363 break;
364 }
365 return true;
366 }
367 /*}}}*/
368 // getCandidateVer - Returns the candidate version of the given package /*{{{*/
369 pkgCache::VerIterator VersionSet::getCandidateVer(pkgCacheFile &Cache,
370 pkgCache::PkgIterator const &Pkg, bool const &AllowError) {
371 pkgCache::VerIterator Cand;
372 if (Cache.IsDepCacheBuilt() == true)
373 Cand = Cache[Pkg].CandidateVerIter(Cache);
374 else {
375 if (unlikely(Cache.BuildPolicy() == false))
376 return pkgCache::VerIterator(*Cache);
377 Cand = Cache.GetPolicy()->GetCandidateVer(Pkg);
378 }
379 if (AllowError == false && Cand.end() == true)
380 _error->Error(_("Can't select candidate version from package %s as it has no candidate"), Pkg.FullName(true).c_str());
381 return Cand;
382 }
383 /*}}}*/
384 // getInstalledVer - Returns the installed version of the given package /*{{{*/
385 pkgCache::VerIterator VersionSet::getInstalledVer(pkgCacheFile &Cache,
386 pkgCache::PkgIterator const &Pkg, bool const &AllowError) {
387 if (AllowError == false && Pkg->CurrentVer == 0)
388 _error->Error(_("Can't select installed version from package %s as it is not installed"), Pkg.FullName(true).c_str());
389 return Pkg.CurrentVer();
390 }
391 /*}}}*/
392 }