1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/ui/SelectableImpl.cc
13 //#include "zypp/base/Logger.h"
15 #include "zypp/ui/SelectableImpl.h"
19 ///////////////////////////////////////////////////////////////////
21 { /////////////////////////////////////////////////////////////////
22 ///////////////////////////////////////////////////////////////////
24 { /////////////////////////////////////////////////////////////////
26 /** Simple ResStatus backup stack.
27 * \ref restore simply rewinds all remembered status.
32 typedef ResStatus::TransactByValue Causer;
36 ResStatus & backup( ResStatus & status_r )
38 _backup.push_back( status_r );
42 ResStatus & backup( const PoolItem & pi_r )
43 { return backup( pi_r.status() ); }
46 ResStatus & operator()( ResStatus & status_r )
47 { return backup( status_r ); }
49 ResStatus & operator()( const PoolItem & pi_r )
50 { return backup( pi_r.status() ); }
52 /** Restore all status. */
55 for_( rit, _backup.rbegin(), _backup.rend() )
57 return false; // restore is done on error - return restore();
61 /** lowlevel \c ResStatus::setTransact */
62 bool setTransact( const PoolItem & pi_r, bool yesno_r, Causer causer_r )
63 { return backup( pi_r ).setTransact( yesno_r, causer_r ); }
65 /** lowlevel \c ResStatus::setLock */
66 bool setLock( const PoolItem & pi_r, bool yesno_r, Causer causer_r )
67 { return backup( pi_r ).setLock( yesno_r, causer_r ); }
69 /** lowlevel \c ResStatus::setTransact(true). */
70 bool setTransactTrue( const PoolItem & pi_r, Causer causer_r )
71 { return setTransact( pi_r, true, causer_r ); }
73 /** lowlevel \c ResStatus::setTransact(false). */
74 bool setTransactFalse( const PoolItem & pi_r, Causer causer_r )
75 { return setTransact( pi_r, false, causer_r ); }
78 /** highevel set transact (force unlock). */
79 bool transact( const PoolItem & pi_r, Causer causer_r )
81 ResStatus & status( backup( pi_r ) );
82 if ( ! status.setLock( false, causer_r ) ) return false;
83 if ( ! status.setTransact( true, causer_r ) ) return false;
87 /** highlevel set locked. */
88 bool lock( const PoolItem & pi_r, Causer causer_r )
90 ResStatus & status( backup( pi_r ) );
91 if ( ! status.setTransact( false, causer_r ) ) return false;
92 if ( ! status.setLock( true, causer_r ) ) return false;
96 /** highlevel unlock (also unsets transact). */
97 bool unlock( const PoolItem & pi_r, Causer causer_r )
99 ResStatus & status( backup( pi_r ) );
100 if ( ! status.setTransact( false, causer_r ) ) return false;
101 if ( ! status.setLock( false, causer_r ) ) return false;
105 /** highlevel remove transact from non-multiversion packages. */
106 bool unsetNonMultiTransact( const PoolItem & pi_r, Causer causer_r )
108 ResStatus & status( backup( pi_r ) );
109 if ( status.transacts() && ! pi_r.multiversionInstall() )
111 if ( ! status.setTransact( false, causer_r ) ) return false;
116 /** highlevel remove transact from multiversion packages. */
117 bool unsetMultiTransact( const PoolItem & pi_r, Causer causer_r )
119 ResStatus & status( backup( pi_r ) );
120 if ( status.transacts() && pi_r.multiversionInstall() )
122 if ( ! status.setTransact( false, causer_r ) ) return false;
127 /** Highlevel action. */
128 typedef bool (StatusBackup::*Action)( const PoolItem &, Causer );
130 /** Highlevel action on range of items. */
131 template <class _Iter>
132 bool forEach( _Iter begin_r, _Iter end_r, Action action_r, Causer causer_r )
134 for_( it, begin_r, end_r )
135 if ( ! (this->*action_r)( *it, causer_r ) )
141 std::vector<resstatus::StatusBackup> _backup;
144 ///////////////////////////////////////////////////////////////////
146 // CLASS NAME : StatusHelper
148 /** \todo Unify status and pickStatus.
152 StatusHelper( const Selectable::Impl & impl, ResStatus::TransactByValue causer_r )
154 , inst( impl.installedObj() )
155 , cand( impl.candidateObj() )
159 typedef Selectable::Impl::available_const_iterator available_const_iterator;
164 bool hasInstalled() const
165 { return bool(inst); }
167 bool hasCandidate() const
168 { return bool(cand); }
170 bool hasInstalledOnly() const
171 { return inst && !cand; }
173 bool hasCandidateOnly() const
174 { return cand && !inst; }
177 { return inst && cand; }
179 /** \name Topevel methods must restore status on failure. */
186 for_( it, _impl.installedBegin(), _impl.installedEnd() )
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() )
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 );
201 if ( ! unlockCandidates() ) return restore();
202 ResStatus & candstatus( backup( cand.status() ) );
203 if ( ! candstatus.setTransact( true, causer ) ) return restore();
213 if ( ! resetTransactingCandidates() ) return restore();
214 for_( it, _impl.installedBegin(), _impl.installedEnd() )
216 ResStatus & inststatus( backup( it->status() ) );
217 if ( ! inststatus.setLock( false, causer ) ) return restore();
218 if ( ! inststatus.setTransact( true, causer ) ) return restore();
229 for_( it, _impl.installedBegin(), _impl.installedEnd() )
231 ResStatus & inststatus( backup( it->status() ) );
232 if ( ! inststatus.setTransact( false, causer ) ) return restore();
233 if ( ! inststatus.setLock( false, causer ) ) return restore();
236 if ( ! unlockCandidates() ) return restore();
242 if ( causer != ResStatus::USER ) // by user only
246 resetTransactingCandidates();
247 for_( it, _impl.installedBegin(), _impl.installedEnd() )
249 it->status().setTransact( false, causer );
250 it->status().setLock( true, causer );
259 if ( causer != ResStatus::USER ) // by user only
271 /** \name Helper methods backup status but do not replay. */
273 bool resetTransactingCandidates()
275 for_( it, _impl.availableBegin(), _impl.availableEnd() )
277 ResStatus & status( backup( (*it).status() ) );
278 if ( ! status.setTransact( false, causer ) ) return false;
282 bool unlockCandidates()
284 for_( it, _impl.availableBegin(), _impl.availableEnd() )
286 ResStatus & status( backup( (*it).status() ) );
287 if ( ! status.setTransact( false, causer ) ) return false;
288 if ( ! status.setLock( false, causer ) ) return false;
292 bool lockCandidates()
294 for_( it, _impl.availableBegin(), _impl.availableEnd() )
296 ResStatus & status( backup( (*it).status() ) );
297 if ( ! status.setTransact( false, causer ) ) return false;
298 if ( ! status.setLock( true, causer ) ) return false;
305 const Selectable::Impl & _impl;
308 ResStatus::TransactByValue causer;
311 bool restore() { return backup.restore(); }
314 ///////////////////////////////////////////////////////////////////
316 ///////////////////////////////////////////////////////////////////
318 // CLASS NAME : Selectable::Impl
320 ///////////////////////////////////////////////////////////////////
322 Status Selectable::Impl::status() const
324 PoolItem cand( candidateObj() );
325 if ( cand && cand.status().transacts() )
327 if ( cand.status().isByUser() )
328 return( installedObj() ? S_Update : S_Install );
330 return( installedObj() ? S_AutoUpdate : S_AutoInstall );
333 if ( installedObj() && installedObj().status().transacts() )
335 return( installedObj().status().isByUser() ? S_Del : S_AutoDel );
338 if ( installedObj() && allInstalledLocked() )
341 if ( !installedObj() && allCandidatesLocked() )
345 if ( installedObj() )
346 return S_KeepInstalled;
347 // Report pseudo installed items as installed, if they are satisfied.
348 if ( traits::isPseudoInstalled( kind() )
349 && cand.status().isSatisfied() ) // no installed, so we must have candidate
350 return S_KeepInstalled;
355 bool Selectable::Impl::setStatus( Status state_r, ResStatus::TransactByValue causer_r )
357 StatusHelper self( *this, causer_r );
362 return self.setProtected();
364 return self.setTaboo();
368 // Auto level is SOLVER level. UI may query, but not
369 // set at this level.
373 return self.setDelete();
377 return self.hasCandidateOnly() && self.setInstall();
381 return self.hasBoth() && self.setInstall();
384 case S_KeepInstalled:
385 return self.hasInstalled() && self.unset();
389 return !self.hasInstalled() && self.unset();
396 PoolItem Selectable::Impl::setCandidate( const PoolItem & newCandidate_r, ResStatus::TransactByValue causer_r )
398 PoolItem newCandidate;
400 if ( newCandidate_r ) // must be in available list
402 for_( it, availableBegin(), availableEnd() )
404 if ( *it == newCandidate_r )
414 PoolItem trans( transactingCandidate() );
415 if ( trans && trans != newCandidate )
417 // adjust transact to the new cancidate
418 if ( trans.status().maySetTransact( false, causer_r )
419 && newCandidate.status().maySetTransact( true, causer_r ) )
421 trans.status().setTransact( false, causer_r );
422 newCandidate.status().setTransact( true, causer_r );
426 // No permission to change a transacting candidate.
427 // Leave _candidate untouched and return NULL.
433 return _candidate = newCandidate;
436 ///////////////////////////////////////////////////////////////////
438 bool Selectable::Impl::pickInstall( const PoolItem & pi_r, ResStatus::TransactByValue causer_r, bool yesno_r )
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 );
445 bool Selectable::Impl::pickDelete( const PoolItem & pi_r, ResStatus::TransactByValue causer_r, bool yesno_r )
447 return setPickStatus( pi_r, ( yesno_r ? S_Del : S_KeepInstalled ), causer_r );
450 bool Selectable::Impl::setPickStatus( const PoolItem & pi_r, Status state_r, ResStatus::TransactByValue causer_r )
452 if ( pi_r.ident() != ident() )
453 return false; // not my PoolItem
456 std::vector<PoolItem> i;
457 std::vector<PoolItem> a;
459 for_( it, installedBegin(), installedEnd() )
460 if ( identical( *it, pi_r ) )
462 for_( it, availableBegin(), availableEnd() )
463 if ( identical( *it, pi_r ) )
469 if ( causer_r == ResStatus::USER && ! i.empty() )
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();
478 if ( causer_r == ResStatus::USER && ! a.empty() )
480 if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::lock, causer_r ) ) return backup.restore();
488 // Auto level is SOLVER level. UI may query, but not
489 // set at this level.
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();
502 if ( i.empty() && ! a.empty() )
504 const PoolItem & cand( pi_r.status().isInstalled() ? *a.begin() : pi_r );
505 if ( cand.multiversionInstall() )
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();
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();
527 if ( ! i.empty() && ! a.empty() )
529 const PoolItem & cand( pi_r.status().isInstalled() ? *a.begin() : pi_r );
530 if ( cand.multiversionInstall() )
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();
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();
553 case S_KeepInstalled:
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();
565 if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
573 Status Selectable::Impl::pickStatus( const PoolItem & pi_r ) const
575 if ( pi_r.satSolvable().ident() != ident() )
576 return Status(-1); // not my PoolItem
578 std::vector<PoolItem> i;
579 std::vector<PoolItem> a;
583 for_( it, installedBegin(), installedEnd() )
584 if ( identical( *it, pi_r ) )
587 if ( ! ti && it->status().transacts() )
591 for_( it, availableBegin(), availableEnd() )
592 if ( identical( *it, pi_r ) )
595 if ( ! ta && it->status().transacts() )
601 if ( ta.status().isByUser() )
602 return( i.empty() ? S_Install : S_Update );
604 return( i.empty() ? S_AutoInstall : S_AutoUpdate );
609 return( ti.status().isByUser() ? S_Del : S_AutoDel );
612 for_( it, i.begin(), i.end() )
613 if ( it->status().isLocked() )
618 bool allALocked = true;
619 for_( it, a.begin(), a.end() )
620 if ( ! it->status().isLocked() )
631 return S_KeepInstalled;
632 // Report pseudo installed items as installed, if they are satisfied.
633 if ( traits::isPseudoInstalled( kind() )
634 && ( ta ? ta : *a.begin() ).status().isSatisfied() ) // no installed, so we must have candidate
635 return S_KeepInstalled;
640 ///////////////////////////////////////////////////////////////////
642 ResStatus::TransactByValue Selectable::Impl::modifiedBy() const
644 PoolItem cand( candidateObj() );
645 if ( cand && cand.status().transacts() )
646 return cand.status().getTransactByValue();
648 if ( installedObj() && installedObj().status().transacts() )
649 return installedObj().status().getTransactByValue();
652 return cand.status().getTransactByValue();
654 if ( installedObj() )
655 return installedObj().status().getTransactByValue();
657 return ResStatus::SOLVER;
660 /////////////////////////////////////////////////////////////////
662 ///////////////////////////////////////////////////////////////////
663 /////////////////////////////////////////////////////////////////
665 ///////////////////////////////////////////////////////////////////