Imported Upstream version 14.45.0
[platform/upstream/libzypp.git] / zypp / ui / SelectableImpl.h
index 841c875..4bafbf0 100644 (file)
 #ifndef ZYPP_UI_SELECTABLEIMPL_H
 #define ZYPP_UI_SELECTABLEIMPL_H
 
-#include <iosfwd>
+#include <iostream>
+#include "zypp/base/LogTools.h"
 
 #include "zypp/base/PtrTypes.h"
 
+#include "zypp/ResPool.h"
+#include "zypp/Resolver.h"
 #include "zypp/ui/Selectable.h"
 #include "zypp/ui/SelectableTraits.h"
 
+using std::endl;
+
 ///////////////////////////////////////////////////////////////////
 namespace zypp
 { /////////////////////////////////////////////////////////////////
@@ -36,29 +41,45 @@ namespace zypp
     */
     struct Selectable::Impl
     {
-      friend std::ostream & operator<<( std::ostream & str, const Selectable::Impl & obj );
-
     public:
 
-      typedef SelectableTraits::AvialableItemSet             AvialableItemSet;
-      typedef SelectableTraits::availableItem_iterator       availableItem_iterator;
-      typedef SelectableTraits::availableItem_const_iterator availableItem_const_iterator;
-      typedef SelectableTraits::availableItem_size_type      availableItem_size_type;
+      typedef SelectableTraits::AvailableItemSet         AvailableItemSet;
+      typedef SelectableTraits::available_iterator       available_iterator;
+      typedef SelectableTraits::available_const_iterator available_const_iterator;
+      typedef SelectableTraits::available_size_type      available_size_type;
+
+      typedef SelectableTraits::InstalledItemSet         InstalledItemSet;
+      typedef SelectableTraits::installed_iterator       installed_iterator;
+      typedef SelectableTraits::installed_const_iterator installed_const_iterator;
+      typedef SelectableTraits::installed_size_type      installed_size_type;
+
+      typedef SelectableTraits::PickList               PickList;
 
     public:
+      template <class _Iterator>
       Impl( const ResObject::Kind & kind_r,
             const std::string & name_r,
-            const PoolItem & installedItem_r,
-            availableItem_const_iterator availableBegin_r,
-            availableItem_const_iterator availableEnd_r )
-      : _kind( kind_r )
+            _Iterator begin_r,
+            _Iterator end_r )
+      : _ident( sat::Solvable::SplitIdent( kind_r, name_r ).ident() )
+      , _kind( kind_r )
       , _name( name_r )
-      , _installedItem( installedItem_r )
-      , _availableItems( availableBegin_r, availableEnd_r )
-      {}
+      {
+        for_( it, begin_r, end_r )
+        {
+          if ( it->status().isInstalled() )
+            _installedItems.insert( *it );
+          else
+            _availableItems.insert( *it );
+        }
+      }
 
     public:
       /**  */
+      IdString ident() const
+      { return _ident; }
+
+      /**  */
       ResObject::Kind kind() const
       { return _kind; }
 
@@ -70,43 +91,342 @@ namespace zypp
       Status status() const;
 
       /**  */
-      bool set_status( const Status state_r );
+      bool setStatus( Status state_r, ResStatus::TransactByValue causer_r );
 
-      /** Installed object. */
+      /** Installed object (transacting ot highest version). */
       PoolItem installedObj() const
-      { return _installedItem; }
+      {
+        if ( installedEmpty() )
+          return PoolItem();
+        PoolItem ret( transactingInstalled() );
+        return ret ? ret : *_installedItems.begin();
+      }
 
       /** Best among available objects.
-       * \note Transacted Objects prefered, Status calculation relies on it.
-       * \note Need sort order based on (arch,edition), requires arch compat lists.
+       * The transacting candidate or the one scheduled to receive
+       * the transact bit.
       */
       PoolItem candidateObj() const
-      { return( _availableItems.empty() ? PoolItem() : *_availableItems.begin() ); }
+      {
+        PoolItem ret( transactingCandidate() );
+        if ( ret )
+          return ret;
+        return _candidate ? _candidate : defaultCandidate();
+      }
+
+      /** Set a userCandidate (out of available objects).
+       * \return The new userCandidate or NULL if choice was invalid
+       * (not among availableObjs).
+      */
+      PoolItem setCandidate( const PoolItem & newCandidate_r, ResStatus::TransactByValue causer_r );
+
+      /** The best candidate provided by a specific \ref Repository, if there is one.
+       * In contrary to \ref candidateObj, this may return no item even if
+       * there are available objects. This simply means the \ref Repository
+       * does not provide this object.
+       */
+      PoolItem candidateObjFrom( Repository repo_r ) const
+      {
+        for_( it, availableBegin(), availableEnd() )
+        {
+          if ( (*it)->repository() == repo_r )
+            return *it;
+        }
+        return PoolItem();
+      }
+
+      /** The best candidate for update, if there is one.
+       * In contrary to \ref candidateObj, this may return no item even if
+       * there are available objects. This simply means the best object is
+       * already installed, and all available objects violate at least one
+       * update policy.
+       */
+      PoolItem updateCandidateObj() const
+      {
+       PoolItem defaultCand( defaultCandidate() );
+
+       // multiversionInstall: This returns the candidate for the last
+       // instance installed. Actually we'd need a list here.
+
+        if ( installedEmpty() || ! defaultCand )
+          return defaultCand;
+        // Here: installed and defaultCand are non NULL and it's not a
+        //       multiversion install.
+
+        PoolItem installed( installedObj() );
+        // check vendor change
+        if ( ! ( ResPool::instance().resolver().allowVendorChange()
+                 || VendorAttr::instance().equivalent( defaultCand->vendor(), installed->vendor() ) ) )
+          return PoolItem();
+
+        // check arch change (arch noarch changes are allowed)
+        if ( defaultCand->arch() != installed->arch()
+           && ! ( defaultCand->arch() == Arch_noarch || installed->arch() == Arch_noarch ) )
+          return PoolItem();
+
+        // check greater edition
+        if ( defaultCand->edition() <= installed->edition() )
+          return PoolItem();
+
+        return defaultCand;
+      }
+
+      /** \copydoc Selectable::highestAvailableVersionObj()const */
+      PoolItem highestAvailableVersionObj() const
+      {
+        PoolItem ret;
+        for_( it, availableBegin(), availableEnd() )
+        {
+          if ( !ret || (*it).satSolvable().edition() > ret.satSolvable().edition() )
+            ret = *it;
+        }
+        return ret;
+      }
+
+      /** \copydoc Selectable::identicalAvailable( const PoolItem & )const */
+      bool identicalAvailable( const PoolItem & rhs ) const
+      { return bool(identicalAvailableObj( rhs )); }
+
+      /** \copydoc Selectable::identicalInstalled( const PoolItem & )const */
+      bool identicalInstalled( const PoolItem & rhs ) const
+      { return bool(identicalInstalledObj( rhs )); }
+
+      /** \copydoc Selectable::identicalAvailableObj( const PoolItem & rhs ) const */
+      PoolItem identicalAvailableObj( const PoolItem & rhs ) const
+      {
+        if ( !availableEmpty() && rhs )
+        {
+          for_( it, _availableItems.begin(), _availableItems.end() )
+          {
+            if ( identical( *it, rhs ) )
+              return *it;
+          }
+        }
+        return PoolItem();
+      }
+
+      /** \copydoc Selectable::identicalInstalledObj( const PoolItem & rhs ) const */
+      PoolItem identicalInstalledObj( const PoolItem & rhs ) const
+      {
+        if ( !installedEmpty() && rhs )
+        {
+          for_( it, _installedItems.begin(), _installedItems.end() )
+          {
+            if ( identical( *it, rhs ) )
+              return *it;
+          }
+        }
+        return PoolItem();
+      }
 
       /** Best among all objects. */
       PoolItem theObj() const
       {
         PoolItem ret( candidateObj() );
-        return( ret ? ret : _installedItem );
+        if ( ret )
+          return ret;
+        return installedObj();
       }
 
-      /**  */
-      availableItem_size_type availableObjs() const
+      ////////////////////////////////////////////////////////////////////////
+
+      bool availableEmpty() const
+      { return _availableItems.empty(); }
+
+      available_size_type availableSize() const
       { return _availableItems.size(); }
 
-      /**  */
-      availableItem_const_iterator availableBegin() const
+      available_const_iterator availableBegin() const
       { return _availableItems.begin(); }
 
-      /**  */
-      availableItem_const_iterator availableEnd() const
+      available_const_iterator availableEnd() const
       { return _availableItems.end(); }
 
+      ////////////////////////////////////////////////////////////////////////
+
+      bool installedEmpty() const
+      { return _installedItems.empty(); }
+
+      installed_size_type installedSize() const
+      { return _installedItems.size(); }
+
+      installed_iterator installedBegin() const
+      { return _installedItems.begin(); }
+
+      installed_iterator installedEnd() const
+      { return _installedItems.end(); }
+
+      ////////////////////////////////////////////////////////////////////////
+
+      const PickList & picklist() const
+      {
+        if ( ! _picklistPtr )
+        {
+          _picklistPtr.reset( new PickList );
+          // installed without identical avaialble first:
+          for_( it, _installedItems.begin(), _installedItems.end() )
+          {
+            if ( ! identicalAvailable( *it ) )
+              _picklistPtr->push_back( *it );
+          }
+          _picklistPtr->insert( _picklistPtr->end(), availableBegin(), availableEnd() );
+        }
+        return *_picklistPtr;
+      }
+
+      bool picklistEmpty() const
+      { return picklist().empty(); }
+
+      picklist_size_type picklistSize() const
+      { return picklist().size(); }
+
+      picklist_iterator picklistBegin() const
+      { return picklist().begin(); }
+
+      picklist_iterator picklistEnd() const
+      { return picklist().end(); }
+
+      ////////////////////////////////////////////////////////////////////////
+
+      bool isUnmaintained() const
+      { return availableEmpty(); }
+
+      bool multiversionInstall() const
+      { return sat::Pool::instance().isMultiversion( ident() ); }
+
+      bool pickInstall( const PoolItem & pi_r, ResStatus::TransactByValue causer_r, bool yesno_r );
+
+      bool pickDelete( const PoolItem & pi_r, ResStatus::TransactByValue causer_r, bool yesno_r );
+
+      Status pickStatus( const PoolItem & pi_r ) const;
+
+      bool setPickStatus( const PoolItem & pi_r, Status state_r, ResStatus::TransactByValue causer_r );
+
+      ////////////////////////////////////////////////////////////////////////
+
+      bool isUndetermined() const
+      {
+        PoolItem cand( candidateObj() );
+        return ! cand || cand.isUndetermined();
+      }
+      bool isRelevant() const
+      {
+        PoolItem cand( candidateObj() );
+        return cand && cand.isRelevant();
+      }
+      bool isSatisfied() const
+       {
+        PoolItem cand( candidateObj() );
+        return cand && cand.isSatisfied();
+      }
+      bool isBroken() const
+      {
+        PoolItem cand( candidateObj() );
+        return cand && cand.isBroken();
+      }
+
+      /** Return who caused the modification. */
+      ResStatus::TransactByValue modifiedBy() const;
+
+      /** Return value of LicenceConfirmed bit. */
+      bool hasLicenceConfirmed() const
+      { return candidateObj() && candidateObj().status().isLicenceConfirmed(); }
+
+      /** Set LicenceConfirmed bit. */
+      void setLicenceConfirmed( bool val_r )
+      { if ( candidateObj() ) candidateObj().status().setLicenceConfirmed( val_r ); }
+
+    private:
+      PoolItem transactingInstalled() const
+      {
+        for_( it, installedBegin(), installedEnd() )
+          {
+            if ( (*it).status().transacts() )
+              return (*it);
+          }
+        return PoolItem();
+      }
+
+      PoolItem transactingCandidate() const
+      {
+        for_( it, availableBegin(), availableEnd() )
+          {
+            if ( (*it).status().transacts() )
+              return (*it);
+          }
+        return PoolItem();
+      }
+
+      PoolItem defaultCandidate() const
+      {
+        if ( ! installedEmpty() )
+        {
+          // prefer the installed objects arch and vendor
+          bool solver_allowVendorChange( ResPool::instance().resolver().allowVendorChange() );
+          for ( installed_const_iterator iit = installedBegin();
+                iit != installedEnd(); ++iit )
+          {
+            PoolItem sameArch; // in case there's no same vendor at least stay with same arch.
+            for ( available_const_iterator it = availableBegin();
+                  it != availableEnd(); ++it )
+            {
+              // 'same arch' includes allowed changes to/from noarch.
+              if ( (*iit)->arch() == (*it)->arch() || (*iit)->arch() == Arch_noarch || (*it)->arch() == Arch_noarch )
+              {
+                if ( ! solver_allowVendorChange )
+                {
+                  if ( VendorAttr::instance().equivalent( (*iit), (*it) ) )
+                    return *it;
+                  else if ( ! sameArch ) // remember best same arch in case no same vendor found
+                     sameArch = *it;
+                }
+                else // same arch is sufficient
+                  return *it;
+              }
+            }
+            if ( sameArch )
+              return sameArch;
+          }
+        }
+        if ( _availableItems.empty() )
+          return PoolItem();
+
+        return *_availableItems.begin();
+      }
+
+      bool allCandidatesLocked() const
+      {
+        for ( available_const_iterator it = availableBegin();
+              it != availableEnd(); ++it )
+          {
+            if ( ! (*it).status().isLocked() )
+              return false;
+          }
+        return( ! _availableItems.empty() );
+      }
+
+      bool allInstalledLocked() const
+      {
+        for ( installed_const_iterator it = installedBegin();
+              it != installedEnd(); ++it )
+          {
+            if ( ! (*it).status().isLocked() )
+              return false;
+          }
+        return( ! _installedItems.empty() );
+      }
+
+
     private:
-      ResObject::Kind  _kind;
-      std::string      _name;
-      PoolItem         _installedItem;
-      AvialableItemSet _availableItems;
+      const IdString         _ident;
+      const ResObject::Kind  _kind;
+      const std::string      _name;
+      InstalledItemSet       _installedItems;
+      AvailableItemSet       _availableItems;
+      //! The object selected by setCandidateObj() method.
+      PoolItem               _candidate;
+      //! lazy initialized picklist
+      mutable scoped_ptr<PickList> _picklistPtr;
     };
     ///////////////////////////////////////////////////////////////////
 
