]> git.saurik.com Git - apt.git/blame - apt-pkg/algorithms.cc
Add an options and timeout config item to ssh/rsh.
[apt.git] / apt-pkg / algorithms.cc
CommitLineData
6c139d6e
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
e59458f7 3// $Id: algorithms.cc,v 1.42 2002/11/09 23:10:32 doogie Exp $
6c139d6e
AL
4/* ######################################################################
5
6 Algorithms - A set of misc algorithms
7
0a8e3465
AL
8 The pkgProblemResolver class has become insanely complex and
9 very sophisticated, it handles every test case I have thrown at it
10 to my satisfaction. Understanding exactly why all the steps the class
11 does are required is difficult and changing though not very risky
12 may result in other cases not working.
13
6c139d6e
AL
14 ##################################################################### */
15 /*}}}*/
16// Include Files /*{{{*/
17#ifdef __GNUG__
094a497d 18#pragma implementation "apt-pkg/algorithms.h"
6c139d6e 19#endif
094a497d
AL
20#include <apt-pkg/algorithms.h>
21#include <apt-pkg/error.h>
0a8e3465 22#include <apt-pkg/configuration.h>
b2e465d6
AL
23#include <apt-pkg/sptr.h>
24
25#include <apti18n.h>
26
90f057fd 27#include <iostream>
6c139d6e
AL
28 /*}}}*/
29
30pkgProblemResolver *pkgProblemResolver::This = 0;
31
32// Simulate::Simulate - Constructor /*{{{*/
33// ---------------------------------------------------------------------
b2e465d6
AL
34/* The legacy translations here of input Pkg iterators is obsolete,
35 this is not necessary since the pkgCaches are fully shared now. */
36pkgSimulate::pkgSimulate(pkgDepCache *Cache) : pkgPackageManager(Cache),
37 iPolicy(Cache),
38 Sim(&Cache->GetCache(),&iPolicy)
6c139d6e 39{
b2e465d6
AL
40 Sim.Init(0);
41 Flags = new unsigned char[Cache->Head().PackageCount];
42 memset(Flags,0,sizeof(*Flags)*Cache->Head().PackageCount);
281daf46
AL
43
44 // Fake a filename so as not to activate the media swapping
45 string Jnk = "SIMULATE";
b2e465d6 46 for (unsigned int I = 0; I != Cache->Head().PackageCount; I++)
281daf46 47 FileNames[I] = Jnk;
6c139d6e
AL
48}
49 /*}}}*/
b2e465d6
AL
50// Simulate::Describe - Describe a package /*{{{*/
51// ---------------------------------------------------------------------
e59458f7
AL
52/* Parameter Now == true gives both current and available varsion,
53 Parameter Now == false gives only the available package version */
b2e465d6
AL
54void pkgSimulate::Describe(PkgIterator Pkg,ostream &out,bool Now)
55{
56 VerIterator Ver(Sim);
e59458f7
AL
57
58 out << Pkg.Name();
59
b2e465d6 60 if (Now == true)
e59458f7 61 {
b2e465d6 62 Ver = Pkg.CurrentVer();
e59458f7
AL
63 if (Ver.end() == false)
64 out << " [" << Ver.VerStr() << ']';
65 }
b2e465d6 66
e59458f7 67 Ver = Sim[Pkg].CandidateVerIter(Sim);
b2e465d6
AL
68 if (Ver.end() == true)
69 return;
70
71 out << " (" << Ver.VerStr() << ' ' << Ver.RelStr() << ')';
72}
73 /*}}}*/
6c139d6e
AL
74// Simulate::Install - Simulate unpacking of a package /*{{{*/
75// ---------------------------------------------------------------------
76/* */
77bool pkgSimulate::Install(PkgIterator iPkg,string /*File*/)
78{
79 // Adapt the iterator
80 PkgIterator Pkg = Sim.FindPkg(iPkg.Name());
81 Flags[Pkg->ID] = 1;
82
b2e465d6 83 cout << "Inst ";
e59458f7 84 Describe(Pkg,cout,true);
6c139d6e
AL
85 Sim.MarkInstall(Pkg,false);
86
87 // Look for broken conflicts+predepends.
88 for (PkgIterator I = Sim.PkgBegin(); I.end() == false; I++)
89 {
90 if (Sim[I].InstallVer == 0)
91 continue;
92
b2e465d6
AL
93 for (DepIterator D = Sim[I].InstVerIter(Sim).DependsList(); D.end() == false;)
94 {
95 DepIterator Start;
96 DepIterator End;
97 D.GlobOr(Start,End);
98 if (Start->Type == pkgCache::Dep::Conflicts ||
99 Start->Type == pkgCache::Dep::Obsoletes ||
100 End->Type == pkgCache::Dep::PreDepends)
6c139d6e 101 {
b2e465d6 102 if ((Sim[End] & pkgDepCache::DepGInstall) == 0)
6c139d6e 103 {
b2e465d6
AL
104 cout << " [" << I.Name() << " on " << Start.TargetPkg().Name() << ']';
105 if (Start->Type == pkgCache::Dep::Conflicts)
6c139d6e
AL
106 _error->Error("Fatal, conflicts violated %s",I.Name());
107 }
b2e465d6
AL
108 }
109 }
6c139d6e
AL
110 }
111
112 if (Sim.BrokenCount() != 0)
113 ShortBreaks();
114 else
04aa15a8 115 cout << endl;
6c139d6e
AL
116 return true;
117}
118 /*}}}*/
119// Simulate::Configure - Simulate configuration of a Package /*{{{*/
120// ---------------------------------------------------------------------
121/* This is not an acurate simulation of relatity, we should really not
122 install the package.. For some investigations it may be necessary
123 however. */
124bool pkgSimulate::Configure(PkgIterator iPkg)
125{
126 // Adapt the iterator
127 PkgIterator Pkg = Sim.FindPkg(iPkg.Name());
128
129 Flags[Pkg->ID] = 2;
130// Sim.MarkInstall(Pkg,false);
131 if (Sim[Pkg].InstBroken() == true)
132 {
04aa15a8 133 cout << "Conf " << Pkg.Name() << " broken" << endl;
6c139d6e
AL
134
135 Sim.Update();
136
137 // Print out each package and the failed dependencies
138 for (pkgCache::DepIterator D = Sim[Pkg].InstVerIter(Sim).DependsList(); D.end() == false; D++)
139 {
140 if (Sim.IsImportantDep(D) == false ||
141 (Sim[D] & pkgDepCache::DepInstall) != 0)
142 continue;
143
b2e465d6
AL
144 if (D->Type == pkgCache::Dep::Obsoletes)
145 cout << " Obsoletes:" << D.TargetPkg().Name();
146 else if (D->Type == pkgCache::Dep::Conflicts)
04aa15a8 147 cout << " Conflicts:" << D.TargetPkg().Name();
6c139d6e 148 else
04aa15a8 149 cout << " Depends:" << D.TargetPkg().Name();
6c139d6e 150 }
04aa15a8 151 cout << endl;
6c139d6e
AL
152
153 _error->Error("Conf Broken %s",Pkg.Name());
154 }
155 else
b2e465d6
AL
156 {
157 cout << "Conf ";
158 Describe(Pkg,cout,false);
159 }
6c139d6e
AL
160
161 if (Sim.BrokenCount() != 0)
162 ShortBreaks();
163 else
04aa15a8 164 cout << endl;
6c139d6e
AL
165
166 return true;
167}
168 /*}}}*/
169// Simulate::Remove - Simulate the removal of a package /*{{{*/
170// ---------------------------------------------------------------------
171/* */
fc4b5c9f 172bool pkgSimulate::Remove(PkgIterator iPkg,bool Purge)
6c139d6e
AL
173{
174 // Adapt the iterator
175 PkgIterator Pkg = Sim.FindPkg(iPkg.Name());
176
177 Flags[Pkg->ID] = 3;
178 Sim.MarkDelete(Pkg);
fc4b5c9f 179 if (Purge == true)
b2e465d6 180 cout << "Purg ";
fc4b5c9f 181 else
b2e465d6
AL
182 cout << "Remv ";
183 Describe(Pkg,cout,false);
6c139d6e
AL
184
185 if (Sim.BrokenCount() != 0)
186 ShortBreaks();
187 else
04aa15a8 188 cout << endl;
6c139d6e
AL
189
190 return true;
191}
192 /*}}}*/
193// Simulate::ShortBreaks - Print out a short line describing all breaks /*{{{*/
194// ---------------------------------------------------------------------
195/* */
196void pkgSimulate::ShortBreaks()
197{
04aa15a8 198 cout << " [";
6c139d6e
AL
199 for (PkgIterator I = Sim.PkgBegin(); I.end() == false; I++)
200 {
201 if (Sim[I].InstBroken() == true)
202 {
203 if (Flags[I->ID] == 0)
04aa15a8 204 cout << I.Name() << ' ';
6c139d6e 205/* else
04aa15a8 206 cout << I.Name() << "! ";*/
6c139d6e
AL
207 }
208 }
04aa15a8 209 cout << ']' << endl;
6c139d6e
AL
210}
211 /*}}}*/
212// ApplyStatus - Adjust for non-ok packages /*{{{*/
213// ---------------------------------------------------------------------
214/* We attempt to change the state of the all packages that have failed
215 installation toward their real state. The ordering code will perform
216 the necessary calculations to deal with the problems. */
217bool pkgApplyStatus(pkgDepCache &Cache)
218{
219 for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
220 {
e481d5b0
AL
221 if (I->VersionList == 0)
222 continue;
223
d38b7b3d
AL
224 // Only choice for a ReInstReq package is to reinstall
225 if (I->InstState == pkgCache::State::ReInstReq ||
226 I->InstState == pkgCache::State::HoldReInstReq)
227 {
5871718b 228 if (I->CurrentVer != 0 && I.CurrentVer().Downloadable() == true)
813c8eea
AL
229 Cache.MarkKeep(I);
230 else
231 {
232 // Is this right? Will dpkg choke on an upgrade?
2a3f3893
AL
233 if (Cache[I].CandidateVer != 0 &&
234 Cache[I].CandidateVerIter(Cache).Downloadable() == true)
813c8eea
AL
235 Cache.MarkInstall(I);
236 else
b2e465d6
AL
237 return _error->Error(_("The package %s needs to be reinstalled, "
238 "but I can't find an archive for it."),I.Name());
813c8eea
AL
239 }
240
d38b7b3d
AL
241 continue;
242 }
243
6c139d6e
AL
244 switch (I->CurrentState)
245 {
813c8eea
AL
246 /* This means installation failed somehow - it does not need to be
247 re-unpacked (probably) */
b518cca6
AL
248 case pkgCache::State::UnPacked:
249 case pkgCache::State::HalfConfigured:
5871718b 250 if ((I->CurrentVer != 0 && I.CurrentVer().Downloadable() == true) ||
813c8eea
AL
251 I.State() != pkgCache::PkgIterator::NeedsUnpack)
252 Cache.MarkKeep(I);
253 else
254 {
2a3f3893
AL
255 if (Cache[I].CandidateVer != 0 &&
256 Cache[I].CandidateVerIter(Cache).Downloadable() == true)
813c8eea
AL
257 Cache.MarkInstall(I);
258 else
259 Cache.MarkDelete(I);
260 }
6c139d6e
AL
261 break;
262
263 // This means removal failed
b518cca6 264 case pkgCache::State::HalfInstalled:
6c139d6e
AL
265 Cache.MarkDelete(I);
266 break;
267
268 default:
b518cca6 269 if (I->InstState != pkgCache::State::Ok)
6c139d6e
AL
270 return _error->Error("The package %s is not ok and I "
271 "don't know how to fix it!",I.Name());
272 }
273 }
274 return true;
275}
276 /*}}}*/
277// FixBroken - Fix broken packages /*{{{*/
278// ---------------------------------------------------------------------
0a8e3465
AL
279/* This autoinstalls every broken package and then runs the problem resolver
280 on the result. */
6c139d6e
AL
281bool pkgFixBroken(pkgDepCache &Cache)
282{
283 // Auto upgrade all broken packages
284 for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
285 if (Cache[I].NowBroken() == true)
286 Cache.MarkInstall(I,true);
7e798dd7 287
6c139d6e
AL
288 /* Fix packages that are in a NeedArchive state but don't have a
289 downloadable install version */
290 for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
291 {
292 if (I.State() != pkgCache::PkgIterator::NeedsUnpack ||
293 Cache[I].Delete() == true)
294 continue;
295
b518cca6 296 if (Cache[I].InstVerIter(Cache).Downloadable() == false)
6c139d6e
AL
297 continue;
298
7e798dd7 299 Cache.MarkInstall(I,true);
6c139d6e
AL
300 }
301
b2e465d6 302 pkgProblemResolver Fix(&Cache);
6c139d6e
AL
303 return Fix.Resolve(true);
304}
305 /*}}}*/
306// DistUpgrade - Distribution upgrade /*{{{*/
307// ---------------------------------------------------------------------
308/* This autoinstalls every package and then force installs every
309 pre-existing package. This creates the initial set of conditions which
310 most likely contain problems because too many things were installed.
311
0a8e3465 312 The problem resolver is used to resolve the problems.
6c139d6e
AL
313 */
314bool pkgDistUpgrade(pkgDepCache &Cache)
315{
316 /* Auto upgrade all installed packages, this provides the basis
317 for the installation */
318 for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
319 if (I->CurrentVer != 0)
320 Cache.MarkInstall(I,true);
321
322 /* Now, auto upgrade all essential packages - this ensures that
323 the essential packages are present and working */
324 for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
b518cca6 325 if ((I->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
6c139d6e
AL
326 Cache.MarkInstall(I,true);
327
328 /* We do it again over all previously installed packages to force
329 conflict resolution on them all. */
330 for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
331 if (I->CurrentVer != 0)
332 Cache.MarkInstall(I,false);
333
b2e465d6 334 pkgProblemResolver Fix(&Cache);
c88edf1d 335
6c139d6e 336 // Hold back held packages.
4490f2de 337 if (_config->FindB("APT::Ignore-Hold",false) == false)
6c139d6e 338 {
c88edf1d 339 for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
6c139d6e 340 {
c88edf1d
AL
341 if (I->SelectedState == pkgCache::State::Hold)
342 {
343 Fix.Protect(I);
344 Cache.MarkKeep(I);
345 }
6c139d6e
AL
346 }
347 }
348
349 return Fix.Resolve();
350}
351 /*}}}*/
0a8e3465
AL
352// AllUpgrade - Upgrade as many packages as possible /*{{{*/
353// ---------------------------------------------------------------------
354/* Right now the system must be consistent before this can be called.
355 It also will not change packages marked for install, it only tries
356 to install packages not marked for install */
357bool pkgAllUpgrade(pkgDepCache &Cache)
358{
b2e465d6 359 pkgProblemResolver Fix(&Cache);
0a8e3465
AL
360
361 if (Cache.BrokenCount() != 0)
362 return false;
363
364 // Upgrade all installed packages
365 for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
366 {
367 if (Cache[I].Install() == true)
368 Fix.Protect(I);
369
b2e465d6 370 if (_config->FindB("APT::Ignore-Hold",false) == false)
c88edf1d
AL
371 if (I->SelectedState == pkgCache::State::Hold)
372 continue;
0a8e3465
AL
373
374 if (I->CurrentVer != 0 && Cache[I].InstallVer != 0)
375 Cache.MarkInstall(I,false);
376 }
377
378 return Fix.ResolveByKeep();
379}
380 /*}}}*/
7e798dd7
AL
381// MinimizeUpgrade - Minimizes the set of packages to be upgraded /*{{{*/
382// ---------------------------------------------------------------------
383/* This simply goes over the entire set of packages and tries to keep
384 each package marked for upgrade. If a conflict is generated then
385 the package is restored. */
386bool pkgMinimizeUpgrade(pkgDepCache &Cache)
387{
388 if (Cache.BrokenCount() != 0)
389 return false;
390
abc8419e 391 // We loop for 10 tries to get the minimal set size.
7e798dd7 392 bool Change = false;
a005475e 393 unsigned int Count = 0;
7e798dd7
AL
394 do
395 {
396 Change = false;
397 for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
398 {
399 // Not interesting
400 if (Cache[I].Upgrade() == false || Cache[I].NewInstall() == true)
401 continue;
a005475e 402
7e798dd7
AL
403 // Keep it and see if that is OK
404 Cache.MarkKeep(I);
405 if (Cache.BrokenCount() != 0)
406 Cache.MarkInstall(I,false);
407 else
a005475e
AL
408 {
409 // If keep didnt actually do anything then there was no change..
410 if (Cache[I].Upgrade() == false)
411 Change = true;
412 }
7e798dd7 413 }
a005475e 414 Count++;
7e798dd7 415 }
a005475e 416 while (Change == true && Count < 10);
7e798dd7
AL
417
418 if (Cache.BrokenCount() != 0)
419 return _error->Error("Internal Error in pkgMinimizeUpgrade");
420
421 return true;
422}
423 /*}}}*/
6c139d6e
AL
424
425// ProblemResolver::pkgProblemResolver - Constructor /*{{{*/
426// ---------------------------------------------------------------------
427/* */
b2e465d6 428pkgProblemResolver::pkgProblemResolver(pkgDepCache *pCache) : Cache(*pCache)
6c139d6e
AL
429{
430 // Allocate memory
b2e465d6 431 unsigned long Size = Cache.Head().PackageCount;
6c139d6e
AL
432 Scores = new signed short[Size];
433 Flags = new unsigned char[Size];
434 memset(Flags,0,sizeof(*Flags)*Size);
435
436 // Set debug to true to see its decision logic
0a8e3465 437 Debug = _config->FindB("Debug::pkgProblemResolver",false);
6c139d6e
AL
438}
439 /*}}}*/
b2e465d6
AL
440// ProblemResolver::~pkgProblemResolver - Destructor /*{{{*/
441// ---------------------------------------------------------------------
442/* */
443pkgProblemResolver::~pkgProblemResolver()
444{
445 delete [] Scores;
446 delete [] Flags;
447}
448 /*}}}*/
6c139d6e
AL
449// ProblemResolver::ScoreSort - Sort the list by score /*{{{*/
450// ---------------------------------------------------------------------
451/* */
452int pkgProblemResolver::ScoreSort(const void *a,const void *b)
453{
454 Package const **A = (Package const **)a;
455 Package const **B = (Package const **)b;
456 if (This->Scores[(*A)->ID] > This->Scores[(*B)->ID])
457 return -1;
458 if (This->Scores[(*A)->ID] < This->Scores[(*B)->ID])
459 return 1;
460 return 0;
461}
462 /*}}}*/
463// ProblemResolver::MakeScores - Make the score table /*{{{*/
464// ---------------------------------------------------------------------
465/* */
466void pkgProblemResolver::MakeScores()
467{
b2e465d6 468 unsigned long Size = Cache.Head().PackageCount;
6c139d6e
AL
469 memset(Scores,0,sizeof(*Scores)*Size);
470
471 // Generate the base scores for a package based on its properties
472 for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
473 {
474 if (Cache[I].InstallVer == 0)
475 continue;
476
477 signed short &Score = Scores[I->ID];
478
479 /* This is arbitary, it should be high enough to elevate an
480 essantial package above most other packages but low enough
481 to allow an obsolete essential packages to be removed by
482 a conflicts on a powerfull normal package (ie libc6) */
b518cca6 483 if ((I->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
6c139d6e
AL
484 Score += 100;
485
486 // We transform the priority
487 // Important Required Standard Optional Extra
488 signed short PrioMap[] = {0,3,2,1,-1,-2};
489 if (Cache[I].InstVerIter(Cache)->Priority <= 5)
490 Score += PrioMap[Cache[I].InstVerIter(Cache)->Priority];
491
492 /* This helps to fix oddball problems with conflicting packages
493 on the same level. We enhance the score of installed packages */
494 if (I->CurrentVer != 0)
495 Score += 1;
496 }
497
498 // Now that we have the base scores we go and propogate dependencies
499 for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
500 {
501 if (Cache[I].InstallVer == 0)
502 continue;
503
504 for (pkgCache::DepIterator D = Cache[I].InstVerIter(Cache).DependsList(); D.end() == false; D++)
505 {
b518cca6 506 if (D->Type == pkgCache::Dep::Depends || D->Type == pkgCache::Dep::PreDepends)
6c139d6e
AL
507 Scores[D.TargetPkg()->ID]++;
508 }
509 }
510
511 // Copy the scores to advoid additive looping
b2e465d6 512 SPtrArray<signed short> OldScores = new signed short[Size];
6c139d6e
AL
513 memcpy(OldScores,Scores,sizeof(*Scores)*Size);
514
515 /* Now we cause 1 level of dependency inheritance, that is we add the
516 score of the packages that depend on the target Package. This
517 fortifies high scoring packages */
518 for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
519 {
520 if (Cache[I].InstallVer == 0)
521 continue;
522
523 for (pkgCache::DepIterator D = I.RevDependsList(); D.end() == false; D++)
524 {
525 // Only do it for the install version
526 if ((pkgCache::Version *)D.ParentVer() != Cache[D.ParentPkg()].InstallVer ||
b518cca6 527 (D->Type != pkgCache::Dep::Depends && D->Type != pkgCache::Dep::PreDepends))
6c139d6e
AL
528 continue;
529
530 Scores[I->ID] += abs(OldScores[D.ParentPkg()->ID]);
531 }
532 }
533
534 /* Now we propogate along provides. This makes the packages that
535 provide important packages extremely important */
536 for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
537 {
538 for (pkgCache::PrvIterator P = I.ProvidesList(); P.end() == false; P++)
539 {
540 // Only do it once per package
541 if ((pkgCache::Version *)P.OwnerVer() != Cache[P.OwnerPkg()].InstallVer)
542 continue;
543 Scores[P.OwnerPkg()->ID] += abs(Scores[I->ID] - OldScores[I->ID]);
544 }
545 }
546
547 /* Protected things are pushed really high up. This number should put them
548 ahead of everything */
549 for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
d2685fd6 550 {
6c139d6e
AL
551 if ((Flags[I->ID] & Protected) != 0)
552 Scores[I->ID] += 10000;
d2685fd6
AL
553 if ((I->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
554 Scores[I->ID] += 5000;
b2e465d6 555 }
6c139d6e
AL
556}
557 /*}}}*/
558// ProblemResolver::DoUpgrade - Attempt to upgrade this package /*{{{*/
559// ---------------------------------------------------------------------
560/* This goes through and tries to reinstall packages to make this package
561 installable */
562bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg)
563{
564 if ((Flags[Pkg->ID] & Upgradable) == 0 || Cache[Pkg].Upgradable() == false)
565 return false;
3a486305
AL
566 if ((Flags[Pkg->ID] & Protected) == Protected)
567 return false;
0a8e3465 568
6c139d6e
AL
569 Flags[Pkg->ID] &= ~Upgradable;
570
571 bool WasKept = Cache[Pkg].Keep();
572 Cache.MarkInstall(Pkg,false);
573
0a8e3465
AL
574 // This must be a virtual package or something like that.
575 if (Cache[Pkg].InstVerIter(Cache).end() == true)
576 return false;
577
6c139d6e
AL
578 // Isolate the problem dependency
579 bool Fail = false;
580 for (pkgCache::DepIterator D = Cache[Pkg].InstVerIter(Cache).DependsList(); D.end() == false;)
581 {
582 // Compute a single dependency element (glob or)
583 pkgCache::DepIterator Start = D;
584 pkgCache::DepIterator End = D;
585 unsigned char State = 0;
4b1b89c5 586 for (bool LastOR = true; D.end() == false && LastOR == true;)
6c139d6e
AL
587 {
588 State |= Cache[D];
b518cca6 589 LastOR = (D->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or;
4b1b89c5 590 D++;
6c139d6e
AL
591 if (LastOR == true)
592 End = D;
593 }
594
595 // We only worry about critical deps.
596 if (End.IsCritical() != true)
597 continue;
4b1b89c5
AL
598
599 // Iterate over all the members in the or group
600 while (1)
0a8e3465 601 {
4b1b89c5
AL
602 // Dep is ok now
603 if ((Cache[End] & pkgDepCache::DepGInstall) == pkgDepCache::DepGInstall)
604 break;
605
606 // Do not change protected packages
607 PkgIterator P = Start.SmartTargetPkg();
608 if ((Flags[P->ID] & Protected) == Protected)
609 {
610 if (Debug == true)
648e3cb4 611 clog << " Reinst Failed because of protected " << P.Name() << endl;
4b1b89c5 612 Fail = true;
4b1b89c5 613 }
648e3cb4 614 else
6c139d6e 615 {
648e3cb4
AL
616 // Upgrade the package if the candidate version will fix the problem.
617 if ((Cache[Start] & pkgDepCache::DepCVer) == pkgDepCache::DepCVer)
618 {
619 if (DoUpgrade(P) == false)
620 {
621 if (Debug == true)
622 clog << " Reinst Failed because of " << P.Name() << endl;
623 Fail = true;
624 }
625 else
626 {
627 Fail = false;
628 break;
629 }
630 }
631 else
4b1b89c5 632 {
648e3cb4
AL
633 /* We let the algorithm deal with conflicts on its next iteration,
634 it is much smarter than us */
b2e465d6
AL
635 if (Start->Type == pkgCache::Dep::Conflicts ||
636 Start->Type == pkgCache::Dep::Obsoletes)
637 break;
648e3cb4 638
4b1b89c5 639 if (Debug == true)
648e3cb4 640 clog << " Reinst Failed early because of " << Start.TargetPkg().Name() << endl;
4b1b89c5 641 Fail = true;
648e3cb4 642 }
4b1b89c5 643 }
6c139d6e 644
4b1b89c5
AL
645 if (Start == End)
646 break;
647 Start++;
648 }
649 if (Fail == true)
6c139d6e 650 break;
6c139d6e
AL
651 }
652
653 // Undo our operations - it might be smart to undo everything this did..
654 if (Fail == true)
655 {
656 if (WasKept == true)
657 Cache.MarkKeep(Pkg);
658 else
659 Cache.MarkDelete(Pkg);
660 return false;
661 }
662
663 if (Debug == true)
0a8e3465 664 clog << " Re-Instated " << Pkg.Name() << endl;
6c139d6e
AL
665 return true;
666}
667 /*}}}*/
668// ProblemResolver::Resolve - Run the resolution pass /*{{{*/
669// ---------------------------------------------------------------------
670/* This routines works by calculating a score for each package. The score
671 is derived by considering the package's priority and all reverse
672 dependents giving an integer that reflects the amount of breakage that
673 adjusting the package will inflict.
674
675 It goes from highest score to lowest and corrects all of the breaks by
676 keeping or removing the dependant packages. If that fails then it removes
677 the package itself and goes on. The routine should be able to intelligently
678 go from any broken state to a fixed state.
679
680 The BrokenFix flag enables a mode where the algorithm tries to
681 upgrade packages to advoid problems. */
682bool pkgProblemResolver::Resolve(bool BrokenFix)
683{
b2e465d6 684 unsigned long Size = Cache.Head().PackageCount;
6c139d6e
AL
685
686 // Record which packages are marked for install
687 bool Again = false;
688 do
689 {
690 Again = false;
691 for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
692 {
693 if (Cache[I].Install() == true)
694 Flags[I->ID] |= PreInstalled;
695 else
696 {
697 if (Cache[I].InstBroken() == true && BrokenFix == true)
698 {
699 Cache.MarkInstall(I,false);
700 if (Cache[I].Install() == true)
701 Again = true;
702 }
703
704 Flags[I->ID] &= ~PreInstalled;
705 }
706 Flags[I->ID] |= Upgradable;
707 }
708 }
709 while (Again == true);
710
711 if (Debug == true)
0a8e3465 712 clog << "Starting" << endl;
6c139d6e
AL
713
714 MakeScores();
715
716 /* We have to order the packages so that the broken fixing pass
717 operates from highest score to lowest. This prevents problems when
718 high score packages cause the removal of lower score packages that
719 would cause the removal of even lower score packages. */
b2e465d6 720 SPtrArray<pkgCache::Package *> PList = new pkgCache::Package *[Size];
6c139d6e
AL
721 pkgCache::Package **PEnd = PList;
722 for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
723 *PEnd++ = I;
724 This = this;
725 qsort(PList,PEnd - PList,sizeof(*PList),&ScoreSort);
726
727/* for (pkgCache::Package **K = PList; K != PEnd; K++)
728 if (Scores[(*K)->ID] != 0)
729 {
730 pkgCache::PkgIterator Pkg(Cache,*K);
0a8e3465 731 clog << Scores[(*K)->ID] << ' ' << Pkg.Name() <<
6c139d6e
AL
732 ' ' << (pkgCache::Version *)Pkg.CurrentVer() << ' ' <<
733 Cache[Pkg].InstallVer << ' ' << Cache[Pkg].CandidateVer << endl;
734 } */
735
736 if (Debug == true)
0a8e3465 737 clog << "Starting 2" << endl;
6c139d6e
AL
738
739 /* Now consider all broken packages. For each broken package we either
740 remove the package or fix it's problem. We do this once, it should
741 not be possible for a loop to form (that is a < b < c and fixing b by
742 changing a breaks c) */
743 bool Change = true;
744 for (int Counter = 0; Counter != 10 && Change == true; Counter++)
745 {
746 Change = false;
747 for (pkgCache::Package **K = PList; K != PEnd; K++)
748 {
749 pkgCache::PkgIterator I(Cache,*K);
750
751 /* We attempt to install this and see if any breaks result,
752 this takes care of some strange cases */
753 if (Cache[I].CandidateVer != Cache[I].InstallVer &&
754 I->CurrentVer != 0 && Cache[I].InstallVer != 0 &&
755 (Flags[I->ID] & PreInstalled) != 0 &&
0a8e3465
AL
756 (Flags[I->ID] & Protected) == 0 &&
757 (Flags[I->ID] & ReInstateTried) == 0)
6c139d6e
AL
758 {
759 if (Debug == true)
0a8e3465 760 clog << " Try to Re-Instate " << I.Name() << endl;
a6568219 761 unsigned long OldBreaks = Cache.BrokenCount();
6c139d6e 762 pkgCache::Version *OldVer = Cache[I].InstallVer;
0a8e3465
AL
763 Flags[I->ID] &= ReInstateTried;
764
6c139d6e
AL
765 Cache.MarkInstall(I,false);
766 if (Cache[I].InstBroken() == true ||
767 OldBreaks < Cache.BrokenCount())
768 {
769 if (OldVer == 0)
770 Cache.MarkDelete(I);
771 else
772 Cache.MarkKeep(I);
773 }
774 else
775 if (Debug == true)
0a8e3465 776 clog << "Re-Instated " << I.Name() << " (" << OldBreaks << " vs " << Cache.BrokenCount() << ')' << endl;
6c139d6e
AL
777 }
778
779 if (Cache[I].InstallVer == 0 || Cache[I].InstBroken() == false)
780 continue;
781
00b47c98
AL
782 if (Debug == true)
783 cout << "Investigating " << I.Name() << endl;
784
6c139d6e
AL
785 // Isolate the problem dependency
786 PackageKill KillList[100];
787 PackageKill *LEnd = KillList;
421c8d10
AL
788 bool InOr = false;
789 pkgCache::DepIterator Start;
790 pkgCache::DepIterator End;
b2e465d6 791 PackageKill *OldEnd = LEnd;
648e3cb4
AL
792
793 enum {OrRemove,OrKeep} OrOp = OrRemove;
421c8d10
AL
794 for (pkgCache::DepIterator D = Cache[I].InstVerIter(Cache).DependsList();
795 D.end() == false || InOr == true;)
6c139d6e
AL
796 {
797 // Compute a single dependency element (glob or)
648e3cb4
AL
798 if (Start == End)
799 {
800 // Decide what to do
801 if (InOr == true)
802 {
803 if (OldEnd == LEnd && OrOp == OrRemove)
70777d4b
AL
804 {
805 if ((Flags[I->ID] & Protected) != Protected)
00b47c98
AL
806 {
807 if (Debug == true)
808 clog << " Or group remove for " << I.Name() << endl;
70777d4b 809 Cache.MarkDelete(I);
cd14eaf2 810 Change = true;
00b47c98 811 }
70777d4b 812 }
648e3cb4 813 if (OldEnd == LEnd && OrOp == OrKeep)
00b47c98
AL
814 {
815 if (Debug == true)
816 clog << " Or group keep for " << I.Name() << endl;
648e3cb4 817 Cache.MarkKeep(I);
cd14eaf2 818 Change = true;
b2e465d6 819 }
648e3cb4
AL
820 }
821
b2e465d6
AL
822 /* We do an extra loop (as above) to finalize the or group
823 processing */
824 InOr = false;
648e3cb4 825 OrOp = OrRemove;
421c8d10 826 D.GlobOr(Start,End);
b2e465d6
AL
827 if (Start.end() == true)
828 break;
cd14eaf2 829
b2e465d6
AL
830 // We only worry about critical deps.
831 if (End.IsCritical() != true)
832 continue;
cd14eaf2 833
648e3cb4
AL
834 InOr = Start != End;
835 OldEnd = LEnd;
cd14eaf2 836 }
421c8d10
AL
837 else
838 Start++;
cd14eaf2 839
6c139d6e
AL
840 // Dep is ok
841 if ((Cache[End] & pkgDepCache::DepGInstall) == pkgDepCache::DepGInstall)
cd14eaf2
AL
842 {
843 InOr = false;
6c139d6e 844 continue;
cd14eaf2
AL
845 }
846
6c139d6e 847 if (Debug == true)
421c8d10 848 clog << "Package " << I.Name() << " has broken dep on " << Start.TargetPkg().Name() << endl;
fcf85120
AL
849
850 /* Look across the version list. If there are no possible
851 targets then we keep the package and bail. This is necessary
852 if a package has a dep on another package that cant be found */
b2e465d6 853 SPtrArray<pkgCache::Version *> VList = Start.AllTargets();
fcf85120 854 if (*VList == 0 && (Flags[I->ID] & Protected) != Protected &&
648e3cb4 855 Start->Type != pkgCache::Dep::Conflicts &&
b2e465d6 856 Start->Type != pkgCache::Dep::Obsoletes &&
fcf85120 857 Cache[I].NowBroken() == false)
648e3cb4
AL
858 {
859 if (InOr == true)
860 {
861 /* No keep choice because the keep being OK could be the
862 result of another element in the OR group! */
863 continue;
864 }
865
fcf85120 866 Change = true;
648e3cb4 867 Cache.MarkKeep(I);
fcf85120
AL
868 break;
869 }
870
6c139d6e
AL
871 bool Done = false;
872 for (pkgCache::Version **V = VList; *V != 0; V++)
873 {
874 pkgCache::VerIterator Ver(Cache,*V);
875 pkgCache::PkgIterator Pkg = Ver.ParentPkg();
a6bfe583 876
6c139d6e 877 if (Debug == true)
421c8d10 878 clog << " Considering " << Pkg.Name() << ' ' << (int)Scores[Pkg->ID] <<
6c139d6e 879 " as a solution to " << I.Name() << ' ' << (int)Scores[I->ID] << endl;
a6bfe583
AL
880
881 /* Try to fix the package under consideration rather than
882 fiddle with the VList package */
6c139d6e 883 if (Scores[I->ID] <= Scores[Pkg->ID] ||
421c8d10 884 ((Cache[Start] & pkgDepCache::DepNow) == 0 &&
b2e465d6
AL
885 End->Type != pkgCache::Dep::Conflicts &&
886 End->Type != pkgCache::Dep::Obsoletes))
6c139d6e 887 {
200f8c52 888 // Try a little harder to fix protected packages..
3b5421b4 889 if ((Flags[I->ID] & Protected) == Protected)
200f8c52
AL
890 {
891 if (DoUpgrade(Pkg) == true)
0296c633 892 {
b2e465d6
AL
893 if (Scores[Pkg->ID] > Scores[I->ID])
894 Scores[Pkg->ID] = Scores[I->ID];
0296c633
AL
895 break;
896 }
897
6c139d6e 898 continue;
200f8c52
AL
899 }
900
901 /* See if a keep will do, unless the package is protected,
648e3cb4
AL
902 then installing it will be necessary */
903 bool Installed = Cache[I].Install();
6c139d6e
AL
904 Cache.MarkKeep(I);
905 if (Cache[I].InstBroken() == false)
906 {
648e3cb4
AL
907 // Unwind operation will be keep now
908 if (OrOp == OrRemove)
909 OrOp = OrKeep;
910
911 // Restore
912 if (InOr == true && Installed == true)
913 Cache.MarkInstall(I,false);
914
6c139d6e 915 if (Debug == true)
421c8d10 916 clog << " Holding Back " << I.Name() << " rather than change " << Start.TargetPkg().Name() << endl;
6c139d6e
AL
917 }
918 else
421c8d10 919 {
6c139d6e
AL
920 if (BrokenFix == false || DoUpgrade(I) == false)
921 {
421c8d10
AL
922 // Consider other options
923 if (InOr == false)
924 {
925 if (Debug == true)
926 clog << " Removing " << I.Name() << " rather than change " << Start.TargetPkg().Name() << endl;
927 Cache.MarkDelete(I);
928 if (Counter > 1)
b2e465d6
AL
929 {
930 if (Scores[Pkg->ID] > Scores[I->ID])
931 Scores[I->ID] = Scores[Pkg->ID];
932 }
421c8d10 933 }
0a8e3465 934 }
6c139d6e 935 }
b5dc9785 936
6c139d6e
AL
937 Change = true;
938 Done = true;
939 break;
940 }
941 else
942 {
a6bfe583
AL
943 /* This is a conflicts, and the version we are looking
944 at is not the currently selected version of the
945 package, which means it is not necessary to
946 remove/keep */
947 if (Cache[Pkg].InstallVer != Ver &&
948 (Start->Type == pkgCache::Dep::Conflicts ||
949 Start->Type == pkgCache::Dep::Obsoletes))
950 continue;
951
648e3cb4 952 // Skip adding to the kill list if it is protected
6c139d6e
AL
953 if ((Flags[Pkg->ID] & Protected) != 0)
954 continue;
a6bfe583
AL
955
956 if (Debug == true)
957 clog << " Added " << Pkg.Name() << " to the remove list" << endl;
6c139d6e
AL
958
959 LEnd->Pkg = Pkg;
960 LEnd->Dep = End;
961 LEnd++;
0a8e3465 962
b2e465d6
AL
963 if (Start->Type != pkgCache::Dep::Conflicts &&
964 Start->Type != pkgCache::Dep::Obsoletes)
6c139d6e
AL
965 break;
966 }
967 }
968
969 // Hm, nothing can possibly satisify this dep. Nuke it.
b2e465d6
AL
970 if (VList[0] == 0 &&
971 Start->Type != pkgCache::Dep::Conflicts &&
972 Start->Type != pkgCache::Dep::Obsoletes &&
648e3cb4 973 (Flags[I->ID] & Protected) != Protected)
6c139d6e 974 {
648e3cb4 975 bool Installed = Cache[I].Install();
6c139d6e
AL
976 Cache.MarkKeep(I);
977 if (Cache[I].InstBroken() == false)
978 {
648e3cb4
AL
979 // Unwind operation will be keep now
980 if (OrOp == OrRemove)
981 OrOp = OrKeep;
982
983 // Restore
984 if (InOr == true && Installed == true)
985 Cache.MarkInstall(I,false);
986
6c139d6e 987 if (Debug == true)
421c8d10 988 clog << " Holding Back " << I.Name() << " because I can't find " << Start.TargetPkg().Name() << endl;
6c139d6e
AL
989 }
990 else
991 {
992 if (Debug == true)
421c8d10 993 clog << " Removing " << I.Name() << " because I can't find " << Start.TargetPkg().Name() << endl;
648e3cb4
AL
994 if (InOr == false)
995 Cache.MarkDelete(I);
6c139d6e
AL
996 }
997
998 Change = true;
999 Done = true;
1000 }
1001
421c8d10
AL
1002 // Try some more
1003 if (InOr == true)
1004 continue;
1005
6c139d6e
AL
1006 if (Done == true)
1007 break;
1008 }
1009
1010 // Apply the kill list now
1011 if (Cache[I].InstallVer != 0)
648e3cb4 1012 {
6c139d6e 1013 for (PackageKill *J = KillList; J != LEnd; J++)
6c139d6e 1014 {
648e3cb4
AL
1015 Change = true;
1016 if ((Cache[J->Dep] & pkgDepCache::DepGNow) == 0)
1017 {
b2e465d6
AL
1018 if (J->Dep->Type == pkgCache::Dep::Conflicts ||
1019 J->Dep->Type == pkgCache::Dep::Obsoletes)
648e3cb4
AL
1020 {
1021 if (Debug == true)
1022 clog << " Fixing " << I.Name() << " via remove of " << J->Pkg.Name() << endl;
1023 Cache.MarkDelete(J->Pkg);
1024 }
1025 }
1026 else
6c139d6e
AL
1027 {
1028 if (Debug == true)
648e3cb4
AL
1029 clog << " Fixing " << I.Name() << " via keep of " << J->Pkg.Name() << endl;
1030 Cache.MarkKeep(J->Pkg);
6c139d6e 1031 }
b2e465d6 1032
648e3cb4 1033 if (Counter > 1)
b2e465d6
AL
1034 {
1035 if (Scores[I->ID] > Scores[J->Pkg->ID])
1036 Scores[J->Pkg->ID] = Scores[I->ID];
1037 }
648e3cb4
AL
1038 }
1039 }
1040 }
6c139d6e
AL
1041 }
1042
1043 if (Debug == true)
0a8e3465 1044 clog << "Done" << endl;
b2e465d6 1045
6c139d6e 1046 if (Cache.BrokenCount() != 0)
b5dc9785
AL
1047 {
1048 // See if this is the result of a hold
1049 pkgCache::PkgIterator I = Cache.PkgBegin();
1050 for (;I.end() != true; I++)
1051 {
1052 if (Cache[I].InstBroken() == false)
1053 continue;
1054 if ((Flags[I->ID] & Protected) != Protected)
b2e465d6 1055 return _error->Error(_("Error, pkgProblemResolver::Resolve generated breaks, this may be caused by held packages."));
b5dc9785 1056 }
b2e465d6 1057 return _error->Error(_("Unable to correct problems, you have held broken packages."));
b5dc9785
AL
1058 }
1059
0a8e3465
AL
1060 return true;
1061}
1062 /*}}}*/
1063// ProblemResolver::ResolveByKeep - Resolve problems using keep /*{{{*/
1064// ---------------------------------------------------------------------
1065/* This is the work horse of the soft upgrade routine. It is very gental
1066 in that it does not install or remove any packages. It is assumed that the
1067 system was non-broken previously. */
1068bool pkgProblemResolver::ResolveByKeep()
1069{
b2e465d6 1070 unsigned long Size = Cache.Head().PackageCount;
0a8e3465
AL
1071
1072 if (Debug == true)
1073 clog << "Entering ResolveByKeep" << endl;
1074
1075 MakeScores();
1076
1077 /* We have to order the packages so that the broken fixing pass
1078 operates from highest score to lowest. This prevents problems when
1079 high score packages cause the removal of lower score packages that
1080 would cause the removal of even lower score packages. */
1081 pkgCache::Package **PList = new pkgCache::Package *[Size];
1082 pkgCache::Package **PEnd = PList;
1083 for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
1084 *PEnd++ = I;
1085 This = this;
1086 qsort(PList,PEnd - PList,sizeof(*PList),&ScoreSort);
1087
1088 // Consider each broken package
1089 pkgCache::Package **LastStop = 0;
1090 for (pkgCache::Package **K = PList; K != PEnd; K++)
1091 {
1092 pkgCache::PkgIterator I(Cache,*K);
1093
1094 if (Cache[I].InstallVer == 0 || Cache[I].InstBroken() == false)
1095 continue;
1096
1097 /* Keep the package. If this works then great, otherwise we have
b2e465d6 1098 to be significantly more agressive and manipulate its dependencies */
0a8e3465
AL
1099 if ((Flags[I->ID] & Protected) == 0)
1100 {
1101 if (Debug == true)
1102 clog << "Keeping package " << I.Name() << endl;
1103 Cache.MarkKeep(I);
1104 if (Cache[I].InstBroken() == false)
1105 {
b2e465d6 1106 K = PList - 1;
0a8e3465
AL
1107 continue;
1108 }
1109 }
1110
1111 // Isolate the problem dependencies
1112 for (pkgCache::DepIterator D = Cache[I].InstVerIter(Cache).DependsList(); D.end() == false;)
1113 {
c5532863
AL
1114 DepIterator Start;
1115 DepIterator End;
1116 D.GlobOr(Start,End);
1117
0a8e3465
AL
1118 // We only worry about critical deps.
1119 if (End.IsCritical() != true)
1120 continue;
1121
1122 // Dep is ok
1123 if ((Cache[End] & pkgDepCache::DepGInstall) == pkgDepCache::DepGInstall)
1124 continue;
c5532863
AL
1125
1126 /* Hm, the group is broken.. I suppose the best thing to do is to
1127 is to try every combination of keep/not-keep for the set, but thats
1128 slow, and this never happens, just be conservative and assume the
1129 list of ors is in preference and keep till it starts to work. */
1130 while (true)
0a8e3465 1131 {
c5532863
AL
1132 if (Debug == true)
1133 clog << "Package " << I.Name() << " has broken dep on " << Start.TargetPkg().Name() << endl;
0a8e3465 1134
c5532863
AL
1135 // Look at all the possible provides on this package
1136 SPtrArray<pkgCache::Version *> VList = Start.AllTargets();
1137 for (pkgCache::Version **V = VList; *V != 0; V++)
0a8e3465 1138 {
c5532863
AL
1139 pkgCache::VerIterator Ver(Cache,*V);
1140 pkgCache::PkgIterator Pkg = Ver.ParentPkg();
1141
1142 // It is not keepable
1143 if (Cache[Pkg].InstallVer == 0 ||
1144 Pkg->CurrentVer == 0)
1145 continue;
1146
1147 if ((Flags[I->ID] & Protected) == 0)
1148 {
1149 if (Debug == true)
1150 clog << " Keeping Package " << Pkg.Name() << " due to dep" << endl;
1151 Cache.MarkKeep(Pkg);
1152 }
1153
1154 if (Cache[I].InstBroken() == false)
1155 break;
0a8e3465
AL
1156 }
1157
1158 if (Cache[I].InstBroken() == false)
1159 break;
0a8e3465 1160
c5532863
AL
1161 if (Start == End)
1162 break;
1163 Start++;
1164 }
1165
0a8e3465
AL
1166 if (Cache[I].InstBroken() == false)
1167 break;
1168 }
1169
1170 if (Cache[I].InstBroken() == true)
1171 continue;
1172
1173 // Restart again.
1174 if (K == LastStop)
1175 return _error->Error("Internal Error, pkgProblemResolver::ResolveByKeep is looping on package %s.",I.Name());
1176 LastStop = K;
b2e465d6 1177 K = PList - 1;
0a8e3465 1178 }
6c139d6e
AL
1179
1180 return true;
1181}
1182 /*}}}*/
3b5421b4
AL
1183// ProblemResolver::InstallProtect - Install all protected packages /*{{{*/
1184// ---------------------------------------------------------------------
1185/* This is used to make sure protected packages are installed */
1186void pkgProblemResolver::InstallProtect()
1187{
1188 for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
1189 {
1190 if ((Flags[I->ID] & Protected) == Protected)
1191 {
1192 if ((Flags[I->ID] & ToRemove) == ToRemove)
1193 Cache.MarkDelete(I);
1194 else
1195 Cache.MarkInstall(I,false);
1196 }
1197 }
1198}
1199 /*}}}*/
b2e465d6
AL
1200
1201// PrioSortList - Sort a list of versions by priority /*{{{*/
1202// ---------------------------------------------------------------------
1203/* This is ment to be used in conjunction with AllTargets to get a list
1204 of versions ordered by preference. */
1205static pkgCache *PrioCache;
1206static int PrioComp(const void *A,const void *B)
1207{
1208 pkgCache::VerIterator L(*PrioCache,*(pkgCache::Version **)A);
1209 pkgCache::VerIterator R(*PrioCache,*(pkgCache::Version **)B);
1210
1211 if ((L.ParentPkg()->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential &&
1212 (L.ParentPkg()->Flags & pkgCache::Flag::Essential) != pkgCache::Flag::Essential)
1213 return 1;
1214 if ((L.ParentPkg()->Flags & pkgCache::Flag::Essential) != pkgCache::Flag::Essential &&
1215 (L.ParentPkg()->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
1216 return -1;
1217
1218 if (L->Priority != R->Priority)
1219 return L->Priority - R->Priority;
1220 return strcmp(L.ParentPkg().Name(),R.ParentPkg().Name());
1221}
1222void pkgPrioSortList(pkgCache &Cache,pkgCache::Version **List)
1223{
1224 unsigned long Count = 0;
1225 PrioCache = &Cache;
1226 for (pkgCache::Version **I = List; *I != 0; I++)
1227 Count++;
1228 qsort(List,Count,sizeof(*List),PrioComp);
1229}
1230 /*}}}*/