* use mark-and-sweep from aptitude now as GC algorithm
[ntk/apt.git] / apt-pkg / depcache.cc
CommitLineData
6c139d6e
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
e7b470ee 3// $Id: depcache.cc,v 1.25 2001/05/27 05:36:04 jgg Exp $
6c139d6e
AL
4/* ######################################################################
5
6 Dependency Cache - Caches Dependency information.
7
8 ##################################################################### */
9 /*}}}*/
10// Include Files /*{{{*/
11#ifdef __GNUG__
094a497d 12#pragma implementation "apt-pkg/depcache.h"
6c139d6e 13#endif
094a497d 14#include <apt-pkg/depcache.h>
094a497d
AL
15#include <apt-pkg/version.h>
16#include <apt-pkg/error.h>
b2e465d6
AL
17#include <apt-pkg/sptr.h>
18#include <apt-pkg/algorithms.h>
afb1e2e3
MV
19
20#include <apt-pkg/fileutl.h>
21#include <apt-pkg/configuration.h>
22#include <apt-pkg/tagfile.h>
120365ce
MV
23
24#include <iostream>
a83d884d 25#include <sstream>
b2e465d6 26#include <apti18n.h>
6c139d6e
AL
27 /*}}}*/
28
29// DepCache::pkgDepCache - Constructors /*{{{*/
30// ---------------------------------------------------------------------
31/* */
b2e465d6
AL
32pkgDepCache::pkgDepCache(pkgCache *pCache,Policy *Plcy) :
33 Cache(pCache), PkgState(0), DepState(0)
6c139d6e 34{
b2e465d6
AL
35 delLocalPolicy = 0;
36 LocalPolicy = Plcy;
37 if (LocalPolicy == 0)
38 delLocalPolicy = LocalPolicy = new Policy;
6c139d6e
AL
39}
40 /*}}}*/
41// DepCache::~pkgDepCache - Destructor /*{{{*/
42// ---------------------------------------------------------------------
43/* */
44pkgDepCache::~pkgDepCache()
45{
46 delete [] PkgState;
47 delete [] DepState;
b2e465d6 48 delete delLocalPolicy;
6c139d6e
AL
49}
50 /*}}}*/
6c139d6e
AL
51// DepCache::Init - Generate the initial extra structures. /*{{{*/
52// ---------------------------------------------------------------------
53/* This allocats the extension buffers and initializes them. */
a246f2dc 54bool pkgDepCache::Init(OpProgress *Prog)
6c139d6e
AL
55{
56 delete [] PkgState;
57 delete [] DepState;
58 PkgState = new StateCache[Head().PackageCount];
59 DepState = new unsigned char[Head().DependsCount];
60 memset(PkgState,0,sizeof(*PkgState)*Head().PackageCount);
61 memset(DepState,0,sizeof(*DepState)*Head().DependsCount);
b2e465d6 62
a246f2dc
AL
63 if (Prog != 0)
64 {
65 Prog->OverallProgress(0,2*Head().PackageCount,Head().PackageCount,
db0db9fe
CP
66 _("Building dependency tree"));
67 Prog->SubProgress(Head().PackageCount,_("Candidate versions"));
a246f2dc
AL
68 }
69
6c139d6e
AL
70 /* Set the current state of everything. In this state all of the
71 packages are kept exactly as is. See AllUpgrade */
a246f2dc
AL
72 int Done = 0;
73 for (PkgIterator I = PkgBegin(); I.end() != true; I++,Done++)
6c139d6e 74 {
a246f2dc
AL
75 if (Prog != 0)
76 Prog->Progress(Done);
77
6c139d6e
AL
78 // Find the proper cache slot
79 StateCache &State = PkgState[I->ID];
80 State.iFlags = 0;
0a57c0f0 81 State.InstallReason = Manual;
afb1e2e3 82
6c139d6e
AL
83 // Figure out the install version
84 State.CandidateVer = GetCandidateVer(I);
85 State.InstallVer = I.CurrentVer();
86 State.Mode = ModeKeep;
87
88 State.Update(I,*this);
89 }
90
a246f2dc
AL
91 if (Prog != 0)
92 {
93
94 Prog->OverallProgress(Head().PackageCount,2*Head().PackageCount,
95 Head().PackageCount,
db0db9fe
CP
96 _("Building dependency tree"));
97 Prog->SubProgress(Head().PackageCount,_("Dependency generation"));
a246f2dc
AL
98 }
99
100 Update(Prog);
e004867d
MV
101
102 if(Prog != 0)
103 Prog->Done();
6c139d6e
AL
104
105 return true;
106}
107 /*}}}*/
6c139d6e 108
a83d884d
MV
109bool pkgDepCache::readStateFile(OpProgress *Prog)
110{
111 FileFd state_file;
112 string state = _config->FindDir("Dir::State") + "pkgstates";
113 if(FileExists(state)) {
114 state_file.Open(state, FileFd::ReadOnly);
115 int file_size = state_file.Size();
116 Prog->OverallProgress(0, file_size, 1,
0a57c0f0 117 _("Reading state information"));
a83d884d
MV
118
119 pkgTagFile tagfile(&state_file);
120 pkgTagSection section;
121 int amt=0;
122 while(tagfile.Step(section)) {
123 string pkgname = section.FindS("Package");
124 pkgCache::PkgIterator pkg=Cache->FindPkg(pkgname);
125 // Silently ignore unknown packages and packages with no actual
126 // version.
127 if(!pkg.end() && !pkg.VersionList().end()) {
0a57c0f0
MV
128 short reason = section.FindI("Install-Reason",pkgDepCache::Manual);
129 PkgState[pkg->ID].InstallReason = (ChangedReason)reason;
130 if(_config->FindB("Debug::pkgAutoRemove",false))
131 std::cout << "Install-Reason for: " << pkgname
132 << " is " << reason << std::endl;
a83d884d
MV
133 amt+=section.size();
134 Prog->OverallProgress(amt, file_size, 1,
0a57c0f0 135 _("Reading state information"));
a83d884d
MV
136 }
137 Prog->OverallProgress(file_size, file_size, 1,
0a57c0f0 138 _("Reading state information"));
a83d884d
MV
139 }
140 }
141
142 return true;
143}
144
145bool pkgDepCache::writeStateFile(OpProgress *prog)
146{
a83d884d
MV
147 FileFd StateFile;
148 string state = _config->FindDir("Dir::State") + "pkgstates";
149
150 if(!StateFile.Open(state, FileFd::WriteEmpty))
151 return _error->Error(_("Failed to write StateFile %s"),
152 state.c_str());
153
154 std::ostringstream ostr;
155 for(pkgCache::PkgIterator pkg=Cache->PkgBegin(); !pkg.end();pkg++) {
80fa0d8a
MV
156
157 // clear out no longer installed pkg
158 if(PkgState[pkg->ID].Delete() || pkg.CurrentVer() == NULL)
0a57c0f0 159 PkgState[pkg->ID].InstallReason = Manual;
80fa0d8a
MV
160
161 // check if we have new information
162 if(PkgState[pkg->ID].Flags & pkgCache::Flag::Auto) {
120365ce
MV
163 if(_config->FindI("Debug::pkgAutoRemove",false))
164 std::clog << "pkg: " << pkg.Name() << " is auto-dep" << std::endl;
0a57c0f0 165 PkgState[pkg->ID].InstallReason = Libapt;
80fa0d8a
MV
166 }
167
0a57c0f0 168 if(PkgState[pkg->ID].InstallReason != Manual) {
a83d884d 169 ostr.str(string(""));
0a57c0f0
MV
170 ostr << "Package: " << pkg.Name()
171 << "\nInstall-Reason: "
172 << (int)(PkgState[pkg->ID].InstallReason) << "\n\n";
a83d884d 173 StateFile.Write(ostr.str().c_str(), ostr.str().size());
a83d884d
MV
174 }
175 }
176 return true;
177}
178
6c139d6e
AL
179// DepCache::CheckDep - Checks a single dependency /*{{{*/
180// ---------------------------------------------------------------------
181/* This first checks the dependency against the main target package and
182 then walks along the package provides list and checks if each provides
183 will be installed then checks the provides against the dep. Res will be
184 set to the package which was used to satisfy the dep. */
185bool pkgDepCache::CheckDep(DepIterator Dep,int Type,PkgIterator &Res)
186{
187 Res = Dep.TargetPkg();
188
189 /* Check simple depends. A depends -should- never self match but
190 we allow it anyhow because dpkg does. Technically it is a packaging
191 bug. Conflicts may never self match */
b2e465d6
AL
192 if (Dep.TargetPkg() != Dep.ParentPkg() ||
193 (Dep->Type != Dep::Conflicts && Dep->Type != Dep::Obsoletes))
6c139d6e
AL
194 {
195 PkgIterator Pkg = Dep.TargetPkg();
196 // Check the base package
197 if (Type == NowVersion && Pkg->CurrentVer != 0)
b2e465d6
AL
198 if (VS().CheckDep(Pkg.CurrentVer().VerStr(),Dep->CompareOp,
199 Dep.TargetVer()) == true)
6c139d6e
AL
200 return true;
201
202 if (Type == InstallVersion && PkgState[Pkg->ID].InstallVer != 0)
b2e465d6
AL
203 if (VS().CheckDep(PkgState[Pkg->ID].InstVerIter(*this).VerStr(),
204 Dep->CompareOp,Dep.TargetVer()) == true)
6c139d6e
AL
205 return true;
206
207 if (Type == CandidateVersion && PkgState[Pkg->ID].CandidateVer != 0)
b2e465d6
AL
208 if (VS().CheckDep(PkgState[Pkg->ID].CandidateVerIter(*this).VerStr(),
209 Dep->CompareOp,Dep.TargetVer()) == true)
6c139d6e
AL
210 return true;
211 }
212
b2e465d6
AL
213 if (Dep->Type == Dep::Obsoletes)
214 return false;
215
6c139d6e
AL
216 // Check the providing packages
217 PrvIterator P = Dep.TargetPkg().ProvidesList();
218 PkgIterator Pkg = Dep.ParentPkg();
219 for (; P.end() != true; P++)
220 {
221 /* Provides may never be applied against the same package if it is
222 a conflicts. See the comment above. */
223 if (P.OwnerPkg() == Pkg && Dep->Type == Dep::Conflicts)
224 continue;
225
226 // Check if the provides is a hit
227 if (Type == NowVersion)
228 {
229 if (P.OwnerPkg().CurrentVer() != P.OwnerVer())
230 continue;
231 }
232
233 if (Type == InstallVersion)
234 {
235 StateCache &State = PkgState[P.OwnerPkg()->ID];
236 if (State.InstallVer != (Version *)P.OwnerVer())
237 continue;
238 }
239
240 if (Type == CandidateVersion)
241 {
242 StateCache &State = PkgState[P.OwnerPkg()->ID];
243 if (State.CandidateVer != (Version *)P.OwnerVer())
244 continue;
245 }
246
247 // Compare the versions.
b2e465d6 248 if (VS().CheckDep(P.ProvideVersion(),Dep->CompareOp,Dep.TargetVer()) == true)
6c139d6e
AL
249 {
250 Res = P.OwnerPkg();
251 return true;
252 }
253 }
254
255 return false;
256}
257 /*}}}*/
258// DepCache::AddSizes - Add the packages sizes to the counters /*{{{*/
259// ---------------------------------------------------------------------
260/* Call with Mult = -1 to preform the inverse opration */
b2e465d6 261void pkgDepCache::AddSizes(const PkgIterator &Pkg,signed long Mult)
6c139d6e
AL
262{
263 StateCache &P = PkgState[Pkg->ID];
264
e7b470ee
AL
265 if (Pkg->VersionList == 0)
266 return;
267
e5a1f2ff
AL
268 if (Pkg.State() == pkgCache::PkgIterator::NeedsConfigure &&
269 P.Keep() == true)
2cca3bd9 270 return;
2cca3bd9 271
6c139d6e
AL
272 // Compute the size data
273 if (P.NewInstall() == true)
274 {
b2e465d6
AL
275 iUsrSize += (signed)(Mult*P.InstVerIter(*this)->InstalledSize);
276 iDownloadSize += (signed)(Mult*P.InstVerIter(*this)->Size);
d38b7b3d 277 return;
6c139d6e
AL
278 }
279
280 // Upgrading
d0c59649
AL
281 if (Pkg->CurrentVer != 0 &&
282 (P.InstallVer != (Version *)Pkg.CurrentVer() ||
283 (P.iFlags & ReInstall) == ReInstall) && P.InstallVer != 0)
6c139d6e 284 {
b2e465d6
AL
285 iUsrSize += (signed)(Mult*((signed)P.InstVerIter(*this)->InstalledSize -
286 (signed)Pkg.CurrentVer()->InstalledSize));
287 iDownloadSize += (signed)(Mult*P.InstVerIter(*this)->Size);
d38b7b3d
AL
288 return;
289 }
290
291 // Reinstall
2cca3bd9
AL
292 if (Pkg.State() == pkgCache::PkgIterator::NeedsUnpack &&
293 P.Delete() == false)
d38b7b3d 294 {
b2e465d6 295 iDownloadSize += (signed)(Mult*P.InstVerIter(*this)->Size);
d38b7b3d 296 return;
6c139d6e
AL
297 }
298
299 // Removing
300 if (Pkg->CurrentVer != 0 && P.InstallVer == 0)
d38b7b3d 301 {
b2e465d6 302 iUsrSize -= (signed)(Mult*Pkg.CurrentVer()->InstalledSize);
d38b7b3d
AL
303 return;
304 }
6c139d6e
AL
305}
306 /*}}}*/
307// DepCache::AddStates - Add the package to the state counter /*{{{*/
308// ---------------------------------------------------------------------
309/* This routine is tricky to use, you must make sure that it is never
310 called twice for the same package. This means the Remove/Add section
311 should be as short as possible and not encompass any code that will
312 calld Remove/Add itself. Remember, dependencies can be circular so
313 while processing a dep for Pkg it is possible that Add/Remove
314 will be called on Pkg */
315void pkgDepCache::AddStates(const PkgIterator &Pkg,int Add)
316{
317 StateCache &State = PkgState[Pkg->ID];
318
319 // The Package is broken
320 if ((State.DepState & DepInstMin) != DepInstMin)
321 iBrokenCount += Add;
322
323 // Bad state
324 if (Pkg.State() != PkgIterator::NeedsNothing)
325 iBadCount += Add;
326
327 // Not installed
328 if (Pkg->CurrentVer == 0)
329 {
d556d1a1
AL
330 if (State.Mode == ModeDelete &&
331 (State.iFlags | Purge) == Purge && Pkg.Purge() == false)
332 iDelCount += Add;
333
6c139d6e
AL
334 if (State.Mode == ModeInstall)
335 iInstCount += Add;
336 return;
337 }
338
339 // Installed, no upgrade
6321777b 340 if (State.Status == 0)
d0c59649 341 {
6c139d6e
AL
342 if (State.Mode == ModeDelete)
343 iDelCount += Add;
d0c59649
AL
344 else
345 if ((State.iFlags & ReInstall) == ReInstall)
346 iInstCount += Add;
347
6c139d6e
AL
348 return;
349 }
350
351 // Alll 3 are possible
352 if (State.Mode == ModeDelete)
353 iDelCount += Add;
354 if (State.Mode == ModeKeep)
355 iKeepCount += Add;
356 if (State.Mode == ModeInstall)
357 iInstCount += Add;
358}
359 /*}}}*/
360// DepCache::BuildGroupOrs - Generate the Or group dep data /*{{{*/
361// ---------------------------------------------------------------------
362/* The or group results are stored in the last item of the or group. This
363 allows easy detection of the state of a whole or'd group. */
364void pkgDepCache::BuildGroupOrs(VerIterator const &V)
365{
366 unsigned char Group = 0;
367
368 for (DepIterator D = V.DependsList(); D.end() != true; D++)
369 {
370 // Build the dependency state.
371 unsigned char &State = DepState[D->ID];
372
373 /* Invert for Conflicts. We have to do this twice to get the
374 right sense for a conflicts group */
b2e465d6 375 if (D->Type == Dep::Conflicts || D->Type == Dep::Obsoletes)
6c139d6e
AL
376 State = ~State;
377
378 // Add to the group if we are within an or..
d2685fd6 379 State &= 0x7;
6c139d6e
AL
380 Group |= State;
381 State |= Group << 3;
382 if ((D->CompareOp & Dep::Or) != Dep::Or)
383 Group = 0;
384
385 // Invert for Conflicts
b2e465d6 386 if (D->Type == Dep::Conflicts || D->Type == Dep::Obsoletes)
6c139d6e
AL
387 State = ~State;
388 }
389}
390 /*}}}*/
391// DepCache::VersionState - Perform a pass over a dependency list /*{{{*/
392// ---------------------------------------------------------------------
393/* This is used to run over a dependency list and determine the dep
394 state of the list, filtering it through both a Min check and a Policy
395 check. The return result will have SetMin/SetPolicy low if a check
396 fails. It uses the DepState cache for it's computations. */
397unsigned char pkgDepCache::VersionState(DepIterator D,unsigned char Check,
398 unsigned char SetMin,
399 unsigned char SetPolicy)
400{
401 unsigned char Dep = 0xFF;
402
403 while (D.end() != true)
404 {
405 // Compute a single dependency element (glob or)
406 DepIterator Start = D;
407 unsigned char State = 0;
408 for (bool LastOR = true; D.end() == false && LastOR == true; D++)
409 {
410 State |= DepState[D->ID];
411 LastOR = (D->CompareOp & Dep::Or) == Dep::Or;
412 }
413
414 // Minimum deps that must be satisfied to have a working package
415 if (Start.IsCritical() == true)
416 if ((State & Check) != Check)
417 Dep &= ~SetMin;
418
419 // Policy deps that must be satisfied to install the package
420 if (IsImportantDep(Start) == true &&
421 (State & Check) != Check)
422 Dep &= ~SetPolicy;
423 }
424
425 return Dep;
426}
427 /*}}}*/
428// DepCache::DependencyState - Compute the 3 results for a dep /*{{{*/
429// ---------------------------------------------------------------------
430/* This is the main dependency computation bit. It computes the 3 main
431 results for a dependencys, Now, Install and Candidate. Callers must
432 invert the result if dealing with conflicts. */
433unsigned char pkgDepCache::DependencyState(DepIterator &D)
434{
435 unsigned char State = 0;
436
437 if (CheckDep(D,NowVersion) == true)
438 State |= DepNow;
439 if (CheckDep(D,InstallVersion) == true)
440 State |= DepInstall;
441 if (CheckDep(D,CandidateVersion) == true)
442 State |= DepCVer;
443
444 return State;
445}
446 /*}}}*/
447// DepCache::UpdateVerState - Compute the Dep member of the state /*{{{*/
448// ---------------------------------------------------------------------
449/* This determines the combined dependency representation of a package
450 for its two states now and install. This is done by using the pre-generated
451 dependency information. */
452void pkgDepCache::UpdateVerState(PkgIterator Pkg)
453{
454 // Empty deps are always true
455 StateCache &State = PkgState[Pkg->ID];
456 State.DepState = 0xFF;
457
458 // Check the Current state
459 if (Pkg->CurrentVer != 0)
460 {
461 DepIterator D = Pkg.CurrentVer().DependsList();
462 State.DepState &= VersionState(D,DepNow,DepNowMin,DepNowPolicy);
463 }
464
465 /* Check the candidate state. We do not compare against the whole as
466 a candidate state but check the candidate version against the
467 install states */
468 if (State.CandidateVer != 0)
469 {
470 DepIterator D = State.CandidateVerIter(*this).DependsList();
471 State.DepState &= VersionState(D,DepInstall,DepCandMin,DepCandPolicy);
472 }
473
474 // Check target state which can only be current or installed
475 if (State.InstallVer != 0)
476 {
477 DepIterator D = State.InstVerIter(*this).DependsList();
478 State.DepState &= VersionState(D,DepInstall,DepInstMin,DepInstPolicy);
479 }
480}
481 /*}}}*/
482// DepCache::Update - Figure out all the state information /*{{{*/
483// ---------------------------------------------------------------------
484/* This will figure out the state of all the packages and all the
485 dependencies based on the current policy. */
a246f2dc 486void pkgDepCache::Update(OpProgress *Prog)
6c139d6e
AL
487{
488 iUsrSize = 0;
489 iDownloadSize = 0;
490 iDelCount = 0;
491 iInstCount = 0;
492 iKeepCount = 0;
493 iBrokenCount = 0;
494 iBadCount = 0;
495
496 // Perform the depends pass
a246f2dc
AL
497 int Done = 0;
498 for (PkgIterator I = PkgBegin(); I.end() != true; I++,Done++)
6c139d6e 499 {
a246f2dc
AL
500 if (Prog != 0 && Done%20 == 0)
501 Prog->Progress(Done);
6c139d6e
AL
502 for (VerIterator V = I.VersionList(); V.end() != true; V++)
503 {
504 unsigned char Group = 0;
505
506 for (DepIterator D = V.DependsList(); D.end() != true; D++)
507 {
508 // Build the dependency state.
509 unsigned char &State = DepState[D->ID];
b2e465d6 510 State = DependencyState(D);
6c139d6e
AL
511
512 // Add to the group if we are within an or..
513 Group |= State;
514 State |= Group << 3;
515 if ((D->CompareOp & Dep::Or) != Dep::Or)
516 Group = 0;
517
518 // Invert for Conflicts
b2e465d6 519 if (D->Type == Dep::Conflicts || D->Type == Dep::Obsoletes)
6c139d6e
AL
520 State = ~State;
521 }
522 }
523
524 // Compute the pacakge dependency state and size additions
525 AddSizes(I);
526 UpdateVerState(I);
527 AddStates(I);
528 }
a246f2dc 529
a83d884d 530 readStateFile(Prog);
afb1e2e3 531
a246f2dc
AL
532 if (Prog != 0)
533 Prog->Progress(Done);
6c139d6e
AL
534}
535 /*}}}*/
536// DepCache::Update - Update the deps list of a package /*{{{*/
537// ---------------------------------------------------------------------
538/* This is a helper for update that only does the dep portion of the scan.
539 It is mainly ment to scan reverse dependencies. */
540void pkgDepCache::Update(DepIterator D)
541{
542 // Update the reverse deps
543 for (;D.end() != true; D++)
544 {
545 unsigned char &State = DepState[D->ID];
546 State = DependencyState(D);
547
548 // Invert for Conflicts
b2e465d6 549 if (D->Type == Dep::Conflicts || D->Type == Dep::Obsoletes)
6c139d6e 550 State = ~State;
b2e465d6 551
6c139d6e
AL
552 RemoveStates(D.ParentPkg());
553 BuildGroupOrs(D.ParentVer());
554 UpdateVerState(D.ParentPkg());
555 AddStates(D.ParentPkg());
556 }
557}
558 /*}}}*/
559// DepCache::Update - Update the related deps of a package /*{{{*/
560// ---------------------------------------------------------------------
561/* This is called whenever the state of a package changes. It updates
562 all cached dependencies related to this package. */
563void pkgDepCache::Update(PkgIterator const &Pkg)
b2e465d6 564{
6c139d6e
AL
565 // Recompute the dep of the package
566 RemoveStates(Pkg);
567 UpdateVerState(Pkg);
568 AddStates(Pkg);
569
570 // Update the reverse deps
571 Update(Pkg.RevDependsList());
572
573 // Update the provides map for the current ver
574 if (Pkg->CurrentVer != 0)
575 for (PrvIterator P = Pkg.CurrentVer().ProvidesList();
576 P.end() != true; P++)
577 Update(P.ParentPkg().RevDependsList());
578
579 // Update the provides map for the candidate ver
9972233d
AL
580 if (PkgState[Pkg->ID].CandidateVer != 0)
581 for (PrvIterator P = PkgState[Pkg->ID].CandidateVerIter(*this).ProvidesList();
582 P.end() != true; P++)
583 Update(P.ParentPkg().RevDependsList());
6c139d6e
AL
584}
585
586 /*}}}*/
587
588// DepCache::MarkKeep - Put the package in the keep state /*{{{*/
589// ---------------------------------------------------------------------
590/* */
591void pkgDepCache::MarkKeep(PkgIterator const &Pkg,bool Soft)
592{
593 // Simplifies other routines.
594 if (Pkg.end() == true)
595 return;
813c8eea
AL
596
597 /* Reject an attempt to keep a non-source broken installed package, those
598 must be upgraded */
599 if (Pkg.State() == PkgIterator::NeedsUnpack &&
600 Pkg.CurrentVer().Downloadable() == false)
601 return;
6c139d6e
AL
602
603 /* We changed the soft state all the time so the UI is a bit nicer
604 to use */
605 StateCache &P = PkgState[Pkg->ID];
606 if (Soft == true)
607 P.iFlags |= AutoKept;
608 else
609 P.iFlags &= ~AutoKept;
610
611 // Check that it is not already kept
612 if (P.Mode == ModeKeep)
613 return;
614
615 // We dont even try to keep virtual packages..
616 if (Pkg->VersionList == 0)
617 return;
618
619 P.Flags &= ~Flag::Auto;
620 RemoveSizes(Pkg);
621 RemoveStates(Pkg);
622
623 P.Mode = ModeKeep;
624 if (Pkg->CurrentVer == 0)
625 P.InstallVer = 0;
626 else
627 P.InstallVer = Pkg.CurrentVer();
628
629 AddStates(Pkg);
630
631 Update(Pkg);
632
633 AddSizes(Pkg);
634}
635 /*}}}*/
636// DepCache::MarkDelete - Put the package in the delete state /*{{{*/
637// ---------------------------------------------------------------------
638/* */
d556d1a1 639void pkgDepCache::MarkDelete(PkgIterator const &Pkg, bool rPurge)
6c139d6e
AL
640{
641 // Simplifies other routines.
642 if (Pkg.end() == true)
643 return;
644
645 // Check that it is not already marked for delete
646 StateCache &P = PkgState[Pkg->ID];
d556d1a1
AL
647 P.iFlags &= ~(AutoKept | Purge);
648 if (rPurge == true)
649 P.iFlags |= Purge;
650
651 if ((P.Mode == ModeDelete || P.InstallVer == 0) &&
652 (Pkg.Purge() == true || rPurge == false))
6c139d6e 653 return;
d556d1a1 654
6c139d6e
AL
655 // We dont even try to delete virtual packages..
656 if (Pkg->VersionList == 0)
657 return;
658
659 RemoveSizes(Pkg);
660 RemoveStates(Pkg);
661
d556d1a1 662 if (Pkg->CurrentVer == 0 && (Pkg.Purge() == true || rPurge == false))
3d615484
AL
663 P.Mode = ModeKeep;
664 else
665 P.Mode = ModeDelete;
6c139d6e 666 P.InstallVer = 0;
afb1e2e3
MV
667 // This was not inverted before, but I think it should be
668 P.Flags &= ~Flag::Auto;
6c139d6e
AL
669
670 AddStates(Pkg);
671 Update(Pkg);
672 AddSizes(Pkg);
673}
674 /*}}}*/
675// DepCache::MarkInstall - Put the package in the install state /*{{{*/
676// ---------------------------------------------------------------------
677/* */
b2e465d6
AL
678void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
679 unsigned long Depth)
680{
681 if (Depth > 100)
682 return;
683
6c139d6e
AL
684 // Simplifies other routines.
685 if (Pkg.end() == true)
686 return;
687
688 /* Check that it is not already marked for install and that it can be
689 installed */
690 StateCache &P = PkgState[Pkg->ID];
691 P.iFlags &= ~AutoKept;
692 if (P.InstBroken() == false && (P.Mode == ModeInstall ||
693 P.CandidateVer == (Version *)Pkg.CurrentVer()))
694 {
695 if (P.CandidateVer == (Version *)Pkg.CurrentVer() && P.InstallVer == 0)
696 MarkKeep(Pkg);
697 return;
698 }
b2e465d6
AL
699
700 // See if there is even any possible instalation candidate
701 if (P.CandidateVer == 0)
702 return;
6c139d6e
AL
703
704 // We dont even try to install virtual packages..
705 if (Pkg->VersionList == 0)
706 return;
707
708 /* Target the candidate version and remove the autoflag. We reset the
709 autoflag below if this was called recursively. Otherwise the user
710 should have the ability to de-auto a package by changing its state */
711 RemoveSizes(Pkg);
712 RemoveStates(Pkg);
713
714 P.Mode = ModeInstall;
715 P.InstallVer = P.CandidateVer;
716 P.Flags &= ~Flag::Auto;
717 if (P.CandidateVer == (Version *)Pkg.CurrentVer())
718 P.Mode = ModeKeep;
719
720 AddStates(Pkg);
721 Update(Pkg);
722 AddSizes(Pkg);
723
724 if (AutoInst == false)
725 return;
726
727 DepIterator Dep = P.InstVerIter(*this).DependsList();
728 for (; Dep.end() != true;)
729 {
730 // Grok or groups
731 DepIterator Start = Dep;
732 bool Result = true;
b2e465d6
AL
733 unsigned Ors = 0;
734 for (bool LastOR = true; Dep.end() == false && LastOR == true; Dep++,Ors++)
6c139d6e
AL
735 {
736 LastOR = (Dep->CompareOp & Dep::Or) == Dep::Or;
737
738 if ((DepState[Dep->ID] & DepInstall) == DepInstall)
739 Result = false;
740 }
741
742 // Dep is satisfied okay.
743 if (Result == false)
744 continue;
745
746 /* Check if this dep should be consider for install. If it is a user
747 defined important dep and we are installed a new package then
748 it will be installed. Otherwise we only worry about critical deps */
749 if (IsImportantDep(Start) == false)
750 continue;
751 if (Pkg->CurrentVer != 0 && Start.IsCritical() == false)
752 continue;
b2e465d6
AL
753
754 /* If we are in an or group locate the first or that can
755 succeed. We have already cached this.. */
756 for (; Ors > 1 && (DepState[Start->ID] & DepCVer) != DepCVer; Ors--)
757 Start++;
2ed9b455 758
b2e465d6
AL
759 /* This bit is for processing the possibilty of an install/upgrade
760 fixing the problem */
761 SPtrArray<Version *> List = Start.AllTargets();
6c139d6e
AL
762 if ((DepState[Start->ID] & DepCVer) == DepCVer)
763 {
b2e465d6
AL
764 // Right, find the best version to install..
765 Version **Cur = List;
766 PkgIterator P = Start.TargetPkg();
767 PkgIterator InstPkg(*Cache,0);
6c139d6e 768
b2e465d6
AL
769 // See if there are direct matches (at the start of the list)
770 for (; *Cur != 0 && (*Cur)->ParentPkg == P.Index(); Cur++)
771 {
772 PkgIterator Pkg(*Cache,Cache->PkgP + (*Cur)->ParentPkg);
773 if (PkgState[Pkg->ID].CandidateVer != *Cur)
774 continue;
775 InstPkg = Pkg;
776 break;
777 }
778
779 // Select the highest priority providing package
2ed9b455 780 if (InstPkg.end() == true)
b2e465d6
AL
781 {
782 pkgPrioSortList(*Cache,Cur);
783 for (; *Cur != 0; Cur++)
784 {
785 PkgIterator Pkg(*Cache,Cache->PkgP + (*Cur)->ParentPkg);
786 if (PkgState[Pkg->ID].CandidateVer != *Cur)
787 continue;
788 InstPkg = Pkg;
789 break;
790 }
791 }
792
793 if (InstPkg.end() == false)
794 {
795 MarkInstall(InstPkg,true,Depth + 1);
6c139d6e 796
b2e465d6
AL
797 // Set the autoflag, after MarkInstall because MarkInstall unsets it
798 if (P->CurrentVer == 0)
799 PkgState[InstPkg->ID].Flags |= Flag::Auto;
800 }
801
6c139d6e
AL
802 continue;
803 }
804
b2e465d6
AL
805 /* For conflicts we just de-install the package and mark as auto,
806 Conflicts may not have or groups */
807 if (Start->Type == Dep::Conflicts || Start->Type == Dep::Obsoletes)
6c139d6e 808 {
6c139d6e
AL
809 for (Version **I = List; *I != 0; I++)
810 {
811 VerIterator Ver(*this,*I);
812 PkgIterator Pkg = Ver.ParentPkg();
813
814 MarkDelete(Pkg);
815 PkgState[Pkg->ID].Flags |= Flag::Auto;
816 }
6c139d6e
AL
817 continue;
818 }
819 }
820}
821 /*}}}*/
d0c59649
AL
822// DepCache::SetReInstall - Set the reinstallation flag /*{{{*/
823// ---------------------------------------------------------------------
824/* */
825void pkgDepCache::SetReInstall(PkgIterator const &Pkg,bool To)
826{
827 RemoveSizes(Pkg);
828 RemoveStates(Pkg);
829
830 StateCache &P = PkgState[Pkg->ID];
831 if (To == true)
832 P.iFlags |= ReInstall;
833 else
834 P.iFlags &= ~ReInstall;
835
836 AddStates(Pkg);
837 AddSizes(Pkg);
838}
839 /*}}}*/
b2e465d6
AL
840// DepCache::SetCandidateVersion - Change the candidate version /*{{{*/
841// ---------------------------------------------------------------------
842/* */
843void pkgDepCache::SetCandidateVersion(VerIterator TargetVer)
844{
845 pkgCache::PkgIterator Pkg = TargetVer.ParentPkg();
846 StateCache &P = PkgState[Pkg->ID];
847
848 RemoveSizes(Pkg);
849 RemoveStates(Pkg);
850
851 if (P.CandidateVer == P.InstallVer)
852 P.InstallVer = (Version *)TargetVer;
853 P.CandidateVer = (Version *)TargetVer;
854 P.Update(Pkg,*this);
855
856 AddStates(Pkg);
857 Update(Pkg);
858 AddSizes(Pkg);
859}
860 /*}}}*/
6c139d6e
AL
861// StateCache::Update - Compute the various static display things /*{{{*/
862// ---------------------------------------------------------------------
863/* This is called whenever the Candidate version changes. */
864void pkgDepCache::StateCache::Update(PkgIterator Pkg,pkgCache &Cache)
865{
866 // Some info
867 VerIterator Ver = CandidateVerIter(Cache);
868
869 // Use a null string or the version string
870 if (Ver.end() == true)
871 CandVersion = "";
872 else
873 CandVersion = Ver.VerStr();
874
875 // Find the current version
876 CurVersion = "";
877 if (Pkg->CurrentVer != 0)
878 CurVersion = Pkg.CurrentVer().VerStr();
879
880 // Strip off the epochs for display
881 CurVersion = StripEpoch(CurVersion);
882 CandVersion = StripEpoch(CandVersion);
883
884 // Figure out if its up or down or equal
885 Status = Ver.CompareVer(Pkg.CurrentVer());
886 if (Pkg->CurrentVer == 0 || Pkg->VersionList == 0 || CandidateVer == 0)
887 Status = 2;
888}
889 /*}}}*/
890// StateCache::StripEpoch - Remove the epoch specifier from the version /*{{{*/
891// ---------------------------------------------------------------------
892/* */
893const char *pkgDepCache::StateCache::StripEpoch(const char *Ver)
894{
895 if (Ver == 0)
896 return 0;
897
898 // Strip any epoch
899 for (const char *I = Ver; *I != 0; I++)
900 if (*I == ':')
901 return I + 1;
902 return Ver;
903}
904 /*}}}*/
b2e465d6
AL
905
906// Policy::GetCandidateVer - Returns the Candidate install version /*{{{*/
6321777b 907// ---------------------------------------------------------------------
b2e465d6
AL
908/* The default just returns the highest available version that is not
909 a source and automatic. */
910pkgCache::VerIterator pkgDepCache::Policy::GetCandidateVer(PkgIterator Pkg)
6321777b 911{
b2e465d6
AL
912 /* Not source/not automatic versions cannot be a candidate version
913 unless they are already installed */
914 VerIterator Last(*(pkgCache *)this,0);
6321777b 915
b2e465d6
AL
916 for (VerIterator I = Pkg.VersionList(); I.end() == false; I++)
917 {
918 if (Pkg.CurrentVer() == I)
919 return I;
920
921 for (VerFileIterator J = I.FileList(); J.end() == false; J++)
922 {
923 if ((J.File()->Flags & Flag::NotSource) != 0)
924 continue;
925
926 /* Stash the highest version of a not-automatic source, we use it
927 if there is nothing better */
928 if ((J.File()->Flags & Flag::NotAutomatic) != 0)
929 {
930 if (Last.end() == true)
931 Last = I;
932 continue;
933 }
934
935 return I;
936 }
937 }
6321777b 938
b2e465d6
AL
939 return Last;
940}
941 /*}}}*/
942// Policy::IsImportantDep - True if the dependency is important /*{{{*/
943// ---------------------------------------------------------------------
944/* */
945bool pkgDepCache::Policy::IsImportantDep(DepIterator Dep)
946{
947 return Dep.IsCritical();
6321777b
AL
948}
949 /*}}}*/