@@ -114,10 +434,87 @@ namespace zypp
     inline std::ostream & operator<<( std::ostream & str, const Selectable::Impl & obj )
     {
       return str << '[' << obj.kind() << ']' << obj.name() << ": " << obj.status()
-                 << " (I " << obj._installedItem << ")"
-                 << " (A " << obj._availableItems.size() << ")";
+                 << " (I " << obj.installedSize() << ")"
+                 << " (A " << obj.availableSize() << ")"
+                 << obj.candidateObj();
     }
 
+    /** \relates Selectable::Impl Stream output */
+    inline std::ostream & dumpOn( std::ostream & str, const Selectable::Impl & obj )
+    {
+      str << '[' << obj.kind() << ']' << obj.name() << ": " << obj.status()
+          << ( obj.multiversionInstall() ? " (multiversion)" : "") << endl;
+
+      if ( obj.installedEmpty() )
+        str << "   (I 0) {}" << endl << "   ";
+      else
+      {
+        PoolItem icand( obj.installedObj() );
+        str << "   (I " << obj.installedSize() << ") {" << endl;
+        for_( it, obj.installedBegin(), obj.installedEnd() )
+        {
+          char t = ' ';
+          if ( *it == icand )
+          {
+            t = 'i';
+          }
+          str << " " << t << " " << *it << endl;
+        }
+        str << "}  ";
+      }
+
+      if ( obj.availableEmpty() )
+      {
+        str << "(A 0) {}" << endl << "   ";
+      }
+      else
+      {
+        PoolItem cand( obj.candidateObj() );
+        PoolItem up( obj.updateCandidateObj() );
+        str << "(A " << obj.availableSize() << ") {" << endl;
+        for_( it, obj.availableBegin(), obj.availableEnd() )
+        {
+          char t = ' ';
+          if ( *it == cand )
+          {
+            t = *it == up ? 'C' : 'c';
+          }
+          else if ( *it == up )
+          {
+            t = 'u';
+          }
+          str << " " << t << " " << *it << endl;
+        }
+        str << "}  ";
+      }
+
+      if ( obj.picklistEmpty() )
+      {
+        str << "(P 0) {}";
+      }
+      else
+      {
+        PoolItem cand( obj.candidateObj() );
+        PoolItem up( obj.updateCandidateObj() );
+        str << "(P " << obj.picklistSize() << ") {" << endl;
+        for_( it, obj.picklistBegin(), obj.picklistEnd() )
+        {
+          char t = ' ';
+          if ( *it == cand )
+          {
+            t = *it == up ? 'C' : 'c';
+          }
+          else if ( *it == up )
+          {
+            t = 'u';
+          }
+          str << " " << t << " " << *it << "\t" << obj.pickStatus( *it ) << endl;
+        }
+        str << "}  ";
+      }
+
+      return str;
+    }
     /////////////////////////////////////////////////////////////////
   } // namespace ui
   ///////////////////////////////////////////////////////////////////