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 unhold
;
18 APT::VersionVector install
;
19 APT::VersionVector deinstall
;
20 APT::VersionVector purge
;
21 APT::VersionVector error
;
24 #define APT_GETTERSETTER(Name, Container) \
25 void StateChanges::Name(pkgCache::VerIterator const &Ver) \
27 Container.push_back(Ver); \
29 APT::VersionVector& StateChanges::Name() \
33 APT_GETTERSETTER(Hold
, d
->hold
)
34 APT_GETTERSETTER(Unhold
, d
->unhold
)
35 APT_GETTERSETTER(Install
, d
->install
)
36 APT_GETTERSETTER(Remove
, d
->deinstall
)
37 APT_GETTERSETTER(Purge
, d
->purge
)
38 #undef APT_GETTERSETTER
39 APT::VersionVector
& StateChanges::Error()
44 void StateChanges::clear()
54 bool StateChanges::empty() const
56 return d
->hold
.empty() &&
59 d
->deinstall
.empty() &&
64 bool StateChanges::Save(bool const DiscardOutput
)
67 if (d
->hold
.empty() && d
->unhold
.empty() && d
->install
.empty() && d
->deinstall
.empty() && d
->purge
.empty())
70 std::vector
<std::string
> Args
= debSystem::GetDpkgBaseCommand();
71 // ensure dpkg knows about the package so that it keeps the status we set
72 if (d
->hold
.empty() == false || d
->install
.empty() == false)
74 APT::VersionVector makeDpkgAvailable
;
75 auto const notInstalled
= [](pkgCache::VerIterator
const &V
) { return V
.ParentPkg()->CurrentVer
== 0; };
76 std::copy_if(d
->hold
.begin(), d
->hold
.end(), std::back_inserter(makeDpkgAvailable
), notInstalled
);
77 std::copy_if(d
->install
.begin(), d
->install
.end(), std::back_inserter(makeDpkgAvailable
), notInstalled
);
79 if (makeDpkgAvailable
.empty() == false)
81 auto const BaseArgs
= Args
.size();
82 Args
.push_back("--merge-avail");
83 // FIXME: supported only since 1.17.7 in dpkg
86 pid_t
const dpkgMergeAvail
= debSystem::ExecDpkg(Args
, &dummyAvail
, nullptr, true);
88 FILE* dpkg
= fdopen(dummyAvail
, "w");
89 for (auto const &V
: makeDpkgAvailable
)
90 fprintf(dpkg
, "Package: %s\nVersion: 0~\nArchitecture: %s\nMaintainer: Dummy Example <dummy@example.org>\n"
91 "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());
94 ExecWait(dpkgMergeAvail
, "dpkg --merge-avail", true);
95 Args
.erase(Args
.begin() + BaseArgs
, Args
.end());
98 bool const dpkgMultiArch
= _system
->MultiArchSupported();
100 Args
.push_back("--set-selections");
102 pid_t
const dpkgSelections
= debSystem::ExecDpkg(Args
, &selections
, nullptr, DiscardOutput
);
104 FILE* dpkg
= fdopen(selections
, "w");
106 auto const dpkgName
= [&](pkgCache::VerIterator
const &V
) {
107 pkgCache::PkgIterator P
= V
.ParentPkg();
108 if (dpkgMultiArch
== false)
109 fprintf(dpkg
, "%s %s\n", P
.FullName(true).c_str(), state
.c_str());
111 fprintf(dpkg
, "%s:%s %s\n", P
.Name(), V
.Arch(), state
.c_str());
113 for (auto const &V
: d
->unhold
)
115 if (V
.ParentPkg()->CurrentVer
!= 0)
121 if (d
->purge
.empty() == false)
124 std::for_each(d
->purge
.begin(), d
->purge
.end(), dpkgName
);
126 if (d
->deinstall
.empty() == false)
129 std::for_each(d
->deinstall
.begin(), d
->deinstall
.end(), dpkgName
);
131 if (d
->hold
.empty() == false)
134 std::for_each(d
->hold
.begin(), d
->hold
.end(), dpkgName
);
136 if (d
->install
.empty() == false)
139 std::for_each(d
->install
.begin(), d
->install
.end(), dpkgName
);
143 if (ExecWait(dpkgSelections
, "dpkg --set-selections") == false)
145 std::move(d
->purge
.begin(), d
->purge
.end(), std::back_inserter(d
->error
));
147 std::move(d
->deinstall
.begin(), d
->deinstall
.end(), std::back_inserter(d
->error
));
148 d
->deinstall
.clear();
149 std::move(d
->hold
.begin(), d
->hold
.end(), std::back_inserter(d
->error
));
151 std::move(d
->unhold
.begin(), d
->unhold
.end(), std::back_inserter(d
->error
));
153 std::move(d
->install
.begin(), d
->install
.end(), std::back_inserter(d
->error
));
156 return d
->error
.empty();
159 StateChanges::StateChanges() : d(new StateChanges::Private()) {}
160 StateChanges::StateChanges(StateChanges
&&) = default;
161 StateChanges
& StateChanges::operator=(StateChanges
&&) = default;
162 StateChanges::~StateChanges() = default;