]> git.saurik.com Git - apt.git/blame - apt-private/private-cacheset.cc
deal with --version more centrally
[apt.git] / apt-private / private-cacheset.cc
CommitLineData
453b82a3
DK
1#include <config.h>
2
b9179170
MV
3#include <apt-pkg/cachefile.h>
4#include <apt-pkg/pkgcache.h>
5#include <apt-pkg/depcache.h>
453b82a3 6#include <apt-pkg/cacheiterators.h>
3addaba1 7#include <apt-pkg/cachefilter.h>
6cfadda1 8#include <apt-pkg/aptconfiguration.h>
453b82a3
DK
9#include <apt-pkg/configuration.h>
10#include <apt-pkg/progress.h>
11#include <apt-pkg/policy.h>
6cfadda1 12#include <apt-pkg/strutl.h>
453b82a3
DK
13
14#include <apt-private/private-cacheset.h>
15
16#include <stddef.h>
b9179170 17
453b82a3 18#include <apti18n.h>
b9179170 19
6cfadda1 20bool GetLocalitySortedVersionSet(pkgCacheFile &CacheFile, /*{{{*/
25594bb5
DK
21 APT::VersionContainerInterface * const vci,
22 OpProgress * const progress)
b9179170
MV
23{
24 Matcher null_matcher = Matcher();
25594bb5 25 return GetLocalitySortedVersionSet(CacheFile, vci,
b9179170
MV
26 null_matcher, progress);
27}
25594bb5
DK
28bool GetLocalitySortedVersionSet(pkgCacheFile &CacheFile,
29 APT::VersionContainerInterface * const vci,
b9179170 30 Matcher &matcher,
25594bb5 31 OpProgress * const progress)
b9179170
MV
32{
33 pkgCache *Cache = CacheFile.GetPkgCache();
34 pkgDepCache *DepCache = CacheFile.GetDepCache();
25594bb5 35 APT::CacheSetHelper helper(false);
b9179170
MV
36
37 int Done=0;
25594bb5
DK
38 if (progress != NULL)
39 progress->SubProgress(Cache->Head().PackageCount, _("Sorting"));
40
41 bool const insertCurrentVer = _config->FindB("APT::Cmd::Installed", false);
42 bool const insertUpgradable = _config->FindB("APT::Cmd::Upgradable", false);
43 bool const insertManualInstalled = _config->FindB("APT::Cmd::Manual-Installed", false);
44
b9179170
MV
45 for (pkgCache::PkgIterator P = Cache->PkgBegin(); P.end() == false; ++P)
46 {
25594bb5
DK
47 if (progress != NULL)
48 {
49 if (Done % 500 == 0)
50 progress->Progress(Done);
51 ++Done;
52 }
53
54 // exclude virtual pkgs
55 if (P->VersionList == 0)
56 continue;
b9179170
MV
57
58 if ((matcher)(P) == false)
25594bb5 59 continue;
b9179170 60
b9179170 61 pkgDepCache::StateCache &state = (*DepCache)[P];
25594bb5 62 if (insertCurrentVer == true)
b9179170 63 {
25594bb5 64 if (P->CurrentVer != 0)
fdba4d53 65 vci->FromPackage(vci, CacheFile, P, APT::CacheSetHelper::INSTALLED, helper);
b9179170 66 }
25594bb5 67 else if (insertUpgradable == true)
b9179170 68 {
25594bb5 69 if(P.CurrentVer() && state.Upgradable())
fdba4d53 70 vci->FromPackage(vci, CacheFile, P, APT::CacheSetHelper::CANDIDATE, helper);
b9179170 71 }
25594bb5 72 else if (insertManualInstalled == true)
3bdf7da5 73 {
25594bb5
DK
74 if (P.CurrentVer() &&
75 ((*DepCache)[P].Flags & pkgCache::Flag::Auto) == false)
fdba4d53 76 vci->FromPackage(vci, CacheFile, P, APT::CacheSetHelper::CANDIDATE, helper);
3bdf7da5 77 }
25594bb5 78 else
b9179170 79 {
fdba4d53 80 if (vci->FromPackage(vci, CacheFile, P, APT::CacheSetHelper::CANDIDATE, helper) == false)
25594bb5
DK
81 {
82 // no candidate, this may happen for packages in
83 // dpkg "deinstall ok config-file" state - we pick the first ver
84 // (which should be the only one)
85 vci->insert(P.VersionList());
86 }
b9179170
MV
87 }
88 }
25594bb5
DK
89 if (progress != NULL)
90 progress->Done();
b9179170
MV
91 return true;
92}
6cfadda1
DK
93 /*}}}*/
94
95// CacheSetHelper saving virtual packages /*{{{*/
96pkgCache::VerIterator CacheSetHelperVirtuals::canNotGetVersion(
97 enum CacheSetHelper::VerSelector const select,
98 pkgCacheFile &Cache,
99 pkgCache::PkgIterator const &Pkg)
100{
101 if (select == NEWEST || select == CANDIDATE || select == ALL)
102 virtualPkgs.insert(Pkg);
103 return CacheSetHelper::canNotGetVersion(select, Cache, Pkg);
104}
105void CacheSetHelperVirtuals::canNotFindVersion(
106 enum CacheSetHelper::VerSelector const select,
107 APT::VersionContainerInterface * vci,
108 pkgCacheFile &Cache,
109 pkgCache::PkgIterator const &Pkg)
110{
111 if (select == NEWEST || select == CANDIDATE || select == ALL)
112 virtualPkgs.insert(Pkg);
113 return CacheSetHelper::canNotFindVersion(select, vci, Cache, Pkg);
114}
3addaba1
DK
115static pkgCache::PkgIterator canNotFindPkgName_impl(pkgCacheFile &Cache, std::string const &str)
116{
117 std::string pkg = str;
118 size_t const archfound = pkg.find_last_of(':');
119 std::string arch;
120 if (archfound != std::string::npos) {
121 arch = pkg.substr(archfound+1);
122 pkg.erase(archfound);
123 if (arch == "all" || arch == "native")
124 arch = _config->Find("APT::Architecture");
125 }
126
127 // If we don't find 'foo:amd64' look for 'foo:amd64:any'.
128 // Note: we prepare for an error here as if foo:amd64 does not exist,
129 // but foo:amd64:any it means that this package is only referenced in a
130 // (architecture specific) dependency. We do not add to virtualPkgs directly
131 // as we can't decide from here which error message has to be printed.
132 // FIXME: This doesn't match 'barbarian' architectures
133 pkgCache::PkgIterator Pkg(Cache, 0);
134 std::vector<std::string> const archs = APT::Configuration::getArchitectures();
135 if (archfound == std::string::npos)
136 {
137 for (auto const &a : archs)
138 {
139 Pkg = Cache.GetPkgCache()->FindPkg(pkg + ':' + a, "any");
140 if (Pkg.end() == false && Pkg->ProvidesList != 0)
141 break;
142 }
143 if (Pkg.end() == true)
144 for (auto const &a : archs)
145 {
146 Pkg = Cache.GetPkgCache()->FindPkg(pkg + ':' + a, "any");
147 if (Pkg.end() == false)
148 break;
149 }
150 }
151 else
152 {
153 Pkg = Cache.GetPkgCache()->FindPkg(pkg + ':' + arch, "any");
154 if (Pkg.end() == true)
155 {
156 APT::CacheFilter::PackageArchitectureMatchesSpecification pams(arch);
157 for (auto const &a : archs)
158 {
159 if (pams(a.c_str()) == false)
160 continue;
161 Pkg = Cache.GetPkgCache()->FindPkg(pkg + ':' + a, "any");
162 if (Pkg.end() == false)
163 break;
164 }
165 }
166 }
167 return Pkg;
168}
169pkgCache::PkgIterator CacheSetHelperVirtuals::canNotFindPkgName(pkgCacheFile &Cache, std::string const &str)
170{
171 pkgCache::PkgIterator const Pkg = canNotFindPkgName_impl(Cache, str);
172 if (Pkg.end())
173 return APT::CacheSetHelper::canNotFindPkgName(Cache, str);
174 return Pkg;
175}
6cfadda1
DK
176CacheSetHelperVirtuals::CacheSetHelperVirtuals(bool const ShowErrors, GlobalError::MsgType const &ErrorType) :
177 CacheSetHelper{ShowErrors, ErrorType}
178{}
179 /*}}}*/
180
181// CacheSetHelperAPTGet - responsible for message telling from the CacheSets/*{{{*/
182CacheSetHelperAPTGet::CacheSetHelperAPTGet(std::ostream &out) :
3dddcdf2 183 APT::CacheSetHelper{true}, out(out)
6cfadda1
DK
184{
185 explicitlyNamed = true;
186}
187void CacheSetHelperAPTGet::showTaskSelection(pkgCache::PkgIterator const &Pkg, std::string const &pattern)
188{
189 ioprintf(out, _("Note, selecting '%s' for task '%s'\n"),
190 Pkg.FullName(true).c_str(), pattern.c_str());
191 explicitlyNamed = false;
192}
193void CacheSetHelperAPTGet::showFnmatchSelection(pkgCache::PkgIterator const &Pkg, std::string const &pattern)
194{
195 ioprintf(out, _("Note, selecting '%s' for glob '%s'\n"),
196 Pkg.FullName(true).c_str(), pattern.c_str());
197 explicitlyNamed = false;
198}
199void CacheSetHelperAPTGet::showRegExSelection(pkgCache::PkgIterator const &Pkg, std::string const &pattern)
200{
201 ioprintf(out, _("Note, selecting '%s' for regex '%s'\n"),
202 Pkg.FullName(true).c_str(), pattern.c_str());
203 explicitlyNamed = false;
204}
205void CacheSetHelperAPTGet::showSelectedVersion(pkgCache::PkgIterator const &/*Pkg*/, pkgCache::VerIterator const Ver,
206 std::string const &ver, bool const /*verIsRel*/)
207{
208 if (ver == Ver.VerStr())
209 return;
210 selectedByRelease.push_back(make_pair(Ver, ver));
211}
212bool CacheSetHelperAPTGet::showVirtualPackageErrors(pkgCacheFile &Cache)
213{
214 if (virtualPkgs.empty() == true)
215 return true;
216 for (APT::PackageSet::const_iterator Pkg = virtualPkgs.begin();
217 Pkg != virtualPkgs.end(); ++Pkg) {
218 if (Pkg->ProvidesList != 0) {
219 ioprintf(c1out,_("Package %s is a virtual package provided by:\n"),
220 Pkg.FullName(true).c_str());
221
222 pkgCache::PrvIterator I = Pkg.ProvidesList();
223 unsigned short provider = 0;
224 for (; I.end() == false; ++I) {
225 pkgCache::PkgIterator Pkg = I.OwnerPkg();
226
227 if (Cache[Pkg].CandidateVerIter(Cache) == I.OwnerVer()) {
228 c1out << " " << Pkg.FullName(true) << " " << I.OwnerVer().VerStr();
229 if (Cache[Pkg].Install() == true && Cache[Pkg].NewInstall() == false)
230 c1out << _(" [Installed]");
231 c1out << std::endl;
232 ++provider;
233 }
234 }
235 // if we found no candidate which provide this package, show non-candidates
236 if (provider == 0)
237 for (I = Pkg.ProvidesList(); I.end() == false; ++I)
238 c1out << " " << I.OwnerPkg().FullName(true) << " " << I.OwnerVer().VerStr()
239 << _(" [Not candidate version]") << std::endl;
240 else
241 out << _("You should explicitly select one to install.") << std::endl;
242 } else {
243 ioprintf(c1out,
244 _("Package %s is not available, but is referred to by another package.\n"
245 "This may mean that the package is missing, has been obsoleted, or\n"
246 "is only available from another source\n"),Pkg.FullName(true).c_str());
247
248 std::string List;
249 std::string VersionsList;
250 std::vector<bool> Seen(Cache.GetPkgCache()->Head().PackageCount, false);
251 APT::PackageList pkglist;
252 for (pkgCache::DepIterator Dep = Pkg.RevDependsList();
253 Dep.end() == false; ++Dep) {
254 if (Dep->Type != pkgCache::Dep::Replaces)
255 continue;
256 pkgCache::PkgIterator const DP = Dep.ParentPkg();
257 if (Seen[DP->ID] == true)
258 continue;
259 Seen[DP->ID] = true;
260 pkglist.insert(DP);
261 }
262 ShowList(c1out, _("However the following packages replace it:"), pkglist,
263 &AlwaysTrue, &PrettyFullName, &EmptyString);
264 }
265 c1out << std::endl;
266 }
267 return false;
268}
269pkgCache::VerIterator CacheSetHelperAPTGet::canNotFindCandidateVer(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg)
270{
271 APT::VersionSet const verset = tryVirtualPackage(Cache, Pkg, CacheSetHelper::CANDIDATE);
272 if (verset.empty() == false)
273 return *(verset.begin());
274 else if (ShowError == true) {
275 _error->Error(_("Package '%s' has no installation candidate"),Pkg.FullName(true).c_str());
276 virtualPkgs.insert(Pkg);
277 }
278 return pkgCache::VerIterator(Cache, 0);
279}
280pkgCache::VerIterator CacheSetHelperAPTGet::canNotFindNewestVer(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg)
281{
282 if (Pkg->ProvidesList != 0)
283 {
284 APT::VersionSet const verset = tryVirtualPackage(Cache, Pkg, CacheSetHelper::NEWEST);
285 if (verset.empty() == false)
286 return *(verset.begin());
287 if (ShowError == true)
288 ioprintf(out, _("Virtual packages like '%s' can't be removed\n"), Pkg.FullName(true).c_str());
289 }
290 else
291 {
292 pkgCache::GrpIterator Grp = Pkg.Group();
293 pkgCache::PkgIterator P = Grp.PackageList();
294 for (; P.end() != true; P = Grp.NextPkg(P))
295 {
296 if (P == Pkg)
297 continue;
298 if (P->CurrentVer != 0) {
299 // TRANSLATORS: Note, this is not an interactive question
300 ioprintf(c1out,_("Package '%s' is not installed, so not removed. Did you mean '%s'?\n"),
301 Pkg.FullName(true).c_str(), P.FullName(true).c_str());
302 break;
303 }
304 }
305 if (P.end() == true)
306 ioprintf(c1out,_("Package '%s' is not installed, so not removed\n"),Pkg.FullName(true).c_str());
307 }
308 return pkgCache::VerIterator(Cache, 0);
309}
310APT::VersionSet CacheSetHelperAPTGet::tryVirtualPackage(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg,
311 CacheSetHelper::VerSelector const select)
312{
313 /* This is a pure virtual package and there is a single available
314 candidate providing it. */
315 if (unlikely(Cache[Pkg].CandidateVer != 0) || Pkg->ProvidesList == 0)
316 return APT::VersionSet();
317
318 pkgCache::PkgIterator Prov;
319 bool found_one = false;
320 for (pkgCache::PrvIterator P = Pkg.ProvidesList(); P; ++P) {
321 pkgCache::VerIterator const PVer = P.OwnerVer();
322 pkgCache::PkgIterator const PPkg = PVer.ParentPkg();
323
324 /* Ignore versions that are not a candidate. */
325 if (Cache[PPkg].CandidateVer != PVer)
326 continue;
327
328 if (found_one == false) {
329 Prov = PPkg;
330 found_one = true;
331 } else if (PPkg != Prov) {
332 // same group, so it's a foreign package
333 if (PPkg->Group == Prov->Group) {
334 // do we already have the requested arch?
335 if (strcmp(Pkg.Arch(), Prov.Arch()) == 0 ||
336 strcmp(Prov.Arch(), "all") == 0 ||
337 unlikely(strcmp(PPkg.Arch(), Prov.Arch()) == 0)) // packages have only on candidate, but just to be sure
338 continue;
339 // see which architecture we prefer more and switch to it
340 std::vector<std::string> archs = APT::Configuration::getArchitectures();
341 if (std::find(archs.begin(), archs.end(), PPkg.Arch()) < std::find(archs.begin(), archs.end(), Prov.Arch()))
342 Prov = PPkg;
343 continue;
344 }
345 found_one = false; // we found at least two
346 break;
347 }
348 }
349
350 if (found_one == true) {
351 ioprintf(out, _("Note, selecting '%s' instead of '%s'\n"),
352 Prov.FullName(true).c_str(), Pkg.FullName(true).c_str());
353 return APT::VersionSet::FromPackage(Cache, Prov, select, *this);
354 }
355 return APT::VersionSet();
3addaba1
DK
356}
357pkgCache::PkgIterator CacheSetHelperAPTGet::canNotFindPkgName(pkgCacheFile &Cache, std::string const &str)
358{
359 pkgCache::PkgIterator const Pkg = canNotFindPkgName_impl(Cache, str);
360 if (Pkg.end())
361 return APT::CacheSetHelper::canNotFindPkgName(Cache, str);
362 return Pkg;
6cfadda1
DK
363}
364 /*}}}*/