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>
13 class StateChanges::Private
16 APT::VersionVector hold
;
17 APT::VersionVector install
;
18 APT::VersionVector error
;
21 void StateChanges::Hold(pkgCache::VerIterator
const &Ver
)
23 d
->hold
.push_back(Ver
);
25 APT::VersionVector
& StateChanges::Hold()
29 void StateChanges::Unhold(pkgCache::VerIterator
const &Ver
)
31 d
->install
.push_back(Ver
);
33 APT::VersionVector
& StateChanges::Unhold()
37 APT::VersionVector
& StateChanges::Error()
42 void StateChanges::Discard()
49 bool StateChanges::Save(bool const DiscardOutput
)
52 if (d
->hold
.empty() && d
->install
.empty())
55 std::vector
<std::string
> Args
= debSystem::GetDpkgBaseCommand();
56 // ensure dpkg knows about the package so that it keeps the status we set
58 APT::VersionVector makeDpkgAvailable
;
59 auto const notInstalled
= [](pkgCache::VerIterator
const &V
) { return V
.ParentPkg()->CurrentVer
== 0; };
60 std::copy_if(d
->hold
.begin(), d
->hold
.end(), std::back_inserter(makeDpkgAvailable
), notInstalled
);
61 std::copy_if(d
->install
.begin(), d
->install
.end(), std::back_inserter(makeDpkgAvailable
), notInstalled
);
63 if (makeDpkgAvailable
.empty() == false)
65 auto const BaseArgs
= Args
.size();
66 Args
.push_back("--merge-avail");
67 // FIXME: supported only since 1.17.7 in dpkg
70 pid_t
const dpkgMergeAvail
= debSystem::ExecDpkg(Args
, &dummyAvail
, nullptr, true);
72 FILE* dpkg
= fdopen(dummyAvail
, "w");
73 for (auto const &V
: makeDpkgAvailable
)
74 fprintf(dpkg
, "Package: %s\nVersion: 0~\nArchitecture: %s\nMaintainer: Dummy Example <dummy@example.org>\n"
75 "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());
78 ExecWait(dpkgMergeAvail
, "dpkg --merge-avail", true);
79 Args
.erase(Args
.begin() + BaseArgs
, Args
.end());
82 bool const dpkgMultiArch
= _system
->MultiArchSupported();
84 Args
.push_back("--set-selections");
86 pid_t
const dpkgSelections
= debSystem::ExecDpkg(Args
, &selections
, nullptr, DiscardOutput
);
88 FILE* dpkg
= fdopen(selections
, "w");
90 auto const dpkgName
= [&](pkgCache::VerIterator
const &V
) {
91 pkgCache::PkgIterator P
= V
.ParentPkg();
92 if (dpkgMultiArch
== false)
93 fprintf(dpkg
, "%s %s\n", P
.FullName(true).c_str(), state
.c_str());
95 fprintf(dpkg
, "%s:%s %s\n", P
.Name(), V
.Arch(), state
.c_str());
97 if (d
->hold
.empty() == false)
100 std::for_each(d
->hold
.begin(), d
->hold
.end(), dpkgName
);
102 if (d
->install
.empty() == false)
105 std::for_each(d
->install
.begin(), d
->install
.end(), dpkgName
);
109 if (ExecWait(dpkgSelections
, "dpkg --set-selections") == false)
112 std::swap(d
->install
, d
->error
);
113 else if (d
->install
.empty())
114 std::swap(d
->hold
, d
->error
);
117 std::swap(d
->hold
, d
->error
);
118 std::move(d
->install
.begin(), d
->install
.end(), std::back_inserter(d
->error
));
122 return d
->error
.empty();
125 StateChanges::StateChanges() : d(new StateChanges::Private()) {}
126 StateChanges::StateChanges(StateChanges
&&) = default;
127 StateChanges
& StateChanges::operator=(StateChanges
&&) = default;
128 StateChanges::~StateChanges() = default;