]> git.saurik.com Git - apt.git/blob - apt-private/private-cacheset.cc
implement dpkgs vision of interpreting pkg:<arch> dependencies
[apt.git] / apt-private / private-cacheset.cc
1 #include <config.h>
2
3 #include <apt-pkg/cachefile.h>
4 #include <apt-pkg/pkgcache.h>
5 #include <apt-pkg/depcache.h>
6 #include <apt-pkg/cacheiterators.h>
7 #include <apt-pkg/cachefilter.h>
8 #include <apt-pkg/aptconfiguration.h>
9 #include <apt-pkg/configuration.h>
10 #include <apt-pkg/progress.h>
11 #include <apt-pkg/policy.h>
12 #include <apt-pkg/strutl.h>
13
14 #include <apt-private/private-cacheset.h>
15
16 #include <stddef.h>
17
18 #include <apti18n.h>
19
20 bool GetLocalitySortedVersionSet(pkgCacheFile &CacheFile, /*{{{*/
21 APT::VersionContainerInterface * const vci,
22 OpProgress * const progress)
23 {
24 Matcher null_matcher = Matcher();
25 return GetLocalitySortedVersionSet(CacheFile, vci,
26 null_matcher, progress);
27 }
28 bool GetLocalitySortedVersionSet(pkgCacheFile &CacheFile,
29 APT::VersionContainerInterface * const vci,
30 Matcher &matcher,
31 OpProgress * const progress)
32 {
33 pkgCache *Cache = CacheFile.GetPkgCache();
34 pkgDepCache *DepCache = CacheFile.GetDepCache();
35 APT::CacheSetHelper helper(false);
36
37 int Done=0;
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
45 for (pkgCache::PkgIterator P = Cache->PkgBegin(); P.end() == false; ++P)
46 {
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;
57
58 if ((matcher)(P) == false)
59 continue;
60
61 pkgDepCache::StateCache &state = (*DepCache)[P];
62 if (insertCurrentVer == true)
63 {
64 if (P->CurrentVer != 0)
65 vci->FromPackage(vci, CacheFile, P, APT::CacheSetHelper::INSTALLED, helper);
66 }
67 else if (insertUpgradable == true)
68 {
69 if(P.CurrentVer() && state.Upgradable())
70 vci->FromPackage(vci, CacheFile, P, APT::CacheSetHelper::CANDIDATE, helper);
71 }
72 else if (insertManualInstalled == true)
73 {
74 if (P.CurrentVer() &&
75 ((*DepCache)[P].Flags & pkgCache::Flag::Auto) == false)
76 vci->FromPackage(vci, CacheFile, P, APT::CacheSetHelper::CANDIDATE, helper);
77 }
78 else
79 {
80 if (vci->FromPackage(vci, CacheFile, P, APT::CacheSetHelper::CANDIDATE, helper) == false)
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 }
87 }
88 }
89 if (progress != NULL)
90 progress->Done();
91 return true;
92 }
93 /*}}}*/
94
95 // CacheSetHelper saving virtual packages /*{{{*/
96 pkgCache::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 }
105 void 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 }
115 static 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 }
169 pkgCache::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 }
176 CacheSetHelperVirtuals::CacheSetHelperVirtuals(bool const ShowErrors, GlobalError::MsgType const &ErrorType) :
177 CacheSetHelper{ShowErrors, ErrorType}
178 {}
179 /*}}}*/
180
181 // CacheSetHelperAPTGet - responsible for message telling from the CacheSets/*{{{*/
182 CacheSetHelperAPTGet::CacheSetHelperAPTGet(std::ostream &out) :
183 APT::CacheSetHelper{true}, out(out)
184 {
185 explicitlyNamed = true;
186 }
187 void 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 }
193 void 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 }
199 void 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 }
205 void 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 }
212 bool 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 }
269 pkgCache::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 }
280 pkgCache::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 }
310 APT::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();
356 }
357 pkgCache::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;
363 }
364 /*}}}*/