]> git.saurik.com Git - apt.git/blame - apt-pkg/edsp.cc
do not call resolver twice on (dist-)upgrade
[apt.git] / apt-pkg / edsp.cc
CommitLineData
6d38011b
DK
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
3/* ######################################################################
4 Set of methods to help writing and reading everything needed for EDSP
5 ##################################################################### */
6 /*}}}*/
7// Include Files /*{{{*/
ea542140
DK
8#include <config.h>
9
c3b85126 10#include <apt-pkg/edsp.h>
6d38011b 11#include <apt-pkg/error.h>
472ff00e 12#include <apt-pkg/cacheset.h>
6d38011b 13#include <apt-pkg/configuration.h>
2029276f 14#include <apt-pkg/tagfile.h>
472ff00e
DK
15#include <apt-pkg/fileutl.h>
16#include <apt-pkg/progress.h>
453b82a3
DK
17#include <apt-pkg/depcache.h>
18#include <apt-pkg/pkgcache.h>
19#include <apt-pkg/cacheiterators.h>
20#include <apt-pkg/strutl.h>
f63c067e 21#include <apt-pkg/pkgrecords.h>
6d38011b 22
453b82a3
DK
23#include <ctype.h>
24#include <stddef.h>
25#include <string.h>
26#include <time.h>
27#include <unistd.h>
6d38011b 28#include <stdio.h>
99055353 29#include <algorithm>
453b82a3
DK
30#include <iostream>
31#include <vector>
32#include <limits>
472ff00e 33#include <string>
453b82a3 34#include <list>
472ff00e 35
ea542140 36#include <apti18n.h>
6d38011b
DK
37 /*}}}*/
38
472ff00e
DK
39using std::string;
40
d4f626ff
DK
41// we could use pkgCache::DepType and ::Priority, but these would be localized stringsā€¦
42const char * const EDSP::PrioMap[] = {0, "important", "required", "standard",
43 "optional", "extra"};
ee8c790a 44const char * const EDSP::DepMap[] = {"", "Depends", "Pre-Depends", "Suggests",
d4f626ff
DK
45 "Recommends" , "Conflicts", "Replaces",
46 "Obsoletes", "Breaks", "Enhances"};
47
c3b85126 48// EDSP::WriteScenario - to the given file descriptor /*{{{*/
b57c0e35 49bool EDSP::WriteScenario(pkgDepCache &Cache, FILE* output, OpProgress *Progress)
6d38011b 50{
b57c0e35
DK
51 if (Progress != NULL)
52 Progress->SubProgress(Cache.Head().VersionCount, _("Send scenario to solver"));
53 unsigned long p = 0;
99055353 54 std::vector<std::string> archs = APT::Configuration::getArchitectures();
6d38011b 55 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg)
99055353
DK
56 {
57 std::string const arch = Pkg.Arch();
58 if (std::find(archs.begin(), archs.end(), arch) == archs.end())
59 continue;
b57c0e35 60 for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() == false; ++Ver, ++p)
6d38011b 61 {
d4f626ff 62 WriteScenarioVersion(Cache, output, Pkg, Ver);
65512241 63 WriteScenarioDependency(output, Ver);
6d38011b 64 fprintf(output, "\n");
b57c0e35
DK
65 if (Progress != NULL && p % 100 == 0)
66 Progress->Progress(p);
6d38011b 67 }
99055353 68 }
6d38011b
DK
69 return true;
70}
71 /*}}}*/
d4f626ff
DK
72// EDSP::WriteLimitedScenario - to the given file descriptor /*{{{*/
73bool EDSP::WriteLimitedScenario(pkgDepCache &Cache, FILE* output,
b57c0e35
DK
74 APT::PackageSet const &pkgset,
75 OpProgress *Progress)
d4f626ff 76{
b57c0e35
DK
77 if (Progress != NULL)
78 Progress->SubProgress(Cache.Head().VersionCount, _("Send scenario to solver"));
79 unsigned long p = 0;
80 for (APT::PackageSet::const_iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg, ++p)
d4f626ff
DK
81 for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() == false; ++Ver)
82 {
83 WriteScenarioVersion(Cache, output, Pkg, Ver);
65512241 84 WriteScenarioLimitedDependency(output, Ver, pkgset);
d4f626ff 85 fprintf(output, "\n");
b57c0e35
DK
86 if (Progress != NULL && p % 100 == 0)
87 Progress->Progress(p);
d4f626ff 88 }
b57c0e35
DK
89 if (Progress != NULL)
90 Progress->Done();
d4f626ff
DK
91 return true;
92}
93 /*}}}*/
94// EDSP::WriteScenarioVersion /*{{{*/
95void EDSP::WriteScenarioVersion(pkgDepCache &Cache, FILE* output, pkgCache::PkgIterator const &Pkg,
96 pkgCache::VerIterator const &Ver)
97{
f63c067e
SZ
98 pkgRecords Recs(Cache);
99 pkgRecords::Parser &rec = Recs.Lookup(Ver.FileList());
100 string srcpkg = rec.SourcePkg().empty() ? Pkg.Name() : rec.SourcePkg();
101
d4f626ff 102 fprintf(output, "Package: %s\n", Pkg.Name());
f63c067e 103 fprintf(output, "Source: %s\n", srcpkg.c_str());
d4f626ff
DK
104 fprintf(output, "Architecture: %s\n", Ver.Arch());
105 fprintf(output, "Version: %s\n", Ver.VerStr());
106 if (Pkg.CurrentVer() == Ver)
107 fprintf(output, "Installed: yes\n");
cbc702ea
DK
108 if (Pkg->SelectedState == pkgCache::State::Hold ||
109 (Cache[Pkg].Keep() == true && Cache[Pkg].Protect() == true))
d4f626ff
DK
110 fprintf(output, "Hold: yes\n");
111 fprintf(output, "APT-ID: %d\n", Ver->ID);
112 fprintf(output, "Priority: %s\n", PrioMap[Ver->Priority]);
113 if ((Pkg->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
114 fprintf(output, "Essential: yes\n");
115 fprintf(output, "Section: %s\n", Ver.Section());
894d672e 116 if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed)
d4f626ff 117 fprintf(output, "Multi-Arch: allowed\n");
894d672e 118 else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign)
d4f626ff 119 fprintf(output, "Multi-Arch: foreign\n");
894d672e 120 else if ((Ver->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same)
d4f626ff
DK
121 fprintf(output, "Multi-Arch: same\n");
122 signed short Pin = std::numeric_limits<signed short>::min();
b5ea5d4a
SZ
123 std::set<string> Releases;
124 for (pkgCache::VerFileIterator I = Ver.FileList(); I.end() == false; ++I) {
125 pkgCache::PkgFileIterator File = I.File();
126 signed short const p = Cache.GetPolicy().GetPriority(File);
d4f626ff
DK
127 if (Pin < p)
128 Pin = p;
b5ea5d4a
SZ
129 if ((File->Flags & pkgCache::Flag::NotSource) != pkgCache::Flag::NotSource) {
130 string Release = File.RelStr();
131 if (!Release.empty())
132 Releases.insert(Release);
133 }
134 }
135 if (!Releases.empty()) {
136 fprintf(output, "APT-Release:\n");
137 for (std::set<string>::iterator R = Releases.begin(); R != Releases.end(); ++R)
138 fprintf(output, " %s\n", R->c_str());
d4f626ff
DK
139 }
140 fprintf(output, "APT-Pin: %d\n", Pin);
141 if (Cache.GetCandidateVer(Pkg) == Ver)
142 fprintf(output, "APT-Candidate: yes\n");
143 if ((Cache[Pkg].Flags & pkgCache::Flag::Auto) == pkgCache::Flag::Auto)
144 fprintf(output, "APT-Automatic: yes\n");
145}
146 /*}}}*/
147// EDSP::WriteScenarioDependency /*{{{*/
65512241 148void EDSP::WriteScenarioDependency( FILE* output, pkgCache::VerIterator const &Ver)
d4f626ff
DK
149{
150 std::string dependencies[pkgCache::Dep::Enhances + 1];
151 bool orGroup = false;
152 for (pkgCache::DepIterator Dep = Ver.DependsList(); Dep.end() == false; ++Dep)
153 {
d5648746 154 if (Dep.IsMultiArchImplicit() == true)
d4f626ff
DK
155 continue;
156 if (orGroup == false)
157 dependencies[Dep->Type].append(", ");
158 dependencies[Dep->Type].append(Dep.TargetPkg().Name());
159 if (Dep->Version != 0)
160 dependencies[Dep->Type].append(" (").append(pkgCache::CompTypeDeb(Dep->CompareOp)).append(" ").append(Dep.TargetVer()).append(")");
161 if ((Dep->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or)
162 {
163 dependencies[Dep->Type].append(" | ");
164 orGroup = true;
165 }
166 else
167 orGroup = false;
168 }
169 for (int i = 1; i < pkgCache::Dep::Enhances + 1; ++i)
170 if (dependencies[i].empty() == false)
171 fprintf(output, "%s: %s\n", DepMap[i], dependencies[i].c_str()+2);
172 string provides;
173 for (pkgCache::PrvIterator Prv = Ver.ProvidesList(); Prv.end() == false; ++Prv)
174 {
d5648746 175 if (Prv.IsMultiArchImplicit() == true)
d4f626ff
DK
176 continue;
177 provides.append(", ").append(Prv.Name());
178 }
179 if (provides.empty() == false)
180 fprintf(output, "Provides: %s\n", provides.c_str()+2);
181}
182 /*}}}*/
183// EDSP::WriteScenarioLimitedDependency /*{{{*/
65512241 184void EDSP::WriteScenarioLimitedDependency(FILE* output,
d4f626ff
DK
185 pkgCache::VerIterator const &Ver,
186 APT::PackageSet const &pkgset)
187{
188 std::string dependencies[pkgCache::Dep::Enhances + 1];
189 bool orGroup = false;
190 for (pkgCache::DepIterator Dep = Ver.DependsList(); Dep.end() == false; ++Dep)
191 {
d5648746 192 if (Dep.IsMultiArchImplicit() == true)
d4f626ff
DK
193 continue;
194 if (orGroup == false)
195 {
196 if (pkgset.find(Dep.TargetPkg()) == pkgset.end())
197 continue;
198 dependencies[Dep->Type].append(", ");
199 }
200 else if (pkgset.find(Dep.TargetPkg()) == pkgset.end())
201 {
202 if ((Dep->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or)
203 continue;
204 dependencies[Dep->Type].erase(dependencies[Dep->Type].end()-3, dependencies[Dep->Type].end());
205 orGroup = false;
206 continue;
207 }
208 dependencies[Dep->Type].append(Dep.TargetPkg().Name());
209 if (Dep->Version != 0)
210 dependencies[Dep->Type].append(" (").append(pkgCache::CompTypeDeb(Dep->CompareOp)).append(" ").append(Dep.TargetVer()).append(")");
211 if ((Dep->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or)
212 {
213 dependencies[Dep->Type].append(" | ");
214 orGroup = true;
215 }
216 else
217 orGroup = false;
218 }
219 for (int i = 1; i < pkgCache::Dep::Enhances + 1; ++i)
220 if (dependencies[i].empty() == false)
221 fprintf(output, "%s: %s\n", DepMap[i], dependencies[i].c_str()+2);
222 string provides;
223 for (pkgCache::PrvIterator Prv = Ver.ProvidesList(); Prv.end() == false; ++Prv)
224 {
d5648746 225 if (Prv.IsMultiArchImplicit() == true)
d4f626ff
DK
226 continue;
227 if (pkgset.find(Prv.ParentPkg()) == pkgset.end())
228 continue;
229 provides.append(", ").append(Prv.Name());
230 }
231 if (provides.empty() == false)
232 fprintf(output, "Provides: %s\n", provides.c_str()+2);
233}
234 /*}}}*/
c3b85126 235// EDSP::WriteRequest - to the given file descriptor /*{{{*/
93794bc9 236bool EDSP::WriteRequest(pkgDepCache &Cache, FILE* output, bool const Upgrade,
b57c0e35
DK
237 bool const DistUpgrade, bool const AutoRemove,
238 OpProgress *Progress)
6d38011b 239{
b57c0e35
DK
240 if (Progress != NULL)
241 Progress->SubProgress(Cache.Head().PackageCount, _("Send request to solver"));
242 unsigned long p = 0;
93794bc9 243 string del, inst;
b57c0e35 244 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg, ++p)
6d38011b 245 {
b57c0e35
DK
246 if (Progress != NULL && p % 100 == 0)
247 Progress->Progress(p);
6d38011b 248 string* req;
036eb012
DK
249 pkgDepCache::StateCache &P = Cache[Pkg];
250 if (P.Delete() == true)
6d38011b 251 req = &del;
036eb012
DK
252 else if (P.NewInstall() == true || P.Upgrade() == true || P.ReInstall() == true ||
253 (P.Mode == pkgDepCache::ModeKeep && (P.iFlags & pkgDepCache::Protected) == pkgDepCache::Protected))
6d38011b 254 req = &inst;
6d38011b
DK
255 else
256 continue;
6d5bd614 257 req->append(" ").append(Pkg.FullName());
6d38011b 258 }
25252738 259 fprintf(output, "Request: EDSP 0.5\n");
caa32793
SZ
260
261 const char *arch = _config->Find("APT::Architecture").c_str();
262 std::vector<string> archs = APT::Configuration::getArchitectures();
263 fprintf(output, "Architecture: %s\n", arch);
264 fprintf(output, "Architectures:");
265 for (std::vector<string>::const_iterator a = archs.begin(); a != archs.end(); ++a)
266 fprintf(output, " %s", a->c_str());
267 fprintf(output, "\n");
268
6d38011b 269 if (del.empty() == false)
6d5bd614 270 fprintf(output, "Remove: %s\n", del.c_str()+1);
6d38011b 271 if (inst.empty() == false)
6d5bd614 272 fprintf(output, "Install: %s\n", inst.c_str()+1);
93794bc9
DK
273 if (Upgrade == true)
274 fprintf(output, "Upgrade: yes\n");
275 if (DistUpgrade == true)
276 fprintf(output, "Dist-Upgrade: yes\n");
277 if (AutoRemove == true)
278 fprintf(output, "Autoremove: yes\n");
279 if (_config->FindB("APT::Solver::Strict-Pinning", true) == false)
280 fprintf(output, "Strict-Pinning: no\n");
281 string solverpref("APT::Solver::");
98278a81 282 solverpref.append(_config->Find("APT::Solver", "internal")).append("::Preferences");
6d5bd614 283 if (_config->Exists(solverpref) == true)
93794bc9 284 fprintf(output, "Preferences: %s\n", _config->Find(solverpref,"").c_str());
6d5bd614 285 fprintf(output, "\n");
6d38011b 286
e3674d91
DK
287 return true;
288}
289 /*}}}*/
2029276f 290// EDSP::ReadResponse - from the given file descriptor /*{{{*/
b57c0e35 291bool EDSP::ReadResponse(int const input, pkgDepCache &Cache, OpProgress *Progress) {
2a33cb16
DK
292 /* We build an map id to mmap offset here
293 In theory we could use the offset as ID, but then VersionCount
294 couldn't be used to create other versionmappings anymore and it
295 would be too easy for a (buggy) solver to segfault APTā€¦ */
296 unsigned long long const VersionCount = Cache.Head().VersionCount;
297 unsigned long VerIdx[VersionCount];
76d4aab0 298 for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; ++P) {
2a33cb16
DK
299 for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; ++V)
300 VerIdx[V->ID] = V.Index();
76d4aab0
DK
301 Cache[P].Marked = true;
302 Cache[P].Garbage = false;
303 }
2a33cb16 304
c80a49f5
DK
305 FileFd in;
306 in.OpenDescriptor(input, FileFd::ReadOnly);
288a76d2 307 pkgTagFile response(&in, 100);
c80a49f5
DK
308 pkgTagSection section;
309
2029276f
DK
310 while (response.Step(section) == true) {
311 std::string type;
312 if (section.Exists("Install") == true)
313 type = "Install";
314 else if (section.Exists("Remove") == true)
315 type = "Remove";
e876223c 316 else if (section.Exists("Progress") == true) {
b57c0e35 317 if (Progress != NULL) {
c6660a4b 318 string msg = section.FindS("Message");
b57c0e35 319 if (msg.empty() == true)
c6660a4b
DK
320 msg = _("Prepare for receiving solution");
321 Progress->SubProgress(100, msg, section.FindI("Percentage", 0));
b57c0e35 322 }
e876223c 323 continue;
ebfeeaed 324 } else if (section.Exists("Error") == true) {
27c69dd0
DK
325 std::string msg = SubstVar(SubstVar(section.FindS("Message"), "\n .\n", "\n\n"), "\n ", "\n");
326 if (msg.empty() == true) {
327 msg = _("External solver failed without a proper error message");
a1e68c33 328 _error->Error("%s", msg.c_str());
27c69dd0
DK
329 } else
330 _error->Error("External solver failed with: %s", msg.substr(0,msg.find('\n')).c_str());
331 if (Progress != NULL)
332 Progress->Done();
ebfeeaed
DK
333 std::cerr << "The solver encountered an error of type: " << section.FindS("Error") << std::endl;
334 std::cerr << "The following information might help you to understand what is wrong:" << std::endl;
27c69dd0
DK
335 std::cerr << msg << std::endl << std::endl;
336 return false;
76d4aab0
DK
337 } else if (section.Exists("Autoremove") == true)
338 type = "Autoremove";
339 else
2029276f 340 continue;
29099cb6 341
2a33cb16
DK
342 size_t const id = section.FindULL(type.c_str(), VersionCount);
343 if (id == VersionCount) {
69a78835
DK
344 _error->Warning("Unable to parse %s request with id value '%s'!", type.c_str(), section.FindS(type.c_str()).c_str());
345 continue;
2a33cb16
DK
346 } else if (id > Cache.Head().VersionCount) {
347 _error->Warning("ID value '%s' in %s request stanza is to high to refer to a known version!", section.FindS(type.c_str()).c_str(), type.c_str());
348 continue;
69a78835 349 }
2029276f 350
2a33cb16 351 pkgCache::VerIterator Ver(Cache.GetCache(), Cache.GetCache().VerP + VerIdx[id]);
69a78835
DK
352 Cache.SetCandidateVersion(Ver);
353 if (type == "Install")
bda94cb8 354 Cache.MarkInstall(Ver.ParentPkg(), false, 0, false);
69a78835
DK
355 else if (type == "Remove")
356 Cache.MarkDelete(Ver.ParentPkg(), false);
76d4aab0
DK
357 else if (type == "Autoremove") {
358 Cache[Ver.ParentPkg()].Marked = false;
359 Cache[Ver.ParentPkg()].Garbage = true;
360 }
2029276f
DK
361 }
362 return true;
363}
364 /*}}}*/
6d5bd614
DK
365// EDSP::ReadLine - first line from the given file descriptor /*{{{*/
366// ---------------------------------------------------------------------
367/* Little helper method to read a complete line into a string. Similar to
368 fgets but we need to use the low-level read() here as otherwise the
369 listparser will be confused later on as mixing of fgets and read isn't
2029276f 370 a supported action according to the manpages and results are undefined */
6d5bd614
DK
371bool EDSP::ReadLine(int const input, std::string &line) {
372 char one;
373 ssize_t data = 0;
374 line.erase();
375 line.reserve(100);
376 while ((data = read(input, &one, sizeof(one))) != -1) {
377 if (data != 1)
378 continue;
379 if (one == '\n')
380 return true;
381 if (one == '\r')
382 continue;
383 if (line.empty() == true && isblank(one) != 0)
384 continue;
385 line += one;
386 }
387 return false;
388}
389 /*}}}*/
40795fca
DK
390// EDSP::StringToBool - convert yes/no to bool /*{{{*/
391// ---------------------------------------------------------------------
392/* we are not as lazy as we are in the global StringToBool as we really
393 only accept yes/no here - but we will ignore leading spaces */
394bool EDSP::StringToBool(char const *answer, bool const defValue) {
395 for (; isspace(*answer) != 0; ++answer);
396 if (strncasecmp(answer, "yes", 3) == 0)
397 return true;
398 else if (strncasecmp(answer, "no", 2) == 0)
399 return false;
400 else
401 _error->Warning("Value '%s' is not a boolean 'yes' or 'no'!", answer);
402 return defValue;
403}
404 /*}}}*/
6d5bd614
DK
405// EDSP::ReadRequest - first stanza from the given file descriptor /*{{{*/
406bool EDSP::ReadRequest(int const input, std::list<std::string> &install,
40795fca
DK
407 std::list<std::string> &remove, bool &upgrade,
408 bool &distUpgrade, bool &autoRemove)
6d5bd614 409{
40795fca
DK
410 install.clear();
411 remove.clear();
412 upgrade = false;
413 distUpgrade = false;
414 autoRemove = false;
6d5bd614
DK
415 std::string line;
416 while (ReadLine(input, line) == true)
417 {
418 // Skip empty lines before request
419 if (line.empty() == true)
420 continue;
421 // The first Tag must be a request, so search for it
40795fca 422 if (line.compare(0, 8, "Request:") != 0)
6d5bd614
DK
423 continue;
424
425 while (ReadLine(input, line) == true)
426 {
427 // empty lines are the end of the request
428 if (line.empty() == true)
429 return true;
430
431 std::list<std::string> *request = NULL;
40795fca 432 if (line.compare(0, 8, "Install:") == 0)
6d5bd614 433 {
40795fca 434 line.erase(0, 8);
6d5bd614
DK
435 request = &install;
436 }
40795fca 437 else if (line.compare(0, 7, "Remove:") == 0)
6d5bd614 438 {
40795fca 439 line.erase(0, 7);
6d5bd614
DK
440 request = &remove;
441 }
40795fca
DK
442 else if (line.compare(0, 8, "Upgrade:") == 0)
443 upgrade = EDSP::StringToBool(line.c_str() + 9, false);
444 else if (line.compare(0, 13, "Dist-Upgrade:") == 0)
445 distUpgrade = EDSP::StringToBool(line.c_str() + 14, false);
446 else if (line.compare(0, 11, "Autoremove:") == 0)
447 autoRemove = EDSP::StringToBool(line.c_str() + 12, false);
1f6cf9e7
DK
448 else if (line.compare(0, 13, "Architecture:") == 0)
449 _config->Set("APT::Architecture", line.c_str() + 14);
450 else if (line.compare(0, 14, "Architectures:") == 0)
451 {
452 std::string const archs = line.c_str() + 15;
453 _config->Set("APT::Architectures", SubstVar(archs, " ", ","));
454 }
40795fca
DK
455 else
456 _error->Warning("Unknown line in EDSP Request stanza: %s", line.c_str());
457
6d5bd614
DK
458 if (request == NULL)
459 continue;
460 size_t end = line.length();
461 do {
462 size_t begin = line.rfind(' ');
463 if (begin == std::string::npos)
464 {
40795fca 465 request->push_back(line.substr(0, end));
6d5bd614
DK
466 break;
467 }
468 else if (begin < end)
469 request->push_back(line.substr(begin + 1, end));
470 line.erase(begin);
471 end = line.find_last_not_of(' ');
472 } while (end != std::string::npos);
473 }
474 }
475 return false;
476}
477 /*}}}*/
478// EDSP::ApplyRequest - first stanza from the given file descriptor /*{{{*/
c3b85126 479bool EDSP::ApplyRequest(std::list<std::string> const &install,
29099cb6
DK
480 std::list<std::string> const &remove,
481 pkgDepCache &Cache)
6d5bd614
DK
482{
483 for (std::list<std::string>::const_iterator i = install.begin();
d4f626ff
DK
484 i != install.end(); ++i) {
485 pkgCache::PkgIterator P = Cache.FindPkg(*i);
486 if (P.end() == true)
487 _error->Warning("Package %s is not known, so can't be installed", i->c_str());
488 else
489 Cache.MarkInstall(P, false);
490 }
6d5bd614
DK
491
492 for (std::list<std::string>::const_iterator i = remove.begin();
d4f626ff
DK
493 i != remove.end(); ++i) {
494 pkgCache::PkgIterator P = Cache.FindPkg(*i);
495 if (P.end() == true)
496 _error->Warning("Package %s is not known, so can't be installed", i->c_str());
497 else
498 Cache.MarkDelete(P);
499 }
6d5bd614
DK
500 return true;
501}
502 /*}}}*/
c3b85126
DK
503// EDSP::WriteSolution - to the given file descriptor /*{{{*/
504bool EDSP::WriteSolution(pkgDepCache &Cache, FILE* output)
e3674d91 505{
6d5bd614 506 bool const Debug = _config->FindB("Debug::EDSP::WriteSolution", false);
e3674d91
DK
507 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg)
508 {
509 if (Cache[Pkg].Delete() == true)
d4f626ff
DK
510 {
511 fprintf(output, "Remove: %d\n", Pkg.CurrentVer()->ID);
512 if (Debug == true)
513 fprintf(output, "Package: %s\nVersion: %s\n", Pkg.FullName().c_str(), Pkg.CurrentVer().VerStr());
514 }
e3674d91 515 else if (Cache[Pkg].NewInstall() == true || Cache[Pkg].Upgrade() == true)
d4f626ff 516 {
e3674d91 517 fprintf(output, "Install: %d\n", Cache.GetCandidateVer(Pkg)->ID);
d4f626ff
DK
518 if (Debug == true)
519 fprintf(output, "Package: %s\nVersion: %s\n", Pkg.FullName().c_str(), Cache.GetCandidateVer(Pkg).VerStr());
520 }
76d4aab0
DK
521 else if (Cache[Pkg].Garbage == true)
522 {
523 fprintf(output, "Autoremove: %d\n", Pkg.CurrentVer()->ID);
524 if (Debug == true)
525 fprintf(output, "Package: %s\nVersion: %s\n", Pkg.FullName().c_str(), Pkg.CurrentVer().VerStr());
76d4aab0 526 }
e3674d91
DK
527 else
528 continue;
e3674d91
DK
529 fprintf(output, "\n");
530 }
531
6d38011b
DK
532 return true;
533}
534 /*}}}*/
e876223c
DK
535// EDSP::WriteProgess - pulse to the given file descriptor /*{{{*/
536bool EDSP::WriteProgress(unsigned short const percent, const char* const message, FILE* output) {
3d17b9ff
DK
537 fprintf(output, "Progress: %s\n", TimeRFC1123(time(NULL)).c_str());
538 fprintf(output, "Percentage: %d\n", percent);
539 fprintf(output, "Message: %s\n\n", message);
540 fflush(output);
e876223c
DK
541 return true;
542}
543 /*}}}*/
ebfeeaed
DK
544// EDSP::WriteError - format an error message to be send to file descriptor /*{{{*/
545bool EDSP::WriteError(char const * const uuid, std::string const &message, FILE* output) {
546 fprintf(output, "Error: %s\n", uuid);
547 fprintf(output, "Message: %s\n\n", SubstVar(SubstVar(message, "\n\n", "\n.\n"), "\n", "\n ").c_str());
548 return true;
549}
550 /*}}}*/
ac5fbff8 551// EDSP::ExecuteSolver - fork requested solver and setup ipc pipes {{{*/
5681b3fc 552pid_t EDSP::ExecuteSolver(const char* const solver, int * const solver_in, int * const solver_out, bool) {
741b7da9
DK
553 std::vector<std::string> const solverDirs = _config->FindVector("Dir::Bin::Solvers");
554 std::string file;
555 for (std::vector<std::string>::const_iterator dir = solverDirs.begin();
556 dir != solverDirs.end(); ++dir) {
557 file = flCombine(*dir, solver);
558 if (RealFileExists(file.c_str()) == true)
559 break;
560 file.clear();
561 }
ac5fbff8 562
741b7da9 563 if (file.empty() == true)
5681b3fc
DK
564 {
565 _error->Error("Can't call external solver '%s' as it is not in a configured directory!", solver);
566 return 0;
567 }
741b7da9
DK
568 int external[4] = {-1, -1, -1, -1};
569 if (pipe(external) != 0 || pipe(external + 2) != 0)
5681b3fc
DK
570 {
571 _error->Errno("Resolve", "Can't create needed IPC pipes for EDSP");
572 return 0;
573 }
741b7da9
DK
574 for (int i = 0; i < 4; ++i)
575 SetCloseExec(external[i], true);
ac5fbff8 576
741b7da9
DK
577 pid_t Solver = ExecFork();
578 if (Solver == 0) {
579 dup2(external[0], STDIN_FILENO);
580 dup2(external[3], STDOUT_FILENO);
581 const char* calling[2] = { file.c_str(), 0 };
582 execv(calling[0], (char**) calling);
583 std::cerr << "Failed to execute solver '" << solver << "'!" << std::endl;
584 _exit(100);
585 }
586 close(external[0]);
587 close(external[3]);
ac5fbff8 588
741b7da9 589 if (WaitFd(external[1], true, 5) == false)
5681b3fc
DK
590 {
591 _error->Errno("Resolve", "Timed out while Waiting on availability of solver stdin");
592 return 0;
593 }
ac5fbff8 594
741b7da9
DK
595 *solver_in = external[1];
596 *solver_out = external[2];
5681b3fc
DK
597 return Solver;
598}
599bool EDSP::ExecuteSolver(const char* const solver, int *solver_in, int *solver_out) {
600 if (ExecuteSolver(solver, solver_in, solver_out, true) == 0)
601 return false;
602 return true;
741b7da9
DK
603}
604 /*}}}*/
605// EDSP::ResolveExternal - resolve problems by asking external for help {{{*/
606bool EDSP::ResolveExternal(const char* const solver, pkgDepCache &Cache,
607 bool const upgrade, bool const distUpgrade,
b57c0e35 608 bool const autoRemove, OpProgress *Progress) {
741b7da9 609 int solver_in, solver_out;
5681b3fc
DK
610 pid_t const solver_pid = EDSP::ExecuteSolver(solver, &solver_in, &solver_out, true);
611 if (solver_pid == 0)
741b7da9
DK
612 return false;
613
614 FILE* output = fdopen(solver_in, "w");
615 if (output == NULL)
616 return _error->Errno("Resolve", "fdopen on solver stdin failed");
b57c0e35
DK
617
618 if (Progress != NULL)
619 Progress->OverallProgress(0, 100, 5, _("Execute external solver"));
620 EDSP::WriteRequest(Cache, output, upgrade, distUpgrade, autoRemove, Progress);
621 if (Progress != NULL)
622 Progress->OverallProgress(5, 100, 20, _("Execute external solver"));
623 EDSP::WriteScenario(Cache, output, Progress);
741b7da9
DK
624 fclose(output);
625
b57c0e35
DK
626 if (Progress != NULL)
627 Progress->OverallProgress(25, 100, 75, _("Execute external solver"));
628 if (EDSP::ReadResponse(solver_out, Cache, Progress) == false)
27c69dd0 629 return false;
741b7da9 630
5681b3fc 631 return ExecWait(solver_pid, solver);
ac5fbff8
DK
632}
633 /*}}}*/