]> git.saurik.com Git - apt.git/blame - apt-private/private-cacheset.cc
tests: apt build-dep actually reports no depends correctly
[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/*{{{*/
258b9e51
DK
182CacheSetHelperAPTGet::CacheSetHelperAPTGet(std::ostream &pout) :
183 APT::CacheSetHelper{true}, out(pout)
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
6cfadda1
DK
248 std::vector<bool> Seen(Cache.GetPkgCache()->Head().PackageCount, false);
249 APT::PackageList pkglist;
250 for (pkgCache::DepIterator Dep = Pkg.RevDependsList();
251 Dep.end() == false; ++Dep) {
252 if (Dep->Type != pkgCache::Dep::Replaces)
253 continue;
254 pkgCache::PkgIterator const DP = Dep.ParentPkg();
255 if (Seen[DP->ID] == true)
256 continue;
257 Seen[DP->ID] = true;
258 pkglist.insert(DP);
259 }
260 ShowList(c1out, _("However the following packages replace it:"), pkglist,
261 &AlwaysTrue, &PrettyFullName, &EmptyString);
262 }
263 c1out << std::endl;
264 }
265 return false;
266}
267pkgCache::VerIterator CacheSetHelperAPTGet::canNotFindCandidateVer(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg)
268{
269 APT::VersionSet const verset = tryVirtualPackage(Cache, Pkg, CacheSetHelper::CANDIDATE);
270 if (verset.empty() == false)
271 return *(verset.begin());
272 else if (ShowError == true) {
273 _error->Error(_("Package '%s' has no installation candidate"),Pkg.FullName(true).c_str());
274 virtualPkgs.insert(Pkg);
275 }
276 return pkgCache::VerIterator(Cache, 0);
277}
278pkgCache::VerIterator CacheSetHelperAPTGet::canNotFindNewestVer(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg)
279{
280 if (Pkg->ProvidesList != 0)
281 {
282 APT::VersionSet const verset = tryVirtualPackage(Cache, Pkg, CacheSetHelper::NEWEST);
283 if (verset.empty() == false)
284 return *(verset.begin());
285 if (ShowError == true)
286 ioprintf(out, _("Virtual packages like '%s' can't be removed\n"), Pkg.FullName(true).c_str());
287 }
288 else
289 {
290 pkgCache::GrpIterator Grp = Pkg.Group();
291 pkgCache::PkgIterator P = Grp.PackageList();
292 for (; P.end() != true; P = Grp.NextPkg(P))
293 {
294 if (P == Pkg)
295 continue;
296 if (P->CurrentVer != 0) {
297 // TRANSLATORS: Note, this is not an interactive question
298 ioprintf(c1out,_("Package '%s' is not installed, so not removed. Did you mean '%s'?\n"),
299 Pkg.FullName(true).c_str(), P.FullName(true).c_str());
300 break;
301 }
302 }
303 if (P.end() == true)
304 ioprintf(c1out,_("Package '%s' is not installed, so not removed\n"),Pkg.FullName(true).c_str());
305 }
306 return pkgCache::VerIterator(Cache, 0);
307}
308APT::VersionSet CacheSetHelperAPTGet::tryVirtualPackage(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg,
309 CacheSetHelper::VerSelector const select)
310{
311 /* This is a pure virtual package and there is a single available
312 candidate providing it. */
313 if (unlikely(Cache[Pkg].CandidateVer != 0) || Pkg->ProvidesList == 0)
314 return APT::VersionSet();
315
316 pkgCache::PkgIterator Prov;
317 bool found_one = false;
318 for (pkgCache::PrvIterator P = Pkg.ProvidesList(); P; ++P) {
319 pkgCache::VerIterator const PVer = P.OwnerVer();
320 pkgCache::PkgIterator const PPkg = PVer.ParentPkg();
321
322 /* Ignore versions that are not a candidate. */
323 if (Cache[PPkg].CandidateVer != PVer)
324 continue;
325
326 if (found_one == false) {
327 Prov = PPkg;
328 found_one = true;
329 } else if (PPkg != Prov) {
330 // same group, so it's a foreign package
331 if (PPkg->Group == Prov->Group) {
332 // do we already have the requested arch?
333 if (strcmp(Pkg.Arch(), Prov.Arch()) == 0 ||
334 strcmp(Prov.Arch(), "all") == 0 ||
335 unlikely(strcmp(PPkg.Arch(), Prov.Arch()) == 0)) // packages have only on candidate, but just to be sure
336 continue;
337 // see which architecture we prefer more and switch to it
338 std::vector<std::string> archs = APT::Configuration::getArchitectures();
339 if (std::find(archs.begin(), archs.end(), PPkg.Arch()) < std::find(archs.begin(), archs.end(), Prov.Arch()))
340 Prov = PPkg;
341 continue;
342 }
343 found_one = false; // we found at least two
344 break;
345 }
346 }
347
348 if (found_one == true) {
349 ioprintf(out, _("Note, selecting '%s' instead of '%s'\n"),
350 Prov.FullName(true).c_str(), Pkg.FullName(true).c_str());
351 return APT::VersionSet::FromPackage(Cache, Prov, select, *this);
352 }
353 return APT::VersionSet();
3addaba1
DK
354}
355pkgCache::PkgIterator CacheSetHelperAPTGet::canNotFindPkgName(pkgCacheFile &Cache, std::string const &str)
356{
357 pkgCache::PkgIterator const Pkg = canNotFindPkgName_impl(Cache, str);
358 if (Pkg.end())
359 return APT::CacheSetHelper::canNotFindPkgName(Cache, str);
360 return Pkg;
6cfadda1
DK
361}
362 /*}}}*/