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 action. */
106 typedef bool (StatusBackup::*Action)( const PoolItem &, Causer );
108 /** Highlevel action on range of items. */
109 template <class _Iter>
110 bool forEach( _Iter begin_r, _Iter end_r, Action action_r, Causer causer_r )
112 for_( it, begin_r, end_r )
113 if ( ! (this->*action_r)( *it, causer_r ) )
119 std::vector<resstatus::StatusBackup> _backup;
122 ///////////////////////////////////////////////////////////////////
124 // CLASS NAME : StatusHelper
126 /** \todo Unify status and pickStatus.
130 StatusHelper( const Selectable::Impl & impl, ResStatus::TransactByValue causer_r )
132 , inst( impl.installedObj() )
133 , cand( impl.candidateObj() )
137 typedef Selectable::Impl::available_const_iterator available_const_iterator;
142 bool hasInstalled() const
143 { return bool(inst); }
145 bool hasCandidate() const
146 { return bool(cand); }
148 bool hasInstalledOnly() const
149 { return inst && !cand; }
151 bool hasCandidateOnly() const
152 { return cand && !inst; }
155 { return inst && cand; }
157 /** \name Topevel methods must restore status on failure. */
164 for_( it, _impl.installedBegin(), _impl.installedEnd() )
166 ResStatus & inststatus( backup( it->status() ) );
167 if ( ! inststatus.setTransact( false, causer ) ) return restore();
168 if ( ! inststatus.setLock ( false, causer ) ) return restore();
169 if ( ! cand->multiversionInstall() )
171 // This is what the solver most probabely will do.
172 // If we are wrong the solver will correct it. But
173 // this way we will get a better disk usage result,
174 // even if no autosolving is on.
175 inststatus.setTransact( true, ResStatus::SOLVER );
179 if ( ! unlockCandidates() ) return restore();
180 ResStatus & candstatus( backup( cand.status() ) );
181 if ( ! candstatus.setTransact( true, causer ) ) return restore();
191 if ( ! resetTransactingCandidates() ) return restore();
192 for_( it, _impl.installedBegin(), _impl.installedEnd() )
194 ResStatus & inststatus( backup( it->status() ) );
195 if ( ! inststatus.setLock( false, causer ) ) return restore();
196 if ( ! inststatus.setTransact( true, causer ) ) return restore();
207 for_( it, _impl.installedBegin(), _impl.installedEnd() )
209 ResStatus & inststatus( backup( it->status() ) );
210 if ( ! inststatus.setTransact( false, causer ) ) return restore();
211 if ( ! inststatus.setLock( false, causer ) ) return restore();
214 if ( ! unlockCandidates() ) return restore();
220 if ( causer != ResStatus::USER ) // by user only
224 resetTransactingCandidates();
225 for_( it, _impl.installedBegin(), _impl.installedEnd() )
227 it->status().setTransact( false, causer );
228 it->status().setLock( true, causer );
237 if ( causer != ResStatus::USER ) // by user only
249 /** \name Helper methods backup status but do not replay. */
251 bool resetTransactingCandidates()
253 for_( it, _impl.availableBegin(), _impl.availableEnd() )
255 ResStatus & status( backup( (*it).status() ) );
256 if ( ! status.setTransact( false, causer ) ) return false;
260 bool unlockCandidates()
262 for_( it, _impl.availableBegin(), _impl.availableEnd() )
264 ResStatus & status( backup( (*it).status() ) );
265 if ( ! status.setTransact( false, causer ) ) return false;
266 if ( ! status.setLock( false, causer ) ) return false;
270 bool lockCandidates()
272 for_( it, _impl.availableBegin(), _impl.availableEnd() )
274 ResStatus & status( backup( (*it).status() ) );
275 if ( ! status.setTransact( false, causer ) ) return false;
276 if ( ! status.setLock( true, causer ) ) return false;
283 const Selectable::Impl & _impl;
286 ResStatus::TransactByValue causer;
289 bool restore() { return backup.restore(); }
292 ///////////////////////////////////////////////////////////////////
294 ///////////////////////////////////////////////////////////////////
296 // CLASS NAME : Selectable::Impl
298 ///////////////////////////////////////////////////////////////////
300 Status Selectable::Impl::status() const
302 PoolItem cand( candidateObj() );
303 if ( cand && cand.status().transacts() )
305 if ( cand.status().isByUser() )
306 return( installedObj() ? S_Update : S_Install );
308 return( installedObj() ? S_AutoUpdate : S_AutoInstall );
311 if ( installedObj() && installedObj().status().transacts() )
313 return( installedObj().status().isByUser() ? S_Del : S_AutoDel );
316 if ( installedObj() && allInstalledLocked() )
319 if ( !installedObj() && allCandidatesLocked() )
323 if ( installedObj() )
324 return S_KeepInstalled;
325 // Report pseudo installed items as installed, if they are satisfied.
326 if ( traits::isPseudoInstalled( kind() )
327 && cand.status().isSatisfied() ) // no installed, so we must have candidate
328 return S_KeepInstalled;
333 bool Selectable::Impl::setStatus( Status state_r, ResStatus::TransactByValue causer_r )
335 StatusHelper self( *this, causer_r );
340 return self.setProtected();
342 return self.setTaboo();
346 // Auto level is SOLVER level. UI may query, but not
347 // set at this level.
351 return self.setDelete();
355 return self.hasCandidateOnly() && self.setInstall();
359 return self.hasBoth() && self.setInstall();
362 case S_KeepInstalled:
363 return self.hasInstalled() && self.unset();
367 return !self.hasInstalled() && self.unset();
374 PoolItem Selectable::Impl::setCandidate( const PoolItem & newCandidate_r, ResStatus::TransactByValue causer_r )
376 PoolItem newCandidate;
378 if ( newCandidate_r ) // must be in available list
380 for_( it, availableBegin(), availableEnd() )
382 if ( *it == newCandidate_r )
392 PoolItem trans( transactingCandidate() );
393 if ( trans && trans != newCandidate )
395 // adjust transact to the new cancidate
396 if ( trans.status().maySetTransact( false, causer_r )
397 && newCandidate.status().maySetTransact( true, causer_r ) )
399 trans.status().setTransact( false, causer_r );
400 newCandidate.status().setTransact( true, causer_r );
404 // No permission to change a transacting candidate.
405 // Leave _candidate untouched and return NULL.
411 return _candidate = newCandidate;
414 ///////////////////////////////////////////////////////////////////
416 bool Selectable::Impl::pickInstall( const PoolItem & pi_r, ResStatus::TransactByValue causer_r, bool yesno_r )
418 if ( identicalInstalled( pi_r ) )
419 return setPickStatus( pi_r, ( yesno_r ? S_Update : S_KeepInstalled ), causer_r );
420 return setPickStatus( pi_r, ( yesno_r ? S_Install : S_NoInst ), causer_r );
423 bool Selectable::Impl::pickDelete( const PoolItem & pi_r, ResStatus::TransactByValue causer_r, bool yesno_r )
425 return setPickStatus( pi_r, ( yesno_r ? S_Del : S_KeepInstalled ), causer_r );
428 bool Selectable::Impl::setPickStatus( const PoolItem & pi_r, Status state_r, ResStatus::TransactByValue causer_r )
430 if ( pi_r.satSolvable().ident() != ident() )
431 return false; // not my PoolItem
433 if ( ! multiversionInstall() )
434 return false; // We're not yet ready for this.
435 // TODO: Without multiversionInstall take care at most ONE available is set
436 // to install. Upon install ALL installed get deleted. Only upon deletetion
437 // one might pick individual versions (but more than one would be an error here).
440 std::vector<PoolItem> i;
441 std::vector<PoolItem> a;
443 for_( it, installedBegin(), installedEnd() )
444 if ( identical( *it, pi_r ) )
446 for_( it, availableBegin(), availableEnd() )
447 if ( identical( *it, pi_r ) )
453 if ( causer_r == ResStatus::USER && ! i.empty() )
455 if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::lock, causer_r ) ) return backup.restore();
456 if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::setTransactFalse, causer_r ) ) return backup.restore();
462 if ( causer_r == ResStatus::USER && ! a.empty() )
464 if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::lock, causer_r ) ) return backup.restore();
472 // Auto level is SOLVER level. UI may query, but not
473 // set at this level.
479 if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::transact, causer_r ) ) return backup.restore();
480 if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::setTransactFalse, causer_r ) ) return backup.restore();
486 if ( i.empty() && ! a.empty() )
488 // maybe unlock candidate only?
489 if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
490 const PoolItem & cand( pi_r.status().isInstalled() ? *a.begin() : pi_r ); // status already backed up above
491 if ( ! cand.status().setTransact( true, causer_r ) ) return backup.restore();
497 if ( ! i.empty() && ! a.empty() )
499 if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
500 if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::setTransactTrue, ResStatus::SOLVER ) ) return backup.restore();
501 // maybe unlock candidate only?
502 if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
503 const PoolItem & cand( pi_r.status().isInstalled() ? *a.begin() : pi_r ); // status already backed up above
504 if ( ! cand.status().setTransact( true, causer_r ) ) return backup.restore();
509 case S_KeepInstalled:
512 if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
513 if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
521 if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
529 Status Selectable::Impl::pickStatus( const PoolItem & pi_r ) const
531 if ( pi_r.satSolvable().ident() != ident() )
532 return Status(-1); // not my PoolItem
534 std::vector<PoolItem> i;
535 std::vector<PoolItem> a;
539 for_( it, installedBegin(), installedEnd() )
540 if ( identical( *it, pi_r ) )
543 if ( ! ti && it->status().transacts() )
547 for_( it, availableBegin(), availableEnd() )
548 if ( identical( *it, pi_r ) )
551 if ( ! ta && it->status().transacts() )
557 if ( ta.status().isByUser() )
558 return( i.empty() ? S_Install : S_Update );
560 return( i.empty() ? S_AutoInstall : S_AutoUpdate );
565 return( ti.status().isByUser() ? S_Del : S_AutoDel );
568 for_( it, i.begin(), i.end() )
569 if ( it->status().isLocked() )
574 bool allALocked = true;
575 for_( it, a.begin(), a.end() )
576 if ( ! it->status().isLocked() )
587 return S_KeepInstalled;
588 // Report pseudo installed items as installed, if they are satisfied.
589 if ( traits::isPseudoInstalled( kind() )
590 && ( ta ? ta : *a.begin() ).status().isSatisfied() ) // no installed, so we must have candidate
591 return S_KeepInstalled;
596 ///////////////////////////////////////////////////////////////////
598 ResStatus::TransactByValue Selectable::Impl::modifiedBy() const
600 PoolItem cand( candidateObj() );
601 if ( cand && cand.status().transacts() )
602 return cand.status().getTransactByValue();
604 if ( installedObj() && installedObj().status().transacts() )
605 return installedObj().status().getTransactByValue();
608 return cand.status().getTransactByValue();
610 if ( installedObj() )
611 return installedObj().status().getTransactByValue();
613 return ResStatus::SOLVER;
616 /////////////////////////////////////////////////////////////////
618 ///////////////////////////////////////////////////////////////////
619 /////////////////////////////////////////////////////////////////
621 ///////////////////////////////////////////////////////////////////