Imported Upstream version 16.3.2
[platform/upstream/libzypp.git] / zypp / ui / SelectableImpl.cc
index 29c129b..5d2a9d6 100644 (file)
@@ -102,12 +102,34 @@ namespace zypp
           return true;
         }
 
+        /** highlevel remove transact from non-multiversion packages. */
+        bool unsetNonMultiTransact(  const PoolItem & pi_r, Causer causer_r )
+       {
+         ResStatus & status( backup( pi_r ) );
+         if ( status.transacts() && ! pi_r.multiversionInstall() )
+         {
+           if ( ! status.setTransact( false, causer_r ) ) return false;
+         }
+         return true;
+       }
+
+        /** highlevel remove transact from multiversion packages. */
+        bool unsetMultiTransact(  const PoolItem & pi_r, Causer causer_r )
+       {
+         ResStatus & status( backup( pi_r ) );
+         if ( status.transacts() && pi_r.multiversionInstall() )
+         {
+           if ( ! status.setTransact( 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 )
+        template <class TIter>
+        bool forEach( TIter begin_r, TIter end_r, Action action_r, Causer causer_r )
         {
           for_( it, begin_r, end_r )
             if ( ! (this->*action_r)( *it, causer_r ) )
@@ -123,7 +145,7 @@ namespace zypp
     //
     // CLASS NAME : StatusHelper
     //
-    /**
+    /** \todo Unify status and pickStatus.
     */
     struct StatusHelper
     {
@@ -140,10 +162,10 @@ namespace zypp
       // Queries
       //
       bool hasInstalled() const
-      { return inst; }
+      { return bool(inst); }
 
       bool hasCandidate() const
-      { return cand; }
+      { return bool(cand); }
 
       bool hasInstalledOnly() const
       { return inst && !cand; }
@@ -161,16 +183,19 @@ namespace zypp
         if ( cand )
         {
           if ( inst ) {
-            ResStatus & inststatus( backup( inst.status() ) );
-            if ( ! inststatus.setTransact( false, causer ) ) return restore();
-            if ( ! inststatus.setLock    ( false, causer ) ) return restore();
-            if ( ! cand->multiversionInstall() )
+            for_( it, _impl.installedBegin(), _impl.installedEnd() )
             {
+              ResStatus & inststatus( backup( it->status() ) );
+              if ( ! inststatus.setTransact( false, causer ) ) return restore();
+              if ( ! inststatus.setLock    ( false, causer ) ) return restore();
+              if ( ! cand->multiversionInstall() )
+              {
               // This is what the solver most probabely will do.
               // If we are wrong the solver will correct it. But
               // this way we will get a better disk usage result,
               // even if no autosolving is on.
-              inststatus.setTransact( true, ResStatus::SOLVER );
+                inststatus.setTransact( true, ResStatus::SOLVER );
+              }
             }
           }
           if ( ! unlockCandidates() ) return restore();
@@ -186,9 +211,12 @@ namespace zypp
         if ( inst )
         {
           if ( ! resetTransactingCandidates() ) return restore();
-          ResStatus & inststatus( backup( inst.status() ) );
-          if ( ! inststatus.setLock( false, causer ) ) return restore();
-          if ( ! inststatus.setTransact( true, causer ) ) return restore();
+          for_( it, _impl.installedBegin(), _impl.installedEnd() )
+          {
+            ResStatus & inststatus( backup( it->status() ) );
+            if ( ! inststatus.setLock( false, causer ) ) return restore();
+            if ( ! inststatus.setTransact( true, causer ) ) return restore();
+          }
           return true;
         }
         return false;
@@ -198,9 +226,12 @@ namespace zypp
       {
         if ( inst )
         {
-          ResStatus & inststatus( backup( inst.status() ) );
-          if ( ! inststatus.setTransact( false, causer ) ) return restore();
-          if ( ! inststatus.setLock( false, causer ) ) return restore();
+          for_( it, _impl.installedBegin(), _impl.installedEnd() )
+          {
+            ResStatus & inststatus( backup( it->status() ) );
+            if ( ! inststatus.setTransact( false, causer ) ) return restore();
+            if ( ! inststatus.setLock( false, causer ) ) return restore();
+          }
         }
         if ( ! unlockCandidates() ) return restore();
         return true;
@@ -213,8 +244,12 @@ namespace zypp
 
         if ( inst ) {
           resetTransactingCandidates();
-          inst.status().setTransact( false, causer );
-          return inst.status().setLock( true, causer );
+          for_( it, _impl.installedBegin(), _impl.installedEnd() )
+          {
+            it->status().setTransact( false, causer );
+            it->status().setLock( true, causer );
+          }
+          return true;
         } else
           return false;
       }
@@ -300,7 +335,7 @@ namespace zypp
           return( installedObj().status().isByUser() ? S_Del : S_AutoDel );
         }
 
-      if ( installedObj() && installedObj().status().isLocked() )
+      if ( installedObj() && allInstalledLocked() )
          return S_Protected;
 
       if ( !installedObj() && allCandidatesLocked() )
@@ -399,17 +434,24 @@ namespace zypp
     }
 
     ///////////////////////////////////////////////////////////////////
+
+    bool Selectable::Impl::pickInstall( const PoolItem & pi_r, ResStatus::TransactByValue causer_r, bool yesno_r )
+    {
+      if ( identicalInstalled( pi_r ) )
+        return setPickStatus( pi_r, ( yesno_r ? S_Update : S_KeepInstalled ), causer_r );
+      return setPickStatus( pi_r, ( yesno_r ? S_Install : S_NoInst ), causer_r );
+    }
+
+    bool Selectable::Impl::pickDelete( const PoolItem & pi_r, ResStatus::TransactByValue causer_r, bool yesno_r )
+    {
+      return setPickStatus( pi_r, ( yesno_r ? S_Del : S_KeepInstalled ), causer_r );
+    }
+
     bool Selectable::Impl::setPickStatus( const PoolItem & pi_r, Status state_r, ResStatus::TransactByValue causer_r )
     {
-      if ( pi_r.satSolvable().ident() == ident() )
+      if ( pi_r.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;
@@ -419,7 +461,7 @@ namespace zypp
           i.push_back( *it );
       for_( it, availableBegin(), availableEnd() )
         if ( identical( *it, pi_r ) )
-          i.push_back( *it );
+          a.push_back( *it );
 
       switch ( state_r )
       {
@@ -456,26 +498,57 @@ namespace zypp
           }
           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_Install:
+         if ( i.empty() && ! a.empty() )
+         {
+           const PoolItem & cand( pi_r.status().isInstalled() ? *a.begin() : pi_r );
+           if ( cand.multiversionInstall() )
+           {
+             if ( ! backup.forEach( availableBegin(), availableEnd(), &StatusBackup::unsetNonMultiTransact, causer_r ) ) return backup.restore();
+             // maybe unlock candidate only?
+             if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
+             if ( ! cand.status().setTransact( true, causer_r ) ) return backup.restore();
+             return true;
+           }
+           else
+           {
+             // For non-multiversion use ordinary setStatus
+             // NOTE that S_Update/S_Install here depends on !installedEmpty()
+             // and not on picklists identicalInstalled.
+             if ( ! backup.forEach( availableBegin(), availableEnd(), &StatusBackup::unsetMultiTransact, causer_r ) ) return backup.restore();
+             if ( ! setCandidate( cand, causer_r ) )  return backup.restore();
+             if ( ! setStatus( installedEmpty() ? S_Install : S_Update, causer_r ) )  return backup.restore();
+             return true;
+           }
+         }
+         break;
+
+       case S_Update:
+         if ( ! i.empty() && ! a.empty() )
+         {
+           const PoolItem & cand( pi_r.status().isInstalled() ? *a.begin() : pi_r );
+           if ( cand.multiversionInstall() )
+           {
+             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();
+             if ( ! backup.forEach( availableBegin(), availableEnd(), &StatusBackup::unsetNonMultiTransact, causer_r ) ) return backup.restore();
+             // maybe unlock candidate only?
+             if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
+             if ( ! cand.status().setTransact( true, causer_r ) ) return backup.restore();
+             return true;
+           }
+           else
+           {
+             // For non-multiversion use ordinary setStatus
+             // NOTE that S_Update/S_Install here depends on !installedEmpty()
+             // and not on picklists identicalInstalled.
+             if ( ! backup.forEach( availableBegin(), availableEnd(), &StatusBackup::unsetMultiTransact, causer_r ) ) return backup.restore();
+             if ( ! setCandidate( cand, causer_r ) )  return backup.restore();
+             if ( ! setStatus( installedEmpty() ? S_Install : S_Update, causer_r ) )  return backup.restore();
+             return true;
+           }
+         }
+         break;
 
         case S_KeepInstalled:
           if ( ! i.empty()  )
@@ -499,73 +572,69 @@ namespace zypp
 
     Status Selectable::Impl::pickStatus( const PoolItem & pi_r ) const
     {
-      if ( pi_r.satSolvable().ident() == ident() )
-      {
-        if ( pi_r.satSolvable().isSystem() )
-        {
-          // have installed!
-          if ( pi_r.status().isLocked() )
-            return S_Protected;
+      if ( pi_r.satSolvable().ident() != ident() )
+        return Status(-1); // not my PoolItem
 
-          // at least one identical available transacing?
-          for_( it, _availableItems.begin(), _availableItems.end() )
-          {
-            if ( identical( *it, pi_r ) )
-            {
-              if ( (*it).status().transacts() )
-                return( (*it).status().isByUser() ? S_Update : S_AutoUpdate );
-            }
-          }
+      std::vector<PoolItem> i;
+      std::vector<PoolItem> a;
+      PoolItem ti;
+      PoolItem ta;
 
-          // no update, so maybe delete?
-          if ( pi_r.status().transacts() )
-            return ( pi_r.status().isByUser() ? S_Del : S_AutoDel );
+      for_( it, installedBegin(), installedEnd() )
+        if ( identical( *it, pi_r ) )
+        {
+          i.push_back( *it );
+          if ( ! ti && it->status().transacts() )
+            ti = *it;
+        }
 
-          // keep
-          return S_KeepInstalled;
+      for_( it, availableBegin(), availableEnd() )
+        if ( identical( *it, pi_r ) )
+        {
+          a.push_back( *it );
+          if ( ! ta && it->status().transacts() )
+            ta = *it;
         }
+
+      if ( ta )
+      {
+        if ( ta.status().isByUser() )
+          return( i.empty() ? S_Install : S_Update );
         else
-        {
-          // have available!
-          if ( pi_r.status().isLocked() )
-            return S_Taboo;
+          return( i.empty() ? S_AutoInstall : S_AutoUpdate );
+      }
 
-          // have identical installed? (maybe transacting):
-          PoolItem inst;
-          for_( it, _installedItems.begin(), _installedItems.end() )
-          {
-            if ( identical( *it, pi_r ) )
-            {
-              if ( (*it).status().transacts() )
-              {
-                inst = *it;
-                break;
-              }
-              if ( !inst )
-                inst = *it;
-            }
-          }
+      if ( ti )
+      {
+        return( ti.status().isByUser() ? S_Del : S_AutoDel );
+      }
+
+      for_( it, i.begin(), i.end() )
+        if ( it->status().isLocked() )
+          return S_Protected;
 
-          // check for inst/update
-          if ( pi_r.status().transacts() )
+      if ( i.empty() )
+      {
+        bool allALocked = true;
+        for_( it, a.begin(), a.end() )
+          if ( ! it->status().isLocked() )
           {
-            if ( inst )
-              return( pi_r.status().isByUser() ? S_Update : S_AutoUpdate );
-            else
-              return( pi_r.status().isByUser() ? S_Install : S_AutoInstall );
+            allALocked = false;
+            break;
           }
+        if ( allALocked )
+          return S_Taboo;
+      }
 
-          // no inst/update, so maybe delete?
-          if ( ! inst )
-            return  S_NoInst;
-
-          if ( inst.status().transacts() )
-            return( inst.status().isByUser() ? S_Del : S_AutoDel );
+      // KEEP state:
+      if ( ! i.empty() )
+        return S_KeepInstalled;
+      // Report pseudo installed items as installed, if they are satisfied.
+      if ( traits::isPseudoInstalled( kind() )
+           && ( ta ? ta : *a.begin() ).status().isSatisfied() ) // no installed, so we must have candidate
+        return S_KeepInstalled;
 
-          return S_KeepInstalled;
-        }
-      }
-      return Status(-1); // not my PoolItem
+      return S_NoInst;
     }
 
     ///////////////////////////////////////////////////////////////////