]> git.saurik.com Git - apt.git/blob - apt-private/private-cacheset.h
Merge remote-tracking branch 'mvo/bugfix/coverity' into debian/sid
[apt.git] / apt-private / private-cacheset.h
1 #ifndef APT_PRIVATE_CACHESET_H
2 #define APT_PRIVATE_CACHESET_H
3
4 #include <apt-pkg/cachefile.h>
5 #include <apt-pkg/cacheset.h>
6 #include <apt-pkg/sptr.h>
7
8 #include <algorithm>
9 #include <vector>
10
11 #include "private-output.h"
12
13 #include <apti18n.h>
14
15 struct VersionSortDescriptionLocality
16 {
17 bool operator () (const pkgCache::VerIterator &v_lhs,
18 const pkgCache::VerIterator &v_rhs)
19 {
20 pkgCache::DescFile *A = v_lhs.TranslatedDescription().FileList();
21 pkgCache::DescFile *B = v_rhs.TranslatedDescription().FileList();
22 if (A == 0 && B == 0)
23 return false;
24
25 if (A == 0)
26 return true;
27
28 if (B == 0)
29 return false;
30
31 if (A->File == B->File)
32 return A->Offset < B->Offset;
33
34 return A->File < B->File;
35 }
36 };
37
38 // sorted by locality which makes iterating much faster
39 typedef APT::VersionContainer<
40 std::set<pkgCache::VerIterator,
41 VersionSortDescriptionLocality> > LocalitySortedVersionSet;
42
43 class Matcher {
44 public:
45 virtual bool operator () (const pkgCache::PkgIterator &P) {
46 return true;};
47 };
48
49 // FIXME: add default argument for OpProgress (or overloaded function)
50 bool GetLocalitySortedVersionSet(pkgCacheFile &CacheFile,
51 LocalitySortedVersionSet &output_set,
52 Matcher &matcher,
53 OpProgress &progress);
54 bool GetLocalitySortedVersionSet(pkgCacheFile &CacheFile,
55 LocalitySortedVersionSet &output_set,
56 OpProgress &progress);
57
58
59 // CacheSetHelper saving virtual packages /*{{{*/
60 class CacheSetHelperVirtuals: public APT::CacheSetHelper {
61 public:
62 APT::PackageSet virtualPkgs;
63
64 virtual pkgCache::VerIterator canNotFindCandidateVer(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg) {
65 virtualPkgs.insert(Pkg);
66 return CacheSetHelper::canNotFindCandidateVer(Cache, Pkg);
67 }
68
69 virtual pkgCache::VerIterator canNotFindNewestVer(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg) {
70 virtualPkgs.insert(Pkg);
71 return CacheSetHelper::canNotFindNewestVer(Cache, Pkg);
72 }
73
74 virtual void canNotFindAllVer(APT::VersionContainerInterface * vci, pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg) {
75 virtualPkgs.insert(Pkg);
76 CacheSetHelper::canNotFindAllVer(vci, Cache, Pkg);
77 }
78
79 CacheSetHelperVirtuals(bool const ShowErrors = true, GlobalError::MsgType const &ErrorType = GlobalError::NOTICE) : CacheSetHelper(ShowErrors, ErrorType) {}
80 };
81 /*}}}*/
82
83 // CacheSetHelperAPTGet - responsible for message telling from the CacheSets/*{{{*/
84 class CacheSetHelperAPTGet : public APT::CacheSetHelper {
85 /** \brief stream message should be printed to */
86 std::ostream &out;
87 /** \brief were things like Task or RegEx used to select packages? */
88 bool explicitlyNamed;
89
90 APT::PackageSet virtualPkgs;
91
92 public:
93 std::list<std::pair<pkgCache::VerIterator, std::string> > selectedByRelease;
94
95 CacheSetHelperAPTGet(std::ostream &out) : APT::CacheSetHelper(true), out(out) {
96 explicitlyNamed = true;
97 }
98
99 virtual void showTaskSelection(pkgCache::PkgIterator const &Pkg, std::string const &pattern) {
100 ioprintf(out, _("Note, selecting '%s' for task '%s'\n"),
101 Pkg.FullName(true).c_str(), pattern.c_str());
102 explicitlyNamed = false;
103 }
104 virtual void showRegExSelection(pkgCache::PkgIterator const &Pkg, std::string const &pattern) {
105 ioprintf(out, _("Note, selecting '%s' for regex '%s'\n"),
106 Pkg.FullName(true).c_str(), pattern.c_str());
107 explicitlyNamed = false;
108 }
109 virtual void showSelectedVersion(pkgCache::PkgIterator const &Pkg, pkgCache::VerIterator const Ver,
110 std::string const &ver, bool const verIsRel) {
111 if (ver == Ver.VerStr())
112 return;
113 selectedByRelease.push_back(make_pair(Ver, ver));
114 }
115
116 bool showVirtualPackageErrors(pkgCacheFile &Cache) {
117 if (virtualPkgs.empty() == true)
118 return true;
119 for (APT::PackageSet::const_iterator Pkg = virtualPkgs.begin();
120 Pkg != virtualPkgs.end(); ++Pkg) {
121 if (Pkg->ProvidesList != 0) {
122 ioprintf(c1out,_("Package %s is a virtual package provided by:\n"),
123 Pkg.FullName(true).c_str());
124
125 pkgCache::PrvIterator I = Pkg.ProvidesList();
126 unsigned short provider = 0;
127 for (; I.end() == false; ++I) {
128 pkgCache::PkgIterator Pkg = I.OwnerPkg();
129
130 if (Cache[Pkg].CandidateVerIter(Cache) == I.OwnerVer()) {
131 c1out << " " << Pkg.FullName(true) << " " << I.OwnerVer().VerStr();
132 if (Cache[Pkg].Install() == true && Cache[Pkg].NewInstall() == false)
133 c1out << _(" [Installed]");
134 c1out << std::endl;
135 ++provider;
136 }
137 }
138 // if we found no candidate which provide this package, show non-candidates
139 if (provider == 0)
140 for (I = Pkg.ProvidesList(); I.end() == false; ++I)
141 c1out << " " << I.OwnerPkg().FullName(true) << " " << I.OwnerVer().VerStr()
142 << _(" [Not candidate version]") << std::endl;
143 else
144 out << _("You should explicitly select one to install.") << std::endl;
145 } else {
146 ioprintf(c1out,
147 _("Package %s is not available, but is referred to by another package.\n"
148 "This may mean that the package is missing, has been obsoleted, or\n"
149 "is only available from another source\n"),Pkg.FullName(true).c_str());
150
151 std::string List;
152 std::string VersionsList;
153 SPtrArray<bool> Seen = new bool[Cache.GetPkgCache()->Head().PackageCount];
154 memset(Seen,0,Cache.GetPkgCache()->Head().PackageCount*sizeof(*Seen));
155 for (pkgCache::DepIterator Dep = Pkg.RevDependsList();
156 Dep.end() == false; ++Dep) {
157 if (Dep->Type != pkgCache::Dep::Replaces)
158 continue;
159 if (Seen[Dep.ParentPkg()->ID] == true)
160 continue;
161 Seen[Dep.ParentPkg()->ID] = true;
162 List += Dep.ParentPkg().FullName(true) + " ";
163 //VersionsList += std::string(Dep.ParentPkg().CurVersion) + "\n"; ???
164 }
165 ShowList(c1out,_("However the following packages replace it:"),List,VersionsList);
166 }
167 c1out << std::endl;
168 }
169 return false;
170 }
171
172 virtual pkgCache::VerIterator canNotFindCandidateVer(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg) {
173 APT::VersionSet const verset = tryVirtualPackage(Cache, Pkg, APT::VersionSet::CANDIDATE);
174 if (verset.empty() == false)
175 return *(verset.begin());
176 else if (ShowError == true) {
177 _error->Error(_("Package '%s' has no installation candidate"),Pkg.FullName(true).c_str());
178 virtualPkgs.insert(Pkg);
179 }
180 return pkgCache::VerIterator(Cache, 0);
181 }
182
183 virtual pkgCache::VerIterator canNotFindNewestVer(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg) {
184 if (Pkg->ProvidesList != 0)
185 {
186 APT::VersionSet const verset = tryVirtualPackage(Cache, Pkg, APT::VersionSet::NEWEST);
187 if (verset.empty() == false)
188 return *(verset.begin());
189 if (ShowError == true)
190 ioprintf(out, _("Virtual packages like '%s' can't be removed\n"), Pkg.FullName(true).c_str());
191 }
192 else
193 {
194 pkgCache::GrpIterator Grp = Pkg.Group();
195 pkgCache::PkgIterator P = Grp.PackageList();
196 for (; P.end() != true; P = Grp.NextPkg(P))
197 {
198 if (P == Pkg)
199 continue;
200 if (P->CurrentVer != 0) {
201 // TRANSLATORS: Note, this is not an interactive question
202 ioprintf(c1out,_("Package '%s' is not installed, so not removed. Did you mean '%s'?\n"),
203 Pkg.FullName(true).c_str(), P.FullName(true).c_str());
204 break;
205 }
206 }
207 if (P.end() == true)
208 ioprintf(c1out,_("Package '%s' is not installed, so not removed\n"),Pkg.FullName(true).c_str());
209 }
210 return pkgCache::VerIterator(Cache, 0);
211 }
212
213 APT::VersionSet tryVirtualPackage(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg,
214 APT::VersionSet::Version const &select) {
215 /* This is a pure virtual package and there is a single available
216 candidate providing it. */
217 if (unlikely(Cache[Pkg].CandidateVer != 0) || Pkg->ProvidesList == 0)
218 return APT::VersionSet();
219
220 pkgCache::PkgIterator Prov;
221 bool found_one = false;
222 for (pkgCache::PrvIterator P = Pkg.ProvidesList(); P; ++P) {
223 pkgCache::VerIterator const PVer = P.OwnerVer();
224 pkgCache::PkgIterator const PPkg = PVer.ParentPkg();
225
226 /* Ignore versions that are not a candidate. */
227 if (Cache[PPkg].CandidateVer != PVer)
228 continue;
229
230 if (found_one == false) {
231 Prov = PPkg;
232 found_one = true;
233 } else if (PPkg != Prov) {
234 // same group, so it's a foreign package
235 if (PPkg->Group == Prov->Group) {
236 // do we already have the requested arch?
237 if (strcmp(Pkg.Arch(), Prov.Arch()) == 0 ||
238 strcmp(Prov.Arch(), "all") == 0 ||
239 unlikely(strcmp(PPkg.Arch(), Prov.Arch()) == 0)) // packages have only on candidate, but just to be sure
240 continue;
241 // see which architecture we prefer more and switch to it
242 std::vector<std::string> archs = APT::Configuration::getArchitectures();
243 if (std::find(archs.begin(), archs.end(), PPkg.Arch()) < std::find(archs.begin(), archs.end(), Prov.Arch()))
244 Prov = PPkg;
245 continue;
246 }
247 found_one = false; // we found at least two
248 break;
249 }
250 }
251
252 if (found_one == true) {
253 ioprintf(out, _("Note, selecting '%s' instead of '%s'\n"),
254 Prov.FullName(true).c_str(), Pkg.FullName(true).c_str());
255 return APT::VersionSet::FromPackage(Cache, Prov, select, *this);
256 }
257 return APT::VersionSet();
258 }
259
260 inline bool allPkgNamedExplicitly() const { return explicitlyNamed; }
261
262 };
263 /*}}}*/
264
265 #endif