Provide setPickStatus implementation
authorMichael Andres <ma@suse.de>
Fri, 4 Dec 2009 12:53:22 +0000 (13:53 +0100)
committerMichael Andres <ma@suse.de>
Fri, 4 Dec 2009 12:53:22 +0000 (13:53 +0100)
zypp/ui/Selectable.cc
zypp/ui/Selectable.h
zypp/ui/SelectableImpl.cc
zypp/ui/SelectableImpl.h

index 94ec2d9..bcb86a9 100644 (file)
@@ -64,7 +64,7 @@ namespace zypp
     Status Selectable::status() const
     { return _pimpl->status(); }
 
-    bool Selectable::setStatus( const Status state_r, ResStatus::TransactByValue causer_r )
+    bool Selectable::setStatus( Status state_r, ResStatus::TransactByValue causer_r )
     { return _pimpl->setStatus( state_r, causer_r ); }
 
     PoolItem Selectable::installedObj() const
@@ -154,7 +154,7 @@ namespace zypp
     bool Selectable::multiversionInstall() const
     { return _pimpl->multiversionInstall(); }
 
-    bool Selectable::setPickStatus( const PoolItem & pi_r, const Status state_r, ResStatus::TransactByValue causer_r )
+    bool Selectable::setPickStatus( const PoolItem & pi_r, Status state_r, ResStatus::TransactByValue causer_r )
     { return _pimpl->setPickStatus( pi_r, state_r, causer_r ); }
 
     Status Selectable::pickStatus( const PoolItem & pi_r ) const
index 62ef05f..b439780 100644 (file)
@@ -309,7 +309,7 @@ namespace zypp
       bool multiversionInstall() const;
 
       /** */
-      bool setPickStatus( const PoolItem & pi_r, const Status state_r, ResStatus::TransactByValue causer_r = ResStatus::USER );
+      bool setPickStatus( const PoolItem & pi_r, Status state_r, ResStatus::TransactByValue causer_r = ResStatus::USER );
 
       /** Compute the \ref ui::Status for an individual PoolItem.
        * This just takes into account the item and any identical
@@ -448,7 +448,7 @@ namespace zypp
        * Try to set a new Status.
        * Returns \c false if the transitions is not allowed.
        */
-      bool setStatus( const Status state_r, ResStatus::TransactByValue causer_r = ResStatus::USER );
+      bool setStatus( Status state_r, ResStatus::TransactByValue causer_r = ResStatus::USER );
 
       /** Return who caused the modification. */
       ResStatus::TransactByValue modifiedBy() const;
