]>
Commit | Line | Data |
---|---|---|
7939f6d1 | 1 | /* |
31f0ccce | 2 | * Copyright (c) 2001, 2003 Robert Collins. |
7939f6d1 RC |
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 | ||
7939f6d1 RC |
21 | #include <stdio.h> |
22 | #include <stdlib.h> | |
23 | #include <unistd.h> | |
24 | #include <strings.h> | |
2e0aaec9 | 25 | #include <algorithm> |
45d60587 | 26 | #include <sstream> |
45e01f23 RC |
27 | #if HAVE_ERRNO_H |
28 | #include <errno.h> | |
29 | #endif | |
7939f6d1 RC |
30 | |
31 | #include "io_stream.h" | |
32 | #include "compress.h" | |
33 | ||
34 | #include "filemanip.h" | |
f3992588 | 35 | #include "package_version.h" |
7939f6d1 RC |
36 | #include "package_db.h" |
37 | #include "package_meta.h" | |
ad646f43 | 38 | #include "Exception.h" |
2f18f94d | 39 | #include "Generic.h" |
f6d6c600 JT |
40 | #include "LogSingleton.h" |
41 | #include "resource.h" | |
1c159e0a | 42 | #include "libsolv.h" |
2602c5c4 | 43 | #include "csu_util/version_compare.h" |
0c539f7f JT |
44 | #include "getopt++/BoolOption.h" |
45 | ||
20f237b4 | 46 | static BoolOption MirrorOption (false, 'm', "mirror-mode", IDS_HELPTEXT_MIRROR_MODE); |
7939f6d1 | 47 | |
7939f6d1 RC |
48 | packagedb::packagedb () |
49 | { | |
b0cccc59 JT |
50 | } |
51 | ||
ab67dafa JT |
52 | void |
53 | packagedb::init () | |
54 | { | |
55 | installeddbread = 0; | |
56 | installeddbver = 0; | |
0c539f7f JT |
57 | prepped = false; |
58 | ||
ab67dafa JT |
59 | packages.clear(); |
60 | sourcePackages.clear(); | |
61 | categories.clear(); | |
62 | solver.clear(); | |
63 | solution.clear(); | |
64 | basepkg = packageversion(); | |
65 | dependencyOrderedPackages.clear(); | |
66 | } | |
67 | ||
b0cccc59 JT |
68 | void |
69 | packagedb::read () | |
70 | { | |
7939f6d1 RC |
71 | if (!installeddbread) |
72 | { | |
b0cccc59 JT |
73 | /* Read in the local installation database. */ |
74 | io_stream *db = 0; | |
26922cd2 | 75 | db = io_stream::open ("cygfile:///etc/setup/installed.db", "rt", 0); |
82573872 | 76 | installeddbread = 1; |
7939f6d1 RC |
77 | if (!db) |
78 | return; | |
f6d6c600 | 79 | char line[1000], pkgname[1000]; |
7939f6d1 | 80 | |
24cbae7f RC |
81 | if (db->gets (line, 1000)) |
82 | { | |
f6d6c600 JT |
83 | /* Look for header line (absent in version 1) */ |
84 | int instsz; | |
24cbae7f RC |
85 | int dbver; |
86 | sscanf (line, "%s %d", pkgname, &instsz); | |
f6d6c600 JT |
87 | if (!strcasecmp (pkgname, "INSTALLED.DB")) |
88 | dbver = instsz; | |
24cbae7f RC |
89 | else |
90 | dbver = 1; | |
91 | delete db; | |
fa0c0d10 | 92 | db = 0; |
f6d6c600 JT |
93 | |
94 | Log (LOG_BABBLE) << "INSTALLED.DB version " << dbver << endLog; | |
95 | ||
96 | if (dbver <= 3) | |
7939f6d1 | 97 | { |
f6d6c600 JT |
98 | char inst[1000]; |
99 | ||
24cbae7f | 100 | db = |
26922cd2 | 101 | io_stream::open ("cygfile:///etc/setup/installed.db", "rt", 0); |
f6d6c600 JT |
102 | |
103 | // skip over already-parsed header line | |
104 | if (dbver >= 2) | |
24cbae7f | 105 | db->gets (line, 1000); |
f6d6c600 | 106 | |
24cbae7f | 107 | while (db->gets (line, 1000)) |
7939f6d1 | 108 | { |
24cbae7f | 109 | int parseable; |
f6d6c600 | 110 | int user_picked = 0; |
4e868a01 RC |
111 | pkgname[0] = '\0'; |
112 | inst[0] = '\0'; | |
4e868a01 | 113 | |
f6d6c600 | 114 | int res = sscanf (line, "%s %s %d", pkgname, inst, &user_picked); |
4e868a01 | 115 | |
f6d6c600 | 116 | if (res < 3 || pkgname[0] == '\0' || inst[0] == '\0') |
4e868a01 RC |
117 | continue; |
118 | ||
24cbae7f RC |
119 | fileparse f; |
120 | parseable = parse_filename (inst, f); | |
121 | if (!parseable) | |
122 | continue; | |
123 | ||
1c159e0a JT |
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; | |
20b98f20 | 133 | data.obsoletes = NULL; |
9c3e3256 | 134 | data.provides = NULL; |
e6433da6 | 135 | data.conflicts = NULL; |
1c159e0a JT |
136 | data.sdesc = ""; |
137 | data.ldesc = ""; | |
2602c5c4 KB |
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; | |
6d23697e KB |
146 | PackageDepends prov; |
147 | PackageDepends conf; | |
2602c5c4 KB |
148 | if (pv) |
149 | { | |
150 | data.sdesc = pv.SDesc(); | |
dff279e2 | 151 | data.ldesc = pv.LDesc(); |
2602c5c4 KB |
152 | data.archive = *pv.source(); |
153 | data.stability = pv.Stability(); | |
154 | data.spkg_id = pv.sourcePackage(); | |
c59b92e8 | 155 | data.spkg = pv.sourcePackageName(); |
2602c5c4 KB |
156 | dep = pv.depends(); |
157 | data.requires = &dep; | |
158 | obs = pv.obsoletes(); | |
159 | data.obsoletes = &obs; | |
6d23697e KB |
160 | prov = pv.provides(); |
161 | data.provides = &prov; | |
162 | conf = pv.conflicts(); | |
163 | data.conflicts = &conf; | |
2602c5c4 KB |
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. | |
1c159e0a | 170 | { |
2602c5c4 KB |
171 | packagemeta *pkgm = findBinary(PackageSpecification(pkgname)); |
172 | if (pkgm) | |
173 | { | |
174 | data.sdesc = pkgm->curr.SDesc(); | |
dff279e2 | 175 | data.ldesc = pkgm->curr.LDesc(); |
2602c5c4 KB |
176 | if (pkgm->curr |
177 | && version_compare (f.ver, pkgm->curr.Canonical_version()) > 0) | |
178 | data.stability = TRUST_TEST; | |
179 | } | |
1c159e0a JT |
180 | } |
181 | ||
182 | packagemeta *pkg = packagedb::addBinary (pkgname, data); | |
183 | ||
184 | pkg->set_installed_version (f.ver); | |
f6d6c600 JT |
185 | |
186 | if (dbver == 3) | |
187 | pkg->user_picked = (user_picked & 1); | |
1c159e0a | 188 | |
7939f6d1 | 189 | } |
24cbae7f | 190 | delete db; |
fa0c0d10 | 191 | db = 0; |
24cbae7f RC |
192 | } |
193 | else | |
f6d6c600 JT |
194 | { |
195 | fatal(NULL, IDS_INSTALLEDB_VERSION); | |
196 | } | |
197 | ||
198 | installeddbver = dbver; | |
7939f6d1 | 199 | } |
7939f6d1 | 200 | } |
1c159e0a JT |
201 | solver.internalize(); |
202 | } | |
203 | ||
d76f912c KB |
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; | |
9c3e3256 | 216 | data.provides = NULL; |
e6433da6 | 217 | data.conflicts = NULL; |
d76f912c KB |
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 | ||
45d60587 JT |
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 | ||
1c159e0a JT |
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 | ||
fa6e8a64 JT |
273 | /* Create the SolvableVersion and register it in packagemeta */ |
274 | pkg->add_version (pkgdata); | |
1c159e0a JT |
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 | ||
fa6e8a64 JT |
291 | /* Create the SolvableVersion and register it in packagemeta */ |
292 | SolvableVersion sv = pkg->add_version (pkgdata); | |
1c159e0a JT |
293 | |
294 | return sv; | |
7939f6d1 RC |
295 | } |
296 | ||
7c7034e8 RC |
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 | ||
b41c2908 | 304 | io_stream::mkpath_p (PATH_TO_FILE, ndbn, 0755); |
7c7034e8 | 305 | |
26922cd2 | 306 | io_stream *ndb = io_stream::open (ndbn, "wb", 0644); |
7c7034e8 | 307 | |
3c054baf | 308 | // XXX if this failed, try removing any existing .new database? |
7c7034e8 RC |
309 | if (!ndb) |
310 | return errno ? errno : 1; | |
311 | ||
f6d6c600 | 312 | ndb->write ("INSTALLED.DB 3\n", strlen ("INSTALLED.DB 3\n")); |
263157cb | 313 | for (packagedb::packagecollection::iterator i = packages.begin (); |
cfae3b8d | 314 | i != packages.end (); ++i) |
7c7034e8 | 315 | { |
263157cb | 316 | packagemeta & pkgm = *(i->second); |
df62e023 RC |
317 | if (pkgm.installed) |
318 | { | |
f6d6c600 JT |
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 | */ | |
d19f12fd | 325 | std::string line; |
f6d6c600 JT |
326 | line = pkgm.name + " " + |
327 | pkgm.name + "-" + std::string(pkgm.installed.Canonical_version()) + ".tar.bz2 " + | |
328 | (pkgm.user_picked ? "1" : "0") + "\n"; | |
d2a3615c | 329 | ndb->write (line.c_str(), line.size()); |
df62e023 | 330 | } |
7c7034e8 RC |
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 | ||
f6d6c600 JT |
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 | ||
3c196821 RC |
354 | packagemeta * |
355 | packagedb::findBinary (PackageSpecification const &spec) const | |
356 | { | |
263157cb JT |
357 | packagedb::packagecollection::iterator n = packages.find(spec.packageName()); |
358 | if (n != packages.end()) | |
3c196821 | 359 | { |
263157cb | 360 | packagemeta & pkgm = *(n->second); |
155eacb6 | 361 | for (std::set<packageversion>::iterator i=pkgm.versions.begin(); |
3c196821 RC |
362 | i != pkgm.versions.end(); ++i) |
363 | if (spec.satisfies (*i)) | |
364 | return &pkgm; | |
365 | } | |
366 | return NULL; | |
367 | } | |
368 | ||
2602c5c4 KB |
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); | |
155eacb6 | 376 | for (std::set<packageversion>::iterator i=pkgm.versions.begin(); |
2602c5c4 KB |
377 | i != pkgm.versions.end(); ++i) |
378 | if (spec.satisfies (*i)) | |
379 | return *i; | |
380 | } | |
381 | return packageversion(); | |
382 | } | |
383 | ||
3c196821 RC |
384 | packagemeta * |
385 | packagedb::findSource (PackageSpecification const &spec) const | |
386 | { | |
263157cb JT |
387 | packagedb::packagecollection::iterator n = sourcePackages.find(spec.packageName()); |
388 | if (n != sourcePackages.end()) | |
3c196821 | 389 | { |
263157cb | 390 | packagemeta & pkgm = *(n->second); |
155eacb6 | 391 | for (std::set<packageversion>::iterator i = pkgm.versions.begin(); |
263157cb | 392 | i != pkgm.versions.end(); ++i) |
3c196821 | 393 | if (spec.satisfies (*i)) |
263157cb | 394 | return &pkgm; |
3c196821 RC |
395 | } |
396 | return NULL; | |
397 | } | |
398 | ||
c59b92e8 JT |
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); | |
155eacb6 | 406 | for (std::set<packageversion>::iterator i = pkgm.versions.begin(); |
c59b92e8 JT |
407 | i != pkgm.versions.end(); ++i) |
408 | if (spec.satisfies (*i)) | |
409 | return *i; | |
410 | } | |
411 | return packageversion(); | |
412 | } | |
413 | ||
65fa35d4 DK |
414 | /* static members */ |
415 | ||
263157cb | 416 | int packagedb::installeddbread = 0; |
f6d6c600 | 417 | int packagedb::installeddbver = 0; |
0c539f7f | 418 | bool packagedb::prepped = false; |
263157cb JT |
419 | packagedb::packagecollection packagedb::packages; |
420 | packagedb::categoriesType packagedb::categories; | |
421 | packagedb::packagecollection packagedb::sourcePackages; | |
422 | PackageDBActions packagedb::task = PackageDB_Install; | |
d76f912c | 423 | packageversion packagedb::basepkg; |
263157cb | 424 | std::vector <packagemeta *> packagedb::dependencyOrderedPackages; |
1c159e0a | 425 | SolverPool packagedb::solver; |
1d553f34 | 426 | SolverSolution packagedb::solution(packagedb::solver); |
ad646f43 | 427 | |
ad646f43 RC |
428 | #include <stack> |
429 | ||
430 | class | |
431 | ConnectedLoopFinder | |
432 | { | |
263157cb JT |
433 | public: |
434 | ConnectedLoopFinder(void); | |
435 | void doIt(void); | |
436 | private: | |
437 | size_t visit (packagemeta *pkg); | |
438 | ||
ad646f43 RC |
439 | packagedb db; |
440 | size_t visited; | |
263157cb JT |
441 | |
442 | typedef std::map<packagemeta *, size_t> visitMap; | |
443 | visitMap visitOrder; | |
444 | std::stack<packagemeta *> nodesInStronglyConnectedComponent; | |
ad646f43 RC |
445 | }; |
446 | ||
447 | ConnectedLoopFinder::ConnectedLoopFinder() : visited(0) | |
448 | { | |
263157cb JT |
449 | for (packagedb::packagecollection::iterator i = db.packages.begin (); |
450 | i != db.packages.end (); ++i) | |
451 | visitOrder.insert(visitMap::value_type(i->second, 0)); | |
ad646f43 RC |
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 | */ | |
a2488a3c CV |
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. | |
c9c19491 CV |
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. */ | |
263157cb JT |
466 | for (packagedb::packagecollection::iterator i = db.packages.begin (); |
467 | i != db.packages.end (); ++i) | |
ad646f43 | 468 | { |
263157cb JT |
469 | packagemeta &pkg (*(i->second)); |
470 | if (pkg.installed && !visitOrder[&pkg]) | |
471 | visit (&pkg); | |
ad646f43 | 472 | } |
157dc2b8 | 473 | Log (LOG_BABBLE) << "Visited: " << visited << " nodes out of " |
92ef6cf8 BD |
474 | << db.packages.size() << " while creating dependency order." |
475 | << endLog; | |
ad646f43 RC |
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 | |
263157cb | 494 | ConnectedLoopFinder::visit(packagemeta *nodeToVisit) |
ad646f43 | 495 | { |
263157cb | 496 | if (!nodeToVisit->installed) |
ad646f43 RC |
497 | /* Can't visit this node, and it is not less than any visted node */ |
498 | return db.packages.size() + 1; | |
263157cb JT |
499 | |
500 | if (visitOrder[nodeToVisit]) | |
501 | return visitOrder[nodeToVisit]; | |
502 | ||
ad646f43 RC |
503 | ++visited; |
504 | visitOrder[nodeToVisit] = visited; | |
505 | ||
263157cb | 506 | #if DEBUG |
157dc2b8 | 507 | Log (LOG_PLAIN) << "visited '" << nodeToVisit->name << "', assigned id " << visited << endLog; |
263157cb JT |
508 | #endif |
509 | ||
ad646f43 RC |
510 | size_t minimumVisitId = visited; |
511 | nodesInStronglyConnectedComponent.push(nodeToVisit); | |
512 | ||
60b4f6ca | 513 | /* walk through each node */ |
f717b243 JT |
514 | const PackageDepends deps = nodeToVisit->installed.depends(); |
515 | PackageDepends::const_iterator dp = deps.begin(); | |
516 | while (dp != deps.end()) | |
ad646f43 | 517 | { |
60b4f6ca JT |
518 | /* check for an installed match */ |
519 | if (checkForInstalled (*dp)) | |
ad646f43 RC |
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 | */ | |
60b4f6ca | 526 | const packagedb::packagecollection::iterator n = db.packages.find((*dp)->packageName()); |
263157cb JT |
527 | |
528 | if (n == db.packages.end()) | |
60b4f6ca | 529 | Log (LOG_PLAIN) << "Search for package '" << (*dp)->packageName() << "' failed." << endLog; |
ad646f43 RC |
530 | else |
531 | { | |
263157cb | 532 | packagemeta *nodeJustVisited = n->second; |
ad646f43 RC |
533 | minimumVisitId = std::min (minimumVisitId, visit (nodeJustVisited)); |
534 | } | |
ad646f43 RC |
535 | } |
536 | /* not installed or not available we ignore */ | |
537 | ++dp; | |
538 | } | |
263157cb | 539 | |
ad646f43 RC |
540 | if (minimumVisitId == visitOrder[nodeToVisit]) |
541 | { | |
263157cb | 542 | packagemeta *popped; |
ad646f43 RC |
543 | do { |
544 | popped = nodesInStronglyConnectedComponent.top(); | |
545 | nodesInStronglyConnectedComponent.pop(); | |
263157cb | 546 | db.dependencyOrderedPackages.push_back(popped); |
ad646f43 RC |
547 | /* mark as displayed in a connected component */ |
548 | visitOrder[popped] = db.packages.size() + 2; | |
549 | } while (popped != nodeToVisit); | |
550 | } | |
263157cb | 551 | |
ad646f43 | 552 | return minimumVisitId; |
263157cb | 553 | } |
ad646f43 RC |
554 | |
555 | PackageDBConnectedIterator | |
556 | packagedb::connectedBegin() | |
557 | { | |
558 | if (!dependencyOrderedPackages.size()) | |
ad646f43 | 559 | { |
92ef6cf8 BD |
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 + " "; | |
157dc2b8 | 568 | Log (LOG_BABBLE) << s << endLog; |
ad646f43 | 569 | } |
ad646f43 RC |
570 | return dependencyOrderedPackages.begin(); |
571 | } | |
572 | ||
573 | PackageDBConnectedIterator | |
574 | packagedb::connectedEnd() | |
575 | { | |
576 | return dependencyOrderedPackages.end(); | |
577 | } | |
8c242540 | 578 | |
31f0ccce RC |
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. */ | |
263157cb | 585 | packagedb::packagecollection::iterator i = packages.begin (); |
31f0ccce RC |
586 | while (i != packages.end ()) |
587 | { | |
263157cb | 588 | packagemeta & pkg = *(i->second); |
31f0ccce | 589 | if (!pkg.installed && !pkg.accessible() && |
263157cb JT |
590 | !pkg.sourceAccessible() ) |
591 | { | |
592 | packagemeta *pkgm = (*i).second; | |
593 | delete pkgm; | |
594 | packages.erase (i++); | |
595 | } | |
31f0ccce | 596 | else |
263157cb | 597 | ++i; |
31f0ccce | 598 | } |
263157cb | 599 | |
31f0ccce RC |
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 | } | |
2f18f94d RC |
617 | |
618 | void | |
619 | packagedb::fillMissingCategory () | |
620 | { | |
263157cb JT |
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(); | |
243f3cc1 JT |
627 | } |
628 | } | |
263157cb | 629 | |
db9818d7 | 630 | void |
a59178eb | 631 | packagedb::defaultTrust (SolverTasks &q, SolverSolution::updateMode mode, bool test) |
db9818d7 | 632 | { |
2506055b | 633 | solution.update(q, mode, test); |
549ab3ec | 634 | solution.augmentTasks(q); |
b5baa4ae JT |
635 | |
636 | // reflect that task list into packagedb | |
637 | solution.trans2db(); | |
347e23de | 638 | } |
db9818d7 | 639 | |
347e23de JT |
640 | void |
641 | packagedb::removeEmptyCategories() | |
642 | { | |
cccc9ec3 JT |
643 | std::vector<std::string> empty; |
644 | ||
db9818d7 JT |
645 | for (packagedb::categoriesType::iterator n = packagedb::categories.begin(); |
646 | n != packagedb::categories.end(); ++n) | |
647 | if (!n->second.size()) | |
648 | { | |
cccc9ec3 | 649 | empty.push_back(n->first); |
db9818d7 | 650 | } |
cccc9ec3 JT |
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 | } | |
db9818d7 | 659 | } |
f6d6c600 JT |
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 | ||
60b4f6ca | 694 | /* walk through each node */ |
f717b243 JT |
695 | const PackageDepends deps = pkgm.installed.depends(); |
696 | std::vector <PackageSpecification *>::const_iterator dp = deps.begin(); | |
697 | while (dp != deps.end()) | |
f6d6c600 | 698 | { |
60b4f6ca JT |
699 | /* check for an installed match */ |
700 | if (checkForInstalled(*dp)) | |
f6d6c600 | 701 | { |
60b4f6ca | 702 | const packagedb::packagecollection::iterator n = packages.find((*dp)->packageName()); |
f6d6c600 JT |
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 | } | |
c59b92e8 JT |
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 | ||
155eacb6 | 725 | for (std::set<packageversion>::iterator i = pkgm.versions.begin(); |
c59b92e8 JT |
726 | i != pkgm.versions.end(); ++i) |
727 | { | |
c59b92e8 JT |
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 | { | |
3c754445 JT |
741 | if (i->sourcePackage() != spkg_id) |
742 | i->fixup_spkg_id(spkg_id); | |
c59b92e8 JT |
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 | } | |
3c754445 JT |
750 | |
751 | solver.internalize(); | |
c59b92e8 | 752 | } |
0c539f7f JT |
753 | |
754 | void | |
755 | packagedb::prep() | |
756 | { | |
757 | /* make packagedb ready for use for chooser */ | |
758 | if (prepped) | |
759 | return; | |
760 | ||
761 | makeBase(); | |
45d60587 | 762 | makeWindows(); |
0c539f7f JT |
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 | } | |
9ca5efb3 KB |
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; | |
6dc6650a JT |
786 | pkg->set_action(packagemeta::NoChange_action, pkg->installed); |
787 | pkg->default_version = pkg->installed; | |
9ca5efb3 KB |
788 | } |
789 | } |