]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (c) 2001, 2003 Robert Collins. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License as published by | |
6 | * the Free Software Foundation; either version 2 of the License, or | |
7 | * (at your option) any later version. | |
8 | * | |
9 | * A copy of the GNU General Public License can be found at | |
10 | * http://www.gnu.org/ | |
11 | * | |
12 | * Written by Robert Collins <rbtcollins@hotmail.com> | |
13 | * | |
14 | */ | |
15 | ||
16 | /* this is the package database class. | |
17 | * It lists all known packages, including custom ones, ones from a mirror and | |
18 | * installed ones. | |
19 | */ | |
20 | ||
21 | #include <stdio.h> | |
22 | #include <stdlib.h> | |
23 | #include <unistd.h> | |
24 | #include <strings.h> | |
25 | #include <algorithm> | |
26 | #include <sstream> | |
27 | #if HAVE_ERRNO_H | |
28 | #include <errno.h> | |
29 | #endif | |
30 | ||
31 | #include "io_stream.h" | |
32 | #include "compress.h" | |
33 | ||
34 | #include "filemanip.h" | |
35 | #include "package_version.h" | |
36 | #include "package_db.h" | |
37 | #include "package_meta.h" | |
38 | #include "Exception.h" | |
39 | #include "Generic.h" | |
40 | #include "LogSingleton.h" | |
41 | #include "resource.h" | |
42 | #include "libsolv.h" | |
43 | #include "csu_util/version_compare.h" | |
44 | #include "getopt++/BoolOption.h" | |
45 | ||
46 | static BoolOption MirrorOption (false, 'm', "mirror-mode", IDS_HELPTEXT_MIRROR_MODE); | |
47 | ||
48 | packagedb::packagedb () | |
49 | { | |
50 | } | |
51 | ||
52 | void | |
53 | packagedb::init () | |
54 | { | |
55 | installeddbread = 0; | |
56 | installeddbver = 0; | |
57 | prepped = false; | |
58 | ||
59 | packages.clear(); | |
60 | sourcePackages.clear(); | |
61 | categories.clear(); | |
62 | solver.clear(); | |
63 | solution.clear(); | |
64 | basepkg = packageversion(); | |
65 | dependencyOrderedPackages.clear(); | |
66 | } | |
67 | ||
68 | void | |
69 | packagedb::read () | |
70 | { | |
71 | if (!installeddbread) | |
72 | { | |
73 | /* Read in the local installation database. */ | |
74 | io_stream *db = 0; | |
75 | db = io_stream::open ("cygfile:///etc/setup/installed.db", "rt", 0); | |
76 | installeddbread = 1; | |
77 | if (!db) | |
78 | return; | |
79 | char line[1000], pkgname[1000]; | |
80 | ||
81 | if (db->gets (line, 1000)) | |
82 | { | |
83 | /* Look for header line (absent in version 1) */ | |
84 | int instsz; | |
85 | int dbver; | |
86 | sscanf (line, "%s %d", pkgname, &instsz); | |
87 | if (!strcasecmp (pkgname, "INSTALLED.DB")) | |
88 | dbver = instsz; | |
89 | else | |
90 | dbver = 1; | |
91 | delete db; | |
92 | db = 0; | |
93 | ||
94 | Log (LOG_BABBLE) << "INSTALLED.DB version " << dbver << endLog; | |
95 | ||
96 | if (dbver <= 3) | |
97 | { | |
98 | char inst[1000]; | |
99 | ||
100 | db = | |
101 | io_stream::open ("cygfile:///etc/setup/installed.db", "rt", 0); | |
102 | ||
103 | // skip over already-parsed header line | |
104 | if (dbver >= 2) | |
105 | db->gets (line, 1000); | |
106 | ||
107 | while (db->gets (line, 1000)) | |
108 | { | |
109 | int parseable; | |
110 | int user_picked = 0; | |
111 | pkgname[0] = '\0'; | |
112 | inst[0] = '\0'; | |
113 | ||
114 | int res = sscanf (line, "%s %s %d", pkgname, inst, &user_picked); | |
115 | ||
116 | if (res < 3 || pkgname[0] == '\0' || inst[0] == '\0') | |
117 | continue; | |
118 | ||
119 | fileparse f; | |
120 | parseable = parse_filename (inst, f); | |
121 | if (!parseable) | |
122 | continue; | |
123 | ||
124 | SolverPool::addPackageData data; | |
125 | data.reponame = "_installed"; | |
126 | data.version = f.ver; | |
127 | data.type = package_binary; | |
128 | ||
129 | // very limited information is available from installed.db, so | |
130 | // we put our best guesses here... | |
131 | data.vendor = "cygwin"; | |
132 | data.requires = NULL; | |
133 | data.obsoletes = NULL; | |
134 | data.provides = NULL; | |
135 | data.conflicts = NULL; | |
136 | data.sdesc = ""; | |
137 | data.ldesc = ""; | |
138 | data.stability = TRUST_UNKNOWN; | |
139 | data.spkg = PackageSpecification(std::string(pkgname) + "-src", f.ver); | |
140 | ||
141 | // supplement this with sdesc, source, and stability | |
142 | // information from setup.ini, if possible... | |
143 | packageversion pv = findBinaryVersion(PackageSpecification(pkgname, f.ver)); | |
144 | PackageDepends dep; | |
145 | PackageDepends obs; | |
146 | PackageDepends prov; | |
147 | PackageDepends conf; | |
148 | if (pv) | |
149 | { | |
150 | data.sdesc = pv.SDesc(); | |
151 | data.ldesc = pv.LDesc(); | |
152 | data.archive = *pv.source(); | |
153 | data.stability = pv.Stability(); | |
154 | data.spkg_id = pv.sourcePackage(); | |
155 | data.spkg = pv.sourcePackageName(); | |
156 | dep = pv.depends(); | |
157 | data.requires = &dep; | |
158 | obs = pv.obsoletes(); | |
159 | data.obsoletes = &obs; | |
160 | prov = pv.provides(); | |
161 | data.provides = &prov; | |
162 | conf = pv.conflicts(); | |
163 | data.conflicts = &conf; | |
164 | } | |
165 | else | |
166 | // This version is no longer available. It could | |
167 | // be old, or it could be a previous test release | |
168 | // that has been replaced by a new test release. | |
169 | // Try to get some info from the packagemeta. | |
170 | { | |
171 | packagemeta *pkgm = findBinary(PackageSpecification(pkgname)); | |
172 | if (pkgm) | |
173 | { | |
174 | data.sdesc = pkgm->curr.SDesc(); | |
175 | data.ldesc = pkgm->curr.LDesc(); | |
176 | if (pkgm->curr | |
177 | && version_compare (f.ver, pkgm->curr.Canonical_version()) > 0) | |
178 | data.stability = TRUST_TEST; | |
179 | } | |
180 | } | |
181 | ||
182 | packagemeta *pkg = packagedb::addBinary (pkgname, data); | |
183 | ||
184 | pkg->set_installed_version (f.ver); | |
185 | ||
186 | if (dbver == 3) | |
187 | pkg->user_picked = (user_picked & 1); | |
188 | ||
189 | } | |
190 | delete db; | |
191 | db = 0; | |
192 | } | |
193 | else | |
194 | { | |
195 | fatal(NULL, IDS_INSTALLEDB_VERSION); | |
196 | } | |
197 | ||
198 | installeddbver = dbver; | |
199 | } | |
200 | } | |
201 | solver.internalize(); | |
202 | } | |
203 | ||
204 | /* Create the fictitious basepkg */ | |
205 | void | |
206 | packagedb::makeBase() | |
207 | { | |
208 | SolverPool::addPackageData data; | |
209 | data.reponame = "_installed"; | |
210 | data.version = "0.0-0"; | |
211 | data.type = package_binary; | |
212 | data.vendor = "cygwin"; | |
213 | data.sdesc = "Ficitious package that requires all Base packages"; | |
214 | data.ldesc = "Ficitious package that requires all Base packages"; | |
215 | data.obsoletes = NULL; | |
216 | data.provides = NULL; | |
217 | data.conflicts = NULL; | |
218 | data.stability = TRUST_CURR; | |
219 | // data.spkg = PackageSpecification(); | |
220 | // data.spkg_id = packageversion(); | |
221 | ||
222 | PackageDepends dep; | |
223 | for (std::vector <packagemeta *>::const_iterator i = categories["Base"].begin(); | |
224 | i != categories["Base"].end(); i++) | |
225 | { | |
226 | packagemeta *pkg = *i; | |
227 | PackageSpecification *spec = new PackageSpecification(pkg->name); | |
228 | dep.push_back(spec); | |
229 | } | |
230 | data.requires = &dep; | |
231 | ||
232 | basepkg = solver.addPackage("base", data); | |
233 | /* We don't register this in packagemeta */ | |
234 | } | |
235 | ||
236 | /* Create the fictitious windows package */ | |
237 | void | |
238 | packagedb::makeWindows() | |
239 | { | |
240 | std::stringstream v; | |
241 | v << OSMajorVersion() << "." << OSMinorVersion() << "." << OSBuildNumber(); | |
242 | ||
243 | SolverPool::addPackageData data; | |
244 | data.reponame = "_installed"; | |
245 | data.version = v.str(); | |
246 | data.type = package_binary; | |
247 | data.vendor = "cygwin"; | |
248 | data.sdesc = "Ficitious package indicating Windows version"; | |
249 | data.ldesc = "Ficitious package indicating Windows version"; | |
250 | data.requires = NULL; | |
251 | data.obsoletes = NULL; | |
252 | data.provides = NULL; | |
253 | data.conflicts = NULL; | |
254 | data.stability = TRUST_CURR; | |
255 | ||
256 | solver.addPackage("_windows", data); | |
257 | /* We don't register this in packagemeta */ | |
258 | } | |
259 | ||
260 | /* Add a package version to the packagedb */ | |
261 | packagemeta * | |
262 | packagedb::addBinary (const std::string &pkgname, | |
263 | const SolverPool::addPackageData &pkgdata) | |
264 | { | |
265 | /* If pkgname isn't already in packagedb, add a packagemeta */ | |
266 | packagemeta *pkg = findBinary (PackageSpecification(pkgname)); | |
267 | if (!pkg) | |
268 | { | |
269 | pkg = new packagemeta (pkgname); | |
270 | packages.insert (packagedb::packagecollection::value_type(pkgname, pkg)); | |
271 | } | |
272 | ||
273 | /* Create the SolvableVersion and register it in packagemeta */ | |
274 | pkg->add_version (pkgdata); | |
275 | ||
276 | return pkg; | |
277 | } | |
278 | ||
279 | packageversion | |
280 | packagedb::addSource (const std::string &pkgname, | |
281 | const SolverPool::addPackageData &pkgdata) | |
282 | { | |
283 | /* If pkgname isn't already in packagedb, add a packagemeta */ | |
284 | packagemeta *pkg = findSource (PackageSpecification(pkgname)); | |
285 | if (!pkg) | |
286 | { | |
287 | pkg = new packagemeta (pkgname); | |
288 | sourcePackages.insert (packagedb::packagecollection::value_type(pkgname, pkg)); | |
289 | } | |
290 | ||
291 | /* Create the SolvableVersion and register it in packagemeta */ | |
292 | SolvableVersion sv = pkg->add_version (pkgdata); | |
293 | ||
294 | return sv; | |
295 | } | |
296 | ||
297 | int | |
298 | packagedb::flush () | |
299 | { | |
300 | /* naive approach - just dump the lot */ | |
301 | char const *odbn = "cygfile:///etc/setup/installed.db"; | |
302 | char const *ndbn = "cygfile:///etc/setup/installed.db.new"; | |
303 | ||
304 | io_stream::mkpath_p (PATH_TO_FILE, ndbn, 0755); | |
305 | ||
306 | io_stream *ndb = io_stream::open (ndbn, "wb", 0644); | |
307 | ||
308 | // XXX if this failed, try removing any existing .new database? | |
309 | if (!ndb) | |
310 | return errno ? errno : 1; | |
311 | ||
312 | ndb->write ("INSTALLED.DB 3\n", strlen ("INSTALLED.DB 3\n")); | |
313 | for (packagedb::packagecollection::iterator i = packages.begin (); | |
314 | i != packages.end (); ++i) | |
315 | { | |
316 | packagemeta & pkgm = *(i->second); | |
317 | if (pkgm.installed) | |
318 | { | |
319 | /* | |
320 | In INSTALLED.DB 3, lines are: 'packagename version flags', where | |
321 | version is encoded in a notional filename for backwards | |
322 | compatibility, and the only currently defined flag is user-picked | |
323 | (bit 0). | |
324 | */ | |
325 | std::string line; | |
326 | line = pkgm.name + " " + | |
327 | pkgm.name + "-" + std::string(pkgm.installed.Canonical_version()) + ".tar.bz2 " + | |
328 | (pkgm.user_picked ? "1" : "0") + "\n"; | |
329 | ndb->write (line.c_str(), line.size()); | |
330 | } | |
331 | } | |
332 | ||
333 | delete ndb; | |
334 | ||
335 | io_stream::remove (odbn); | |
336 | ||
337 | if (io_stream::move (ndbn, odbn)) | |
338 | return errno ? errno : 1; | |
339 | return 0; | |
340 | } | |
341 | ||
342 | void | |
343 | packagedb::upgrade() | |
344 | { | |
345 | if (installeddbver < 3) | |
346 | { | |
347 | /* Guess which packages were user_picked. This has to take place after | |
348 | setup.ini has been parsed as it needs dependency information. */ | |
349 | guessUserPicked(); | |
350 | installeddbver = 3; | |
351 | } | |
352 | } | |
353 | ||
354 | packagemeta * | |
355 | packagedb::findBinary (PackageSpecification const &spec) const | |
356 | { | |
357 | packagedb::packagecollection::iterator n = packages.find(spec.packageName()); | |
358 | if (n != packages.end()) | |
359 | { | |
360 | packagemeta & pkgm = *(n->second); | |
361 | for (std::set<packageversion>::iterator i=pkgm.versions.begin(); | |
362 | i != pkgm.versions.end(); ++i) | |
363 | if (spec.satisfies (*i)) | |
364 | return &pkgm; | |
365 | } | |
366 | return NULL; | |
367 | } | |
368 | ||
369 | packageversion | |
370 | packagedb::findBinaryVersion (PackageSpecification const &spec) const | |
371 | { | |
372 | packagedb::packagecollection::iterator n = packages.find(spec.packageName()); | |
373 | if (n != packages.end()) | |
374 | { | |
375 | packagemeta & pkgm = *(n->second); | |
376 | for (std::set<packageversion>::iterator i=pkgm.versions.begin(); | |
377 | i != pkgm.versions.end(); ++i) | |
378 | if (spec.satisfies (*i)) | |
379 | return *i; | |
380 | } | |
381 | return packageversion(); | |
382 | } | |
383 | ||
384 | packagemeta * | |
385 | packagedb::findSource (PackageSpecification const &spec) const | |
386 | { | |
387 | packagedb::packagecollection::iterator n = sourcePackages.find(spec.packageName()); | |
388 | if (n != sourcePackages.end()) | |
389 | { | |
390 | packagemeta & pkgm = *(n->second); | |
391 | for (std::set<packageversion>::iterator i = pkgm.versions.begin(); | |
392 | i != pkgm.versions.end(); ++i) | |
393 | if (spec.satisfies (*i)) | |
394 | return &pkgm; | |
395 | } | |
396 | return NULL; | |
397 | } | |
398 | ||
399 | packageversion | |
400 | packagedb::findSourceVersion (PackageSpecification const &spec) const | |
401 | { | |
402 | packagedb::packagecollection::iterator n = sourcePackages.find(spec.packageName()); | |
403 | if (n != sourcePackages.end()) | |
404 | { | |
405 | packagemeta & pkgm = *(n->second); | |
406 | for (std::set<packageversion>::iterator i = pkgm.versions.begin(); | |
407 | i != pkgm.versions.end(); ++i) | |
408 | if (spec.satisfies (*i)) | |
409 | return *i; | |
410 | } | |
411 | return packageversion(); | |
412 | } | |
413 | ||
414 | /* static members */ | |
415 | ||
416 | int packagedb::installeddbread = 0; | |
417 | int packagedb::installeddbver = 0; | |
418 | bool packagedb::prepped = false; | |
419 | packagedb::packagecollection packagedb::packages; | |
420 | packagedb::categoriesType packagedb::categories; | |
421 | packagedb::packagecollection packagedb::sourcePackages; | |
422 | PackageDBActions packagedb::task = PackageDB_Install; | |
423 | packageversion packagedb::basepkg; | |
424 | std::vector <packagemeta *> packagedb::dependencyOrderedPackages; | |
425 | SolverPool packagedb::solver; | |
426 | SolverSolution packagedb::solution(packagedb::solver); | |
427 | ||
428 | #include <stack> | |
429 | ||
430 | class | |
431 | ConnectedLoopFinder | |
432 | { | |
433 | public: | |
434 | ConnectedLoopFinder(void); | |
435 | void doIt(void); | |
436 | private: | |
437 | size_t visit (packagemeta *pkg); | |
438 | ||
439 | packagedb db; | |
440 | size_t visited; | |
441 | ||
442 | typedef std::map<packagemeta *, size_t> visitMap; | |
443 | visitMap visitOrder; | |
444 | std::stack<packagemeta *> nodesInStronglyConnectedComponent; | |
445 | }; | |
446 | ||
447 | ConnectedLoopFinder::ConnectedLoopFinder() : visited(0) | |
448 | { | |
449 | for (packagedb::packagecollection::iterator i = db.packages.begin (); | |
450 | i != db.packages.end (); ++i) | |
451 | visitOrder.insert(visitMap::value_type(i->second, 0)); | |
452 | } | |
453 | ||
454 | void | |
455 | ConnectedLoopFinder::doIt() | |
456 | { | |
457 | /* XXX this could be done useing a class to hold both the visitedInIteration and the package | |
458 | * meta reference. Then we could use a range, not an int loop. | |
459 | */ | |
460 | /* We have to expect dependency loops. These loops break the topological | |
461 | sorting which would be a result of the below algorithm looking for | |
462 | strongly connected components in a directed graph. Unfortunately it's | |
463 | not possible to order a directed graph with loops topologially. | |
464 | So we always have to make sure that the really important packages don't | |
465 | introduce dependency loops, since we can't do this from within setup. */ | |
466 | for (packagedb::packagecollection::iterator i = db.packages.begin (); | |
467 | i != db.packages.end (); ++i) | |
468 | { | |
469 | packagemeta &pkg (*(i->second)); | |
470 | if (pkg.installed && !visitOrder[&pkg]) | |
471 | visit (&pkg); | |
472 | } | |
473 | Log (LOG_BABBLE) << "Visited: " << visited << " nodes out of " | |
474 | << db.packages.size() << " while creating dependency order." | |
475 | << endLog; | |
476 | } | |
477 | ||
478 | static bool | |
479 | checkForInstalled (PackageSpecification *spec) | |
480 | { | |
481 | packagedb db; | |
482 | packagemeta *required = db.findBinary (*spec); | |
483 | if (!required) | |
484 | return false; | |
485 | if (spec->satisfies (required->installed) | |
486 | && required->desired == required->installed ) | |
487 | /* done, found a satisfactory installed version that will remain | |
488 | installed */ | |
489 | return true; | |
490 | return false; | |
491 | } | |
492 | ||
493 | size_t | |
494 | ConnectedLoopFinder::visit(packagemeta *nodeToVisit) | |
495 | { | |
496 | if (!nodeToVisit->installed) | |
497 | /* Can't visit this node, and it is not less than any visted node */ | |
498 | return db.packages.size() + 1; | |
499 | ||
500 | if (visitOrder[nodeToVisit]) | |
501 | return visitOrder[nodeToVisit]; | |
502 | ||
503 | ++visited; | |
504 | visitOrder[nodeToVisit] = visited; | |
505 | ||
506 | #if DEBUG | |
507 | Log (LOG_PLAIN) << "visited '" << nodeToVisit->name << "', assigned id " << visited << endLog; | |
508 | #endif | |
509 | ||
510 | size_t minimumVisitId = visited; | |
511 | nodesInStronglyConnectedComponent.push(nodeToVisit); | |
512 | ||
513 | /* walk through each node */ | |
514 | const PackageDepends deps = nodeToVisit->installed.depends(); | |
515 | PackageDepends::const_iterator dp = deps.begin(); | |
516 | while (dp != deps.end()) | |
517 | { | |
518 | /* check for an installed match */ | |
519 | if (checkForInstalled (*dp)) | |
520 | { | |
521 | /* we found an installed ok package */ | |
522 | /* visit it if needed */ | |
523 | /* UGLY. Need to refactor. iterators in the outer would help as we could simply | |
524 | * vist the iterator | |
525 | */ | |
526 | const packagedb::packagecollection::iterator n = db.packages.find((*dp)->packageName()); | |
527 | ||
528 | if (n == db.packages.end()) | |
529 | Log (LOG_PLAIN) << "Search for package '" << (*dp)->packageName() << "' failed." << endLog; | |
530 | else | |
531 | { | |
532 | packagemeta *nodeJustVisited = n->second; | |
533 | minimumVisitId = std::min (minimumVisitId, visit (nodeJustVisited)); | |
534 | } | |
535 | } | |
536 | /* not installed or not available we ignore */ | |
537 | ++dp; | |
538 | } | |
539 | ||
540 | if (minimumVisitId == visitOrder[nodeToVisit]) | |
541 | { | |
542 | packagemeta *popped; | |
543 | do { | |
544 | popped = nodesInStronglyConnectedComponent.top(); | |
545 | nodesInStronglyConnectedComponent.pop(); | |
546 | db.dependencyOrderedPackages.push_back(popped); | |
547 | /* mark as displayed in a connected component */ | |
548 | visitOrder[popped] = db.packages.size() + 2; | |
549 | } while (popped != nodeToVisit); | |
550 | } | |
551 | ||
552 | return minimumVisitId; | |
553 | } | |
554 | ||
555 | PackageDBConnectedIterator | |
556 | packagedb::connectedBegin() | |
557 | { | |
558 | if (!dependencyOrderedPackages.size()) | |
559 | { | |
560 | ConnectedLoopFinder doMe; | |
561 | doMe.doIt(); | |
562 | std::string s = "Dependency order of packages: "; | |
563 | ||
564 | for (std::vector<packagemeta *>::iterator i = | |
565 | dependencyOrderedPackages.begin(); | |
566 | i != dependencyOrderedPackages.end(); ++i) | |
567 | s = s + (*i)->name + " "; | |
568 | Log (LOG_BABBLE) << s << endLog; | |
569 | } | |
570 | return dependencyOrderedPackages.begin(); | |
571 | } | |
572 | ||
573 | PackageDBConnectedIterator | |
574 | packagedb::connectedEnd() | |
575 | { | |
576 | return dependencyOrderedPackages.end(); | |
577 | } | |
578 | ||
579 | void | |
580 | packagedb::setExistence () | |
581 | { | |
582 | /* binary packages */ | |
583 | /* Remove packages that are in the db, not installed, and have no | |
584 | mirror info and are not cached for both binary and source packages. */ | |
585 | packagedb::packagecollection::iterator i = packages.begin (); | |
586 | while (i != packages.end ()) | |
587 | { | |
588 | packagemeta & pkg = *(i->second); | |
589 | if (!pkg.installed && !pkg.accessible() && | |
590 | !pkg.sourceAccessible() ) | |
591 | { | |
592 | packagemeta *pkgm = (*i).second; | |
593 | delete pkgm; | |
594 | packages.erase (i++); | |
595 | } | |
596 | else | |
597 | ++i; | |
598 | } | |
599 | ||
600 | #if 0 | |
601 | /* remove any source packages which are not accessible */ | |
602 | vector <packagemeta *>::iterator i = db.sourcePackages.begin(); | |
603 | while (i != db.sourcePackages.end()) | |
604 | { | |
605 | packagemeta & pkg = **i; | |
606 | if (!packageAccessible (pkg)) | |
607 | { | |
608 | packagemeta *pkgm = *i; | |
609 | delete pkgm; | |
610 | i = db.sourcePackages.erase (i); | |
611 | } | |
612 | else | |
613 | ++i; | |
614 | } | |
615 | #endif | |
616 | } | |
617 | ||
618 | void | |
619 | packagedb::fillMissingCategory () | |
620 | { | |
621 | for (packagedb::packagecollection::iterator i = packages.begin(); i != packages.end(); i++) | |
622 | { | |
623 | if (i->second->hasNoCategories()) | |
624 | i->second->setDefaultCategories(); | |
625 | ||
626 | i->second->addToCategoryAll(); | |
627 | } | |
628 | } | |
629 | ||
630 | void | |
631 | packagedb::defaultTrust (SolverTasks &q, SolverSolution::updateMode mode, bool test) | |
632 | { | |
633 | solution.update(q, mode, test); | |
634 | solution.augmentTasks(q); | |
635 | ||
636 | // reflect that task list into packagedb | |
637 | solution.trans2db(); | |
638 | } | |
639 | ||
640 | void | |
641 | packagedb::removeEmptyCategories() | |
642 | { | |
643 | std::vector<std::string> empty; | |
644 | ||
645 | for (packagedb::categoriesType::iterator n = packagedb::categories.begin(); | |
646 | n != packagedb::categories.end(); ++n) | |
647 | if (!n->second.size()) | |
648 | { | |
649 | empty.push_back(n->first); | |
650 | } | |
651 | ||
652 | for (unsigned int i = 0; i < empty.size(); ++i) | |
653 | { | |
654 | packagedb::categoriesType::iterator n = packagedb::categories.find(empty[i]); | |
655 | Log (LOG_BABBLE) << "Removing empty category " << empty[i] << endLog; | |
656 | if (n != packagedb::categories.end()) | |
657 | packagedb::categories.erase(n); | |
658 | } | |
659 | } | |
660 | ||
661 | void | |
662 | packagedb::guessUserPicked() | |
663 | { | |
664 | /* | |
665 | Assume that any non-base installed package which is a dependency of an | |
666 | installed package wasn't user_picked | |
667 | ||
668 | i.e. only installed packages which aren't in the base category, and aren't | |
669 | a dependency of any installed package are user_picked | |
670 | */ | |
671 | ||
672 | /* First mark all installed non-base packages */ | |
673 | for (packagedb::packagecollection::iterator i = packages.begin (); | |
674 | i != packages.end (); ++i) | |
675 | { | |
676 | packagemeta & pkgm = *(i->second); | |
677 | ||
678 | if (pkgm.categories.find ("Base") != pkgm.categories.end ()) | |
679 | continue; | |
680 | ||
681 | if (pkgm.installed) | |
682 | pkgm.user_picked = TRUE; | |
683 | } | |
684 | ||
685 | /* Then clear the mark for all dependencies of all installed packages */ | |
686 | for (packagedb::packagecollection::iterator i = packages.begin (); | |
687 | i != packages.end (); ++i) | |
688 | { | |
689 | packagemeta & pkgm = *(i->second); | |
690 | ||
691 | if (!pkgm.installed) | |
692 | continue; | |
693 | ||
694 | /* walk through each node */ | |
695 | const PackageDepends deps = pkgm.installed.depends(); | |
696 | std::vector <PackageSpecification *>::const_iterator dp = deps.begin(); | |
697 | while (dp != deps.end()) | |
698 | { | |
699 | /* check for an installed match */ | |
700 | if (checkForInstalled(*dp)) | |
701 | { | |
702 | const packagedb::packagecollection::iterator n = packages.find((*dp)->packageName()); | |
703 | if (n != packages.end()) | |
704 | { | |
705 | packagemeta *pkgm2 = n->second; | |
706 | pkgm2->user_picked = FALSE; | |
707 | } | |
708 | /* skip to next and clause */ | |
709 | ++dp; | |
710 | continue; | |
711 | } | |
712 | ++dp; | |
713 | } | |
714 | } | |
715 | } | |
716 | ||
717 | void | |
718 | packagedb::fixup_source_package_ids() | |
719 | { | |
720 | for (packagecollection::iterator i = packages.begin (); | |
721 | i != packages.end (); ++i) | |
722 | { | |
723 | packagemeta &pkgm = *(i->second); | |
724 | ||
725 | for (std::set<packageversion>::iterator i = pkgm.versions.begin(); | |
726 | i != pkgm.versions.end(); ++i) | |
727 | { | |
728 | /* Some packages really have no source, indicated by no [sS]ource: | |
729 | line in setup.ini, which becomes an empty source package name */ | |
730 | const std::string spkg = i->sourcePackageName(); | |
731 | if (spkg.empty()) | |
732 | continue; | |
733 | ||
734 | /* Otherwise, we need to find the source package and fix up the source | |
735 | package id*/ | |
736 | packageversion spkg_id = findSourceVersion(PackageSpecification(spkg, | |
737 | i->Canonical_version())); | |
738 | ||
739 | if (spkg_id) | |
740 | { | |
741 | if (i->sourcePackage() != spkg_id) | |
742 | i->fixup_spkg_id(spkg_id); | |
743 | } | |
744 | else | |
745 | { | |
746 | Log (LOG_BABBLE) << "No source package for '" << i->Name() << "' " << i->Canonical_version() << ", source package name '" << spkg << "'" << endLog; | |
747 | } | |
748 | } | |
749 | } | |
750 | ||
751 | solver.internalize(); | |
752 | } | |
753 | ||
754 | void | |
755 | packagedb::prep() | |
756 | { | |
757 | /* make packagedb ready for use for chooser */ | |
758 | if (prepped) | |
759 | return; | |
760 | ||
761 | makeBase(); | |
762 | makeWindows(); | |
763 | read(); | |
764 | upgrade(); | |
765 | fixup_source_package_ids(); | |
766 | removeEmptyCategories(); | |
767 | ||
768 | /* XXX: this needs to be broken out somewhere where it can do progress | |
769 | reporting, as it can take a long time... */ | |
770 | if (source == IDC_SOURCE_DOWNLOAD || source ==IDC_SOURCE_LOCALDIR) | |
771 | packagemeta::ScanDownloadedFiles (MirrorOption); | |
772 | ||
773 | setExistence (); | |
774 | fillMissingCategory (); | |
775 | ||
776 | prepped = true; | |
777 | } | |
778 | ||
779 | void | |
780 | packagedb::noChanges () | |
781 | { | |
782 | for (packagecollection::iterator i = packages.begin(); | |
783 | i != packages.end(); i++) | |
784 | { | |
785 | packagemeta *pkg = i->second; | |
786 | pkg->set_action(packagemeta::NoChange_action, pkg->installed); | |
787 | pkg->default_version = pkg->installed; | |
788 | } | |
789 | } |