index 5ecbfe5..29c129b 100644 (file)
@@ -23,6 +23,102 @@ namespace zypp
   namespace ui
   { /////////////////////////////////////////////////////////////////
 
+    /** Simple ResStatus backup stack.
+     * \ref restore simply rewinds all remembered status.
+    */
+    class StatusBackup
+    {
+      public:
+        typedef ResStatus::TransactByValue Causer;
+
+      public:
+        /** Backup status. */
+        ResStatus & backup( ResStatus & status_r )
+        {
+          _backup.push_back( status_r );
+          return status_r;
+        }
+        /** \overload */
+        ResStatus & backup( const PoolItem & pi_r )
+        { return backup( pi_r.status() ); }
+
+        /** Backup status. */
+        ResStatus & operator()( ResStatus & status_r )
+        { return backup( status_r ); }
+        /** \overload */
+        ResStatus & operator()( const PoolItem & pi_r )
+        { return backup( pi_r.status() ); }
+
+        /** Restore all status. */
+        bool restore()
+        {
+          for_( rit, _backup.rbegin(), _backup.rend() )
+            rit->replay();
+          return false; // restore is done on error - return restore();
+        }
+
+      public:
+        /** lowlevel \c ResStatus::setTransact */
+        bool setTransact( const PoolItem & pi_r, bool yesno_r, Causer causer_r )
+        { return backup( pi_r ).setTransact( yesno_r, causer_r ); }
+
+        /** lowlevel \c ResStatus::setLock */
+        bool setLock( const PoolItem & pi_r, bool yesno_r, Causer causer_r )
+        { return backup( pi_r ).setLock( yesno_r, causer_r ); }
+
+        /** lowlevel \c ResStatus::setTransact(true). */
+        bool setTransactTrue( const PoolItem & pi_r, Causer causer_r )
+        { return setTransact( pi_r, true, causer_r ); }
+
+        /** lowlevel \c ResStatus::setTransact(false). */
+        bool setTransactFalse( const PoolItem & pi_r, Causer causer_r )
+        { return setTransact( pi_r, false, causer_r ); }
+
+      public:
+        /** highevel set transact (force unlock). */
+        bool transact( const PoolItem & pi_r, Causer causer_r )
+        {
+          ResStatus & status( backup( pi_r ) );
+          if ( ! status.setLock( false, causer_r ) ) return false;
+          if ( ! status.setTransact( true, causer_r ) ) return false;
+          return true;
+        }
+
+        /** highlevel set locked. */
+        bool lock( const PoolItem & pi_r, Causer causer_r )
+        {
+          ResStatus & status( backup( pi_r ) );
+          if ( ! status.setTransact( false, causer_r ) ) return false;
+          if ( ! status.setLock( true, causer_r ) ) return false;
+          return true;
+        }
+
+        /** highlevel unlock (also unsets transact). */
+        bool unlock( const PoolItem & pi_r, Causer causer_r )
+        {
+          ResStatus & status( backup( pi_r ) );
+          if ( ! status.setTransact( false, causer_r ) ) return false;
+          if ( ! status.setLock( false, causer_r ) ) return false;
+          return true;
+        }
+
+        /** Highlevel action. */
+        typedef bool (StatusBackup::*Action)( const PoolItem &, Causer );
+
+        /** Highlevel action on range of items. */
+        template <class _Iter>
+        bool forEach( _Iter begin_r, _Iter end_r, Action action_r, Causer causer_r )
+        {
+          for_( it, begin_r, end_r )
+            if ( ! (this->*action_r)( *it, causer_r ) )
+              return false;
+          return true;
+        }
+
+      private:
+        std::vector<resstatus::StatusBackup> _backup;
+    };
+
     ///////////////////////////////////////////////////////////////////
     //
     // CLASS NAME : StatusHelper
@@ -68,7 +164,7 @@ namespace zypp
             ResStatus & inststatus( backup( inst.status() ) );
             if ( ! inststatus.setTransact( false, causer ) ) return restore();
             if ( ! inststatus.setLock    ( false, causer ) ) return restore();
-            if ( ! cand->installOnly() )
+            if ( ! cand->multiversionInstall() )
             {
               // This is what the solver most probabely will do.
               // If we are wrong the solver will correct it. But
@@ -177,29 +273,8 @@ namespace zypp
       ResStatus::TransactByValue causer;
 
     private:
-      // No backup replay needed if causer is user,
-      // because actions should always succeed.
-
-      ResStatus & backup( ResStatus & status_r )
-      {
-        if ( causer != ResStatus::USER )
-          _backup.push_back( status_r );
-        return status_r;
-      }
-
-      bool restore()
-      {
-        if ( causer != ResStatus::USER )
-        {
-          for_( rit, _backup.rbegin(), _backup.rend() )
-          {
-            rit->replay();
-          }
-        }
-        return false; // restore is done on error - return restore();
-      }
-
-      std::vector<resstatus::StatusBackup> _backup;
+      bool restore() { return backup.restore(); }
+      StatusBackup backup;
     };
     ///////////////////////////////////////////////////////////////////
 
@@ -242,7 +317,7 @@ namespace zypp
       return S_NoInst;
     }
 
-    bool Selectable::Impl::setStatus( const Status state_r, ResStatus::TransactByValue causer_r )
+    bool Selectable::Impl::setStatus( Status state_r, ResStatus::TransactByValue causer_r )
     {
       StatusHelper self( *this, causer_r );
 
@@ -324,9 +399,101 @@ namespace zypp
     }
 
     ///////////////////////////////////////////////////////////////////
