#include <apt-pkg/debsystem.h>
#include <apt-pkg/fileutl.h>
#include <apt-pkg/statechanges.h>
+#include <apt-pkg/prettyprinters.h>
#include <algorithm>
#include <memory>
{
public:
APT::VersionVector hold;
+ APT::VersionVector unhold;
APT::VersionVector install;
+ APT::VersionVector deinstall;
+ APT::VersionVector purge;
APT::VersionVector error;
};
-void StateChanges::Hold(pkgCache::VerIterator const &Ver)
-{
- d->hold.push_back(Ver);
-}
-APT::VersionVector& StateChanges::Hold()
-{
- return d->hold;
-}
-void StateChanges::Unhold(pkgCache::VerIterator const &Ver)
-{
- d->install.push_back(Ver);
-}
-APT::VersionVector& StateChanges::Unhold()
-{
- return d->install;
+#define APT_GETTERSETTER(Name, Container) \
+void StateChanges::Name(pkgCache::VerIterator const &Ver) \
+{ \
+ if (Ver.end() == false) \
+ Container.push_back(Ver); \
+}\
+APT::VersionVector& StateChanges::Name() \
+{ \
+ return Container; \
}
+APT_GETTERSETTER(Hold, d->hold)
+APT_GETTERSETTER(Unhold, d->unhold)
+APT_GETTERSETTER(Install, d->install)
+APT_GETTERSETTER(Remove, d->deinstall)
+APT_GETTERSETTER(Purge, d->purge)
+#undef APT_GETTERSETTER
APT::VersionVector& StateChanges::Error()
{
return d->error;
}
-void StateChanges::Discard()
+void StateChanges::clear()
{
d->hold.clear();
+ d->unhold.clear();
d->install.clear();
+ d->deinstall.clear();
+ d->purge.clear();
d->error.clear();
}
+bool StateChanges::empty() const
+{
+ return d->hold.empty() &&
+ d->unhold.empty() &&
+ d->install.empty() &&
+ d->deinstall.empty() &&
+ d->purge.empty() &&
+ d->error.empty();
+}
+
bool StateChanges::Save(bool const DiscardOutput)
{
+ bool const Debug = _config->FindB("Debug::pkgDpkgPm", false);
d->error.clear();
- if (d->hold.empty() && d->install.empty())
+ if (d->hold.empty() && d->unhold.empty() && d->install.empty() && d->deinstall.empty() && d->purge.empty())
return true;
std::vector<std::string> Args = debSystem::GetDpkgBaseCommand();
// ensure dpkg knows about the package so that it keeps the status we set
+ if (d->hold.empty() == false || d->install.empty() == false)
{
APT::VersionVector makeDpkgAvailable;
auto const notInstalled = [](pkgCache::VerIterator const &V) { return V.ParentPkg()->CurrentVer == 0; };
// FIXME: supported only since 1.17.7 in dpkg
Args.push_back("-");
int dummyAvail = -1;
- pid_t const dpkgMergeAvail = debSystem::ExecDpkg(Args, &dummyAvail, nullptr, true);
+ if (Debug)
+ {
+ for (auto const &V: makeDpkgAvailable)
+ {
+ std::clog << "echo 'Dummy record for " << V.ParentPkg().FullName(false) << "' | ";
+ std::copy(Args.begin(), Args.end(), std::ostream_iterator<std::string>(std::clog, " "));
+ std::clog << std::endl;
+ }
+ }
+ else
+ {
+ pid_t const dpkgMergeAvail = debSystem::ExecDpkg(Args, &dummyAvail, nullptr, true);
- FILE* dpkg = fdopen(dummyAvail, "w");
- for (auto const &V: makeDpkgAvailable)
- fprintf(dpkg, "Package: %s\nVersion: 0~\nArchitecture: %s\nMaintainer: Dummy Example <dummy@example.org>\n"
- "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());
- fclose(dpkg);
+ FILE* dpkg = fdopen(dummyAvail, "w");
+ for (auto const &V: makeDpkgAvailable)
+ fprintf(dpkg, "Package: %s\nVersion: 0~\nArchitecture: %s\nMaintainer: Dummy Example <dummy@example.org>\n"
+ "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());
+ fclose(dpkg);
- ExecWait(dpkgMergeAvail, "dpkg --merge-avail", true);
+ ExecWait(dpkgMergeAvail, "dpkg --merge-avail", true);
+ }
Args.erase(Args.begin() + BaseArgs, Args.end());
}
}
bool const dpkgMultiArch = _system->MultiArchSupported();
Args.push_back("--set-selections");
- int selections = -1;
- pid_t const dpkgSelections = debSystem::ExecDpkg(Args, &selections, nullptr, DiscardOutput);
-
- FILE* dpkg = fdopen(selections, "w");
- std::string state;
- auto const dpkgName = [&](pkgCache::VerIterator const &V) {
- pkgCache::PkgIterator P = V.ParentPkg();
- if (dpkgMultiArch == false)
- fprintf(dpkg, "%s %s\n", P.FullName(true).c_str(), state.c_str());
- else
- fprintf(dpkg, "%s:%s %s\n", P.Name(), V.Arch(), state.c_str());
- };
- if (d->hold.empty() == false)
+ if (Debug)
{
- state = "hold";
- std::for_each(d->hold.begin(), d->hold.end(), dpkgName);
+ std::string state;
+ auto const dpkgName = [&](pkgCache::VerIterator const &V) {
+ pkgCache::PkgIterator P = V.ParentPkg();
+ if (strcmp(V.Arch(), "none") == 0)
+ ioprintf(std::clog, "echo '%s %s' | ", P.Name(), state.c_str());
+ else if (dpkgMultiArch == false)
+ ioprintf(std::clog, "echo '%s %s' | ", P.FullName(true).c_str(), state.c_str());
+ else
+ ioprintf(std::clog, "echo '%s:%s %s' | ", P.Name(), V.Arch(), state.c_str());
+ std::copy(Args.begin(), Args.end(), std::ostream_iterator<std::string>(std::clog, " "));
+ std::clog << std::endl;
+ };
+ for (auto const &V: d->unhold)
+ {
+ if (V.ParentPkg()->CurrentVer != 0)
+ state = "install";
+ else
+ state = "deinstall";
+ dpkgName(V);
+ }
+ if (d->purge.empty() == false)
+ {
+ state = "purge";
+ std::for_each(d->purge.begin(), d->purge.end(), dpkgName);
+ }
+ if (d->deinstall.empty() == false)
+ {
+ state = "deinstall";
+ std::for_each(d->deinstall.begin(), d->deinstall.end(), dpkgName);
+ }
+ if (d->hold.empty() == false)
+ {
+ state = "hold";
+ std::for_each(d->hold.begin(), d->hold.end(), dpkgName);
+ }
+ if (d->install.empty() == false)
+ {
+ state = "install";
+ std::for_each(d->install.begin(), d->install.end(), dpkgName);
+ }
}
- if (d->install.empty() == false)
+ else
{
- state = "install";
- std::for_each(d->install.begin(), d->install.end(), dpkgName);
- }
- fclose(dpkg);
+ int selections = -1;
+ pid_t const dpkgSelections = debSystem::ExecDpkg(Args, &selections, nullptr, DiscardOutput);
- if (ExecWait(dpkgSelections, "dpkg --set-selections") == false)
- {
- if (d->hold.empty())
- std::swap(d->install, d->error);
- else if (d->install.empty())
- std::swap(d->hold, d->error);
- else
+ FILE* dpkg = fdopen(selections, "w");
+ std::string state;
+ auto const dpkgName = [&](pkgCache::VerIterator const &V) {
+ pkgCache::PkgIterator P = V.ParentPkg();
+ if (strcmp(V.Arch(), "none") == 0)
+ fprintf(dpkg, "%s %s\n", P.Name(), state.c_str());
+ else if (dpkgMultiArch == false)
+ fprintf(dpkg, "%s %s\n", P.FullName(true).c_str(), state.c_str());
+ else
+ fprintf(dpkg, "%s:%s %s\n", P.Name(), V.Arch(), state.c_str());
+ };
+ for (auto const &V: d->unhold)
+ {
+ if (V.ParentPkg()->CurrentVer != 0)
+ state = "install";
+ else
+ state = "deinstall";
+ dpkgName(V);
+ }
+ if (d->purge.empty() == false)
+ {
+ state = "purge";
+ std::for_each(d->purge.begin(), d->purge.end(), dpkgName);
+ }
+ if (d->deinstall.empty() == false)
+ {
+ state = "deinstall";
+ std::for_each(d->deinstall.begin(), d->deinstall.end(), dpkgName);
+ }
+ if (d->hold.empty() == false)
+ {
+ state = "hold";
+ std::for_each(d->hold.begin(), d->hold.end(), dpkgName);
+ }
+ if (d->install.empty() == false)
+ {
+ state = "install";
+ std::for_each(d->install.begin(), d->install.end(), dpkgName);
+ }
+ fclose(dpkg);
+
+ if (ExecWait(dpkgSelections, "dpkg --set-selections") == false)
{
- std::swap(d->hold, d->error);
+ std::move(d->purge.begin(), d->purge.end(), std::back_inserter(d->error));
+ d->purge.clear();
+ std::move(d->deinstall.begin(), d->deinstall.end(), std::back_inserter(d->error));
+ d->deinstall.clear();
+ std::move(d->hold.begin(), d->hold.end(), std::back_inserter(d->error));
+ d->hold.clear();
+ std::move(d->unhold.begin(), d->unhold.end(), std::back_inserter(d->error));
+ d->unhold.clear();
std::move(d->install.begin(), d->install.end(), std::back_inserter(d->error));
d->install.clear();
}