]>
git.saurik.com Git - apt.git/blob - apt-pkg/algorithms.cc
e3012489d376878cf2f80b837d948c75d25db44b
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: algorithms.cc,v 1.1 1998/07/07 04:17:00 jgg Exp $
4 /* ######################################################################
6 Algorithms - A set of misc algorithms
8 ##################################################################### */
10 // Include Files /*{{{*/
12 #pragma implementation "pkglib/algorithms.h"
14 #include <pkglib/algorithms.h>
15 #include <pkglib/error.h>
16 #include <pkglib/pkgelement.h>
20 pkgProblemResolver
*pkgProblemResolver::This
= 0;
22 // Simulate::Simulate - Constructor /*{{{*/
23 // ---------------------------------------------------------------------
25 pkgSimulate::pkgSimulate(pkgDepCache
&Cache
) : pkgPackageManager(Cache
),
28 Flags
= new unsigned char[Cache
.HeaderP
->PackageCount
];
29 memset(Flags
,0,sizeof(*Flags
)*Cache
.HeaderP
->PackageCount
);
32 // Simulate::Install - Simulate unpacking of a package /*{{{*/
33 // ---------------------------------------------------------------------
35 bool pkgSimulate::Install(PkgIterator iPkg
,string
/*File*/)
38 PkgIterator Pkg
= Sim
.FindPkg(iPkg
.Name());
41 cout
<< "Inst " << Pkg
.Name();
42 Sim
.MarkInstall(Pkg
,false);
44 // Look for broken conflicts+predepends.
45 for (PkgIterator I
= Sim
.PkgBegin(); I
.end() == false; I
++)
47 if (Sim
[I
].InstallVer
== 0)
50 for (DepIterator D
= Sim
[I
].InstVerIter(Sim
).DependsList(); D
.end() == false; D
++)
51 if (D
->Type
== pkgDEP_Conflicts
|| D
->Type
== pkgDEP_PreDepends
)
53 if ((Sim
[D
] & pkgDepCache::DepInstall
) == 0)
55 cout
<< " [" << I
.Name() << " on " << D
.TargetPkg().Name() << ']';
56 if (D
->Type
== pkgDEP_Conflicts
)
57 _error
->Error("Fatal, conflicts violated %s",I
.Name());
62 if (Sim
.BrokenCount() != 0)
69 // Simulate::Configure - Simulate configuration of a Package /*{{{*/
70 // ---------------------------------------------------------------------
71 /* This is not an acurate simulation of relatity, we should really not
72 install the package.. For some investigations it may be necessary
74 bool pkgSimulate::Configure(PkgIterator iPkg
)
77 PkgIterator Pkg
= Sim
.FindPkg(iPkg
.Name());
80 // Sim.MarkInstall(Pkg,false);
81 if (Sim
[Pkg
].InstBroken() == true)
83 cout
<< "Conf " << Pkg
.Name() << " broken" << endl
;
87 // Print out each package and the failed dependencies
88 for (pkgCache::DepIterator D
= Sim
[Pkg
].InstVerIter(Sim
).DependsList(); D
.end() == false; D
++)
90 if (Sim
.IsImportantDep(D
) == false ||
91 (Sim
[D
] & pkgDepCache::DepInstall
) != 0)
94 if (D
->Type
== pkgDEP_Conflicts
)
95 cout
<< " Conflicts:" << D
.TargetPkg().Name();
97 cout
<< " Depends:" << D
.TargetPkg().Name();
101 _error
->Error("Conf Broken %s",Pkg
.Name());
104 cout
<< "Conf " << Pkg
.Name();
106 if (Sim
.BrokenCount() != 0)
114 // Simulate::Remove - Simulate the removal of a package /*{{{*/
115 // ---------------------------------------------------------------------
117 bool pkgSimulate::Remove(PkgIterator iPkg
)
119 // Adapt the iterator
120 PkgIterator Pkg
= Sim
.FindPkg(iPkg
.Name());
124 cout
<< "Remv " << Pkg
.Name();
126 if (Sim
.BrokenCount() != 0)
134 // Simulate::ShortBreaks - Print out a short line describing all breaks /*{{{*/
135 // ---------------------------------------------------------------------
137 void pkgSimulate::ShortBreaks()
140 for (PkgIterator I
= Sim
.PkgBegin(); I
.end() == false; I
++)
142 if (Sim
[I
].InstBroken() == true)
144 if (Flags
[I
->ID
] == 0)
145 cout
<< I
.Name() << ' ';
147 cout << I.Name() << "! ";*/
153 // ApplyStatus - Adjust for non-ok packages /*{{{*/
154 // ---------------------------------------------------------------------
155 /* We attempt to change the state of the all packages that have failed
156 installation toward their real state. The ordering code will perform
157 the necessary calculations to deal with the problems. */
158 bool pkgApplyStatus(pkgDepCache
&Cache
)
160 for (pkgCache::PkgIterator I
= Cache
.PkgBegin(); I
.end() == false; I
++)
162 switch (I
->CurrentState
)
164 // This means installation failed somehow
165 case pkgSTATE_UnPacked
:
166 case pkgSTATE_HalfConfigured
:
170 // This means removal failed
171 case pkgSTATE_HalfInstalled
:
176 if (I
->InstState
!= pkgSTATE_Ok
)
177 return _error
->Error("The package %s is not ok and I "
178 "don't know how to fix it!",I
.Name());
184 // FixBroken - Fix broken packages /*{{{*/
185 // ---------------------------------------------------------------------
186 /* This autoinstalls every broken package and then runs ScoredFix on the
188 bool pkgFixBroken(pkgDepCache
&Cache
)
190 // Auto upgrade all broken packages
191 for (pkgCache::PkgIterator I
= Cache
.PkgBegin(); I
.end() == false; I
++)
192 if (Cache
[I
].NowBroken() == true)
193 Cache
.MarkInstall(I
,true);
195 /* Fix packages that are in a NeedArchive state but don't have a
196 downloadable install version */
197 for (pkgCache::PkgIterator I
= Cache
.PkgBegin(); I
.end() == false; I
++)
199 if (I
.State() != pkgCache::PkgIterator::NeedsUnpack
||
200 Cache
[I
].Delete() == true)
203 if ((Cache
[I
].InstVerIter(Cache
).File()->Flags
& pkgFLAG_NotSource
) == 0)
206 Cache
.MarkInstall(I
,true);
209 pkgProblemResolver
Fix(Cache
);
210 return Fix
.Resolve(true);
213 // DistUpgrade - Distribution upgrade /*{{{*/
214 // ---------------------------------------------------------------------
215 /* This autoinstalls every package and then force installs every
216 pre-existing package. This creates the initial set of conditions which
217 most likely contain problems because too many things were installed.
219 ScoredFix is used to resolve the problems.
221 bool pkgDistUpgrade(pkgDepCache
&Cache
)
223 /* Auto upgrade all installed packages, this provides the basis
224 for the installation */
225 for (pkgCache::PkgIterator I
= Cache
.PkgBegin(); I
.end() == false; I
++)
226 if (I
->CurrentVer
!= 0)
227 Cache
.MarkInstall(I
,true);
229 /* Now, auto upgrade all essential packages - this ensures that
230 the essential packages are present and working */
231 for (pkgCache::PkgIterator I
= Cache
.PkgBegin(); I
.end() == false; I
++)
232 if ((I
->Flags
& pkgFLAG_Essential
) == pkgFLAG_Essential
)
233 Cache
.MarkInstall(I
,true);
235 /* We do it again over all previously installed packages to force
236 conflict resolution on them all. */
237 for (pkgCache::PkgIterator I
= Cache
.PkgBegin(); I
.end() == false; I
++)
238 if (I
->CurrentVer
!= 0)
239 Cache
.MarkInstall(I
,false);
241 pkgProblemResolver
Fix(Cache
);
243 // Hold back held packages.
244 for (pkgCache::PkgIterator I
= Cache
.PkgBegin(); I
.end() == false; I
++)
246 if (I
->SelectedState
== pkgSTATE_Hold
)
253 return Fix
.Resolve();
257 // ProblemResolver::pkgProblemResolver - Constructor /*{{{*/
258 // ---------------------------------------------------------------------
260 pkgProblemResolver::pkgProblemResolver(pkgDepCache
&Cache
) : Cache(Cache
)
263 unsigned long Size
= Cache
.HeaderP
->PackageCount
;
264 Scores
= new signed short[Size
];
265 Flags
= new unsigned char[Size
];
266 memset(Flags
,0,sizeof(*Flags
)*Size
);
268 // Set debug to true to see its decision logic
272 // ProblemResolver::ScoreSort - Sort the list by score /*{{{*/
273 // ---------------------------------------------------------------------
275 int pkgProblemResolver::ScoreSort(const void *a
,const void *b
)
277 Package
const **A
= (Package
const **)a
;
278 Package
const **B
= (Package
const **)b
;
279 if (This
->Scores
[(*A
)->ID
] > This
->Scores
[(*B
)->ID
])
281 if (This
->Scores
[(*A
)->ID
] < This
->Scores
[(*B
)->ID
])
286 // ProblemResolver::MakeScores - Make the score table /*{{{*/
287 // ---------------------------------------------------------------------
289 void pkgProblemResolver::MakeScores()
291 unsigned long Size
= Cache
.HeaderP
->PackageCount
;
292 memset(Scores
,0,sizeof(*Scores
)*Size
);
294 // Generate the base scores for a package based on its properties
295 for (pkgCache::PkgIterator I
= Cache
.PkgBegin(); I
.end() == false; I
++)
297 if (Cache
[I
].InstallVer
== 0)
300 signed short &Score
= Scores
[I
->ID
];
302 /* This is arbitary, it should be high enough to elevate an
303 essantial package above most other packages but low enough
304 to allow an obsolete essential packages to be removed by
305 a conflicts on a powerfull normal package (ie libc6) */
306 if ((I
->Flags
& pkgFLAG_Essential
) == pkgFLAG_Essential
)
309 // We transform the priority
310 // Important Required Standard Optional Extra
311 signed short PrioMap
[] = {0,3,2,1,-1,-2};
312 if (Cache
[I
].InstVerIter(Cache
)->Priority
<= 5)
313 Score
+= PrioMap
[Cache
[I
].InstVerIter(Cache
)->Priority
];
315 /* This helps to fix oddball problems with conflicting packages
316 on the same level. We enhance the score of installed packages */
317 if (I
->CurrentVer
!= 0)
321 // Now that we have the base scores we go and propogate dependencies
322 for (pkgCache::PkgIterator I
= Cache
.PkgBegin(); I
.end() == false; I
++)
324 if (Cache
[I
].InstallVer
== 0)
327 for (pkgCache::DepIterator D
= Cache
[I
].InstVerIter(Cache
).DependsList(); D
.end() == false; D
++)
329 if (D
->Type
== pkgDEP_Depends
|| D
->Type
== pkgDEP_PreDepends
)
330 Scores
[D
.TargetPkg()->ID
]++;
334 // Copy the scores to advoid additive looping
335 signed short *OldScores
= new signed short[Size
];
336 memcpy(OldScores
,Scores
,sizeof(*Scores
)*Size
);
338 /* Now we cause 1 level of dependency inheritance, that is we add the
339 score of the packages that depend on the target Package. This
340 fortifies high scoring packages */
341 for (pkgCache::PkgIterator I
= Cache
.PkgBegin(); I
.end() == false; I
++)
343 if (Cache
[I
].InstallVer
== 0)
346 for (pkgCache::DepIterator D
= I
.RevDependsList(); D
.end() == false; D
++)
348 // Only do it for the install version
349 if ((pkgCache::Version
*)D
.ParentVer() != Cache
[D
.ParentPkg()].InstallVer
||
350 (D
->Type
!= pkgDEP_Depends
&& D
->Type
!= pkgDEP_PreDepends
))
353 Scores
[I
->ID
] += abs(OldScores
[D
.ParentPkg()->ID
]);
357 /* Now we propogate along provides. This makes the packages that
358 provide important packages extremely important */
359 for (pkgCache::PkgIterator I
= Cache
.PkgBegin(); I
.end() == false; I
++)
361 for (pkgCache::PrvIterator P
= I
.ProvidesList(); P
.end() == false; P
++)
363 // Only do it once per package
364 if ((pkgCache::Version
*)P
.OwnerVer() != Cache
[P
.OwnerPkg()].InstallVer
)
366 Scores
[P
.OwnerPkg()->ID
] += abs(Scores
[I
->ID
] - OldScores
[I
->ID
]);
370 /* Protected things are pushed really high up. This number should put them
371 ahead of everything */
372 for (pkgCache::PkgIterator I
= Cache
.PkgBegin(); I
.end() == false; I
++)
373 if ((Flags
[I
->ID
] & Protected
) != 0)
374 Scores
[I
->ID
] += 10000;
379 // ProblemResolver::DoUpgrade - Attempt to upgrade this package /*{{{*/
380 // ---------------------------------------------------------------------
381 /* This goes through and tries to reinstall packages to make this package
383 bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg
)
385 if ((Flags
[Pkg
->ID
] & Upgradable
) == 0 || Cache
[Pkg
].Upgradable() == false)
387 Flags
[Pkg
->ID
] &= ~Upgradable
;
389 bool WasKept
= Cache
[Pkg
].Keep();
390 Cache
.MarkInstall(Pkg
,false);
392 // Isolate the problem dependency
394 for (pkgCache::DepIterator D
= Cache
[Pkg
].InstVerIter(Cache
).DependsList(); D
.end() == false;)
396 // Compute a single dependency element (glob or)
397 pkgCache::DepIterator Start
= D
;
398 pkgCache::DepIterator End
= D
;
399 unsigned char State
= 0;
400 for (bool LastOR
= true; D
.end() == false && LastOR
== true; D
++)
403 LastOR
= (D
->CompareOp
& pkgOP_OR
) == pkgOP_OR
;
408 // We only worry about critical deps.
409 if (End
.IsCritical() != true)
413 if ((Cache
[End
] & pkgDepCache::DepGInstall
) == pkgDepCache::DepGInstall
)
416 // Hm, the group is broken.. I have no idea how to handle this
419 cout
<< "Note, a broken or group was found in " << Pkg
.Name() << "." << endl
;
424 // Upgrade the package if the candidate version will fix the problem.
425 if ((Cache
[Start
] & pkgDepCache::DepCVer
) == pkgDepCache::DepCVer
)
427 PkgIterator P
= Start
.SmartTargetPkg();
428 if (DoUpgrade(P
) == false)
431 cout
<< " Reinst Failed because of " << P
.Name() << endl
;
438 /* We let the algorithm deal with conflicts on its next iteration,
439 it is much smarter than us */
440 if (End
->Type
== pkgDEP_Conflicts
)
444 cout
<< " Reinst Failed early because of " << Start
.TargetPkg().Name() << endl
;
450 // Undo our operations - it might be smart to undo everything this did..
456 Cache
.MarkDelete(Pkg
);
461 cout
<< " Re-Instated " << Pkg
.Name() << endl
;
465 // ProblemResolver::Resolve - Run the resolution pass /*{{{*/
466 // ---------------------------------------------------------------------
467 /* This routines works by calculating a score for each package. The score
468 is derived by considering the package's priority and all reverse
469 dependents giving an integer that reflects the amount of breakage that
470 adjusting the package will inflict.
472 It goes from highest score to lowest and corrects all of the breaks by
473 keeping or removing the dependant packages. If that fails then it removes
474 the package itself and goes on. The routine should be able to intelligently
475 go from any broken state to a fixed state.
477 The BrokenFix flag enables a mode where the algorithm tries to
478 upgrade packages to advoid problems. */
479 bool pkgProblemResolver::Resolve(bool BrokenFix
)
481 unsigned long Size
= Cache
.HeaderP
->PackageCount
;
483 // Record which packages are marked for install
488 for (pkgCache::PkgIterator I
= Cache
.PkgBegin(); I
.end() == false; I
++)
490 if (Cache
[I
].Install() == true)
491 Flags
[I
->ID
] |= PreInstalled
;
494 if (Cache
[I
].InstBroken() == true && BrokenFix
== true)
496 Cache
.MarkInstall(I
,false);
497 if (Cache
[I
].Install() == true)
501 Flags
[I
->ID
] &= ~PreInstalled
;
503 Flags
[I
->ID
] |= Upgradable
;
506 while (Again
== true);
509 cout
<< "Starting" << endl
;
513 /* We have to order the packages so that the broken fixing pass
514 operates from highest score to lowest. This prevents problems when
515 high score packages cause the removal of lower score packages that
516 would cause the removal of even lower score packages. */
517 pkgCache::Package
**PList
= new pkgCache::Package
*[Size
];
518 pkgCache::Package
**PEnd
= PList
;
519 for (pkgCache::PkgIterator I
= Cache
.PkgBegin(); I
.end() == false; I
++)
522 qsort(PList
,PEnd
- PList
,sizeof(*PList
),&ScoreSort
);
524 /* for (pkgCache::Package **K = PList; K != PEnd; K++)
525 if (Scores[(*K)->ID] != 0)
527 pkgCache::PkgIterator Pkg(Cache,*K);
528 cout << Scores[(*K)->ID] << ' ' << Pkg.Name() <<
529 ' ' << (pkgCache::Version *)Pkg.CurrentVer() << ' ' <<
530 Cache[Pkg].InstallVer << ' ' << Cache[Pkg].CandidateVer << endl;
534 cout
<< "Starting 2" << endl
;
536 /* Now consider all broken packages. For each broken package we either
537 remove the package or fix it's problem. We do this once, it should
538 not be possible for a loop to form (that is a < b < c and fixing b by
539 changing a breaks c) */
541 for (int Counter
= 0; Counter
!= 10 && Change
== true; Counter
++)
544 for (pkgCache::Package
**K
= PList
; K
!= PEnd
; K
++)
546 pkgCache::PkgIterator
I(Cache
,*K
);
548 /* We attempt to install this and see if any breaks result,
549 this takes care of some strange cases */
550 if (Cache
[I
].CandidateVer
!= Cache
[I
].InstallVer
&&
551 I
->CurrentVer
!= 0 && Cache
[I
].InstallVer
!= 0 &&
552 (Flags
[I
->ID
] & PreInstalled
) != 0 &&
553 (Flags
[I
->ID
] & Protected
) == 0)
556 cout
<< " Try to Re-Instate " << I
.Name() << endl
;
557 int OldBreaks
= Cache
.BrokenCount();
558 pkgCache::Version
*OldVer
= Cache
[I
].InstallVer
;
560 Cache
.MarkInstall(I
,false);
561 if (Cache
[I
].InstBroken() == true ||
562 OldBreaks
< Cache
.BrokenCount())
571 cout
<< "Re-Instated " << I
.Name() << endl
;
574 if (Cache
[I
].InstallVer
== 0 || Cache
[I
].InstBroken() == false)
577 // Isolate the problem dependency
578 PackageKill KillList
[100];
579 PackageKill
*LEnd
= KillList
;
580 for (pkgCache::DepIterator D
= Cache
[I
].InstVerIter(Cache
).DependsList(); D
.end() == false;)
582 // Compute a single dependency element (glob or)
583 pkgCache::DepIterator Start
= D
;
584 pkgCache::DepIterator End
= D
;
585 unsigned char State
= 0;
586 for (bool LastOR
= true; D
.end() == false && LastOR
== true; D
++)
589 LastOR
= (D
->CompareOp
& pkgOP_OR
) == pkgOP_OR
;
594 // We only worry about critical deps.
595 if (End
.IsCritical() != true)
599 if ((Cache
[End
] & pkgDepCache::DepGInstall
) == pkgDepCache::DepGInstall
)
602 // Hm, the group is broken.. I have no idea how to handle this
605 cout
<< "Note, a broken or group was found in " << I
.Name() << "." << endl
;
611 cout
<< "Package " << I
.Name() << " has broken dep on " << End
.TargetPkg().Name() << endl
;
613 /* Conflicts is simple, decide if we should remove this package
614 or the conflicted one */
615 pkgCache::Version
**VList
= End
.AllTargets();
617 for (pkgCache::Version
**V
= VList
; *V
!= 0; V
++)
619 pkgCache::VerIterator
Ver(Cache
,*V
);
620 pkgCache::PkgIterator Pkg
= Ver
.ParentPkg();
623 cout
<< " Considering " << Pkg
.Name() << ' ' << (int)Scores
[Pkg
->ID
] <<
624 " as a solution to " << I
.Name() << ' ' << (int)Scores
[I
->ID
] << endl
;
625 if (Scores
[I
->ID
] <= Scores
[Pkg
->ID
] ||
626 ((Cache
[End
] & pkgDepCache::DepGNow
) == 0 &&
627 End
->Type
!= pkgDEP_Conflicts
))
629 if ((Flags
[I
->ID
] & Protected
) != 0)
632 // See if a keep will do
634 if (Cache
[I
].InstBroken() == false)
637 cout
<< " Holding Back " << I
.Name() << " rather than change " << End
.TargetPkg().Name() << endl
;
641 if (BrokenFix
== false || DoUpgrade(I
) == false)
644 cout
<< " Removing " << I
.Name() << " rather than change " << End
.TargetPkg().Name() << endl
;
647 Scores
[I
->ID
] = Scores
[Pkg
->ID
];
657 // Skip this if it is protected
658 if ((Flags
[Pkg
->ID
] & Protected
) != 0)
664 if (End
->Type
!= pkgDEP_Conflicts
)
669 // Hm, nothing can possibly satisify this dep. Nuke it.
670 if (VList
[0] == 0 && End
->Type
!= pkgDEP_Conflicts
)
673 if (Cache
[I
].InstBroken() == false)
676 cout
<< " Holding Back " << I
.Name() << " because I can't find " << End
.TargetPkg().Name() << endl
;
681 cout
<< " Removing " << I
.Name() << " because I can't find " << End
.TargetPkg().Name() << endl
;
694 // Apply the kill list now
695 if (Cache
[I
].InstallVer
!= 0)
696 for (PackageKill
*J
= KillList
; J
!= LEnd
; J
++)
699 if ((Cache
[J
->Dep
] & pkgDepCache::DepGNow
) == 0)
701 if (J
->Dep
->Type
== pkgDEP_Conflicts
)
704 cout
<< " Fixing " << I
.Name() << " via remove of " << J
->Pkg
.Name() << endl
;
705 Cache
.MarkDelete(J
->Pkg
);
711 cout
<< " Fixing " << I
.Name() << " via keep of " << J
->Pkg
.Name() << endl
;
712 Cache
.MarkKeep(J
->Pkg
);
716 Scores
[J
->Pkg
->ID
] = Scores
[I
->ID
];
722 cout
<< "Done" << endl
;
727 if (Cache
.BrokenCount() != 0)
728 return _error
->Error("Internal error, ScoredFix generated breaks.");