-
-    bool Selectable::Impl::setPickStatus( const PoolItem & pi_r, const Status state_r, ResStatus::TransactByValue causer_r )
+    bool Selectable::Impl::setPickStatus( const PoolItem & pi_r, Status state_r, ResStatus::TransactByValue causer_r )
     {
+      if ( pi_r.satSolvable().ident() == ident() )
+        return false;  // not my PoolItem
+
+      if ( ! multiversionInstall() )
+        return false;  // We're not yet ready for this.
+      // TODO: Without multiversionInstall take care at most ONE available is set
+      // to install. Upon install ALL installed get deleted. Only upon deletetion
+      // one might pick individual versions (but more than one would be an error here).
+
+      StatusBackup backup;
+      std::vector<PoolItem> i;
+      std::vector<PoolItem> a;
+
+      for_( it, installedBegin(), installedEnd() )
+        if ( identical( *it, pi_r ) )
+          i.push_back( *it );
+      for_( it, availableBegin(), availableEnd() )
+        if ( identical( *it, pi_r ) )
+          i.push_back( *it );
+
+      switch ( state_r )
+      {
+        case S_Protected:
+          if ( causer_r == ResStatus::USER && ! i.empty() )
+          {
+            if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::lock, causer_r ) ) return backup.restore();
+            if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::setTransactFalse, causer_r ) ) return backup.restore();
+            return true;
+          }
+          break;
+
+        case S_Taboo:
+          if ( causer_r == ResStatus::USER && ! a.empty() )
+          {
+            if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::lock, causer_r ) ) return backup.restore();
+            return true;
+          }
+          break;
+
+        case S_AutoDel:
+        case S_AutoInstall:
+        case S_AutoUpdate:
+          // Auto level is SOLVER level. UI may query, but not
+          // set at this level.
+          break;
+
+        case S_Del:
+          if ( ! i.empty() )
+          {
+            if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::transact, causer_r ) ) return backup.restore();
+            if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::setTransactFalse, causer_r ) ) return backup.restore();
+            return true;
+          }
+          break;
+
+        case S_Install:
+          if ( i.empty() && ! a.empty() )
+          {
+            // maybe unlock candidate only?
+            if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
+            const PoolItem & cand( pi_r.status().isInstalled() ? *a.begin() : pi_r ); // status already backed up above
+            if ( ! cand.status().setTransact( true, causer_r ) ) return backup.restore();
+            return true;
+          }
+          break;
+
+        case S_Update:
+          if ( ! i.empty() && ! a.empty() )
+          {
+            if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
+            if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::setTransactTrue, ResStatus::SOLVER ) ) return backup.restore();
+
+            return true;
+          }
+          break;
+
+        case S_KeepInstalled:
+          if ( ! i.empty()  )
+          {
+            if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
+            if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
+            return true;
+          }
+          break;
+
+        case S_NoInst:
+          if ( i.empty()  )
+          {
+            if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
+            return true;
+          }
+          break;
+      }
       return false;
     }
 
index 3f437b5..9fc2e75 100644 (file)
@@ -91,7 +91,7 @@ namespace zypp
       Status status() const;
 
       /**  */
-      bool setStatus( const Status state_r, ResStatus::TransactByValue causer_r );
+      bool setStatus( Status state_r, ResStatus::TransactByValue causer_r );
 
       /** Installed object (transacting ot highest version). */
       PoolItem installedObj() const
@@ -285,7 +285,7 @@ namespace zypp
       bool multiversionInstall() const
       { return theObj().satSolvable().multiversionInstall(); }
 
-      bool setPickStatus( const PoolItem & pi_r, const Status state_r, ResStatus::TransactByValue causer_r );
+      bool setPickStatus( const PoolItem & pi_r, Status state_r, ResStatus::TransactByValue causer_r );
 
       Status pickStatus( const PoolItem & pi_r ) const;