]> git.saurik.com Git - apt.git/blob - apt-pkg/edsp.cc
55bc0a0d9202584ee7025f60638632c9d904c9ac
[apt.git] / apt-pkg / edsp.cc
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 /*{{{*/
8 #include <apt-pkg/edsp.h>
9 #include <apt-pkg/error.h>
10 #include <apt-pkg/configuration.h>
11 #include <apt-pkg/version.h>
12 #include <apt-pkg/policy.h>
13 #include <apt-pkg/tagfile.h>
14
15 #include <apti18n.h>
16 #include <limits>
17
18 #include <stdio.h>
19 /*}}}*/
20
21 // EDSP::WriteScenario - to the given file descriptor /*{{{*/
22 bool EDSP::WriteScenario(pkgDepCache &Cache, FILE* output)
23 {
24 // we could use pkgCache::DepType and ::Priority, but these would be lokalized strings…
25 const char * const PrioMap[] = {0, "important", "required", "standard",
26 "optional", "extra"};
27 const char * const DepMap[] = {"", "Depends", "PreDepends", "Suggests",
28 "Recommends" , "Conflicts", "Replaces",
29 "Obsoletes", "Breaks", "Enhances"};
30
31 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg)
32 {
33 for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() == false; ++Ver)
34 {
35 fprintf(output, "Package: %s\n", Pkg.Name());
36 fprintf(output, "Architecture: %s\n", Ver.Arch());
37 fprintf(output, "Version: %s\n", Ver.VerStr());
38 if (Pkg.CurrentVer() == Ver)
39 fprintf(output, "Installed: yes\n");
40 if (Pkg->SelectedState == pkgCache::State::Hold)
41 fprintf(output, "Hold: yes\n");
42 fprintf(output, "APT-ID: %d\n", Ver->ID);
43 fprintf(output, "Priority: %s\n", PrioMap[Ver->Priority]);
44 if ((Pkg->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
45 fprintf(output, "Essential: yes\n");
46 fprintf(output, "Section: %s\n", Ver.Section());
47 if (Ver->MultiArch == pkgCache::Version::Allowed || Ver->MultiArch == pkgCache::Version::AllAllowed)
48 fprintf(output, "Multi-Arch: allowed\n");
49 else if (Ver->MultiArch == pkgCache::Version::Foreign || Ver->MultiArch == pkgCache::Version::AllForeign)
50 fprintf(output, "Multi-Arch: foreign\n");
51 else if (Ver->MultiArch == pkgCache::Version::Same)
52 fprintf(output, "Multi-Arch: same\n");
53 signed short Pin = std::numeric_limits<signed short>::min();
54 for (pkgCache::VerFileIterator File = Ver.FileList(); File.end() == false; ++File) {
55 signed short const p = Cache.GetPolicy().GetPriority(File.File());
56 if (Pin < p)
57 Pin = p;
58 }
59 fprintf(output, "APT-Pin: %d\n", Pin);
60 if (Cache.GetCandidateVer(Pkg) == Ver)
61 fprintf(output, "APT-Candidate: yes\n");
62 if ((Cache[Pkg].Flags & pkgCache::Flag::Auto) == pkgCache::Flag::Auto)
63 fprintf(output, "APT-Automatic: yes\n");
64 std::string dependencies[pkgCache::Dep::Enhances + 1];
65 bool orGroup = false;
66 for (pkgCache::DepIterator Dep = Ver.DependsList(); Dep.end() == false; ++Dep)
67 {
68 // Ignore implicit dependencies for multiarch here
69 if (strcmp(Pkg.Arch(), Dep.TargetPkg().Arch()) != 0)
70 continue;
71 if (orGroup == false)
72 dependencies[Dep->Type].append(", ");
73 dependencies[Dep->Type].append(Dep.TargetPkg().Name());
74 if (Dep->Version != 0)
75 dependencies[Dep->Type].append(" (").append(pkgCache::CompTypeDeb(Dep->CompareOp)).append(" ").append(Dep.TargetVer()).append(")");
76 if ((Dep->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or)
77 {
78 dependencies[Dep->Type].append(" | ");
79 orGroup = true;
80 }
81 else
82 orGroup = false;
83 }
84 for (int i = 1; i < pkgCache::Dep::Enhances + 1; ++i)
85 if (dependencies[i].empty() == false)
86 fprintf(output, "%s: %s\n", DepMap[i], dependencies[i].c_str()+2);
87 string provides;
88 for (pkgCache::PrvIterator Prv = Ver.ProvidesList(); Prv.end() == false; ++Prv)
89 {
90 // Ignore implicit provides for multiarch here
91 if (strcmp(Pkg.Arch(), Prv.ParentPkg().Arch()) != 0 || strcmp(Pkg.Name(),Prv.Name()) == 0)
92 continue;
93 provides.append(", ").append(Prv.Name());
94 }
95 if (provides.empty() == false)
96 fprintf(output, "Provides: %s\n", provides.c_str()+2);
97
98
99 fprintf(output, "\n");
100 }
101 }
102 return true;
103 }
104 /*}}}*/
105 // EDSP::WriteRequest - to the given file descriptor /*{{{*/
106 bool EDSP::WriteRequest(pkgDepCache &Cache, FILE* output, bool const Upgrade,
107 bool const DistUpgrade, bool const AutoRemove)
108 {
109 string del, inst;
110 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg)
111 {
112 string* req;
113 if (Cache[Pkg].Delete() == true)
114 req = &del;
115 else if (Cache[Pkg].NewInstall() == true || Cache[Pkg].Upgrade() == true)
116 req = &inst;
117 else
118 continue;
119 req->append(" ").append(Pkg.FullName());
120 }
121 fprintf(output, "Request: EDSP 0.2\n");
122 if (del.empty() == false)
123 fprintf(output, "Remove: %s\n", del.c_str()+1);
124 if (inst.empty() == false)
125 fprintf(output, "Install: %s\n", inst.c_str()+1);
126 if (Upgrade == true)
127 fprintf(output, "Upgrade: yes\n");
128 if (DistUpgrade == true)
129 fprintf(output, "Dist-Upgrade: yes\n");
130 if (AutoRemove == true)
131 fprintf(output, "Autoremove: yes\n");
132 if (_config->FindB("APT::Solver::Strict-Pinning", true) == false)
133 fprintf(output, "Strict-Pinning: no\n");
134 string solverpref("APT::Solver::");
135 solverpref.append(_config->Find("APT::Solver::Name", "internal")).append("::Preferences");
136 if (_config->Exists(solverpref) == true)
137 fprintf(output, "Preferences: %s\n", _config->Find(solverpref,"").c_str());
138 fprintf(output, "\n");
139
140 return true;
141 }
142 /*}}}*/
143 // EDSP::ReadResponse - from the given file descriptor /*{{{*/
144 bool EDSP::ReadResponse(int const input, pkgDepCache &Cache) {
145 FileFd in;
146 in.OpenDescriptor(input, FileFd::ReadOnly);
147 pkgTagFile response(&in);
148 pkgTagSection section;
149
150 /* We build an map id to mmap offset here
151 In theory we could use the offset as ID, but then VersionCount
152 couldn't be used to create other versionmappings anymore and it
153 would be too easy for a (buggy) solver to segfault APT… */
154 unsigned long long const VersionCount = Cache.Head().VersionCount;
155 unsigned long VerIdx[VersionCount];
156 for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; ++P)
157 for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; ++V)
158 VerIdx[V->ID] = V.Index();
159
160 while (response.Step(section) == true) {
161 std::string type;
162 if (section.Exists("Install") == true)
163 type = "Install";
164 else if (section.Exists("Remove") == true)
165 type = "Remove";
166 //FIXME: handle progress
167 else
168 continue;
169
170 size_t const id = section.FindULL(type.c_str(), VersionCount);
171 if (id == VersionCount) {
172 _error->Warning("Unable to parse %s request with id value '%s'!", type.c_str(), section.FindS(type.c_str()).c_str());
173 continue;
174 } else if (id > Cache.Head().VersionCount) {
175 _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());
176 continue;
177 }
178
179 pkgCache::VerIterator Ver(Cache.GetCache(), Cache.GetCache().VerP + VerIdx[id]);
180 Cache.SetCandidateVersion(Ver);
181 if (type == "Install")
182 Cache.MarkInstall(Ver.ParentPkg(), false, false);
183 else if (type == "Remove")
184 Cache.MarkDelete(Ver.ParentPkg(), false);
185 }
186 return true;
187 }
188 /*}}}*/
189 // EDSP::ReadLine - first line from the given file descriptor /*{{{*/
190 // ---------------------------------------------------------------------
191 /* Little helper method to read a complete line into a string. Similar to
192 fgets but we need to use the low-level read() here as otherwise the
193 listparser will be confused later on as mixing of fgets and read isn't
194 a supported action according to the manpages and results are undefined */
195 bool EDSP::ReadLine(int const input, std::string &line) {
196 char one;
197 ssize_t data = 0;
198 line.erase();
199 line.reserve(100);
200 while ((data = read(input, &one, sizeof(one))) != -1) {
201 if (data != 1)
202 continue;
203 if (one == '\n')
204 return true;
205 if (one == '\r')
206 continue;
207 if (line.empty() == true && isblank(one) != 0)
208 continue;
209 line += one;
210 }
211 return false;
212 }
213 /*}}}*/
214 // EDSP::StringToBool - convert yes/no to bool /*{{{*/
215 // ---------------------------------------------------------------------
216 /* we are not as lazy as we are in the global StringToBool as we really
217 only accept yes/no here - but we will ignore leading spaces */
218 bool EDSP::StringToBool(char const *answer, bool const defValue) {
219 for (; isspace(*answer) != 0; ++answer);
220 if (strncasecmp(answer, "yes", 3) == 0)
221 return true;
222 else if (strncasecmp(answer, "no", 2) == 0)
223 return false;
224 else
225 _error->Warning("Value '%s' is not a boolean 'yes' or 'no'!", answer);
226 return defValue;
227 }
228 /*}}}*/
229 // EDSP::ReadRequest - first stanza from the given file descriptor /*{{{*/
230 bool EDSP::ReadRequest(int const input, std::list<std::string> &install,
231 std::list<std::string> &remove, bool &upgrade,
232 bool &distUpgrade, bool &autoRemove)
233 {
234 install.clear();
235 remove.clear();
236 upgrade = false;
237 distUpgrade = false;
238 autoRemove = false;
239 std::string line;
240 while (ReadLine(input, line) == true)
241 {
242 // Skip empty lines before request
243 if (line.empty() == true)
244 continue;
245 // The first Tag must be a request, so search for it
246 if (line.compare(0, 8, "Request:") != 0)
247 continue;
248
249 while (ReadLine(input, line) == true)
250 {
251 // empty lines are the end of the request
252 if (line.empty() == true)
253 return true;
254
255 std::list<std::string> *request = NULL;
256 if (line.compare(0, 8, "Install:") == 0)
257 {
258 line.erase(0, 8);
259 request = &install;
260 }
261 else if (line.compare(0, 7, "Remove:") == 0)
262 {
263 line.erase(0, 7);
264 request = &remove;
265 }
266 else if (line.compare(0, 8, "Upgrade:") == 0)
267 upgrade = EDSP::StringToBool(line.c_str() + 9, false);
268 else if (line.compare(0, 13, "Dist-Upgrade:") == 0)
269 distUpgrade = EDSP::StringToBool(line.c_str() + 14, false);
270 else if (line.compare(0, 11, "Autoremove:") == 0)
271 autoRemove = EDSP::StringToBool(line.c_str() + 12, false);
272 else
273 _error->Warning("Unknown line in EDSP Request stanza: %s", line.c_str());
274
275 if (request == NULL)
276 continue;
277 size_t end = line.length();
278 do {
279 size_t begin = line.rfind(' ');
280 if (begin == std::string::npos)
281 {
282 request->push_back(line.substr(0, end));
283 break;
284 }
285 else if (begin < end)
286 request->push_back(line.substr(begin + 1, end));
287 line.erase(begin);
288 end = line.find_last_not_of(' ');
289 } while (end != std::string::npos);
290 }
291 }
292 return false;
293 }
294 /*}}}*/
295 // EDSP::ApplyRequest - first stanza from the given file descriptor /*{{{*/
296 bool EDSP::ApplyRequest(std::list<std::string> const &install,
297 std::list<std::string> const &remove,
298 pkgDepCache &Cache)
299 {
300 for (std::list<std::string>::const_iterator i = install.begin();
301 i != install.end(); ++i)
302 Cache.MarkInstall(Cache.FindPkg(*i), false);
303
304 for (std::list<std::string>::const_iterator i = remove.begin();
305 i != remove.end(); ++i)
306 Cache.MarkDelete(Cache.FindPkg(*i));
307 return true;
308 }
309 /*}}}*/
310 // EDSP::WriteSolution - to the given file descriptor /*{{{*/
311 bool EDSP::WriteSolution(pkgDepCache &Cache, FILE* output)
312 {
313 bool const Debug = _config->FindB("Debug::EDSP::WriteSolution", false);
314 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg)
315 {
316 if (Cache[Pkg].Delete() == true)
317 fprintf(output, "Remove: %d\n", Cache.GetCandidateVer(Pkg)->ID);
318 else if (Cache[Pkg].NewInstall() == true || Cache[Pkg].Upgrade() == true)
319 fprintf(output, "Install: %d\n", Cache.GetCandidateVer(Pkg)->ID);
320 else
321 continue;
322 if (Debug == true)
323 fprintf(output, "Package: %s\nVersion: %s\n", Pkg.FullName().c_str(), Cache.GetCandidateVer(Pkg).VerStr());
324 fprintf(output, "\n");
325 }
326
327 return true;
328 }
329 /*}}}*/
330 bool EDSP::WriteError(std::string const &message, FILE* output) { return false; }