Imported Upstream version 14.45.0
[platform/upstream/libzypp.git] / zypp / pool / PoolImpl.h
index c24c12c..9c0aeb5 100644 (file)
 #include "zypp/base/Easy.h"
 #include "zypp/base/LogTools.h"
 #include "zypp/base/SerialNumber.h"
-#include "zypp/base/Deprecated.h"
+#include "zypp/APIConfig.h"
 
 #include "zypp/pool/PoolTraits.h"
 #include "zypp/ResPoolProxy.h"
+#include "zypp/PoolQueryResult.h"
 
 #include "zypp/sat/Pool.h"
+#include "zypp/Product.h"
 
 using std::endl;
 
 ///////////////////////////////////////////////////////////////////
 namespace zypp
 { /////////////////////////////////////////////////////////////////
+
+  namespace resstatus
+  {
+    /** Manipulator for \ref ResStatus::UserLockQueryField.
+     * Field is not public available. It is intended to remember the
+     * initial lock status usually derived from /etc/zypp/locks. So
+     * we are able to detect changes we have to write back on commit.
+    */
+    struct UserLockQueryManip
+    {
+      /** Set lock and UserLockQuery bit according to \c yesno_r. */
+      static void setLock( ResStatus & status_r, bool yesno_r )
+      {
+        status_r.setLock( yesno_r, ResStatus::USER );
+        status_r.setUserLockQueryMatch( yesno_r );
+      }
+
+      /** Update lock and UserLockQuery bit IFF the item gained the bit. */
+      static void reapplyLock( ResStatus & status_r, bool yesno_r )
+      {
+        if ( yesno_r && ! status_r.isUserLockQueryMatch() )
+        {
+          status_r.setLock( yesno_r, ResStatus::USER );
+          status_r.setUserLockQueryMatch( yesno_r );
+        }
+      }
+
+      /** Test whether the lock status differs from the remembered UserLockQuery bit. */
+      static int diffLock( const ResStatus & status_r )
+      {
+        bool userLock( status_r.isUserLocked() );
+        if ( userLock == status_r.isUserLockQueryMatch() )
+          return 0;
+        return userLock ? 1 : -1;
+      }
+
+    };
+  }
+
+  namespace
+  {
+    inline PoolQuery makeTrivialQuery( IdString ident_r )
+    {
+      sat::Solvable::SplitIdent ident( ident_r );
+
+      PoolQuery q;
+      q.addAttribute( sat::SolvAttr::name, ident.name().asString() );
+      q.addKind( ident.kind() );
+      q.setMatchExact();
+      q.setCaseSensitive(true);
+      return q;
+   }
+
+    inline bool hardLockQueriesRemove( pool::PoolTraits::HardLockQueries & activeLocks_r, IdString ident_r )
+    {
+      unsigned s( activeLocks_r.size() );
+      activeLocks_r.remove( makeTrivialQuery( ident_r ) );
+      return( activeLocks_r.size() != s );
+    }
+
+    inline bool hardLockQueriesAdd( pool::PoolTraits::HardLockQueries & activeLocks_r, IdString ident_r )
+    {
+      PoolQuery q( makeTrivialQuery( ident_r ) );
+      for_( it, activeLocks_r.begin(), activeLocks_r.end() )
+      {
+        if ( *it == q )
+          return false;
+      }
+      activeLocks_r.push_back( q );
+      return true;
+    }
+  }
+
   ///////////////////////////////////////////////////////////////////
   namespace pool
   { /////////////////////////////////////////////////////////////////
@@ -134,76 +209,94 @@ namespace zypp
         repository_iterator knownRepositoriesEnd() const
         { checkSerial(); return satpool().reposEnd(); }
 
+        Repository reposFind( const std::string & alias_r ) const
+        { checkSerial(); return satpool().reposFind( alias_r ); }
+
         ///////////////////////////////////////////////////////////////////
         //
         ///////////////////////////////////////////////////////////////////
       public:
-        bool hardLockAppliesTo( sat::Solvable solv_r ) const
-        {
-          return false;
-        }
-
-      public:
-        typedef PoolTraits::AutoSoftLocks          AutoSoftLocks;
-        typedef PoolTraits::autoSoftLocks_iterator autoSoftLocks_iterator;
+        typedef PoolTraits::HardLockQueries           HardLockQueries;
+        typedef PoolTraits::hardLockQueries_iterator  hardLockQueries_iterator;
 
-        const AutoSoftLocks & autoSoftLocks() const
-        { return _autoSoftLocks; }
+        const HardLockQueries & hardLockQueries() const
+        { return _hardLockQueries; }
 
-        bool autoSoftLockAppliesTo( sat::Solvable solv_r ) const
-        { return( _autoSoftLocks.find( solv_r.ident() ) != _autoSoftLocks.end() ); }
+        void reapplyHardLocks() const
+        {
+          // It is assumed that reapplyHardLocks is called after new
+          // items were added to the pool, but the _hardLockQueries
+          // did not change since. Action is to be performed only on
+          // those items that gained the bit in the UserLockQueryField.
+          MIL << "Re-apply " << _hardLockQueries.size() << " HardLockQueries" << endl;
+          PoolQueryResult locked;
+          for_( it, _hardLockQueries.begin(), _hardLockQueries.end() )
+          {
+            locked += *it;
+          }
+          MIL << "HardLockQueries match " << locked.size() << " Solvables." << endl;
+          for_( it, begin(), end() )
+          {
+            resstatus::UserLockQueryManip::reapplyLock( it->status(), locked.contains( *it ) );
+          }
+        }
 
-        void setAutoSoftLocks( const AutoSoftLocks & newLocks_r )
+        void setHardLockQueries( const HardLockQueries & newLocks_r )
         {
-          MIL << "Apply " << newLocks_r.size() << " AutoSoftLocks: " << newLocks_r << endl;
-          _autoSoftLocks = newLocks_r;
+          MIL << "Apply " << newLocks_r.size() << " HardLockQueries" << endl;
+          _hardLockQueries = newLocks_r;
           // now adjust the pool status
+          PoolQueryResult locked;
+          for_( it, _hardLockQueries.begin(), _hardLockQueries.end() )
+          {
+            locked += *it;
+          }
+          MIL << "HardLockQueries match " << locked.size() << " Solvables." << endl;
           for_( it, begin(), end() )
           {
-            if ( ! it->status().isKept() )
-              continue;
-
-            if ( newLocks_r.find( it->satSolvable().ident() ) != newLocks_r.end() )
-              it->status().setSoftLock( ResStatus::USER );
-            else
-              it->status().resetTransact( ResStatus::USER );
+            resstatus::UserLockQueryManip::setLock( it->status(), locked.contains( *it ) );
           }
         }
 
-        void getActiveSoftLocks( AutoSoftLocks & activeLocks_r )
+        bool getHardLockQueries( HardLockQueries & activeLocks_r )
         {
-          activeLocks_r = _autoSoftLocks; // currentsoft-locks
-          AutoSoftLocks todel;            // + names to be deleted
-          AutoSoftLocks toins;            // - names to be installed
-
+          activeLocks_r = _hardLockQueries; // current queries
+          // Now diff to the pool collecting names only.
+          // Thus added and removed locks are not necessarily
+          // disjoint. Added locks win.
+          typedef std::tr1::unordered_set<IdString> IdentSet;
+          IdentSet addedLocks;
+          IdentSet removedLocks;
           for_( it, begin(), end() )
           {
-            ResStatus & status( it->status() );
-            if ( ! status.isByUser() )
-              continue;
-
-            switch ( status.getTransactValue() )
+            switch ( resstatus::UserLockQueryManip::diffLock( it->status() ) )
             {
-              case ResStatus::KEEP_STATE:
-                activeLocks_r.insert( it->satSolvable().ident() );
-                break;
-              case ResStatus::LOCKED:
-                //  NOOP
+              case 0:  // unchanged
                 break;
-              case ResStatus::TRANSACT:
-                (status.isInstalled() ? todel : toins).insert( it->satSolvable().ident() );
+              case 1:
+                addedLocks.insert( it->satSolvable().ident() );
                 break;
+              case -1:
+                removedLocks.insert( it->satSolvable().ident() );
+               break;
             }
           }
-          for_( it, todel.begin(), todel.end() )
+          // now the bad part - adjust the queries
+          bool setChanged = false;
+          for_( it, removedLocks.begin(), removedLocks.end() )
           {
-            activeLocks_r.insert( *it );
+            if ( addedLocks.find( *it ) != addedLocks.end() )
+              continue; // Added locks win
+            if ( hardLockQueriesRemove( activeLocks_r, *it ) && ! setChanged )
+              setChanged = true;
           }
-          for_( it, toins.begin(), toins.end() )
+          for_( it, addedLocks.begin(), addedLocks.end() )
           {
-            activeLocks_r.erase( *it );
+            if ( hardLockQueriesAdd( activeLocks_r, *it ) && ! setChanged )
+              setChanged = true;
           }
-        }
+          return setChanged;
+       }
 
       public:
         const ContainerT & store() const
@@ -212,11 +305,10 @@ namespace zypp
           if ( _storeDirty )
           {
             sat::Pool pool( satpool() );
+            bool addedItems = false;
+            std::list<PoolItem> addedProducts;
 
-            if ( pool.capacity() != _store.capacity() )
-            {
-              _store.resize( pool.capacity() );
-            }
+           _store.resize( pool.capacity() );
 
             if ( pool.capacity() )
             {
@@ -233,19 +325,32 @@ namespace zypp
                 {
                   // new PoolItem to add
                   pi = PoolItem::makePoolItem( s ); // the only way to create a new one!
-                  // and a few checks...
-                  if ( hardLockAppliesTo( s ) )
-                  {
-                    pi.status().setLock( true, ResStatus::USER );
-                  }
-                  else if ( autoSoftLockAppliesTo( s ) )
-                  {
-                    pi.status().setSoftLock( ResStatus::USER );
-                  }
+                  // remember products for buddy processing (requires clean store)
+                  if ( s.isKind( ResKind::product ) )
+                    addedProducts.push_back( pi );
+                  if ( !addedItems )
+                    addedItems = true;
                 }
               }
             }
             _storeDirty = false;
+
+            // Now, as the pool is adjusted, ....
+
+            // .... we check for product buddies.
+            if ( ! addedProducts.empty() )
+            {
+              for_( it, addedProducts.begin(), addedProducts.end() )
+              {
+                it->setBuddy( asKind<Product>(*it)->referencePackage() );
+              }
+            }
+
+            // .... we must reapply those query based hard locks.
+            if ( addedItems )
+            {
+              reapplyHardLocks();
+            }
           }
           return _store;
         }
@@ -302,8 +407,8 @@ namespace zypp
         mutable shared_ptr<ResPoolProxy>      _poolProxy;
 
       private:
-        /** Set of solvable idents that should be soft locked per default. */
-        AutoSoftLocks                         _autoSoftLocks;
+        /** Set of queries that define hardlocks. */
+        HardLockQueries                       _hardLockQueries;
     };
     ///////////////////////////////////////////////////////////////////