libzypp 17.31.1
SelectableImpl.cc
Go to the documentation of this file.
1/*---------------------------------------------------------------------\
2| ____ _ __ __ ___ |
3| |__ / \ / / . \ . \ |
4| / / \ V /| _/ _/ |
5| / /__ | | | | | | |
6| /_____||_| |_| |_| |
7| |
8\---------------------------------------------------------------------*/
12#include <iostream>
13//#include <zypp/base/Logger.h>
14
16
17using std::endl;
18
20namespace zypp
21{
23 namespace ui
24 {
25
30 {
31 public:
33
34 public:
36 ResStatus & backup( ResStatus & status_r )
37 {
38 _backup.push_back( status_r );
39 return status_r;
40 }
42 ResStatus & backup( const PoolItem & pi_r )
43 { return backup( pi_r.status() ); }
44
47 { return backup( status_r ); }
49 ResStatus & operator()( const PoolItem & pi_r )
50 { return backup( pi_r.status() ); }
51
53 bool restore()
54 {
55 for_( rit, _backup.rbegin(), _backup.rend() )
56 rit->replay();
57 return false; // restore is done on error - return restore();
58 }
59
60 public:
62 bool setTransact( const PoolItem & pi_r, bool yesno_r, Causer causer_r )
63 { return backup( pi_r ).setTransact( yesno_r, causer_r ); }
64
66 bool setLock( const PoolItem & pi_r, bool yesno_r, Causer causer_r )
67 { return backup( pi_r ).setLock( yesno_r, causer_r ); }
68
70 bool setTransactTrue( const PoolItem & pi_r, Causer causer_r )
71 { return setTransact( pi_r, true, causer_r ); }
72
74 bool setTransactFalse( const PoolItem & pi_r, Causer causer_r )
75 { return setTransact( pi_r, false, causer_r ); }
76
77 public:
79 bool transact( const PoolItem & pi_r, Causer causer_r )
80 {
81 ResStatus & status( backup( pi_r ) );
82 if ( ! status.setLock( false, causer_r ) ) return false;
83 if ( ! status.setTransact( true, causer_r ) ) return false;
84 return true;
85 }
86
88 bool lock( const PoolItem & pi_r, Causer causer_r )
89 {
90 ResStatus & status( backup( pi_r ) );
91 if ( ! status.setTransact( false, causer_r ) ) return false;
92 if ( ! status.setLock( true, causer_r ) ) return false;
93 return true;
94 }
95
97 bool unlock( const PoolItem & pi_r, Causer causer_r )
98 {
99 ResStatus & status( backup( pi_r ) );
100 if ( ! status.setTransact( false, causer_r ) ) return false;
101 if ( ! status.setLock( false, causer_r ) ) return false;
102 return true;
103 }
104
106 bool unsetNonMultiTransact( const PoolItem & pi_r, Causer causer_r )
107 {
108 ResStatus & status( backup( pi_r ) );
109 if ( status.transacts() && ! pi_r.multiversionInstall() )
110 {
111 if ( ! status.setTransact( false, causer_r ) ) return false;
112 }
113 return true;
114 }
115
117 bool unsetMultiTransact( const PoolItem & pi_r, Causer causer_r )
118 {
119 ResStatus & status( backup( pi_r ) );
120 if ( status.transacts() && pi_r.multiversionInstall() )
121 {
122 if ( ! status.setTransact( false, causer_r ) ) return false;
123 }
124 return true;
125 }
126
128 typedef bool (StatusBackup::*Action)( const PoolItem &, Causer );
129
131 template <class TIter>
132 bool forEach( TIter begin_r, TIter end_r, Action action_r, Causer causer_r )
133 {
134 for_( it, begin_r, end_r )
135 if ( ! (this->*action_r)( *it, causer_r ) )
136 return false;
137 return true;
138 }
139
140 private:
141 std::vector<resstatus::StatusBackup> _backup;
142 };
143
145 //
146 // CLASS NAME : StatusHelper
147 //
151 {
153 : _impl( impl )
154 , inst( impl.installedObj() )
155 , cand( impl.candidateObj() )
156 , causer( causer_r )
157 {}
158
160
161 //
162 // Queries
163 //
164 bool hasInstalled() const
165 { return bool(inst); }
166
167 bool hasCandidate() const
168 { return bool(cand); }
169
170 bool hasInstalledOnly() const
171 { return inst && !cand; }
172
173 bool hasCandidateOnly() const
174 { return cand && !inst; }
175
176 bool hasBoth() const
177 { return inst && cand; }
178
182 {
183 if ( cand )
184 {
185 if ( inst ) {
187 {
188 ResStatus & inststatus( backup( it->status() ) );
189 if ( ! inststatus.setTransact( false, causer ) ) return restore();
190 if ( ! inststatus.setLock ( false, causer ) ) return restore();
191 if ( ! cand->multiversionInstall() )
192 {
193 // This is what the solver most probabely will do.
194 // If we are wrong the solver will correct it. But
195 // this way we will get a better disk usage result,
196 // even if no autosolving is on.
197 inststatus.setTransact( true, ResStatus::SOLVER );
198 }
199 }
200 }
201 if ( ! unlockCandidates() ) return restore();
202 ResStatus & candstatus( backup( cand.status() ) );
203 if ( ! candstatus.setTransact( true, causer ) ) return restore();
204 return true;
205 }
206 return false;
207 }
208
210 {
211 if ( inst )
212 {
213 if ( ! resetTransactingCandidates() ) return restore();
215 {
216 ResStatus & inststatus( backup( it->status() ) );
217 if ( ! inststatus.setLock( false, causer ) ) return restore();
218 if ( ! inststatus.setTransact( true, causer ) ) return restore();
219 }
220 return true;
221 }
222 return false;
223 }
224
225 bool unset()
226 {
227 if ( inst )
228 {
230 {
231 ResStatus & inststatus( backup( it->status() ) );
232 if ( ! inststatus.setTransact( false, causer ) ) return restore();
233 if ( ! inststatus.setLock( false, causer ) ) return restore();
234 }
235 }
236 if ( ! unlockCandidates() ) return restore();
237 return true;
238 }
239
241 {
242 if ( causer != ResStatus::USER ) // by user only
243 return false;
244
245 if ( inst ) {
248 {
249 it->status().setTransact( false, causer );
250 it->status().setLock( true, causer );
251 }
252 return true;
253 } else
254 return false;
255 }
256
257 bool setTaboo()
258 {
259 if ( causer != ResStatus::USER ) // by user only
260 return false;
261
262 if ( cand ) {
264 return true;
265 } else
266 return false;
267 }
269
270 private:
274 {
276 {
277 ResStatus & status( backup( (*it).status() ) );
278 if ( ! status.setTransact( false, causer ) ) return false;
279 }
280 return true;
281 }
283 {
285 {
286 ResStatus & status( backup( (*it).status() ) );
287 if ( ! status.setTransact( false, causer ) ) return false;
288 if ( ! status.setLock( false, causer ) ) return false;
289 }
290 return true;
291 }
293 {
295 {
296 ResStatus & status( backup( (*it).status() ) );
297 if ( ! status.setTransact( false, causer ) ) return false;
298 if ( ! status.setLock( true, causer ) ) return false;
299 }
300 return true;
301 }
303
304 private:
309
310 private:
311 bool restore() { return backup.restore(); }
313 };
315
317 //
318 // CLASS NAME : Selectable::Impl
319 //
321
323 {
324 PoolItem cand( candidateObj() );
325 if ( cand && cand.status().transacts() )
326 {
327 if ( cand.status().isByUser() )
328 return( installedObj() ? S_Update : S_Install );
329 else
331 }
332
333 if ( installedObj() && installedObj().status().transacts() )
334 {
335 return( installedObj().status().isByUser() ? S_Del : S_AutoDel );
336 }
337
338 if ( installedObj() && allInstalledLocked() )
339 return S_Protected;
340
341 if ( !installedObj() && allCandidatesLocked() )
342 return S_Taboo;
343
344 // KEEP state:
345 if ( installedObj() )
346 return S_KeepInstalled;
347 // Report pseudo installed items as installed, if they are satisfied.
349 && cand.status().isSatisfied() ) // no installed, so we must have candidate
350 return S_KeepInstalled;
351
352 return S_NoInst;
353 }
354
356 {
357 StatusHelper self( *this, causer_r );
358
359 switch ( state_r )
360 {
361 case S_Protected:
362 return self.setProtected();
363 case S_Taboo:
364 return self.setTaboo();
365 case S_AutoDel:
366 case S_AutoInstall:
367 case S_AutoUpdate:
368 // Auto level is SOLVER level. UI may query, but not
369 // set at this level.
370 break;
371
372 case S_Del:
373 return self.setDelete();
374 break;
375
376 case S_Install:
377 return self.hasCandidateOnly() && self.setInstall();
378 break;
379
380 case S_Update:
381 return self.hasBoth() && self.setInstall();
382 break;
383
384 case S_KeepInstalled:
385 return self.hasInstalled() && self.unset();
386 break;
387
388 case S_NoInst:
389 return !self.hasInstalled() && self.unset();
390 break;
391 }
392
393 return false;
394 }
395
397 {
398 PoolItem newCandidate;
399
400 if ( newCandidate_r ) // must be in available list
401 {
403 {
404 if ( *it == newCandidate_r )
405 {
406 newCandidate = *it;
407 break;
408 }
409 }
410 }
411
412 if ( newCandidate )
413 {
414 PoolItem trans( transactingCandidate() );
415 if ( trans && trans != newCandidate )
416 {
417 // adjust transact to the new cancidate
418 if ( trans.status().maySetTransact( false, causer_r )
419 && newCandidate.status().maySetTransact( true, causer_r ) )
420 {
421 trans.status().setTransact( false, causer_r );
422 newCandidate.status().setTransact( true, causer_r );
423 }
424 else
425 {
426 // No permission to change a transacting candidate.
427 // Leave _candidate untouched and return NULL.
428 return PoolItem();
429 }
430 }
431 }
432
433 return _candidate = newCandidate;
434 }
435
437
438 bool Selectable::Impl::pickInstall( const PoolItem & pi_r, ResStatus::TransactByValue causer_r, bool yesno_r )
439 {
440 if ( identicalInstalled( pi_r ) )
441 return setPickStatus( pi_r, ( yesno_r ? S_Update : S_KeepInstalled ), causer_r );
442 return setPickStatus( pi_r, ( yesno_r ? S_Install : S_NoInst ), causer_r );
443 }
444
445 bool Selectable::Impl::pickDelete( const PoolItem & pi_r, ResStatus::TransactByValue causer_r, bool yesno_r )
446 {
447 return setPickStatus( pi_r, ( yesno_r ? S_Del : S_KeepInstalled ), causer_r );
448 }
449
451 {
452 if ( pi_r.ident() != ident() )
453 return false; // not my PoolItem
454
455 StatusBackup backup;
456 std::vector<PoolItem> i;
457 std::vector<PoolItem> a;
458
460 if ( identical( *it, pi_r ) )
461 i.push_back( *it );
463 if ( identical( *it, pi_r ) )
464 a.push_back( *it );
465
466 switch ( state_r )
467 {
468 case S_Protected:
469 if ( causer_r == ResStatus::USER && ! i.empty() )
470 {
471 if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::lock, causer_r ) ) return backup.restore();
472 if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::setTransactFalse, causer_r ) ) return backup.restore();
473 return true;
474 }
475 break;
476
477 case S_Taboo:
478 if ( causer_r == ResStatus::USER && ! a.empty() )
479 {
480 if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::lock, causer_r ) ) return backup.restore();
481 return true;
482 }
483 break;
484
485 case S_AutoDel:
486 case S_AutoInstall:
487 case S_AutoUpdate:
488 // Auto level is SOLVER level. UI may query, but not
489 // set at this level.
490 break;
491
492 case S_Del:
493 if ( ! i.empty() )
494 {
495 if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::transact, causer_r ) ) return backup.restore();
496 if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::setTransactFalse, causer_r ) ) return backup.restore();
497 return true;
498 }
499 break;
500
501 case S_Install:
502 if ( i.empty() && ! a.empty() )
503 {
504 const PoolItem & cand( pi_r.status().isInstalled() ? *a.begin() : pi_r );
505 if ( cand.multiversionInstall() )
506 {
507 if ( ! backup.forEach( availableBegin(), availableEnd(), &StatusBackup::unsetNonMultiTransact, causer_r ) ) return backup.restore();
508 // maybe unlock candidate only?
509 if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
510 if ( ! cand.status().setTransact( true, causer_r ) ) return backup.restore();
511 return true;
512 }
513 else
514 {
515 // For non-multiversion use ordinary setStatus
516 // NOTE that S_Update/S_Install here depends on !installedEmpty()
517 // and not on picklists identicalInstalled.
518 if ( ! backup.forEach( availableBegin(), availableEnd(), &StatusBackup::unsetMultiTransact, causer_r ) ) return backup.restore();
519 if ( ! setCandidate( cand, causer_r ) ) return backup.restore();
520 if ( ! setStatus( installedEmpty() ? S_Install : S_Update, causer_r ) ) return backup.restore();
521 return true;
522 }
523 }
524 break;
525
526 case S_Update:
527 if ( ! i.empty() && ! a.empty() )
528 {
529 const PoolItem & cand( pi_r.status().isInstalled() ? *a.begin() : pi_r );
530 if ( cand.multiversionInstall() )
531 {
532 if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
533 if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::setTransactTrue, ResStatus::SOLVER ) ) return backup.restore();
534 if ( ! backup.forEach( availableBegin(), availableEnd(), &StatusBackup::unsetNonMultiTransact, causer_r ) ) return backup.restore();
535 // maybe unlock candidate only?
536 if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
537 if ( ! cand.status().setTransact( true, causer_r ) ) return backup.restore();
538 return true;
539 }
540 else
541 {
542 // For non-multiversion use ordinary setStatus
543 // NOTE that S_Update/S_Install here depends on !installedEmpty()
544 // and not on picklists identicalInstalled.
545 if ( ! backup.forEach( availableBegin(), availableEnd(), &StatusBackup::unsetMultiTransact, causer_r ) ) return backup.restore();
546 if ( ! setCandidate( cand, causer_r ) ) return backup.restore();
547 if ( ! setStatus( installedEmpty() ? S_Install : S_Update, causer_r ) ) return backup.restore();
548 return true;
549 }
550 }
551 break;
552
553 case S_KeepInstalled:
554 if ( ! i.empty() )
555 {
556 if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
557 if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
558 return true;
559 }
560 break;
561
562 case S_NoInst:
563 if ( i.empty() )
564 {
565 if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
566 return true;
567 }
568 break;
569 }
570 return false;
571 }
572
574 {
575 if ( pi_r.satSolvable().ident() != ident() )
576 return Status(-1); // not my PoolItem
577
578 std::vector<PoolItem> i;
579 std::vector<PoolItem> a;
580 PoolItem ti;
581 PoolItem ta;
582
584 if ( identical( *it, pi_r ) )
585 {
586 i.push_back( *it );
587 if ( ! ti && it->status().transacts() )
588 ti = *it;
589 }
590
592 if ( identical( *it, pi_r ) )
593 {
594 a.push_back( *it );
595 if ( ! ta && it->status().transacts() )
596 ta = *it;
597 }
598
599 if ( ta )
600 {
601 if ( ta.status().isByUser() )
602 return( i.empty() ? S_Install : S_Update );
603 else
604 return( i.empty() ? S_AutoInstall : S_AutoUpdate );
605 }
606
607 if ( ti )
608 {
609 return( ti.status().isByUser() ? S_Del : S_AutoDel );
610 }
611
612 for_( it, i.begin(), i.end() )
613 if ( it->status().isLocked() )
614 return S_Protected;
615
616 if ( i.empty() )
617 {
618 bool allALocked = true;
619 for_( it, a.begin(), a.end() )
620 if ( ! it->status().isLocked() )
621 {
622 allALocked = false;
623 break;
624 }
625 if ( allALocked )
626 return S_Taboo;
627 }
628
629 // KEEP state:
630 if ( ! i.empty() )
631 return S_KeepInstalled;
632 // Report pseudo installed items as installed, if they are satisfied.
634 && ( ta ? ta : *a.begin() ).status().isSatisfied() ) // no installed, so we must have candidate
635 return S_KeepInstalled;
636
637 return S_NoInst;
638 }
639
641
643 {
644 PoolItem cand( candidateObj() );
645 if ( cand && cand.status().transacts() )
646 return cand.status().getTransactByValue();
647
648 if ( installedObj() && installedObj().status().transacts() )
650
651 if ( cand )
652 return cand.status().getTransactByValue();
653
654 if ( installedObj() )
656
657 return ResStatus::SOLVER;
658 }
659
661 } // namespace ui
664} // namespace zypp
Combining sat::Solvable and ResStatus.
Definition: PoolItem.h:51
ResStatus & status() const
Returns the current status.
Definition: PoolItem.cc:211
Status bitfield.
Definition: ResStatus.h:54
bool setTransact(bool toTansact_r, TransactByValue causer_r)
Toggle between TRANSACT and KEEP_STATE.
Definition: ResStatus.h:432
bool setLock(bool toLock_r, TransactByValue causer_r)
Apply a lock (prevent transaction).
Definition: ResStatus.h:387
bool isByUser() const
Definition: ResStatus.h:299
bool transacts() const
Definition: ResStatus.h:276
bool isInstalled() const
Definition: ResStatus.h:240
bool maySetTransact(bool val_r, TransactByValue causer)
Definition: ResStatus.h:463
TransactByValue getTransactByValue() const
Definition: ResStatus.h:302
bool isSatisfied() const
Definition: ResStatus.h:219
IdString ident() const
The identifier.
Definition: Solvable.cc:269
bool setStatus(Status state_r, ResStatus::TransactByValue causer_r=ResStatus::USER)
Try to set a new Status.
Definition: Selectable.cc:67
available_iterator availableEnd() const
Definition: Selectable.cc:127
installed_iterator installedBegin() const
Definition: Selectable.cc:138
PoolItem installedObj() const
The last Installed object.
Definition: Selectable.cc:70
IdString ident() const
The identifier.
Definition: Selectable.cc:55
installed_iterator installedEnd() const
Definition: Selectable.cc:141
available_iterator availableBegin() const
Definition: Selectable.cc:124
PoolItem setCandidate(const PoolItem &newCandidate_r, ResStatus::TransactByValue causer_r=ResStatus::USER)
Set a candidate (out of available objects).
Definition: Selectable.cc:100
PoolItem candidateObj() const
The 'best' or 'most interesting' among all available objects.
Definition: Selectable.cc:73
bool setPickStatus(const PoolItem &pi_r, Status state_r, ResStatus::TransactByValue causer_r=ResStatus::USER)
Assign a new status to a specific item.
Definition: Selectable.cc:209
Status status() const
Return the current Status.
Definition: Selectable.cc:64
bool identicalInstalled(const PoolItem &rhs) const
True if rhs has the same content as an installed one.
Definition: Selectable.cc:91
ResKind kind() const
The ResObjects kind.
Definition: Selectable.cc:58
bool installedEmpty() const
Definition: Selectable.cc:132
Simple ResStatus backup stack.
bool lock(const PoolItem &pi_r, Causer causer_r)
highlevel set locked.
bool transact(const PoolItem &pi_r, Causer causer_r)
highevel set transact (force unlock).
bool forEach(TIter begin_r, TIter end_r, Action action_r, Causer causer_r)
Highlevel action on range of items.
bool setTransact(const PoolItem &pi_r, bool yesno_r, Causer causer_r)
lowlevel ResStatus::setTransact
bool unsetNonMultiTransact(const PoolItem &pi_r, Causer causer_r)
highlevel remove transact from non-multiversion packages.
bool unsetMultiTransact(const PoolItem &pi_r, Causer causer_r)
highlevel remove transact from multiversion packages.
bool setTransactTrue(const PoolItem &pi_r, Causer causer_r)
lowlevel ResStatus::setTransact(true).
bool setTransactFalse(const PoolItem &pi_r, Causer causer_r)
lowlevel ResStatus::setTransact(false).
bool unlock(const PoolItem &pi_r, Causer causer_r)
highlevel unlock (also unsets transact).
ResStatus & backup(ResStatus &status_r)
Backup status.
std::vector< resstatus::StatusBackup > _backup
ResStatus::TransactByValue Causer
ResStatus & operator()(ResStatus &status_r)
Backup status.
ResStatus & backup(const PoolItem &pi_r)
This is an overloaded member function, provided for convenience. It differs from the above function o...
ResStatus & operator()(const PoolItem &pi_r)
This is an overloaded member function, provided for convenience. It differs from the above function o...
bool restore()
Restore all status.
bool setLock(const PoolItem &pi_r, bool yesno_r, Causer causer_r)
lowlevel ResStatus::setLock
bool(StatusBackup::* Action)(const PoolItem &, Causer)
Highlevel action.
bool identical(const SolvableType< Derived > &lhs, const Solvable &rhs)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: SolvableType.h:219
bool isPseudoInstalled(ResKind kind_r)
Those are denoted to be installed, if the solver verifies them as being satisfied.
Definition: ResTraits.h:28
Status
UI status Status values calculated by Selectable.
Definition: Status.h:35
@ S_AutoUpdate
Definition: Status.h:44
@ S_Taboo
Definition: Status.h:37
@ S_AutoInstall
Definition: Status.h:45
@ S_Install
Definition: Status.h:41
@ S_AutoDel
Definition: Status.h:43
@ S_NoInst
Definition: Status.h:48
@ S_Protected
Definition: Status.h:36
@ S_KeepInstalled
Definition: Status.h:47
@ S_Del
Definition: Status.h:39
@ S_Update
Definition: Status.h:40
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:2
Solvable satSolvable() const
Return the corresponding sat::Solvable.
Definition: SolvableType.h:57
IdString ident() const
Definition: SolvableType.h:61
bool multiversionInstall() const
Definition: SolvableType.h:82
Selectable implementation.
PoolItem installedObj() const
Installed object (transacting ot highest version).
installed_iterator installedEnd() const
bool setPickStatus(const PoolItem &pi_r, Status state_r, ResStatus::TransactByValue causer_r)
available_iterator availableBegin() const
installed_iterator installedBegin() const
available_iterator availableEnd() const
bool pickInstall(const PoolItem &pi_r, ResStatus::TransactByValue causer_r, bool yesno_r)
bool setStatus(Status state_r, ResStatus::TransactByValue causer_r)
ResStatus::TransactByValue modifiedBy() const
Return who caused the modification.
PoolItem candidateObj() const
Best among available objects.
Status pickStatus(const PoolItem &pi_r) const
PoolItem setCandidate(const PoolItem &newCandidate_r, ResStatus::TransactByValue causer_r)
Set a userCandidate (out of available objects).
SelectableTraits::available_const_iterator available_const_iterator
bool pickDelete(const PoolItem &pi_r, ResStatus::TransactByValue causer_r, bool yesno_r)
bool hasCandidateOnly() const
ResStatus::TransactByValue causer
bool hasInstalledOnly() const
Selectable::Impl::available_const_iterator available_const_iterator
const Selectable::Impl & _impl
StatusHelper(const Selectable::Impl &impl, ResStatus::TransactByValue causer_r)
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
Definition: Easy.h:28