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