statechanges.cc 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. #include <apt-pkg/pkgcache.h>
  2. #include <apt-pkg/cacheset.h>
  3. #include <apt-pkg/debsystem.h>
  4. #include <apt-pkg/fileutl.h>
  5. #include <apt-pkg/statechanges.h>
  6. #include <algorithm>
  7. #include <memory>
  8. namespace APT
  9. {
  10. class StateChanges::Private
  11. {
  12. public:
  13. APT::VersionVector hold;
  14. APT::VersionVector install;
  15. APT::VersionVector error;
  16. };
  17. void StateChanges::Hold(pkgCache::VerIterator const &Ver)
  18. {
  19. d->hold.push_back(Ver);
  20. }
  21. APT::VersionVector& StateChanges::Hold()
  22. {
  23. return d->hold;
  24. }
  25. void StateChanges::Unhold(pkgCache::VerIterator const &Ver)
  26. {
  27. d->install.push_back(Ver);
  28. }
  29. APT::VersionVector& StateChanges::Unhold()
  30. {
  31. return d->install;
  32. }
  33. APT::VersionVector& StateChanges::Error()
  34. {
  35. return d->error;
  36. }
  37. void StateChanges::Discard()
  38. {
  39. d->hold.clear();
  40. d->install.clear();
  41. d->error.clear();
  42. }
  43. bool StateChanges::Save(bool const DiscardOutput)
  44. {
  45. d->error.clear();
  46. if (d->hold.empty() && d->install.empty())
  47. return true;
  48. std::vector<std::string> Args = debSystem::GetDpkgBaseCommand();
  49. // ensure dpkg knows about the package so that it keeps the status we set
  50. {
  51. APT::VersionVector makeDpkgAvailable;
  52. auto const notInstalled = [](pkgCache::VerIterator const &V) { return V.ParentPkg()->CurrentVer == 0; };
  53. std::copy_if(d->hold.begin(), d->hold.end(), std::back_inserter(makeDpkgAvailable), notInstalled);
  54. std::copy_if(d->install.begin(), d->install.end(), std::back_inserter(makeDpkgAvailable), notInstalled);
  55. if (makeDpkgAvailable.empty() == false)
  56. {
  57. auto const BaseArgs = Args.size();
  58. Args.push_back("--merge-avail");
  59. // FIXME: supported only since 1.17.7 in dpkg
  60. Args.push_back("-");
  61. int dummyAvail = -1;
  62. pid_t const dpkgMergeAvail = debSystem::ExecDpkg(Args, &dummyAvail, nullptr, true);
  63. FILE* dpkg = fdopen(dummyAvail, "w");
  64. for (auto const &V: makeDpkgAvailable)
  65. fprintf(dpkg, "Package: %s\nVersion: 0~\nArchitecture: %s\nMaintainer: Dummy Example <dummy@example.org>\n"
  66. "Description: dummy package record\n A record is needed to put a package on hold, so here it is.\n\n", V.ParentPkg().Name(), V.Arch());
  67. fclose(dpkg);
  68. ExecWait(dpkgMergeAvail, "dpkg --merge-avail", true);
  69. Args.erase(Args.begin() + BaseArgs, Args.end());
  70. }
  71. }
  72. bool const dpkgMultiArch = _system->MultiArchSupported();
  73. Args.push_back("--set-selections");
  74. int selections = -1;
  75. pid_t const dpkgSelections = debSystem::ExecDpkg(Args, &selections, nullptr, DiscardOutput);
  76. FILE* dpkg = fdopen(selections, "w");
  77. std::string state;
  78. auto const dpkgName = [&](pkgCache::VerIterator const &V) {
  79. pkgCache::PkgIterator P = V.ParentPkg();
  80. if (dpkgMultiArch == false)
  81. fprintf(dpkg, "%s %s\n", P.FullName(true).c_str(), state.c_str());
  82. else
  83. fprintf(dpkg, "%s:%s %s\n", P.Name(), V.Arch(), state.c_str());
  84. };
  85. if (d->hold.empty() == false)
  86. {
  87. state = "hold";
  88. std::for_each(d->hold.begin(), d->hold.end(), dpkgName);
  89. }
  90. if (d->install.empty() == false)
  91. {
  92. state = "install";
  93. std::for_each(d->install.begin(), d->install.end(), dpkgName);
  94. }
  95. fclose(dpkg);
  96. if (ExecWait(dpkgSelections, "dpkg --set-selections") == false)
  97. {
  98. if (d->hold.empty())
  99. std::swap(d->install, d->error);
  100. else if (d->install.empty())
  101. std::swap(d->hold, d->error);
  102. else
  103. {
  104. std::swap(d->hold, d->error);
  105. std::move(d->install.begin(), d->install.end(), std::back_inserter(d->error));
  106. d->install.clear();
  107. }
  108. }
  109. return d->error.empty();
  110. }
  111. StateChanges::StateChanges() : d(new StateChanges::Private()) {}
  112. StateChanges::StateChanges(StateChanges&&) = default;
  113. StateChanges& StateChanges::operator=(StateChanges&&) = default;
  114. StateChanges::~StateChanges() = default;
  115. }