private-cacheset.h 9.9 KB

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