]> git.saurik.com Git - apt.git/blame - apt-pkg/statechanges.cc
apt-key: change to / before find to satisfy its CWD needs
[apt.git] / apt-pkg / statechanges.cc
CommitLineData
b49068c5
DK
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
7#include <algorithm>
8#include <memory>
9
10namespace APT
11{
12
13class StateChanges::Private
14{
15public:
16 APT::VersionVector hold;
64e3414e 17 APT::VersionVector unhold;
b49068c5 18 APT::VersionVector install;
64e3414e
DK
19 APT::VersionVector deinstall;
20 APT::VersionVector purge;
b49068c5
DK
21 APT::VersionVector error;
22};
23
64e3414e
DK
24#define APT_GETTERSETTER(Name, Container) \
25void StateChanges::Name(pkgCache::VerIterator const &Ver) \
26{ \
27 Container.push_back(Ver); \
28}\
29APT::VersionVector& StateChanges::Name() \
30{ \
31 return Container; \
b49068c5 32}
64e3414e
DK
33APT_GETTERSETTER(Hold, d->hold)
34APT_GETTERSETTER(Unhold, d->unhold)
35APT_GETTERSETTER(Install, d->install)
36APT_GETTERSETTER(Remove, d->deinstall)
37APT_GETTERSETTER(Purge, d->purge)
38#undef APT_GETTERSETTER
b49068c5
DK
39APT::VersionVector& StateChanges::Error()
40{
41 return d->error;
42}
43
64e3414e 44void StateChanges::clear()
b49068c5
DK
45{
46 d->hold.clear();
64e3414e 47 d->unhold.clear();
b49068c5 48 d->install.clear();
64e3414e
DK
49 d->deinstall.clear();
50 d->purge.clear();
b49068c5
DK
51 d->error.clear();
52}
53
64e3414e
DK
54bool StateChanges::empty() const
55{
56 return d->hold.empty() &&
57 d->unhold.empty() &&
58 d->install.empty() &&
59 d->deinstall.empty() &&
60 d->purge.empty() &&
61 d->error.empty();
62}
63
b49068c5
DK
64bool StateChanges::Save(bool const DiscardOutput)
65{
66 d->error.clear();
64e3414e 67 if (d->hold.empty() && d->unhold.empty() && d->install.empty() && d->deinstall.empty() && d->purge.empty())
b49068c5
DK
68 return true;
69
70 std::vector<std::string> Args = debSystem::GetDpkgBaseCommand();
71 // ensure dpkg knows about the package so that it keeps the status we set
64e3414e 72 if (d->hold.empty() == false || d->install.empty() == false)
b49068c5
DK
73 {
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);
78
79 if (makeDpkgAvailable.empty() == false)
80 {
81 auto const BaseArgs = Args.size();
82 Args.push_back("--merge-avail");
83 // FIXME: supported only since 1.17.7 in dpkg
84 Args.push_back("-");
85 int dummyAvail = -1;
86 pid_t const dpkgMergeAvail = debSystem::ExecDpkg(Args, &dummyAvail, nullptr, true);
87
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());
92 fclose(dpkg);
93
94 ExecWait(dpkgMergeAvail, "dpkg --merge-avail", true);
95 Args.erase(Args.begin() + BaseArgs, Args.end());
96 }
97 }
98 bool const dpkgMultiArch = _system->MultiArchSupported();
99
100 Args.push_back("--set-selections");
101 int selections = -1;
102 pid_t const dpkgSelections = debSystem::ExecDpkg(Args, &selections, nullptr, DiscardOutput);
103
104 FILE* dpkg = fdopen(selections, "w");
105 std::string state;
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());
110 else
111 fprintf(dpkg, "%s:%s %s\n", P.Name(), V.Arch(), state.c_str());
112 };
64e3414e
DK
113 for (auto const &V: d->unhold)
114 {
115 if (V.ParentPkg()->CurrentVer != 0)
116 state = "install";
117 else
118 state = "deinstall";
119 dpkgName(V);
120 }
121 if (d->purge.empty() == false)
122 {
123 state = "purge";
124 std::for_each(d->purge.begin(), d->purge.end(), dpkgName);
125 }
126 if (d->deinstall.empty() == false)
127 {
128 state = "deinstall";
129 std::for_each(d->deinstall.begin(), d->deinstall.end(), dpkgName);
130 }
b49068c5
DK
131 if (d->hold.empty() == false)
132 {
133 state = "hold";
134 std::for_each(d->hold.begin(), d->hold.end(), dpkgName);
135 }
136 if (d->install.empty() == false)
137 {
138 state = "install";
139 std::for_each(d->install.begin(), d->install.end(), dpkgName);
140 }
141 fclose(dpkg);
142
143 if (ExecWait(dpkgSelections, "dpkg --set-selections") == false)
144 {
64e3414e
DK
145 std::move(d->purge.begin(), d->purge.end(), std::back_inserter(d->error));
146 d->purge.clear();
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));
150 d->hold.clear();
151 std::move(d->unhold.begin(), d->unhold.end(), std::back_inserter(d->error));
152 d->unhold.clear();
153 std::move(d->install.begin(), d->install.end(), std::back_inserter(d->error));
154 d->install.clear();
b49068c5
DK
155 }
156 return d->error.empty();
157}
158
159StateChanges::StateChanges() : d(new StateChanges::Private()) {}
160StateChanges::StateChanges(StateChanges&&) = default;
161StateChanges& StateChanges::operator=(StateChanges&&) = default;
162StateChanges::~StateChanges() = default;
163
164}