libzypp  10.5.0
SelectableImpl.h
Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00012 #ifndef ZYPP_UI_SELECTABLEIMPL_H
00013 #define ZYPP_UI_SELECTABLEIMPL_H
00014 
00015 #include <iostream>
00016 #include "zypp/base/LogTools.h"
00017 
00018 #include "zypp/base/PtrTypes.h"
00019 
00020 #include "zypp/ResPool.h"
00021 #include "zypp/Resolver.h"
00022 #include "zypp/ui/Selectable.h"
00023 #include "zypp/ui/SelectableTraits.h"
00024 
00025 using std::endl;
00026 
00028 namespace zypp
00029 { 
00030 
00031   namespace ui
00032   { 
00033 
00035     //
00036     //  CLASS NAME : Selectable::Impl
00037     //
00042     struct Selectable::Impl
00043     {
00044     public:
00045 
00046       typedef SelectableTraits::AvailableItemSet         AvailableItemSet;
00047       typedef SelectableTraits::available_iterator       available_iterator;
00048       typedef SelectableTraits::available_const_iterator available_const_iterator;
00049       typedef SelectableTraits::available_size_type      available_size_type;
00050 
00051       typedef SelectableTraits::InstalledItemSet         InstalledItemSet;
00052       typedef SelectableTraits::installed_iterator       installed_iterator;
00053       typedef SelectableTraits::installed_const_iterator installed_const_iterator;
00054       typedef SelectableTraits::installed_size_type      installed_size_type;
00055 
00056       typedef SelectableTraits::PickList                PickList;
00057 
00058     public:
00059       template <class _Iterator>
00060       Impl( const ResObject::Kind & kind_r,
00061             const std::string & name_r,
00062             _Iterator begin_r,
00063             _Iterator end_r )
00064       : _ident( sat::Solvable::SplitIdent( kind_r, name_r ).ident() )
00065       , _kind( kind_r )
00066       , _name( name_r )
00067       {
00068         for_( it, begin_r, end_r )
00069         {
00070           if ( it->status().isInstalled() )
00071             _installedItems.insert( *it );
00072           else
00073             _availableItems.insert( *it );
00074         }
00075       }
00076 
00077     public:
00079       IdString ident() const
00080       { return _ident; }
00081 
00083       ResObject::Kind kind() const
00084       { return _kind; }
00085 
00087       const std::string & name() const
00088       { return _name; }
00089 
00091       Status status() const;
00092 
00094       bool setStatus( Status state_r, ResStatus::TransactByValue causer_r );
00095 
00097       PoolItem installedObj() const
00098       {
00099         if ( installedEmpty() )
00100           return PoolItem();
00101         PoolItem ret( transactingInstalled() );
00102         return ret ? ret : *_installedItems.begin();
00103       }
00104 
00109       PoolItem candidateObj() const
00110       {
00111         PoolItem ret( transactingCandidate() );
00112         if ( ret )
00113           return ret;
00114         return _candidate ? _candidate : defaultCandidate();
00115       }
00116 
00121       PoolItem setCandidate( const PoolItem & newCandidate_r, ResStatus::TransactByValue causer_r );
00122 
00128       PoolItem candidateObjFrom( Repository repo_r ) const
00129       {
00130         for_( it, availableBegin(), availableEnd() )
00131         {
00132           if ( (*it)->repository() == repo_r )
00133             return *it;
00134         }
00135         return PoolItem();
00136       }
00137 
00144       PoolItem updateCandidateObj() const
00145       {
00146         PoolItem defaultCand( defaultCandidate() );
00147 
00148         if ( multiversionInstall() )
00149           return identicalInstalled( defaultCand ) ? PoolItem() : defaultCand;
00150 
00151         if ( installedEmpty() || ! defaultCand )
00152           return defaultCand;
00153         // Here: installed and defaultCand are non NULL and it's not a
00154         //       multiversion install.
00155 
00156         // update candidate must come from the highest priority repo
00157         if ( defaultCand->repoInfo().priority() != (*availableBegin())->repoInfo().priority() )
00158           return PoolItem();
00159 
00160         PoolItem installed( installedObj() );
00161         // check vendor change
00162         if ( ! ( ResPool::instance().resolver().allowVendorChange()
00163                  || VendorAttr::instance().equivalent( defaultCand->vendor(), installed->vendor() ) ) )
00164           return PoolItem();
00165 
00166         // check arch change (arch noarch changes are allowed)
00167         if ( defaultCand->arch() != installed->arch()
00168            && ! ( defaultCand->arch() == Arch_noarch || installed->arch() == Arch_noarch ) )
00169           return PoolItem();
00170 
00171         // check greater edition
00172         if ( defaultCand->edition() <= installed->edition() )
00173           return PoolItem();
00174 
00175         return defaultCand;
00176       }
00177 
00179       PoolItem highestAvailableVersionObj() const
00180       {
00181         PoolItem ret;
00182         for_( it, availableBegin(), availableEnd() )
00183         {
00184           if ( !ret || (*it).satSolvable().edition() > ret.satSolvable().edition() )
00185             ret = *it;
00186         }
00187         return ret;
00188       }
00189 
00191       bool identicalAvailable( const PoolItem & rhs ) const
00192       { return identicalAvailableObj( rhs ); }
00193 
00195       bool identicalInstalled( const PoolItem & rhs ) const
00196       { return identicalInstalledObj( rhs ); }
00197 
00199       PoolItem identicalAvailableObj( const PoolItem & rhs ) const
00200       {
00201         if ( !availableEmpty() && rhs )
00202         {
00203           for_( it, _availableItems.begin(), _availableItems.end() )
00204           {
00205             if ( identical( *it, rhs ) )
00206               return *it;
00207           }
00208         }
00209         return PoolItem();
00210       }
00211 
00213       PoolItem identicalInstalledObj( const PoolItem & rhs ) const
00214       {
00215         if ( !installedEmpty() && rhs )
00216         {
00217           for_( it, _installedItems.begin(), _installedItems.end() )
00218           {
00219             if ( identical( *it, rhs ) )
00220               return *it;
00221           }
00222         }
00223         return PoolItem();
00224       }
00225 
00227       PoolItem theObj() const
00228       {
00229         PoolItem ret( candidateObj() );
00230         if ( ret )
00231           return ret;
00232         return installedObj();
00233       }
00234 
00236 
00237       bool availableEmpty() const
00238       { return _availableItems.empty(); }
00239 
00240       available_size_type availableSize() const
00241       { return _availableItems.size(); }
00242 
00243       available_const_iterator availableBegin() const
00244       { return _availableItems.begin(); }
00245 
00246       available_const_iterator availableEnd() const
00247       { return _availableItems.end(); }
00248 
00250 
00251       bool installedEmpty() const
00252       { return _installedItems.empty(); }
00253 
00254       installed_size_type installedSize() const
00255       { return _installedItems.size(); }
00256 
00257       installed_iterator installedBegin() const
00258       { return _installedItems.begin(); }
00259 
00260       installed_iterator installedEnd() const
00261       { return _installedItems.end(); }
00262 
00264 
00265       const PickList & picklist() const
00266       {
00267         if ( ! _picklistPtr )
00268         {
00269           _picklistPtr.reset( new PickList );
00270           // installed without identical avaialble first:
00271           for_( it, _installedItems.begin(), _installedItems.end() )
00272           {
00273             if ( ! identicalAvailable( *it ) )
00274               _picklistPtr->push_back( *it );
00275           }
00276           _picklistPtr->insert( _picklistPtr->end(), availableBegin(), availableEnd() );
00277         }
00278         return *_picklistPtr;
00279       }
00280 
00281       bool picklistEmpty() const
00282       { return picklist().empty(); }
00283 
00284       picklist_size_type picklistSize() const
00285       { return picklist().size(); }
00286 
00287       picklist_iterator picklistBegin() const
00288       { return picklist().begin(); }
00289 
00290       picklist_iterator picklistEnd() const
00291       { return picklist().end(); }
00292 
00294 
00295       bool isUnmaintained() const
00296       { return availableEmpty(); }
00297 
00298       bool multiversionInstall() const
00299       { return sat::Pool::instance().isMultiversion( ident() ); }
00300 
00301       bool pickInstall( const PoolItem & pi_r, ResStatus::TransactByValue causer_r, bool yesno_r );
00302 
00303       bool pickDelete( const PoolItem & pi_r, ResStatus::TransactByValue causer_r, bool yesno_r );
00304 
00305       Status pickStatus( const PoolItem & pi_r ) const;
00306 
00307       bool setPickStatus( const PoolItem & pi_r, Status state_r, ResStatus::TransactByValue causer_r );
00308 
00310 
00311       bool isUndetermined() const
00312       {
00313         PoolItem cand( candidateObj() );
00314         return ! cand || cand.isUndetermined();
00315       }
00316       bool isRelevant() const
00317       {
00318         PoolItem cand( candidateObj() );
00319         return cand && cand.isRelevant();
00320       }
00321       bool isSatisfied() const
00322        {
00323         PoolItem cand( candidateObj() );
00324         return cand && cand.isSatisfied();
00325       }
00326       bool isBroken() const
00327       {
00328         PoolItem cand( candidateObj() );
00329         return cand && cand.isBroken();
00330       }
00331 
00333       ResStatus::TransactByValue modifiedBy() const;
00334 
00336       bool hasLicenceConfirmed() const
00337       { return candidateObj() && candidateObj().status().isLicenceConfirmed(); }
00338 
00340       void setLicenceConfirmed( bool val_r )
00341       { if ( candidateObj() ) candidateObj().status().setLicenceConfirmed( val_r ); }
00342 
00343     private:
00344       PoolItem transactingInstalled() const
00345       {
00346         for_( it, installedBegin(), installedEnd() )
00347           {
00348             if ( (*it).status().transacts() )
00349               return (*it);
00350           }
00351         return PoolItem();
00352       }
00353 
00354       PoolItem transactingCandidate() const
00355       {
00356         for_( it, availableBegin(), availableEnd() )
00357           {
00358             if ( (*it).status().transacts() )
00359               return (*it);
00360           }
00361         return PoolItem();
00362       }
00363 
00364       PoolItem defaultCandidate() const
00365       {
00366         if ( ! ( multiversionInstall() || installedEmpty() ) )
00367         {
00368           // prefer the installed objects arch and vendor
00369           bool solver_allowVendorChange( ResPool::instance().resolver().allowVendorChange() );
00370           for ( installed_const_iterator iit = installedBegin();
00371                 iit != installedEnd(); ++iit )
00372           {
00373             PoolItem sameArch; // in case there's no same vendor at least stay with same arch.
00374             for ( available_const_iterator it = availableBegin();
00375                   it != availableEnd(); ++it )
00376             {
00377               // 'same arch' includes allowed changes to/from noarch.
00378               if ( (*iit)->arch() == (*it)->arch() || (*iit)->arch() == Arch_noarch || (*it)->arch() == Arch_noarch )
00379               {
00380                 if ( ! solver_allowVendorChange )
00381                 {
00382                   if ( VendorAttr::instance().equivalent( (*iit), (*it) ) )
00383                     return *it;
00384                   else if ( ! sameArch ) // remember best same arch in case no same vendor found
00385                      sameArch = *it;
00386                 }
00387                 else // same arch is sufficient
00388                   return *it;
00389               }
00390             }
00391             if ( sameArch )
00392               return sameArch;
00393           }
00394         }
00395         if ( _availableItems.empty() )
00396           return PoolItem();
00397 
00398         return *_availableItems.begin();
00399       }
00400 
00401       bool allCandidatesLocked() const
00402       {
00403         for ( available_const_iterator it = availableBegin();
00404               it != availableEnd(); ++it )
00405           {
00406             if ( ! (*it).status().isLocked() )
00407               return false;
00408           }
00409         return( ! _availableItems.empty() );
00410       }
00411 
00412       bool allInstalledLocked() const
00413       {
00414         for ( installed_const_iterator it = installedBegin();
00415               it != installedEnd(); ++it )
00416           {
00417             if ( ! (*it).status().isLocked() )
00418               return false;
00419           }
00420         return( ! _installedItems.empty() );
00421       }
00422 
00423 
00424     private:
00425       const IdString         _ident;
00426       const ResObject::Kind  _kind;
00427       const std::string      _name;
00428       InstalledItemSet       _installedItems;
00429       AvailableItemSet       _availableItems;
00431       PoolItem               _candidate;
00433       mutable scoped_ptr<PickList> _picklistPtr;
00434     };
00436 
00438     inline std::ostream & operator<<( std::ostream & str, const Selectable::Impl & obj )
00439     {
00440       return str << '[' << obj.kind() << ']' << obj.name() << ": " << obj.status()
00441                  << " (I " << obj.installedSize() << ")"
00442                  << " (A " << obj.availableSize() << ")"
00443                  << obj.candidateObj();
00444     }
00445 
00447     inline std::ostream & dumpOn( std::ostream & str, const Selectable::Impl & obj )
00448     {
00449       str << '[' << obj.kind() << ']' << obj.name() << ": " << obj.status()
00450           << ( obj.multiversionInstall() ? " (multiversion)" : "") << endl;
00451 
00452       if ( obj.installedEmpty() )
00453         str << "   (I 0) {}" << endl << "   ";
00454       else
00455       {
00456         PoolItem icand( obj.installedObj() );
00457         str << "   (I " << obj.installedSize() << ") {" << endl;
00458         for_( it, obj.installedBegin(), obj.installedEnd() )
00459         {
00460           char t = ' ';
00461           if ( *it == icand )
00462           {
00463             t = 'i';
00464           }
00465           str << " " << t << " " << *it << endl;
00466         }
00467         str << "}  ";
00468       }
00469 
00470       if ( obj.availableEmpty() )
00471       {
00472         str << "(A 0) {}" << endl << "   ";
00473       }
00474       else
00475       {
00476         PoolItem cand( obj.candidateObj() );
00477         PoolItem up( obj.updateCandidateObj() );
00478         str << "(A " << obj.availableSize() << ") {" << endl;
00479         for_( it, obj.availableBegin(), obj.availableEnd() )
00480         {
00481           char t = ' ';
00482           if ( *it == cand )
00483           {
00484             t = *it == up ? 'C' : 'c';
00485           }
00486           else if ( *it == up )
00487           {
00488             t = 'u';
00489           }
00490           str << " " << t << " " << *it << endl;
00491         }
00492         str << "}  ";
00493       }
00494 
00495       if ( obj.picklistEmpty() )
00496       {
00497         str << "(P 0) {}";
00498       }
00499       else
00500       {
00501         PoolItem cand( obj.candidateObj() );
00502         PoolItem up( obj.updateCandidateObj() );
00503         str << "(P " << obj.picklistSize() << ") {" << endl;
00504         for_( it, obj.picklistBegin(), obj.picklistEnd() )
00505         {
00506           char t = ' ';
00507           if ( *it == cand )
00508           {
00509             t = *it == up ? 'C' : 'c';
00510           }
00511           else if ( *it == up )
00512           {
00513             t = 'u';
00514           }
00515           str << " " << t << " " << *it << "\t" << obj.pickStatus( *it ) << endl;
00516         }
00517         str << "}  ";
00518       }
00519 
00520       return str;
00521     }
00523   } // namespace ui
00526 } // namespace zypp
00528 #endif // ZYPP_UI_SELECTABLEIMPL_H