]> git.saurik.com Git - apt.git/blame - apt-pkg/statechanges.cc
VersionHash: Do not skip too long dependency lines
[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>
27f38567 6#include <apt-pkg/prettyprinters.h>
b49068c5
DK
7
8#include <algorithm>
9#include <memory>
10
11namespace APT
12{
13
14class StateChanges::Private
15{
16public:
17 APT::VersionVector hold;
64e3414e 18 APT::VersionVector unhold;
b49068c5 19 APT::VersionVector install;
64e3414e
DK
20 APT::VersionVector deinstall;
21 APT::VersionVector purge;
b49068c5
DK
22 APT::VersionVector error;
23};
24
64e3414e
DK
25#define APT_GETTERSETTER(Name, Container) \
26void StateChanges::Name(pkgCache::VerIterator const &Ver) \
27{ \
b820fd59
DK
28 if (Ver.end() == false) \
29 Container.push_back(Ver); \
64e3414e
DK
30}\
31APT::VersionVector& StateChanges::Name() \
32{ \
33 return Container; \
b49068c5 34}
64e3414e
DK
35APT_GETTERSETTER(Hold, d->hold)
36APT_GETTERSETTER(Unhold, d->unhold)
37APT_GETTERSETTER(Install, d->install)
38APT_GETTERSETTER(Remove, d->deinstall)
39APT_GETTERSETTER(Purge, d->purge)
40#undef APT_GETTERSETTER
b49068c5
DK
41APT::VersionVector& StateChanges::Error()
42{
43 return d->error;
44}
45
64e3414e 46void StateChanges::clear()
b49068c5
DK
47{
48 d->hold.clear();
64e3414e 49 d->unhold.clear();
b49068c5 50 d->install.clear();
64e3414e
DK
51 d->deinstall.clear();
52 d->purge.clear();
b49068c5
DK
53 d->error.clear();
54}
55
64e3414e
DK
56bool StateChanges::empty() const
57{
58 return d->hold.empty() &&
59 d->unhold.empty() &&
60 d->install.empty() &&
61 d->deinstall.empty() &&
62 d->purge.empty() &&
63 d->error.empty();
64}
65
b49068c5
DK
66bool StateChanges::Save(bool const DiscardOutput)
67{
27f38567 68 bool const Debug = _config->FindB("Debug::pkgDpkgPm", false);
b49068c5 69 d->error.clear();
64e3414e 70 if (d->hold.empty() && d->unhold.empty() && d->install.empty() && d->deinstall.empty() && d->purge.empty())
b49068c5
DK
71 return true;
72
73 std::vector<std::string> Args = debSystem::GetDpkgBaseCommand();
74 // ensure dpkg knows about the package so that it keeps the status we set
64e3414e 75 if (d->hold.empty() == false || d->install.empty() == false)
b49068c5
DK
76 {
77 APT::VersionVector makeDpkgAvailable;
78 auto const notInstalled = [](pkgCache::VerIterator const &V) { return V.ParentPkg()->CurrentVer == 0; };
79 std::copy_if(d->hold.begin(), d->hold.end(), std::back_inserter(makeDpkgAvailable), notInstalled);
80 std::copy_if(d->install.begin(), d->install.end(), std::back_inserter(makeDpkgAvailable), notInstalled);
81
82 if (makeDpkgAvailable.empty() == false)
83 {
84 auto const BaseArgs = Args.size();
85 Args.push_back("--merge-avail");
86 // FIXME: supported only since 1.17.7 in dpkg
87 Args.push_back("-");
88 int dummyAvail = -1;
27f38567
DK
89 if (Debug)
90 {
91 for (auto const &V: makeDpkgAvailable)
92 {
93 std::clog << "echo 'Dummy record for " << V.ParentPkg().FullName(false) << "' | ";
94 std::copy(Args.begin(), Args.end(), std::ostream_iterator<std::string>(std::clog, " "));
95 std::clog << std::endl;
96 }
97 }
98 else
99 {
100 pid_t const dpkgMergeAvail = debSystem::ExecDpkg(Args, &dummyAvail, nullptr, true);
101
102 FILE* dpkg = fdopen(dummyAvail, "w");
103 for (auto const &V: makeDpkgAvailable)
104 fprintf(dpkg, "Package: %s\nVersion: 0~\nArchitecture: %s\nMaintainer: Dummy Example <dummy@example.org>\n"
105 "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());
106 fclose(dpkg);
107
108 ExecWait(dpkgMergeAvail, "dpkg --merge-avail", true);
109 }
b49068c5
DK
110 Args.erase(Args.begin() + BaseArgs, Args.end());
111 }
112 }
113 bool const dpkgMultiArch = _system->MultiArchSupported();
114
115 Args.push_back("--set-selections");
27f38567 116 if (Debug)
64e3414e 117 {
27f38567
DK
118 std::string state;
119 auto const dpkgName = [&](pkgCache::VerIterator const &V) {
120 pkgCache::PkgIterator P = V.ParentPkg();
121 if (strcmp(V.Arch(), "none") == 0)
122 ioprintf(std::clog, "echo '%s %s' | ", P.Name(), state.c_str());
123 else if (dpkgMultiArch == false)
124 ioprintf(std::clog, "echo '%s %s' | ", P.FullName(true).c_str(), state.c_str());
125 else
126 ioprintf(std::clog, "echo '%s:%s %s' | ", P.Name(), V.Arch(), state.c_str());
127 std::copy(Args.begin(), Args.end(), std::ostream_iterator<std::string>(std::clog, " "));
128 std::clog << std::endl;
129 };
130 for (auto const &V: d->unhold)
131 {
132 if (V.ParentPkg()->CurrentVer != 0)
133 state = "install";
134 else
135 state = "deinstall";
136 dpkgName(V);
137 }
138 if (d->purge.empty() == false)
139 {
140 state = "purge";
141 std::for_each(d->purge.begin(), d->purge.end(), dpkgName);
142 }
143 if (d->deinstall.empty() == false)
144 {
64e3414e 145 state = "deinstall";
27f38567
DK
146 std::for_each(d->deinstall.begin(), d->deinstall.end(), dpkgName);
147 }
148 if (d->hold.empty() == false)
149 {
150 state = "hold";
151 std::for_each(d->hold.begin(), d->hold.end(), dpkgName);
152 }
153 if (d->install.empty() == false)
154 {
155 state = "install";
156 std::for_each(d->install.begin(), d->install.end(), dpkgName);
157 }
b49068c5 158 }
27f38567 159 else
b49068c5 160 {
27f38567
DK
161 int selections = -1;
162 pid_t const dpkgSelections = debSystem::ExecDpkg(Args, &selections, nullptr, DiscardOutput);
163
164 FILE* dpkg = fdopen(selections, "w");
165 std::string state;
166 auto const dpkgName = [&](pkgCache::VerIterator const &V) {
167 pkgCache::PkgIterator P = V.ParentPkg();
168 if (strcmp(V.Arch(), "none") == 0)
169 fprintf(dpkg, "%s %s\n", P.Name(), state.c_str());
170 else if (dpkgMultiArch == false)
171 fprintf(dpkg, "%s %s\n", P.FullName(true).c_str(), state.c_str());
172 else
173 fprintf(dpkg, "%s:%s %s\n", P.Name(), V.Arch(), state.c_str());
174 };
175 for (auto const &V: d->unhold)
176 {
177 if (V.ParentPkg()->CurrentVer != 0)
178 state = "install";
179 else
180 state = "deinstall";
181 dpkgName(V);
182 }
183 if (d->purge.empty() == false)
184 {
185 state = "purge";
186 std::for_each(d->purge.begin(), d->purge.end(), dpkgName);
187 }
188 if (d->deinstall.empty() == false)
189 {
190 state = "deinstall";
191 std::for_each(d->deinstall.begin(), d->deinstall.end(), dpkgName);
192 }
193 if (d->hold.empty() == false)
194 {
195 state = "hold";
196 std::for_each(d->hold.begin(), d->hold.end(), dpkgName);
197 }
198 if (d->install.empty() == false)
199 {
200 state = "install";
201 std::for_each(d->install.begin(), d->install.end(), dpkgName);
202 }
203 fclose(dpkg);
b49068c5 204
27f38567
DK
205 if (ExecWait(dpkgSelections, "dpkg --set-selections") == false)
206 {
207 std::move(d->purge.begin(), d->purge.end(), std::back_inserter(d->error));
208 d->purge.clear();
209 std::move(d->deinstall.begin(), d->deinstall.end(), std::back_inserter(d->error));
210 d->deinstall.clear();
211 std::move(d->hold.begin(), d->hold.end(), std::back_inserter(d->error));
212 d->hold.clear();
213 std::move(d->unhold.begin(), d->unhold.end(), std::back_inserter(d->error));
214 d->unhold.clear();
215 std::move(d->install.begin(), d->install.end(), std::back_inserter(d->error));
216 d->install.clear();
217 }
b49068c5
DK
218 }
219 return d->error.empty();
220}
221
222StateChanges::StateChanges() : d(new StateChanges::Private()) {}
223StateChanges::StateChanges(StateChanges&&) = default;
224StateChanges& StateChanges::operator=(StateChanges&&) = default;
225StateChanges::~StateChanges() = default;
226
227}