SelectableImpl.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00012 #include <iostream>
00013 //#include "zypp/base/Logger.h"
00014 
00015 #include "zypp/ui/SelectableImpl.h"
00016 
00017 using std::endl;
00018 
00020 namespace zypp
00021 { 
00022 
00023   namespace ui
00024   { 
00025 
00029     class StatusBackup
00030     {
00031       public:
00032         typedef ResStatus::TransactByValue Causer;
00033 
00034       public:
00036         ResStatus & backup( ResStatus & status_r )
00037         {
00038           _backup.push_back( status_r );
00039           return status_r;
00040         }
00042         ResStatus & backup( const PoolItem & pi_r )
00043         { return backup( pi_r.status() ); }
00044 
00046         ResStatus & operator()( ResStatus & status_r )
00047         { return backup( status_r ); }
00049         ResStatus & operator()( const PoolItem & pi_r )
00050         { return backup( pi_r.status() ); }
00051 
00053         bool restore()
00054         {
00055           for_( rit, _backup.rbegin(), _backup.rend() )
00056             rit->replay();
00057           return false; // restore is done on error - return restore();
00058         }
00059 
00060       public:
00062         bool setTransact( const PoolItem & pi_r, bool yesno_r, Causer causer_r )
00063         { return backup( pi_r ).setTransact( yesno_r, causer_r ); }
00064 
00066         bool setLock( const PoolItem & pi_r, bool yesno_r, Causer causer_r )
00067         { return backup( pi_r ).setLock( yesno_r, causer_r ); }
00068 
00070         bool setTransactTrue( const PoolItem & pi_r, Causer causer_r )
00071         { return setTransact( pi_r, true, causer_r ); }
00072 
00074         bool setTransactFalse( const PoolItem & pi_r, Causer causer_r )
00075         { return setTransact( pi_r, false, causer_r ); }
00076 
00077       public:
00079         bool transact( const PoolItem & pi_r, Causer causer_r )
00080         {
00081           ResStatus & status( backup( pi_r ) );
00082           if ( ! status.setLock( false, causer_r ) ) return false;
00083           if ( ! status.setTransact( true, causer_r ) ) return false;
00084           return true;
00085         }
00086 
00088         bool lock( const PoolItem & pi_r, Causer causer_r )
00089         {
00090           ResStatus & status( backup( pi_r ) );
00091           if ( ! status.setTransact( false, causer_r ) ) return false;
00092           if ( ! status.setLock( true, causer_r ) ) return false;
00093           return true;
00094         }
00095 
00097         bool unlock( const PoolItem & pi_r, Causer causer_r )
00098         {
00099           ResStatus & status( backup( pi_r ) );
00100           if ( ! status.setTransact( false, causer_r ) ) return false;
00101           if ( ! status.setLock( false, causer_r ) ) return false;
00102           return true;
00103         }
00104 
00106         typedef bool (StatusBackup::*Action)( const PoolItem &, Causer );
00107 
00109         template <class _Iter>
00110         bool forEach( _Iter begin_r, _Iter end_r, Action action_r, Causer causer_r )
00111         {
00112           for_( it, begin_r, end_r )
00113             if ( ! (this->*action_r)( *it, causer_r ) )
00114               return false;
00115           return true;
00116         }
00117 
00118       private:
00119         std::vector<resstatus::StatusBackup> _backup;
00120     };
00121 
00123     //
00124     //  CLASS NAME : StatusHelper
00125     //
00128     struct StatusHelper
00129     {
00130       StatusHelper( const Selectable::Impl & impl, ResStatus::TransactByValue causer_r )
00131       : _impl( impl )
00132       , inst( impl.installedObj() )
00133       , cand( impl.candidateObj() )
00134       , causer( causer_r )
00135       {}
00136 
00137       typedef Selectable::Impl::available_const_iterator available_const_iterator;
00138 
00139       //
00140       // Queries
00141       //
00142       bool hasInstalled() const
00143       { return inst; }
00144 
00145       bool hasCandidate() const
00146       { return cand; }
00147 
00148       bool hasInstalledOnly() const
00149       { return inst && !cand; }
00150 
00151       bool hasCandidateOnly() const
00152       { return cand && !inst; }
00153 
00154       bool hasBoth() const
00155       { return inst && cand; }
00156 
00159       bool setInstall()
00160       {
00161         if ( cand )
00162         {
00163           if ( inst ) {
00164             for_( it, _impl.installedBegin(), _impl.installedEnd() )
00165             {
00166               ResStatus & inststatus( backup( it->status() ) );
00167               if ( ! inststatus.setTransact( false, causer ) ) return restore();
00168               if ( ! inststatus.setLock    ( false, causer ) ) return restore();
00169               if ( ! cand->multiversionInstall() )
00170               {
00171               // This is what the solver most probabely will do.
00172               // If we are wrong the solver will correct it. But
00173               // this way we will get a better disk usage result,
00174               // even if no autosolving is on.
00175                 inststatus.setTransact( true, ResStatus::SOLVER );
00176               }
00177             }
00178           }
00179           if ( ! unlockCandidates() ) return restore();
00180           ResStatus & candstatus( backup( cand.status() ) );
00181           if ( ! candstatus.setTransact( true, causer ) ) return restore();
00182           return true;
00183         }
00184         return false;
00185       }
00186 
00187       bool setDelete()
00188       {
00189         if ( inst )
00190         {
00191           if ( ! resetTransactingCandidates() ) return restore();
00192           for_( it, _impl.installedBegin(), _impl.installedEnd() )
00193           {
00194             ResStatus & inststatus( backup( it->status() ) );
00195             if ( ! inststatus.setLock( false, causer ) ) return restore();
00196             if ( ! inststatus.setTransact( true, causer ) ) return restore();
00197           }
00198           return true;
00199         }
00200         return false;
00201       }
00202 
00203       bool unset()
00204       {
00205         if ( inst )
00206         {
00207           for_( it, _impl.installedBegin(), _impl.installedEnd() )
00208           {
00209             ResStatus & inststatus( backup( it->status() ) );
00210             if ( ! inststatus.setTransact( false, causer ) ) return restore();
00211             if ( ! inststatus.setLock( false, causer ) ) return restore();
00212           }
00213         }
00214         if ( ! unlockCandidates() ) return restore();
00215         return true;
00216       }
00217 
00218       bool setProtected()
00219       {
00220         if ( causer != ResStatus::USER ) // by user only
00221           return false;
00222 
00223         if ( inst ) {
00224           resetTransactingCandidates();
00225           for_( it, _impl.installedBegin(), _impl.installedEnd() )
00226           {
00227             it->status().setTransact( false, causer );
00228             it->status().setLock( true, causer );
00229           }
00230           return true;
00231         } else
00232           return false;
00233       }
00234 
00235       bool setTaboo()
00236       {
00237         if ( causer != ResStatus::USER ) // by user only
00238           return false;
00239 
00240         if ( cand ) {
00241           lockCandidates();
00242           return true;
00243         } else
00244           return false;
00245       }
00247 
00248     private:
00251       bool resetTransactingCandidates()
00252       {
00253         for_( it, _impl.availableBegin(), _impl.availableEnd() )
00254         {
00255           ResStatus & status( backup( (*it).status() ) );
00256           if ( ! status.setTransact( false, causer ) ) return false;
00257         }
00258         return true;
00259       }
00260       bool unlockCandidates()
00261       {
00262         for_( it, _impl.availableBegin(), _impl.availableEnd() )
00263         {
00264           ResStatus & status( backup( (*it).status() ) );
00265           if ( ! status.setTransact( false, causer ) ) return false;
00266           if ( ! status.setLock( false, causer ) ) return false;
00267         }
00268         return true;
00269       }
00270       bool lockCandidates()
00271       {
00272         for_( it, _impl.availableBegin(), _impl.availableEnd() )
00273         {
00274           ResStatus & status( backup( (*it).status() ) );
00275           if ( ! status.setTransact( false, causer ) ) return false;
00276           if ( ! status.setLock( true, causer ) ) return false;
00277         }
00278         return true;
00279       }
00281 
00282     private:
00283       const Selectable::Impl & _impl;
00284       PoolItem                   inst;
00285       PoolItem                   cand;
00286       ResStatus::TransactByValue causer;
00287 
00288     private:
00289       bool restore() { return backup.restore(); }
00290       StatusBackup backup;
00291     };
00293 
00295     //
00296     //  CLASS NAME : Selectable::Impl
00297     //
00299 
00300     Status Selectable::Impl::status() const
00301     {
00302       PoolItem cand( candidateObj() );
00303       if ( cand && cand.status().transacts() )
00304         {
00305           if ( cand.status().isByUser() )
00306             return( installedObj() ? S_Update : S_Install );
00307           else
00308             return( installedObj() ? S_AutoUpdate : S_AutoInstall );
00309         }
00310 
00311       if ( installedObj() && installedObj().status().transacts() )
00312         {
00313           return( installedObj().status().isByUser() ? S_Del : S_AutoDel );
00314         }
00315 
00316       if ( installedObj() && allInstalledLocked() )
00317           return S_Protected;
00318 
00319       if ( !installedObj() && allCandidatesLocked() )
00320           return S_Taboo;
00321 
00322       // KEEP state:
00323       if ( installedObj() )
00324         return S_KeepInstalled;
00325       // Report pseudo installed items as installed, if they are satisfied.
00326       if ( traits::isPseudoInstalled( kind() )
00327            && cand.status().isSatisfied() ) // no installed, so we must have candidate
00328         return S_KeepInstalled;
00329 
00330       return S_NoInst;
00331     }
00332 
00333     bool Selectable::Impl::setStatus( Status state_r, ResStatus::TransactByValue causer_r )
00334     {
00335       StatusHelper self( *this, causer_r );
00336 
00337       switch ( state_r )
00338         {
00339         case S_Protected:
00340             return self.setProtected();
00341         case S_Taboo:
00342             return self.setTaboo();
00343         case S_AutoDel:
00344         case S_AutoInstall:
00345         case S_AutoUpdate:
00346           // Auto level is SOLVER level. UI may query, but not
00347           // set at this level.
00348           break;
00349 
00350         case S_Del:
00351           return self.setDelete();
00352           break;
00353 
00354         case S_Install:
00355           return self.hasCandidateOnly() && self.setInstall();
00356           break;
00357 
00358         case S_Update:
00359           return self.hasBoth() && self.setInstall();
00360           break;
00361 
00362         case S_KeepInstalled:
00363           return self.hasInstalled() && self.unset();
00364           break;
00365 
00366         case S_NoInst:
00367           return !self.hasInstalled() && self.unset();
00368           break;
00369         }
00370 
00371       return false;
00372     }
00373 
00374     PoolItem Selectable::Impl::setCandidate( const PoolItem & newCandidate_r, ResStatus::TransactByValue causer_r )
00375     {
00376       PoolItem newCandidate;
00377 
00378       if ( newCandidate_r ) // must be in available list
00379       {
00380         for_( it, availableBegin(), availableEnd() )
00381         {
00382           if ( *it == newCandidate_r )
00383           {
00384             newCandidate = *it;
00385             break;
00386           }
00387         }
00388       }
00389 
00390       if ( newCandidate )
00391       {
00392         PoolItem trans( transactingCandidate() );
00393         if ( trans && trans != newCandidate )
00394         {
00395           // adjust transact to the new cancidate
00396           if (    trans.status().maySetTransact( false, causer_r )
00397                && newCandidate.status().maySetTransact( true, causer_r ) )
00398           {
00399             trans.status().setTransact( false, causer_r );
00400             newCandidate.status().setTransact( true, causer_r );
00401           }
00402           else
00403           {
00404             // No permission to change a transacting candidate.
00405             // Leave _candidate untouched and return NULL.
00406             return PoolItem();
00407           }
00408         }
00409       }
00410 
00411       return _candidate = newCandidate;
00412     }
00413 
00415 
00416     bool Selectable::Impl::pickInstall( const PoolItem & pi_r, ResStatus::TransactByValue causer_r, bool yesno_r )
00417     {
00418       if ( identicalInstalled( pi_r ) )
00419         return setPickStatus( pi_r, ( yesno_r ? S_Update : S_KeepInstalled ), causer_r );
00420       return setPickStatus( pi_r, ( yesno_r ? S_Install : S_NoInst ), causer_r );
00421     }
00422 
00423     bool Selectable::Impl::pickDelete( const PoolItem & pi_r, ResStatus::TransactByValue causer_r, bool yesno_r )
00424     {
00425       return setPickStatus( pi_r, ( yesno_r ? S_Del : S_KeepInstalled ), causer_r );
00426     }
00427 
00428     bool Selectable::Impl::setPickStatus( const PoolItem & pi_r, Status state_r, ResStatus::TransactByValue causer_r )
00429     {
00430       if ( pi_r.satSolvable().ident() != ident() )
00431         return false;  // not my PoolItem
00432 
00433       if ( ! multiversionInstall() )
00434         return false;  // We're not yet ready for this.
00435       // TODO: Without multiversionInstall take care at most ONE available is set
00436       // to install. Upon install ALL installed get deleted. Only upon deletetion
00437       // one might pick individual versions (but more than one would be an error here).
00438 
00439       StatusBackup backup;
00440       std::vector<PoolItem> i;
00441       std::vector<PoolItem> a;
00442 
00443       for_( it, installedBegin(), installedEnd() )
00444         if ( identical( *it, pi_r ) )
00445           i.push_back( *it );
00446       for_( it, availableBegin(), availableEnd() )
00447         if ( identical( *it, pi_r ) )
00448           a.push_back( *it );
00449 
00450       switch ( state_r )
00451       {
00452         case S_Protected:
00453           if ( causer_r == ResStatus::USER && ! i.empty() )
00454           {
00455             if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::lock, causer_r ) ) return backup.restore();
00456             if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::setTransactFalse, causer_r ) ) return backup.restore();
00457             return true;
00458           }
00459           break;
00460 
00461         case S_Taboo:
00462           if ( causer_r == ResStatus::USER && ! a.empty() )
00463           {
00464             if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::lock, causer_r ) ) return backup.restore();
00465             return true;
00466           }
00467           break;
00468 
00469         case S_AutoDel:
00470         case S_AutoInstall:
00471         case S_AutoUpdate:
00472           // Auto level is SOLVER level. UI may query, but not
00473           // set at this level.
00474           break;
00475 
00476         case S_Del:
00477           if ( ! i.empty() )
00478           {
00479             if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::transact, causer_r ) ) return backup.restore();
00480             if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::setTransactFalse, causer_r ) ) return backup.restore();
00481             return true;
00482           }
00483           break;
00484 
00485         case S_Install:
00486           if ( i.empty() && ! a.empty() )
00487           {
00488             // maybe unlock candidate only?
00489             if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
00490             const PoolItem & cand( pi_r.status().isInstalled() ? *a.begin() : pi_r ); // status already backed up above
00491             if ( ! cand.status().setTransact( true, causer_r ) ) return backup.restore();
00492             return true;
00493           }
00494           break;
00495 
00496         case S_Update:
00497           if ( ! i.empty() && ! a.empty() )
00498           {
00499             if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
00500             if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::setTransactTrue, ResStatus::SOLVER ) ) return backup.restore();
00501             // maybe unlock candidate only?
00502             if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
00503             const PoolItem & cand( pi_r.status().isInstalled() ? *a.begin() : pi_r ); // status already backed up above
00504             if ( ! cand.status().setTransact( true, causer_r ) ) return backup.restore();
00505             return true;
00506           }
00507           break;
00508 
00509         case S_KeepInstalled:
00510           if ( ! i.empty()  )
00511           {
00512             if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
00513             if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
00514             return true;
00515           }
00516           break;
00517 
00518         case S_NoInst:
00519           if ( i.empty()  )
00520           {
00521             if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
00522             return true;
00523           }
00524           break;
00525       }
00526       return false;
00527     }
00528 
00529     Status Selectable::Impl::pickStatus( const PoolItem & pi_r ) const
00530     {
00531       if ( pi_r.satSolvable().ident() != ident() )
00532         return Status(-1); // not my PoolItem
00533 
00534       std::vector<PoolItem> i;
00535       std::vector<PoolItem> a;
00536       PoolItem ti;
00537       PoolItem ta;
00538 
00539       for_( it, installedBegin(), installedEnd() )
00540         if ( identical( *it, pi_r ) )
00541         {
00542           i.push_back( *it );
00543           if ( ! ti && it->status().transacts() )
00544             ti = *it;
00545         }
00546 
00547       for_( it, availableBegin(), availableEnd() )
00548         if ( identical( *it, pi_r ) )
00549         {
00550           a.push_back( *it );
00551           if ( ! ta && it->status().transacts() )
00552             ta = *it;
00553         }
00554 
00555       if ( ta )
00556       {
00557         if ( ta.status().isByUser() )
00558           return( i.empty() ? S_Install : S_Update );
00559         else
00560           return( i.empty() ? S_AutoInstall : S_AutoUpdate );
00561       }
00562 
00563       if ( ti )
00564       {
00565         return( ti.status().isByUser() ? S_Del : S_AutoDel );
00566       }
00567 
00568       for_( it, i.begin(), i.end() )
00569         if ( it->status().isLocked() )
00570           return S_Protected;
00571 
00572       if ( i.empty() )
00573       {
00574         bool allALocked = true;
00575         for_( it, a.begin(), a.end() )
00576           if ( ! it->status().isLocked() )
00577           {
00578             allALocked = false;
00579             break;
00580           }
00581         if ( allALocked )
00582           return S_Taboo;
00583       }
00584 
00585       // KEEP state:
00586       if ( ! i.empty() )
00587         return S_KeepInstalled;
00588       // Report pseudo installed items as installed, if they are satisfied.
00589       if ( traits::isPseudoInstalled( kind() )
00590            && ( ta ? ta : *a.begin() ).status().isSatisfied() ) // no installed, so we must have candidate
00591         return S_KeepInstalled;
00592 
00593       return S_NoInst;
00594     }
00595 
00597 
00598     ResStatus::TransactByValue Selectable::Impl::modifiedBy() const
00599     {
00600       PoolItem cand( candidateObj() );
00601       if ( cand && cand.status().transacts() )
00602         return cand.status().getTransactByValue();
00603 
00604       if ( installedObj() && installedObj().status().transacts() )
00605         return installedObj().status().getTransactByValue();
00606 
00607       if ( cand )
00608         return cand.status().getTransactByValue();
00609 
00610       if ( installedObj() )
00611         return installedObj().status().getTransactByValue();
00612 
00613       return ResStatus::SOLVER;
00614     }
00615 
00617   } // namespace ui
00620 } // namespace zypp

doxygen